diff --git a/coco/xreate.ATG b/coco/xreate.ATG index 6574680..c24f5bc 100644 --- a/coco/xreate.ATG +++ b/coco/xreate.ATG @@ -1,454 +1,515 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" #include #include #define wprintf(format, ...) \ char __buffer[100]; \ wcstombs(__buffer, format, 100); \ fprintf(stderr, __buffer, __VA_ARGS__) using namespace xreate; using namespace std; COMPILER Xreate xreate::AST root; // current program unit struct { std::stack scopesOld; xreate::CodeScope* scope = nullptr; } context; void pushContextScope(CodeScope* scope){ context.scopesOld.push(context.scope); context.scope = scope; } void popContextScope(){ context.scope = context.scopesOld.top(); context.scopesOld.pop(); } int skipIdent() { int kind = 0; scanner->ResetPeek(); while ((kind = scanner->Peek()->kind) == _colon) if (scanner->Peek()->kind != _ident) return 0; return kind; } bool checkParametersList() { return la->kind == _ident && skipIdent() == _lparen; } bool checkInfix() { return la->kind == _ident && skipIdent() == _ident; } bool checkIndex() { return la->kind == _ident && skipIdent() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int xkind = skipIdent(); Token* y = scanner->Peek(); - return xkind == _assign && y->kind == _function; + return xkind == _assign && (y->kind == _function || y->kind == _pre); } bool checkAssignment() { scanner->ResetPeek(); Token* x = scanner->Peek(); return la->kind == _ident && x->kind == _assign; } CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter | '_') {letter | digit | '_'}. number = digit {digit}. string = '"' { any } '"'. function = "function". + pre = "pre". lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. + lcurbrack = '{'. + rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. + context = "context". tagcolon = "::". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS -Xreate = { ( RuleDecl | InterfaceData | Imprt | IF(checkFuncDecl()) FDecl | TDecl ) }. +Xreate = (. Function* function; .) +{ ( RuleDecl | InterfaceData | Imprt | ContextSection + | IF(checkFuncDecl()) FDecl (. root.add(function); .) + | TDecl ) }. Ident = ident {':' ident} (. name = t->val; .). -FDecl<> = (. std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; .) -Ident assign function (. Function* f = new Function(fname); CodeScope* entry = f->getEntryScope(); .) -( Type (. f->setReturnType(typOut); .) -| '(' [Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn)); .) + +FDecl = (. std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; .) +Ident assign +[pre (. flagIsPrefunct = true; .)] +function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) + +['(' Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn)); .) {',' Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn));.) -}] ')' tagcolon Type (. f->setReturnType(typOut); .) -{';' FnTag } -) BDecl (. entry->__body.bindType(move(typOut)); root.add(f); .) +} ')'] + +[ tagcolon +( IF(flagIsPrefunct) FnTag + | Type (. f->setReturnType(typOut); .) +) +{';' FnTag }] +BDecl (. entry->__body.bindType(move(typOut));.) . +ContextSection<>= (. std::wstring context; Function* f; .) +"case" "context" tagcolon Ident +lcurbrack { FDecl (. root.add(f, context); .) +} rcurbrack. + /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ("string" | "int" | "num" | "float" | "bool") (. typ = Atom(t->val); .) . Type = (. TypeAnnotation typ2; TypeAtom typ3; std::wstring tid, field; .) ( TList | TStruct | TypeTerm (. typ = TypeAnnotation(typ3); .) |IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) {',' Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {',' Type (. typ.__operands.push_back(typ2); .) } ')'] ) . TList = (. TypeAnnotation ty; .) '[' Type (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) {',' Type (. typ.__operator = TypeOperator::TUPLE; typ.__operands.push_back(ty); .) }']' . TStruct = (. TypeAnnotation t; std::wstring field; .) '{' Ident tagcolon Type (. typ = TypeAnnotation(TypeOperator::STRUCT, {t}); typ.fields.push_back(Atom(field).get()); .) {',' Ident tagcolon Type} (. typ.__operands.push_back(t); typ.fields.push_back(Atom(field).get()); .) '}'. - TDecl = (. std::wstring ttag; TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) + TDecl = (. std::wstring ttag; TypeAnnotation t, t1; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ( "alias" Type (. root.add(move(t), Atom(tname)); .) + | "variant" lparen Ident (. t = TypeAnnotation(TypeOperator::VARIANT, {}); args.push_back(Atom(arg)); .) + {',' Ident (. args.push_back(Atom(arg)); .) + } rparen (. t.addFields(move(args)); root.add(move(t), Atom(tname)); .) + | Ident ['(' Ident (. args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } ')'] Type (. t.addBindings(move(args)); root.add(move(t), Atom(tname)); .) ) '.' . VDecl = (. std::wstring vname; Expression e; TypeAnnotation typ;.) Ident assign ExprTyped (. f->addDeclaration(move(vname), move(typ), move(e)); .) . +ContextDecl = (. Expression tag; .) +context tagcolon +MetaSimpExpr (. scope->tags.push_back(move(tag)); .) +{';' MetaSimpExpr (. scope->tags.push_back(move(tag)); .) +}. + +//TODO forbid multiple body declaration (ExprTyped) BDecl = (. Expression body; TypeAnnotation typ; pushContextScope(scope); .) -'{' { ( - IF(checkAssignment()) VDecl '.' - | ExprTyped (. scope->setBody(body);.) -)} (. popContextScope(); .) -'}'. +'{' { (RuleContextDecl | ContextDecl '.' + | IF(checkAssignment()) VDecl '.' + | ExprTyped (. scope->setBody(body); popContextScope();.) +)} '}'. IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(context.scope)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(context.scope)); TypeAnnotation typIf; .) "if" '(' Expr ')' tagcolon Type BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e = Expression(Operator::IF, {cond}); e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = - (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc; TypeAnnotation typEl, typAcc; + (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; TypeAnnotation typEl, typAcc; ManagedScpPtr block = root.add(new xreate::CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident tagcolon Type ')' tagcolon Type BDecl<&*block> (. e = Expression(Operator::MAP, {eIn}); e.addBindings({Atom(varEl)}); block->addArg(Atom(varEl), move(typEl)); e.addBlock(block); .) |"fold" '(' Expr implic Ident tagcolon Type ['|' Expr ] ',' Expr implic Ident tagcolon Type ')' tagcolon Type BDecl<&*block> (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); block->addArg(Atom(varEl), move(typEl)); block->addArg(Atom(varAcc), move(typAcc)); e.addBlock(block); .) + + | "context" '(' string (. contextClass = t->val; .) + ')' BDecl<&*block> + (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); + e.addBlock(block); + .) ). -SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); .) - // ["switch" [tagcolon Type {';' MetaSimpExpr}]] +SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) +["switch" + ("ad" "hoc" lparen Expr tagcolon MetaSimpExpr rparen (. eSwitch.op = Operator::SWITCH_ADHOC; eSwitch.operands.push_back(eCondition); eSwitch.tags.emplace(tag.getValueString(), move(tag)); .) + | lparen Expr rparen tagcolon Type (. eSwitch.operands.push_back(eCondition); eSwitch.type = typ; .) + ) +] CaseDecl {CaseDecl} . -CaseDecl = (. Expression inner(Operator::CASE, {}); - ManagedScpPtr scopeCond = root.add(new xreate::CodeScope(context.scope)); - ManagedScpPtr scopeBody = root.add(new xreate::CodeScope(&*scopeCond)); .) +CaseDecl = (. ManagedScpPtr scope = root.add(new xreate::CodeScope(context.scope)); .) "case" - ( "default" - | CaseParams<&*scopeCond> - ) + ( "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); + exprCase.addBlock(scope); + outer.operands.insert(++outer.operands.begin(), exprCase); .) - BDecl<&*scopeBody> (. inner.addBlock(scopeCond); inner.addBlock(scopeBody); outer.addArg(move(inner)); .) -. + | CaseParams<&*scope> (. ManagedScpPtr scopeBody = root.add(new xreate::CodeScope(&*scope)); .) + BDecl<&*scopeBody> (. Expression exprCase(Operator::CASE, {}); + exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) + ). CaseParams = (. Expression e; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) CaseParam - {',' CaseParam + {',' CaseParam } (. scope->setBody(guard); popContextScope(); .). CaseParam = (. TypeAnnotation argtyp; Expression condition; .) ( IF(checkAssignment()) VDecl | ExprTyped (. guard.addArg(move(condition)); .) ). /*============================ INTERFACES ===============================*/ Imprt<> = -"import" "raw" '(' string (. root.__rawImports.push_back(Atom(t->val).get()); .) -')' '.' . +"import" "raw" lparen string (. root.__rawImports.push_back(Atom(t->val).get()); .) +rparen . InterfaceData<> = "interface" '(' ( "dfa" ')' InterfaceDFA | "extern-c" ')' InterfaceExternC | "cfa" ')' InterfaceCFA - ). - + | "adhoc" ')' InterfaceAdhoc + + ). + +InterfaceAdhoc<> = + '{' [ PrefunctionSchemeDecl ] '}'. + +PrefunctionSchemeDecl<> = (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .) + pre function Ident tagcolon Type + '{' SwitchDecl '}' + (. Expression prefData(Operator::CALL, {Atom(prefName), exprCases}); + prefData.type = typReturn; + root.addInterfaceData(Adhoc, move(prefData)); + .). + + InterfaceExternC<> = (.xreate::ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root.addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = '{' { InstructDecl } '}' . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root.addDFAData(move(scheme)); .) '.'. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = '{' { InstructCFADecl } '}' . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] '.' (. root.addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) '(' Ident tagcolon Domain (. args.add(arg, typ); .) {',' Ident tagcolon Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] '{' RBody '}' . +/* - TODO use RGuard for guards-*/ +RuleContextDecl = (.Expression eHead, eGuards, eBody; .) +"rule" "context" tagcolon MetaSimpExpr +"case" MetaSimpExpr +'{' MetaSimpExpr '}' (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). + Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( '(' MetaExpr ')' | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) '(' [ CalleeParams ] ')' | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | Ident (. e = Expression(Atom(i1)); .) ). RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . - - - - /*============================ Expressions ===============================*/ + /*============================ Expressions ===============================*/ ExprTyped = (. Expression tag; .) Expr [tagcolon Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. e.tags.emplace(tag.getValueString(), move(tag)); .) }] . Expr< Expression& e> (. Operator op; Expression e2; .) = SimExpr< e> [ RelOp< op> SimExpr< e2> (. e = Expression(op, {e, e2}); .) ]. SimExpr< Expression& e> (. Operator op; Expression e2; .) = Term< e> { AddOp< op> Term< e2> (. e = Expression(op, {e, e2});.) }. Term< Expression& e> (. Operator op; Expression e2; .) = Factor< e> { MulOp< op> Factor< e2> (. e = Expression(op, {e, e2}); .) }. Factor< Expression& e> (. std::wstring name; TypeAnnotation typ; .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); .) '(' [CalleeParams] ')' |IF (checkIndex()) Ident lbrack CalleeParams rbrack (. e.setOp(Operator::INDEX); e.setValue({Atom(name)}); .) - | Ident< name> (. e = Expression(Atom(name)); .) + | Ident< name> (. e = Expression(Atom(name)); root.recognizeVariantIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl + | AdhocDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | '-' Factor< e> (. e = Expression(Operator::NEG, {e}); .) | '(' Expr ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; .) '{' Ident '=' Expr (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' Ident '=' Expr (.e.addArg(move(val)); keys.push_back(Atom(key)); .) } '}' (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) '[' [ Expr (. e.addArg(std::move(eFrom)); .) (".." Expr (. e.addArg(std::move(eTo)); e.setOp(Operator::LIST_RANGE); .) |{',' Expr (. e.addArg(std::move(eFrom)); .) } (. e.setOp(Operator::LIST); .) ) ] ']'. +AdhocDecl = (. Expression command; .) +"ad" "hoc" Expr (. e.setOp(Operator::ADHOC); e.addArg(std::move(command)); .). + CalleeParams = (. Expression e2; TypeAnnotation typ; .) ExprTyped (. e.addArg(std::move(e2)); .) {',' ExprTyped (. e.addArg(std::move(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | '<' (. op = Operator::LSS; .) | '>' (. op = Operator::GTR; .) ). END Xreate. diff --git a/config/default.json b/config/default.json index 7d03a30..ef2aff4 100644 --- a/config/default.json +++ b/config/default.json @@ -1,54 +1,56 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", - "scope": "bind_scope" + "scope": "bind_scope", + "scope_weak" : "bind_scope_weak" }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "default", + "template": "adhocs", "templates": { - "basic": "EntryFunction*", + "basic": "EntryFunction*", "default": "*-", "types": "Types*-", "containers": "Containers*-", "ast": "AST*", "non-containers": "*-Containers*", "log": "Logging*", - "clang": "ClangAPI*" + "clang": "ClangAPI*", "cfg": "CFG.*", "skip": "SkipDetection*", "raw-xml": "libxml2*", - "xml": "Xml.*" + "xml": "Xml.*", + "adhocs": "ExpressionSerializer.*:Adhoc.*:Context.*" } } } diff --git a/core/control-context.lp b/core/control-context.lp new file mode 100644 index 0000000..1c27c0f --- /dev/null +++ b/core/control-context.lp @@ -0,0 +1,27 @@ +%TODO context-dependent function specialization implemenetation(inline/...) + + % context propagation + +bind_scope_demand(Scope, Context):- bind_scope_demand(ScopeChild, Context), cfa_parent(ScopeChild, scope(Scope)). +bind_scope_demand(Scope, Context):- bind_function_demand(FnChild, Context), cfa_call(Scope, FnChild). +bind_function_demand(Fn, Context):- bind_scope_demand(ScopeChild, Context), cfa_parent(ScopeChild, function(Fn)). + +bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context), cfa_parent(Scope, scope(ScopeParent)). +bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context): cfa_call(ScopeParent, FnCurrent); cfa_call(_, FnCurrent) + , cfa_parent(Scope, function(FnCurrent)), bind_scope(_, Context), scope(Scope). + +bind_scope_weak(Scope, Context) :- bind_scope(Scope, Context), bind_scope_demand(Scope, Context). +bind_scope_weak(Scope, Context) :- cfa_parent(Scope, scope(ScopeParent)), bind_scope_weak(ScopeParent, Context), scope(Scope), scope(ScopeParent). +bind_scope_weak(Scope, Context) :- bind_scope_weak(ScopeParent, Context), + cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). + +% adhoc classes(unfinished): +%bind_func(Fn, adhoc_class(Context)) := bind_func(Fn, adhoc(Context)), bind_scope(Scope, Context), cfa_parent(Scope, function(Fn)). + +%scope_parent(Scope, ScopeParent) :- cfa_parent(Scope, scope(ScopeParent)). +%scope_parent(Scope, ScopeParent2) :- cfa_parent(Scope, scope(ScopeParent)), scope_parent(ScopeParent, ScopeParent2). + +%scope_function(Scope, Fn) :- cfa_parent(Scope, function(Fn)). +%scope_function(Scope, Fn) :- cfa_parent(Scope, scope(ScopeParent)), scope_function(ScopeParent, Fn). + + diff --git a/core/dependencies.lp b/core/dependencies.lp new file mode 100644 index 0000000..5dab87b --- /dev/null +++ b/core/dependencies.lp @@ -0,0 +1,9 @@ +node(a; b; c; d). +depends(b,a). +depends(c,a). +depends(d, a). +depends(d, c). + +level(X, 0) :- not depends(X, _); node(X). + +level(X, LEVEL):- LEVEL = #max{L+1, level(Y, L): level(Y, L), depends(X, Y)}; node(X); LEVEL > 0. diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 269bdff..9630011 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,149 +1,174 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) find_package(LLVM REQUIRED CONFIG) +# MACRO (ADD_PCH_RULE _header_filename _src_list) +# SET(_gch_filename "${_header_filename}.gch") +# LIST(APPEND ${_src_list} ${_gch_filename}) +# SET (_args ${CMAKE_CXX_FLAGS}) +# LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) +# GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) +# foreach (_inc ${DIRINC}) +# LIST(APPEND _args "-I" ${_inc}) +# endforeach(_inc ${DIRINC}) +# SEPARATE_ARGUMENTS(_args) +# add_custom_command(OUTPUT ${_gch_filename} +# COMMAND rm -f ${_gch_filename} +# COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} +# DEPENDS ${_header_filename}) +# ENDMACRO(ADD_PCH_RULE _header_filename _src_list) + +set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake-tools") +include(PCH_GCC4_v2) + set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) link_directories(${LLVM_LIBRARY_DIRS}) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) message ("MPATH:" ${CMAKE_MODULE_PATH}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") #find_package(Clang REQUIRED clangTooling libClang) set(CMAKE_BUILD_TYPE Debug) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS") set(POTASSCO_PATH "/opt/potassco/gringo" CACHE PATH "Path to gringo sources") set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) link_directories(${LIBCLASP_PATH}) FILE (GLOB TEST_FILES ./tests/*.cpp) message("TEST: " ${TEST_FILES}) set(SOURCE_FILES ${TEST_FILES} ./src/ast.cpp ./src/llvmlayer.cpp ./src/clasplayer.cpp #./src/main.cpp ./src/utils.cpp ./src/passmanager.cpp + ./src/pass/abstractpass.cpp ./src/pass/dfgpass.cpp ./src/pass/compilepass.cpp ./src/pass/cfgpass.cpp - ./src/pass/logging.cpp + ./src/pass/loggerpass.cpp + ./src/pass/adhocpass.cpp #./src/pass/rulespass.cpp - ./src/instructions/instr-containers.cpp + ./src/compilation/instr-containers.cpp + ./src/compilation/latecontext.cpp ./src/query/containers.cpp ./src/query/ptrvalid.cpp + ./src/query/context.cpp + ./src/attachments.cpp + ./src/contextrule.cpp + ./src/expressionserializer.cpp + #${POTASSCO_PATH}/app/shared/src/clingocontrol.cc #${POTASSCO_PATH}/app/pyclingo/src/clingo_lib.cc ) set(COCO_PATH ${CMAKE_HOME_DIRECTORY}/../coco/) set(COCO_SOURCE_FILES ${COCO_PATH}/Parser.h ${COCO_PATH}/Scanner.h ${COCO_PATH}/Parser.cpp ${COCO_PATH}/Scanner.cpp ) - - INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES(${COCO_PATH} ./src) INCLUDE_DIRECTORIES(${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ) include_directories(${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/) #execute_process(COMMAND ${COCO_PATH}/gen-xreate WORKING_DIRECTORY OUTPUT_VARIABLE COCO_OUTPUT) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) - -add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES} src/ExternLayer.cpp src/ExternLayer.h) +#add_definitions() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winvalid-pch -std=c++14 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0 -DWITH_THREADS=1") -set(COCO_TARGET grammar) +# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) +# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) +# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) +# ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) -add_custom_target(${COCO_TARGET} - WORKING_DIRECTORY ${COCO_PATH} -) - -add_custom_command(TARGET ${COCO_TARGET} - PRE_BUILD +add_custom_command(OUTPUT ${COCO_PATH}/Parser.cpp COMMAND ${COCO_PATH}/gen-grammar WORKING_DIRECTORY ${COCO_PATH} + DEPENDS ${COCO_PATH}/xreate.ATG ) +add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES} src/ExternLayer.cpp src/ExternLayer.h) + add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) message(STATUS "BINARY DIR" ${CMAKE_BINARY_DIR}) #add_dependencies(${PROJECT_NAME} coverageTarget) llvm_map_components_to_libnames(llvm_libs support core irreader all native nativecodegen) message(STATUS "LLVM LIBS: " ${llvm_libs}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify ) message(STATUS "CLANG LIBS: " ${CLANG_LIBS}) message(STATUS "CLASP LIBS: " ${LIBCLASP_LIBS}) -add_definitions(-DWITH_THREADS=1) + FUNCTION(PREPEND var prefix) SET(listVar "") FOREACH(f ${ARGN}) LIST(APPEND listVar "${prefix}/${f}") ENDFOREACH(f) SET(${var} "${listVar}" PARENT_SCOPE) ENDFUNCTION(PREPEND) find_package(GTest REQUIRED) INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0") - set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) - target_link_libraries(xreate ${GTEST_LIBRARIES} LLVM-${LLVM_VERSION} ${LIBCLASP_LIBS} ${CLANG_LIBS} pthread xml2 gcov tbb) +#set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") +#cotire(xreate) \ No newline at end of file diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index ea80e4b..2bebce2 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,642 +1,726 @@ #include "ast.h" #include "ExternLayer.h" #include #include #include using namespace std; namespace xreate{ class TypesResolver { private: const AST* ast; std::map scope; std::map signatures; ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()){ return TypesResolver(ast, scope, signatures)(t, args); } std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation& t){ return expandType(t); }); return pack; } public: TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), std::map signaturesOuter = std::map()) : ast(root), scope(scopeOuter), signatures(signaturesOuter) { } ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { - assert(args.size() == t.bindings.size()); // invalid number of arguments + //assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i=0; i elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, t.__size)); } case TypeOperator::STRUCT: { assert(t.__operands.size()); std::vector&& pack = expandOperands(t.__operands); auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack)); tnew.fields = t.fields; return ExpandedType(move(tnew)); }; case TypeOperator::CALL: { std::string alias = t.__valueCustom; //find in local scope: TypeAnnotation ty; if (scope.count(alias)) { ty = scope.at(alias); } else if (ast->__indexTypeAliases.count(alias)){ ty = ast->__indexTypeAliases.at(alias); } else { assert(false && "Undefined or external type"); } std::vector&& operands = expandOperands(t.__operands); TypeAnnotation signature(TypeOperator::CALL, move(operands)); signature.__valueCustom = alias; if (signatures.count(signature)) { auto link = TypeAnnotation(TypeOperator::LINK, {}); link.conjuctionId = signatures.at(signature); return ExpandedType(move(link)); } int cid = signatures.size(); signatures[signature] = cid; TypeAnnotation tyResult = expandType(ty, operands); tyResult.conjuctionId = cid; return ExpandedType(move(tyResult)); }; case TypeOperator::CUSTOM: { std::string alias = t.__valueCustom; /* if (signatures.count(alias)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures[alias].emplace(t); */ //find in local scope: if (scope.count(alias)) { return expandType(scope.at(alias)); } // find in general scope: if(ast->__indexTypeAliases.count(alias)) { return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); } //if type is unknown keep it as is. return ExpandedType(TypeAnnotation(t)); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; ExpandedType tyAlias= ExpandedType(TypeAnnotation()); //find in local scope: if (scope.count(alias)) { tyAlias = expandType(scope.at(alias)); //find in global scope: } else if((ast->__indexTypeAliases.count(alias))) { tyAlias = expandType(ast->__indexTypeAliases.at(alias)); } else { assert(false && "Undefined or external type"); } assert(tyAlias->__operator == TypeOperator::STRUCT); for (const string& field: t.fields){ auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); assert(fieldIt != tyAlias->fields.end() && "unknown field"); int fieldId = fieldIt - tyAlias->fields.begin(); tyAlias = expandType(tyAlias->__operands.at(fieldId)); } return tyAlias; } case TypeOperator::TUPLE: { assert(t.__operands.size()); std::vector pack; pack.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation& t){ return expandType(t); }); return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack))); } + case TypeOperator::VARIANT: { + return ExpandedType(TypeAnnotation(t)); + } + case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() { } TypeAnnotation::TypeAnnotation(const Atom &typ) : __value(typ.get()) { ; } TypeAnnotation::TypeAnnotation (TypePrimitive typ) : __value(typ) {} TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation (TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) {} TypeAnnotation::TypeAnnotation (llvm_array_tag, TypeAnnotation typ, int size) :TypeAnnotation(TypeOperator::ARRAY, {typ}) { __size=size; } bool TypeAnnotation::operator< (const TypeAnnotation& t) const{ if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS){ if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} */ void TypeAnnotation::addBindings(std::vector>&& params) { - bindings.reserve(params.size()); + bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident){return ident.get(); }); } +void +TypeAnnotation::addFields(std::vector>&& listFields) +{ + fields.reserve(fields.size() + listFields.size()); + + std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), + [](const Atom& ident){return ident.get(); }); +} + Expression::Expression(const Atom& number) : __state(NUMBER), op(Operator::NONE), __valueD(number.get()) { } Expression::Expression(const Atom& a) : __state(STRING), op(Operator::NONE), __valueS(a.get()) { } Expression::Expression(const Atom &ident) : __state(IDENT), op(Operator::NONE), __valueS(ident.get()) { - - if (ident.get() == "null") { - __state = NONE; - } } Expression::Expression(const Operator &oprt, std::initializer_list params) : __state(COMPOUND), op(oprt) { if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin()+1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::NONE: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation&& t) { type = t; } void Expression::addBlock(ManagedScpPtr scope) { blocks.push_back(scope.operator ->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v){ __valueS = v.get(); } -bool -Expression::isNone() const{ - return (op == Operator::NONE && __state == NONE); +void Expression::setValueDouble(double value){ + __valueD = value; } bool Expression::isValid() const{ return (__state != INVALID); } Expression::Expression() : __state(INVALID), op(Operator::NONE) {} AST::AST() { } void AST::addInterfaceData(const ASTInterface& interface, Expression&& data ) { __interfacesData.emplace(interface, move(data)); } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } void AST::addExternData(ExternData &&data) { __externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end()); } void AST::add(Function* f) { __functions.push_back(f); - __indexFunctions[f->getName()] = __functions.size()-1; + __indexFunctions.emplace(f->getName(), FunctionSpecialization{"", __functions.size()-1}); +} + +void +AST::add(Function* f, Atom && context){ + __functions.push_back(f); + __indexFunctions.emplace(f->getName(), FunctionSpecialization{context.get(), __functions.size()-1}); } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void AST::add(TypeAnnotation&& t, Atom&& alias){ + if (t.__operator == TypeOperator::VARIANT){ + for (int i=0, size=t.fields.size(); i< size; ++i){ + __dictVariants.emplace(t.fields[i], make_pair(t, i)); + } + } + __indexTypeAliases.emplace(alias.get(), t); } ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size()-1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr AST::findFunction(const std::string& name) { - if (! __indexFunctions.count(name)) { + int count = __indexFunctions.count(name); + if (!count) { return ManagedFnPtr::Invalid(); } - return ManagedPtr(__indexFunctions.at(name), &__functions); + + assert(count ==1); + + auto range = __indexFunctions.equal_range(name); + return ManagedPtr(range.first->second.id, &this->__functions); +} + +std::list +AST::getFunctionVariants(const std::string& name){ + 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.id, &this->__functions);}); + + return result; +} + +ManagedFnPtr +AST::findFunctionVariant(const std::string& name, const FunctionSpecializationQuery& query) { + boost::optional variant; + boost::optional variantDefault; + + auto functions = __indexFunctions.equal_range(name); + + for (AST::FUNCTIONS_REGISTRY::const_iterator function = functions.first; function != functions.second; ++function){ + const string& guard = function->second.guard; + if (guard.empty()){ + assert(!variantDefault); + variantDefault = function->second; + } + + if (query.context.count(guard)){ + assert(!variant); + variant = function->second; + } + } + + //Pickup default specialization if necessary + if (!variant){ + variant = variantDefault; + } + + if (variant) return ManagedPtr(variant->id, &__functions); + + //case of no appropriate variant found + assert(0 == std::distance(functions.first, functions.second)); + + //case of external functions + return ManagedFnPtr::Invalid(); } template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__functions);} template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__scopes);} template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__rules);} Expanded AST::expandType(const TypeAnnotation &t) const { return TypesResolver(this)(t); } Expanded AST::findType(const std::string& name){ // find in general scope: if(__indexTypeAliases.count(name)) return expandType(__indexTypeAliases.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::CUSTOM, {}); t.__valueCustom = name; return ExpandedType(move(t)); } +void +AST::recognizeVariantIdentifier(Expression& identifier){ + assert(identifier.__state == Expression::IDENT); + + std::string name = identifier.getValueString(); + if (__dictVariants.count(name)){ + auto record = __dictVariants.at(name); + const TypeAnnotation& typ = record.first; + + identifier.__state = Expression::VARIANT; + identifier.setValueDouble(record.second); + identifier.type = typ; + } +} + Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { __tags.emplace_back(tag, mod); } const std::vector& Function::getAnnotations() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void CodeScope::addArg(Atom && name, TypeAnnotation&& typ) { registerVar(std::move(const_cast(name.get())), std::move(typ)); __args.push_back(name.get()); } ; void Function::addArg(Atom && name, TypeAnnotation&& typ) { __entry->addArg(move(name), move(typ)); } void Function::setReturnType(const TypeAnnotation &rtyp) { __entry->__definitions[0] = rtyp; } const std::string& Function::getName() const { return __name; } CodeScope::CodeScope(CodeScope* parent) :__parent(parent) {} CodeScope::~CodeScope() {} VID CodeScope::registerVar(std::string&& name, TypeAnnotation &&typ) { __vartable[name] = ++__vCounter; __definitions[__vCounter] = typ; return __vCounter; } void CodeScope::addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body) { VID id = registerVar(std::move(const_cast(name.get())), move(typ)); __declarations[id] = body; } void CodeScope::setBody(const Expression &body) { __body = body; } TypeAnnotation& CodeScope::findDefinition(const Symbol& symbol) { CodeScope* self = symbol.scope; assert(self->__definitions.count(symbol.identifier)); return self->__definitions[symbol.identifier]; } +//TODO get rid of findSymbol. Determine symbol while AST parsing. Refind symbols not found while first pass. Symbol CodeScope::findSymbol(const std::string &name) { //search var in current block if (__vartable.count(name)) { VID vId = __vartable.at(name); Symbol result{vId, this}; return result; } //search in parent scope if (__parent) { return __parent->findSymbol(name); } //exception: Ident not found assert(false && "Symbol not found"); } - - bool CodeScope:: hasDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; return (self->__declarations.count(symbol.identifier)); } const Expression& CodeScope::findDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; if (! self->__declarations.count(symbol.identifier)) { // no declaration exists assert(false); } return self->__declarations[symbol.identifier]; } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) {} MetaRuleAbstract::~MetaRuleAbstract(){} RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) {} RuleWarning::~RuleWarning(){} void RuleWarning::compile(ClaspLayer& layer) { layer.addRuleWarning(*this); } bool operator< (const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope==s2.scope && s1.identifier #include #include #include #include #include #include #include "attachments.h" #include "utils.h" #include namespace llvm{ class Value; } namespace xreate { struct String_t{}; struct Identifier_t {}; struct Number_t {}; struct Type_t {}; template class Atom {}; //DEBT hold for all atoms/identifiers Parser::Token data, like line:col position template<> class Atom { public: Atom(const std::wstring& value) { char buffer[32]; wcstombs(buffer, value.c_str(), 32); __value = buffer; } Atom(std::string && name): __value(name) {} const std::string& get() const{return __value; } private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value) { __value = wcstol(value, 0, 10); } Atom(int value) : __value(value) {} double get()const {return __value; } private: double __value; }; template<> class Atom { public: - Atom(const std::wstring& value) - : __value(++value.begin(), --value.end()) - {} + Atom(const std::wstring& value){ + assert(value.size()); + __value = std::string(++value.begin(), --value.end()); + } const std::string& get() const {return __value; } private: std::string __value; }; enum class TypePrimitive {Bool, Int, Float, Num, String, I32, I8}; template<> class Atom { public: Atom(wchar_t* value) { char buffer_[32]; wcstombs(buffer_, value, 32); std::string buffer(buffer_); if (buffer=="bool"){ __value = TypePrimitive ::Bool; } else if (buffer=="int") { __value = TypePrimitive::Int; } else if (buffer=="float") { __value = TypePrimitive::Float; } else if (buffer=="num") { __value = TypePrimitive::Num; } else if (buffer=="string") { __value = TypePrimitive::String; } } Atom() { } TypePrimitive get() const { return __value; } private: TypePrimitive __value; }; typedef Atom TypeAtom; -enum class TypeOperator{NONE, CALL, CUSTOM, ARRAY, TUPLE, STRUCT, ACCESS, LINK}; +enum class TypeOperator{NONE, CALL, CUSTOM, VARIANT, ARRAY, TUPLE, STRUCT, ACCESS, LINK}; struct llvm_array_tag {}; struct struct_tag{}; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation (const Atom& typ); TypeAnnotation (TypePrimitive typ); TypeAnnotation (llvm_array_tag, TypeAnnotation typ, int size); TypeAnnotation (TypeOperator op, std::initializer_list operands); TypeAnnotation (TypeOperator op, std::vector&& operands); void addBindings(std::vector>&& params); + void addFields(std::vector>&& listFields); bool operator< (const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); TypeOperator __operator = TypeOperator::NONE; std::vector __operands; TypePrimitive __value; std::string __valueCustom; int conjuctionId=-1; //conjunction point id (relevant for recursive types) uint64_t __size = 0; std::vector fields; std::vector bindings; private: }; enum class Operator { -ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, LIST_RANGE, LIST_NAMED, CALL, NONE, IMPL/* implication */, MAP, FOLD, INDEX, IF, SWITCH, CASE, LOGIC_AND +ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, LIST_RANGE, LIST_NAMED, CALL, NONE, IMPL/* implication */, MAP, FOLD, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE }; 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() + inline unsigned int id() const { return __id; } private: unsigned int __id =0; const std::vector * __storage=0; }; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); struct Expression { friend class CodeScope; friend class ClaspLayer; friend class CFGPass; Expression(const Operator &oprt, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); Expression(const Atom& a); Expression(); void setOp(Operator oprt); void addArg(Expression&& arg); void addBindings(std::initializer_list> params); void bindType(TypeAnnotation&& t); template void addBindings(InputIt paramsBegin, InputIt paramsEnd); void addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; + void setValueDouble(double value); const std::string& getValueString() const; void setValue(const Atom&& v); - bool isNone() const; bool isValid() const; - enum {INVALID, COMPOUND, IDENT, NUMBER, STRING, NONE} __state = INVALID; + enum {INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT} __state = INVALID; Operator op; std::vector bindings; std::map __indexBindings; std::vector operands; TypeAnnotation type; std::map tags; std::list blocks; private: std::string __valueS; double __valueD; }; template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom){ std::string key = atom.get(); this->__indexBindings[key] = index++; return key; }); } typedef std::list ExpressionList; enum class TagModifier {NONE, ASSERT, REQUIRE}; enum class DomainAnnotation {FUNCTION, VARIABLE}; class RuleArguments: public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards: public std::vector { public: void add(Expression&& e); }; class ClaspLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(ClaspLayer& layer) =0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning: public MetaRuleAbstract { friend class ClaspLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(ClaspLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VID; /* class Expression: ExpressionAbstract { friend class CFGPass; public: llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; }; */ typedef std::pair VariableDefinition; typedef std::pair VariableDeclaration; typedef std::pair Tag; struct Symbol { VID identifier; CodeScope * scope; }; struct SymbolTags_t{}; template<> struct AttachmentsDict { typedef std::map Data; static const unsigned int key = 2; }; bool operator< (const Symbol& s1, const Symbol& s2); bool operator== (const Symbol& s1, const Symbol& s2); class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent=0); void setBody(const Expression& body); void addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body); void addArg(Atom && name, TypeAnnotation&& typ); //TODO exclude forceCompile partz Symbol findSymbol(const std::string &name); static const Expression& findDeclaration(const Symbol& symbol); static TypeAnnotation& findDefinition(const Symbol& symbol); static bool hasDeclaration(const Symbol& symbol); ~CodeScope(); std::vector __args; Expression __body; //TODO move __body to __declarations[0] SymbolAttachments attachments; std::map __vartable; /** * definition of return type has variable index Zero(0) */ //TODO move __definitions to SymbolsAttachments data std::unordered_map __definitions; std::unordered_map __declarations; + std::vector tags; + std::vector contextRules; protected: - - - VID __vCounter=1; CodeScope* __parent; std::list __storage; VID registerVar(std::string&& name, TypeAnnotation &&typ); }; class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); void addArg(Atom && name, TypeAnnotation&& typ); void addTag(Expression&& tag, const TagModifier mod); void setReturnType(const TypeAnnotation& rtyp); const std::string& getName() const; const std::vector& getAnnotations() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; + bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag + + Expression guardContext; private: std::vector __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; enum ASTInterface { - CFA, DFA, Extern + CFA, DFA, Extern, Adhoc +}; + +struct FunctionSpecialization { + std::string guard; + size_t id; +}; + +struct FunctionSpecializationQuery { + std::unordered_set context; }; class AST { public: AST(); //TASK extern and DFA interfaces move into addINterfaceData /** * DFA Interface */ void addDFAData(Expression&& data); /** * Extern Interface */ void addExternData(ExternData&& data); void addInterfaceData(const ASTInterface& interface, Expression&& data ); void add(Function* f); + void add(Function* f, Atom && context); + void add(MetaRuleAbstract* r); ManagedScpPtr add(CodeScope* scope); std::string getModuleName(); ManagedPtr findFunction(const std::string& name); + typedef std::multimap FUNCTIONS_REGISTRY; + std::list> getAllFunctions(); + template ManagedPtr begin(); std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; - std::map __indexFunctions; + FUNCTIONS_REGISTRY __indexFunctions; // ***** TYPES SECTION ***** public: std::map __indexTypeAliases; ExpandedType expandType(const TypeAnnotation &t) const; ExpandedType findType(const std::string& name); void add(TypeAnnotation&& t, Atom&& alias); +void recognizeVariantIdentifier(Expression& identifier); + private: +std::map> __dictVariants; ExpandedType expandType(const TypeAnnotation &t, std::map scope, const std::vector &args = std::vector()) const; // ***** TYPES SECTION END ***** }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } #endif // AST_H diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp index c074c43..adc4701 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,623 +1,670 @@ #include "clasplayer.h" #include #include "utils.h" #include #include #include using namespace std; namespace xreate { void ClaspLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsRange = __model.equal_range(warningTag); for (auto warning=warningsRange.first; warning!= warningsRange.second; ++warning) { unsigned int warningId; Gringo::Value params; std::tie(warningId, params) = parse(warning->second); cout << "Warning: " << __warnings.at(warningId) << " "; params.print(out); out< warnings; cout << "Model: " << endl; const string& atomBindVar = Config::get("clasp.bindings.variable"); const string& atomBindFunc = Config::get("clasp.bindings.function"); + const string& atomBindScope = Config::get("clasp.bindings.scope"); for (Gringo::Value atom : model.atoms(Gringo::Model::ATOMS)) { atom.print(cout); cout <<" | "<< endl; - if (*atom.name() == atomBindVar || *atom.name() == atomBindFunc){ + if (*atom.name() == atomBindVar || *atom.name() == atomBindFunc || *atom.name() == atomBindScope){ string name = *std::get<1>(parse(atom)).name(); __model.emplace(move(name), move(atom)); - continue; } __model.emplace(*atom.name(), move(atom)); } return true; } list multiplyLists(list> &&lists) { typedef list StringList; assert(lists.size()); StringList result(*lists.begin()); lists.pop_front(); boost::format concat("%s, %s"); for (StringList &list: lists) { StringList::const_iterator end = result.end(); for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { if (list.size() == 0) continue; StringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) result.push_back(str(concat %(*expr1I) %(*expr2I))); *expr1I = str(concat %(*expr1I) %(*expr2I)); } } return result; } void ClaspLayer::setCFAData(CFAGraph &&graph) { cfagraph = graph; } void ClaspLayer::addDFAData(DFAGraph &&graph) { dfaData = graph; std::set symbols; ostream &cout = __partGeneral; cout << endl << "%\t\tStatic analysis: DFA" << endl; std::vector>::iterator i1; std::vector::iterator i2; boost::format formatDfaConnection("dfa_connection(%1%, %2%, %3%)."); boost::format format2Args("(%1%, %2%)"); for (i1= dfaData.__edges.begin(), i2 = dfaData.__data.begin(); i1!= dfaData.__edges.end(); ++i1, ++i2 ) { string edgeName; switch (*i2) { case DFGConnection::OPT: edgeName = "opt"; break; case DFGConnection::ALIAS: edgeName = "alias"; break; case DFGConnection::PROTO: edgeName = "proto"; break; } cout << formatDfaConnection %(format2Args %(i1->first.identifier) %(i1->first.scope)).str() %(format2Args %(i1->second.identifier) %(i1->second.scope)).str() %edgeName << " %" <first) << " - " << getHintForPackedSymbol(i1->second) <first); symbols.insert(i1->second); } boost::format formatBind("bind(%1%, %2%)."); for (const pair& tag: dfaData.__tags) { for (string variant: compile(tag.second)) { cout << (formatBind % (format2Args %(tag.first.identifier) %(tag.first.scope)) % (variant)) << "%" << getHintForPackedSymbol(tag.first) << endl; } symbols.insert(tag.first); } for (const SymbolPacked& s: symbols) { cout << "v(" << format2Args % (s.identifier) % (s.scope) << ")." << " %" << getHintForPackedSymbol(s) < tagRaw = compile(tag.first); assert(tagRaw.size() == 1); cout << formatBind - % (atomBinding) % (function.second) % (tagRaw.front()) << endl; ++counterTags; } } if (counterTags == 0) { cout << "%no tags at all" << endl; } - //show scope tags: + //declare scopes boost::format formatScope("scope(%1%)."); for (auto scope: __indexScopes) { //std::string function = scope.first. cout << formatScope % scope.second << std::endl; } + //show context rules: + for (auto rule: cfagraph.__contextRules) { + cout << ContextRule(rule.second).compile(rule.first) << std::endl; + }; + + //show scope tags: counterTags = 0; - boost::format formatScopeBind("%1%(%2%, %3%)."); + boost::format formatScopeBind(atomBindingScope + "(%1%, %2%)."); for (auto entry: cfagraph.__scopeTags) { ScopePacked scopeId = entry.first; const Expression& tag = entry.second; list tagRaw = compile(tag); assert(tagRaw.size() == 1); - cout << formatScopeBind % atomBindingScope % scopeId %(tagRaw.front()) << endl; + cout << formatScopeBind % scopeId %(tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { - cout << "%no tags at all" << endl; + cout << "%scope tags: no tags at all" << endl; } cout << endl << "%\t\tStatic analysis: CFA" << endl; - boost::format formatCall("call(%1%, %2%)."); - for (const auto &relation: cfagraph.__relations) { + //parent connections + //TEST CFG parent function + boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); + for (const auto &relation: cfagraph.__parentFunctionRelations) { + const string& function = cfagraph.__nodesFunction.left.at(relation.second); + + cout << formatFunctionParent % relation.first % function << endl; + } + + //TEST CFG parent scope + boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); + for (const auto &relation: cfagraph.__parentScopeRelations) { + cout << formatScopeParent % relation.first % relation.second << endl; + } + + //call connections + boost::format formatCall("cfa_call(%1%, %2%)."); + + for (const auto &relation: cfagraph.__callRelations) { const ScopePacked scopeFrom = relation.first; const string& functionTo = cfagraph.__nodesFunction.left.at(relation.second); cout << formatCall % (scopeFrom) % (functionTo) << endl; } } void ClaspLayer::addRuleWarning(const RuleWarning &rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { return compile(guard); }); const list& guards = multiplyLists(std::move(guardsRaw)); list &&branches = compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); for (const string &guardsJoined: guards) for (const string &branch: branches) { unsigned int hook = registerWarning(string(rule.__message)); __partGeneral << formatWarning %(hook) %(boost::algorithm::join(vars, ", ")) %(branch) %(guardsJoined) %(boost::algorithm::join(domains, ", ")) < - ClaspLayer::compile(const Expression &e) const { + ClaspLayer::compile(const Expression &e){ list result; switch (e.op) { case Operator::CALL: { assert(e.__state == Expression::COMPOUND); std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), - [this](const Expression &e) { - return compile(e); + [](const Expression &e) { + return ClaspLayer::compile(e); }); list &&operands_ = multiplyLists(std::move(operands)); result.push_back(boost::str(boost::format("%1%(%2%)") % (e.__valueS) % (boost::algorithm::join(operands_, ", ")))); break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back((boost::format("not %1%")%(rawOp.front())).str()); break; }; case Operator::NONE: { switch (e.__state) { case Expression::IDENT: result.push_back(e.__valueS); break; case Expression::NUMBER: result.push_back(to_string(e.__valueD)); break; default: assert(true); } break; } default: break; } - if (e.isNone()){ - result.push_back(e.__valueS); - } +//TODO Null ad hoc ClaspLayer implementation +// if (e.isNone()){ +// result.push_back(e.__valueS); +// } assert(result.size()); return result; } std::list - ClaspLayer::compileNeg(const Expression &e) const { + ClaspLayer::compileNeg(const Expression &e){ list result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); list operands1 = compile(e.operands.at(0)); list operands2 = compile(e.operands.at(1)); boost::format formatNeg("%1%, not %2%"); for (const auto &op1: operands1) for (const auto &op2: operands2) { result.push_back(boost::str(formatNeg %(op1) % (op2))); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back(rawOp.front()); break; }; default: assert(true); } return result; } unsigned int ClaspLayer::registerWarning(std::string &&message) { static int warningId = 0; __warnings.emplace(warningId, message); return warningId++;; } void ClaspLayer::involveImports() { ostream &out = __partGeneral; for (string fn: ast->__rawImports) { std::ifstream file(fn); if (!file) continue; while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void ClaspLayer::addRawScript(std::string&& script){ __partGeneral << script; } void ClaspLayer::run() { involveImports(); involveCFAData(); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data()); ctl.add("base", {}, program.str()); ctl.ground({{"base", {}}}, nullptr); // solve Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { this->onModel(model); return true; }, {}); if (result == Gringo::SolveResult::SAT) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } // invoke all query plugins to process clasp data - for (IQuery* q: __queries) + for (auto q: __queries) { - q->init(this); + q.second->init(this); } } ClaspLayer::ClaspLayer() { } ClaspLayer::ModelFragment ClaspLayer::query(const std::string& atom) { if (! __model.count(atom)){ return boost::none; } return ModelFragment(__model.equal_range(atom)); } ScopePacked ClaspLayer::pack(CodeScope* scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); if (pos.second) __registryScopes.push_back(scope); return pos.first->second; } SymbolPacked ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result; result.scope = pack(symbol.scope); result.identifier = symbol.identifier; __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } Symbol ClaspLayer::unpack(const SymbolPacked& symbol) { return Symbol{symbol.identifier, __registryScopes[symbol.scope]}; }; std::string ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ auto result = __indexSymbolNameHints.find(symbol); return (result == __indexSymbolNameHints.end())? "" : result->second; } /* void AspOutPrinter::reportSolution(const Clasp::Solver&, const Clasp::Enumerator&, bool complete) { if (complete) std::cout << "No more models!" << std::endl; else std::cout << "More models possible!" << std::endl; } void AspOutPrinter::reportModel(const Clasp::Solver& s, const Clasp::Enumerator&) { std::cout << "Model " << s.stats.solve.models << ": \n"; // get the symbol table from the solver const Clasp::AtomIndex& symTab = *s.strategies().symTab; for (Clasp::AtomIndex::const_iterator it = symTab.begin(); it != symTab.end(); ++it) { // print each named atom that is true w.r.t the current assignment } std::cout << std::endl; } */ /***************************************** * CFAGraph ***************************************** */ void - CFAGraph::addFunctionNodeTags(const std::string& function, const std::vector&tags) { + CFAGraph::addFunctionAnnotations(const std::string& function, const std::vector&tags) { unsigned int fid = registerNodeFunction(function); for (Tag tag: tags){ __functionTags.emplace(fid, tag); } } void - CFAGraph::addScopeNodeTags(const ScopePacked& scope, const std::vector& tags){ + CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags){ for (Expression tag: tags){ __scopeTags.emplace(scope, tag); } } void - CFAGraph::addLink(const ScopePacked& scopeFrom, const std::string& functionTo) { + CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules){ + for (Expression rule: rules){ + __contextRules.emplace(scope, rule); + } + } + + void + CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { unsigned int idFuncTo = registerNodeFunction(functionTo); - __relations.emplace(scopeFrom, idFuncTo); + __callRelations.emplace(scopeFrom, idFuncTo); + } + + void + CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){ + __parentFunctionRelations.emplace(scope, registerNodeFunction(functionParent)); + } + + void + CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){ + __parentScopeRelations.emplace(scope, scopeParent); } unsigned int CFAGraph::registerNodeFunction(const std::string& fname){ auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); return pos.first->first; } /***************************************** * DFAGraph ***************************************** */ class VisitorAddTag: public boost::static_visitor<> { public: void operator()(const SymbolPacked& symbol){ __graph->__tags.emplace(symbol, move(__tag)); } void operator()(SymbolTransient& symbol){ symbol.tags.push_back(move(__tag)); } void operator()(const SymbolInvalid& symbol){ assert(false && "Undefined behaviour"); } VisitorAddTag(DFAGraph* const dfagraph, Expression&& tag): __graph(dfagraph), __tag(tag) {} private: DFAGraph* const __graph; Expression __tag; }; class VisitorAddLink: public boost::static_visitor<> { public: void operator()(const SymbolPacked& nodeFrom){ - if (!__graph->linkExists(__nodeTo, nodeFrom)) + if (!__graph->isConnected(__nodeTo, nodeFrom)) { __graph->__edges.emplace_back(__nodeTo, nodeFrom); __graph->__data.push_back(__link); DFAGraph::EdgeId eid = __graph->__edges.size()-1; __graph->__outEdges.emplace(nodeFrom, eid); } } void operator()(const SymbolTransient& symbolFrom){ if (__link != DFGConnection::ALIAS){ assert(false && "Undefined behaviour"); } for (const Expression& tag: symbolFrom.tags){ __graph->__tags.emplace(__nodeTo, tag); } } void operator()(const SymbolInvalid&){ if (__link == DFGConnection::ALIAS) return; if (__link == DFGConnection::OPT) return; assert(false && "Undefined behaviour"); } VisitorAddLink(DFAGraph* const dfagraph, const SymbolPacked& nodeTo, DFGConnection link): __graph(dfagraph), __nodeTo(nodeTo), __link(link) {} private: DFAGraph* const __graph; SymbolPacked __nodeTo; DFGConnection __link; }; bool - DFAGraph::linkExists(const SymbolPacked& node1, const SymbolPacked& node2) + DFAGraph::isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom) { - auto range = __outEdges.equal_range(node2); + auto range = __outEdges.equal_range(identifierFrom); for(std::multimap::iterator edge = range.first; edge != range.second; ++edge) { - if (__edges[edge->second].second == node1) + if (__edges[edge->second].second == identifierTo) return true; } return false; } void - DFAGraph::addLink(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { + DFAGraph::addConnection(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { VisitorAddLink visitor(this, nodeTo, link); boost::apply_visitor(visitor, nodeFrom); } void - DFAGraph::addTag(SymbolNode& node, Expression&& tag) { + DFAGraph::addAnnotation(SymbolNode& node, Expression&& tag) { VisitorAddTag visitor(this, move(tag)); boost::apply_visitor(visitor, node); } bool operator==(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.identifier == s2.identifier && s1.scope == s2.scope; } bool operator<(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } - void ClaspLayer::registerdQuery(IQuery *query) { - __queries.push_back(query); + IQuery* + ClaspLayer::registerQuery(IQuery *query, const QueryId& id) { + return __queries.emplace(id, query).first->second; + } + + IQuery* + ClaspLayer::getQuery(const QueryId& id){ + assert(__queries.count(id) && "Undefined query"); + return __queries.at(id); } } diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index c89196a..2e208d3 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,202 +1,239 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H -#include +#include "ast.h" +#include "contextrule.h" #include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; class CFAGraph { friend class ClaspLayer; public: - void addFunctionNodeTags(const std::string& function, const std::vector&tags); - void addScopeNodeTags(const ScopePacked& scope, const std::vector&tags); - void addLink(const ScopePacked& scopeFrom, const std::string& functionTo); - //void print(std::ostream &cout) const; + void addFunctionAnnotations(const std::string& function, const std::vector&tags); + void addScopeAnnotations(const ScopePacked& scope, const std::vector&tags); + void addContextRules(const ScopePacked& scope, const std::vector&rules); + + void addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo); + void addParentConnection(const ScopePacked& scope, const std::string& functionParent); + void addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent); +// void addScopeRetIdentifier(const ScopePacked& scope, const SymbolPacked& identifier); private: - std::map __relations; + std::map __parentFunctionRelations; + std::map __parentScopeRelations; + std::multimap __callRelations; boost::bimap __nodesFunction; std::multimap __functionTags; std::multimap __scopeTags; + std::multimap __contextRules; unsigned int registerNodeFunction(const std::string& fname); }; struct SymbolPacked { VID identifier; ScopePacked scope; }; struct SymbolTransient{ std::list tags; }; struct SymbolInvalid{}; typedef boost::variant SymbolNode; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); enum class DFGConnection{ ALIAS, OPT, PROTO}; class VisitorAddTag; class VisitorAddLink; class DFAGraph { friend class ClaspLayer; friend class VisitorAddTag; friend class VisitorAddLink; public: - void addTag(SymbolNode& node, Expression&& tag); - void addLink(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link); - bool linkExists(const SymbolPacked& node1, const SymbolPacked& node2); + void addAnnotation(SymbolNode& identifier, Expression&& tag); + void addConnection(const SymbolPacked& identifierTo, const SymbolNode& identifierFrom, DFGConnection link); + bool isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom); private: typedef unsigned int EdgeId; std::vector> __edges; std::multimap __outEdges; std::vector __data; std::multimap __tags; }; class IQuery { public: virtual void init(ClaspLayer* clasp)=0; virtual ~IQuery() {} }; + enum class QueryId{ + ContainersQuery, + ContextQuery, + PtrvalidQuery + }; + class ClaspLayer { + friend class ContextRule; public: AST *ast; DFAGraph dfaData; CFAGraph cfagraph; ClaspLayer(); - void registerdQuery(IQuery* query); + IQuery* registerQuery(IQuery* query, const QueryId& id); + IQuery* getQuery(const QueryId& id); void addFunctionTags(const std::string &function, const std::vector &tags); void setCFAData(CFAGraph &&graph); void addDFAData(DFAGraph &&graph); void addRuleWarning(const RuleWarning &rule); void run(); template static std::tuple parse(const Gringo::Value& atom); typedef std::multimap::const_iterator ModelIterator; typedef boost::optional> ModelFragment; ModelFragment query(const std::string& atom); ScopePacked pack(CodeScope* scope); SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName=""); Symbol unpack(const SymbolPacked& symbol); std::string getHintForPackedSymbol(const SymbolPacked& symbol); void addRawScript(std::string&& script); + private: // all query plugins to process clasp data - std::list __queries; + std::map __queries; std::multimap __model; std::map __warnings; std::ostringstream __partTags; std::ostringstream __partGeneral; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; void printWarnings(std::ostream& out); bool onModel(Gringo::Model const &model); - std::list compile(const Expression &e) const; - std::list compileNeg(const Expression &e) const; + static std::list compile(const Expression &e); + static std::list compileNeg(const Expression &e); unsigned int registerWarning(std::string &&message); void involveImports(); void involveCFAData(); - - }; template struct ParseImplAtom { static typ get(const Gringo::Value& atom) { return atom.num(); } }; template<> struct ParseImplAtom { static std::string get(const Gringo::Value& atom) { return *atom.string(); }}; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Value& atom) { auto result = ClaspLayer::parse(atom); return SymbolPacked{std::get<0>(result), std::get<1>(result)}; }}; template<> struct ParseImplAtom { static Gringo::Value get(const Gringo::Value& atom) { return atom; }}; + template<> + struct ParseImplAtom { + static Expression get(const Gringo::Value& atom) + { + switch (atom.type()){ + case Gringo::Value::NUM: return Expression(atom.num()); + case Gringo::Value::ID: return Expression((std::string(atom.string()))); + case Gringo::Value::FUNC: { + Expression result(Operator::CALL, {Expression(std::string(atom.name()))}); + for(const Gringo::Value& arg: atom.args()){ + result.addArg(ParseImplAtom::get(arg)); + } + + return result; + } + + default: { + assert(false); + } + } + }}; + template struct Parse_Impl { static void parse(Tuple& tup, Gringo::FWValVec::const_iterator arg) { const size_t tupleSize = std::tuple_size::value; typedef typename std::tuple_element::type ElType; ElType& el = std::get(tup); Gringo::Value atom = *arg; el = ParseImplAtom::get(atom); Parse_Impl::parse(tup, ++arg); } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::FWValVec::const_iterator arg) {} }; template std::tuple ClaspLayer::parse(const Gringo::Value& atom) { typedef std::tuple Tuple; Tuple tup; Parse_Impl::value>::parse(tup, atom.args().begin()); return tup; } } #endif diff --git a/cpp/src/instructions/instr-containers.cpp b/cpp/src/compilation/instr-containers.cpp similarity index 83% rename from cpp/src/instructions/instr-containers.cpp rename to cpp/src/compilation/instr-containers.cpp index 793aec7..38192a0 100644 --- a/cpp/src/instructions/instr-containers.cpp +++ b/cpp/src/compilation/instr-containers.cpp @@ -1,501 +1,575 @@ #include "instr-containers.h" #include "llvmlayer.h" #include "ast.h" +#include "query/context.h" #include "query/containers.h" #include "query/ptrvalid.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ CompilePass::CodeScopeUnit* scope = context.scope; \ - CompilePass::FunctionUnit* function = context.function; \ + CompilePass::FunctionUnit* function = context.function; Instructions::Instructions(CompilePass::Context ctx) : context(ctx), tyNum (static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) {} llvm::Value* Instructions::compileMapSolid(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT //initialization std::string varIn = expr.getOperands()[0].getValueString(); Symbol symbolIn = scope->scope->findSymbol(varIn); ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list size_t size = implIn.size; CodeScope* scopeLoop = expr.blocks.front(); std::string varEl = scopeLoop->__args[0]; Iterator* it = Iterator::create(context, symbolIn); llvm::Value *rangeFrom = it->begin(); llvm::Value *rangeTo = it->end(); //definitions ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); llvm::IRBuilder<> &builder = llvm->builder; llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", function->raw); llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postloop", function->raw); Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); // * initial check Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); // create PHI: builder.SetInsertPoint(blockLoop); llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // loop body: Value* elIn = it->get(stateLoop, varEl); CompilePass::CodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop,llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, blockLoop); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* Instructions::compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); //TODO find out symbol identifier in order to name it in raw llvm; llvm::Value* data = scope->compileSymbol(dataSymbol); const Expression& decl = CodeScope::findDeclaration(dataSymbol); if (decl.op == Operator::LIST) { assert(indexes.size() == 1); return llvm->builder.CreateExtractElement(data, indexes[0], NAME("el")); } indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); Value *pEl = llvm->builder.CreateGEP(data, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* Instructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx){ EXPAND_CONTEXT UNUSED(scope); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i=0, size = fields.size(); i refs; llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::ConstantInt* zero = llvm::ConstantInt::get(tyInt, 0, false); llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); // safety check: not null ptr Symbol s; if (! QueryPtrValid::assertValidPtr(s)){ PointerType* tyAggr = dyn_cast(aggregate->getType()); llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); llvm->builder.CreateCondBr(condNull, blockSafe, blockException); llvm->initExceptionBlock(blockException); } llvm->builder.SetInsertPoint(blockSafe); std::vector indexes; //dereference pointer if (types.isPointer(t)){ indexes.push_back(zero); } indexes.push_back(ConstantInt::get(tyInt, i)); Value* addr = llvm->builder.CreateGEP(aggregate, indexes); return llvm->builder.CreateLoad(addr); } } assert(false && "not found required struct field"); } llvm::Value* Instructions::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = scope->scope->findSymbol(fold.getOperands()[0].getValueString()); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeFrom = it->begin(); llvm::Value* rangeTo = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; llvm::Value* valSat = nullptr; bool flagHasSaturation = false; //false; // TODO add `saturation` ann. llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", function->raw); llvm::BasicBlock *blockEarly = llvm::BasicBlock::Create(llvm::getGlobalContext(), "earlyret", function->raw); // * initial check Value* condBefore = llvm->builder.CreateICmpNE(rangeFrom, rangeTo); llvm->builder.CreateCondBr(condBefore, blockLoop, blockEarly); llvm->builder.SetInsertPoint(blockEarly); llvm->builder.CreateRet(accumInit); //TODO implement saturation; add unittests; // Saturation check if (flagHasSaturation) { Value* condSat = llvm->builder.CreateICmpNE(accumInit, valSat); llvm->builder.CreateCondBr(condSat, blockLoop, blockAfterLoop); } // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(tyNum, 2, NAME("accum")); accum->addIncoming(accumInit, blockBeforeLoop); llvm::PHINode *stateLoop = llvm->builder.CreatePHI(rangeFrom->getType(), 2, "foldIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); CompilePass::CodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); Value* elIn = it->get(stateLoop); loopUnit->bindArg(accum, move(varAccum)); loopUnit->bindArg(elIn, move(varEl)); Value* accumNext = loopUnit->compile(); // * break checks, continue checks if (flagHasSaturation) { llvm::BasicBlock *blockChecks = llvm::BasicBlock::Create(llvm::getGlobalContext(), "checks", function->raw); Value* condSat = llvm->builder.CreateICmpNE(accumNext, valSat); llvm->builder.CreateCondBr(condSat, blockChecks, blockAfterLoop); llvm->builder.SetInsertPoint(blockChecks); } // * computing next iteration state Value *stateLoopNext = it->move(stateLoop); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); stateLoop->addIncoming(stateLoopNext, llvm->builder.GetInsertBlock()); // * next iteration checks Value* condAfter = llvm->builder.CreateICmpNE(stateLoopNext, rangeTo); llvm->builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accum; } +llvm::Value* +Instructions::compileLoopContext(const Expression& expression, const std::string& hintRetVar){ + EXPAND_CONTEXT + llvm::IRBuilder<>& builder = llvm->builder; + + ContextQuery* queryContext = reinterpret_cast (context.pass->man->clasp->getQuery(QueryId::ContextQuery)); + + ScopePacked scopeOuterId = context.pass->man->clasp->pack(scope->scope); + std::list contextScopeOuter = queryContext->getContext(scopeOuterId); + std::string classSelected = expression.operands[0].getValueString(); + + std::list elementsSelected; + for (const Expression& c: contextScopeOuter){ + if (c.op == Operator::CALL && c.getValueString() == classSelected){ + assert(c.operands.size()); + elementsSelected.push_back(c.operands[0]); + } + } + + assert(expression.blocks.size()); + CodeScope* scopeInner = expression.blocks.front(); + CompilePass::CodeScopeUnit* scopeInnerUnit = function->getScopeUnit(scopeInner); + ScopePacked scopeInnerId = context.pass->man->clasp->pack(scopeInner); + + llvm::Value* result = nullptr; + for (const Expression& element: elementsSelected){ + std::string blockName = "context" + element.getValueString(); + llvm::BasicBlock *blockInner = llvm::BasicBlock::Create(llvm::getGlobalContext(), blockName, function->raw); + builder.CreateBr(blockInner); + builder.SetInsertPoint(blockInner); + + queryContext->forceContext(scopeInnerId, {element}); + scopeInnerUnit->reset(); + result = scopeInnerUnit->compile(); + } + + return result; +} + llvm::Value* Instructions::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT //initialization: const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockAfter); llvm::PHINode *ret = builder.CreatePHI(tyNum, 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } //TODO implement switch llvm::Value* Instructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar){ EXPAND_CONTEXT UNUSED(scope); UNUSED(function); - UNUSED(llvm); - return nullptr; - //llvm::IRBuilder<>& builder = llvm->builder; - //builder.CreateSwitch() + assert(exprSwitch.operands.size() >= 2); + assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT); + int countCases = exprSwitch.operands.size()-1; + llvm::IRBuilder<>& builder = llvm->builder; + + llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); + builder.SetInsertPoint(blockEpilog); + llvm::Type* exprSwitchType = llvm->toLLVMType(ExpandedType(exprSwitch.type)); + llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); + + builder.SetInsertPoint(blockProlog); + llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); + llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); + llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); + + for (int size = exprSwitch.operands.size(), i=2; iraw); + + llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); + builder.SetInsertPoint(blockCase); + llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); + builder.CreateBr(blockEpilog); + + ret->addIncoming(resultCase, builder.GetInsertBlock()); + builder.SetInsertPoint(blockProlog); + instructionSwitch->addCase(dyn_cast(condCase), blockCase); + } + + //compile default block: + builder.SetInsertPoint(blockDefault); + CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); + llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); + builder.CreateBr(blockEpilog); + ret->addIncoming(resultDefault, builder.GetInsertBlock()); + builder.SetInsertPoint(blockEpilog); + + return ret; } llvm::Value* Instructions::compileConstantArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); const size_t& __size = expr.getOperands().size(); const Expression& __data = expr; ArrayType* typList = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I32, __size)))); Type*typI32 = llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::I32))); std::vector list; list.reserve(__size); const std::vector operands = __data.getOperands(); std::transform(operands.begin(), operands.end(), std::inserter(list, list.begin()), [typI32](const Expression& e){return ConstantInt::get(typI32, e.getValueDouble());}); Value* listSource = ConstantArray::get(typList, ArrayRef(list)); /* Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); */ return listSource; } llvm::Value* Instructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data); Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } template class IteratorForward; template<> class IteratorForward : public Iterator { private: LLVMLayer* llvm; const xreate::Symbol current; const Symbol source; const ImplementationLinkedList linkedlist; CodeScope* const sourceScope; //TODO initialize ans mark as const (three fields) CompilePass::CodeScopeUnit* sourceUnit; CompilePass::FunctionUnit* function; //TODO is used somewhere? const Expression& sourceDecl; CompilePass::Context context; llvm::Type* sourceRawType =nullptr; public: IteratorForward(CompilePass::Context ctx, const xreate::Symbol& s, const ImplementationRec& implementation) : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), sourceUnit(new CompilePass::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), sourceDecl(CodeScope::findDeclaration(source)), context(ctx) { } llvm::Value* begin() { switch(sourceDecl.op) { case xreate::Operator::LIST: { sourceRawType = Type::getInt32Ty(llvm::getGlobalContext()); return ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); }; case xreate::Operator::LIST_RANGE:{ assert(sourceDecl.operands.size()==2); llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); sourceRawType = result->getType(); return result; }; default: break; } if (linkedlist){ llvm::Value* result = sourceUnit->process(sourceDecl); sourceRawType = result->getType(); return result; } assert(false); } llvm::Value* end(){ switch(sourceDecl.op) { case xreate::Operator::LIST: { size_t idLast = sourceDecl.operands.size() - 1; return ConstantInt::get(sourceRawType, idLast); } case xreate::Operator::LIST_RANGE: { assert(sourceDecl.operands.size() == 2); return sourceUnit->process(sourceDecl.operands.at(1)); }; default: break; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* get(Value* index,const std::string& hintRetVar="") override{ const Expression& currentDecl = CodeScope::findDeclaration(current); switch (currentDecl.op) { case xreate::Operator::LIST: { //TODO re check is it right scope(source) to compilation currentDecl. Write unittests for this. //llvm::Value* currentValue = sourceUnit->process(currentDecl); return Instructions(context).compileArrayIndex(current, vector{index}); }; case xreate::Operator::LIST_RANGE: { return index; }; case xreate::Operator::MAP: { assert(currentDecl.getOperands().size()==1); assert(currentDecl.bindings.size()); assert(currentDecl.blocks.size()); CodeScope* scopeLoop = currentDecl.blocks.front(); const std::string& varIn = currentDecl.getOperands()[0].getValueString(); std::string varEl = currentDecl.bindings[0]; const Symbol& symbIn = current.scope->findSymbol(varIn); auto it = std::unique_ptr(Iterator::create(context, symbIn)); Value* elIn = it->get(index, varEl); CompilePass::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(elIn, std::move(varEl)); return unitLoop->compile(); } case xreate::Operator::NONE: { assert(currentDecl.__state==Expression::IDENT); const Symbol& symbIn = current.scope->findSymbol(currentDecl.getValueString()); auto it = std::unique_ptr(Iterator::create(context, symbIn)); return it->get(index); }; default: break; } if (linkedlist){ return index; } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* move(Value* index, const std::string& hintRetVar) override{ switch(sourceDecl.op) { case xreate::Operator::LIST: case xreate::Operator::LIST_RANGE: return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); default: break; } if (linkedlist){ ExpandedType tySource = llvm->ast->expandType(sourceScope->findDefinition(source)); assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); return Instructions(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } assert(false && "Unknown declaration"); return nullptr; } }; Iterator* Iterator::create(CompilePass::Context context, const Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(context, var, data.extract()); default: assert(true); } assert(false && "Unknown declaration"); return nullptr; } diff --git a/cpp/src/instructions/instr-containers.h b/cpp/src/compilation/instr-containers.h similarity index 93% rename from cpp/src/instructions/instr-containers.h rename to cpp/src/compilation/instr-containers.h index 9465d35..5651085 100644 --- a/cpp/src/instructions/instr-containers.h +++ b/cpp/src/compilation/instr-containers.h @@ -1,86 +1,87 @@ #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "llvmlayer.h" #include "ast.h" #include #include #include "pass/compilepass.h" namespace xreate { namespace containers { class Iterator{ public : virtual llvm::Value* begin() =0; virtual llvm::Value* end() = 0; virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0; virtual llvm::Value* move(llvm::Value* index, const std::string& hintRetVar="")=0; virtual ~Iterator(){}; static Iterator* create(CompilePass::Context context, const Symbol& var); }; class Instructions { public: Instructions(CompilePass::Context ctx); llvm::Value* compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string ident = ""); llvm::Value* compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx); /* * - map Computation -> Llvm_Array: Prohibited, we do not know a result size * - map Llvm_Array -> Computation: considered in `compileGetElement` * - map Llvm_Array -> Llvm_Array considered by this method */ - llvm::Value*compileMapSolid(const Expression &expr, const std::string hintRetVar = ""); + llvm::Value* compileMapSolid(const Expression &expr, const std::string hintRetVar = ""); llvm::Value* compileFold(const Expression& fold, const std::string& ident=""); + llvm::Value* compileLoopContext(const Expression& expression, const std::string& hintRetVar); llvm::Value* compileIf(const Expression& exprIf, const std::string& ident); llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar); llvm::Value* compileConstantStringAsPChar(const string &data, const std::string& hintRetVar); llvm::Value* compileConstantArray(const Expression &expr, const std::string& hintRetVar=""); private: CompilePass::Context context; llvm::IntegerType* const tyNum; }; }} #endif //CODEINSTRUCTIONS_H /* template struct InstructionClasses {}; template<> struct InstructionClasses { typedef InstructionList Impl; }; template<> struct InstructionClasses { typedef InstructionMap Impl; }; template class CodeInstruction: public InstructionClasses::Impl { typedef typename InstructionClasses::Impl InstructionImpl; public: CodeInstruction(CodeScope* parent) : InstructionImpl(parent) {} llvm::Value * compileExpression(const Expression &expr, LLVMLayer &l, const std::string * const hintRetVar) { if (expr.op == Instruction) return InstructionImpl::compileDefault(expr, l, hintRetVar); return CodeScope::compileExpression(expr, l, hintRetVar); } }; } */ diff --git a/cpp/src/compilation/latecontext.cpp b/cpp/src/compilation/latecontext.cpp new file mode 100644 index 0000000..9269b4a --- /dev/null +++ b/cpp/src/compilation/latecontext.cpp @@ -0,0 +1,151 @@ +/* + * LateContext.cpp + * + * Created on: Jan 8, 2016 + * Author: pgess + */ + +#include "pass/compilepass.h" +#include "compilation/latecontext.h" +#include "query/context.h" +#include "llvmlayer.h" + +namespace xreate { + +LateContext::LateContext(const std::string& function, CompilePass* compilePass) + : pass(compilePass), domain(&compilePass->queryContext->getFunctionDomain(function)) +{} + +LateContext::~LateContext() +{} + +llvm::Value* +LateContext::compileCheckContext(const Expression& e){ +// llvm::Value* environment; +// LLVMLayer* llvm; +// +// PackedExpression rep = __context.pack(e); +// assert(storage.count(rep)); +// +// size_t id = storage.at(rep); +// //TODO determine short name of expression +// return llvm->builder.CreateExtractElement(environment, id, NAME("checkContext"+e.getValueString())); + + return nullptr; +} + +llvm::Value* +LateContext::findFunction(const std::string name, ScopePacked scopeOuter, llvm::Function* functionOuter){ + LLVMLayer* llvm = pass->man->llvm; + ContextQuery* queryContext = pass->queryContext; + const FunctionSpecializations& specializations = queryContext->getFunctionSpecializations(name); + + //check external function + if (!specializations.size()){ + return nullptr; + } + + const std::list& context = queryContext->getContext(scopeOuter); + + boost::optional variant; + for(const Expression& c: context){ + if (specializations.count(c)){ + assert(!variant); + variant = specializations.at(c); + } + } + + if (variant) { + return pass->getFunctionUnit(*variant)->compile();// RETURN compiled function unit + } + + //require default variant if no appropriate static context exists + assert(specializations.count(Expression())); + llvm::Value* funcDefault = pass->getFunctionUnit(specializations.at(Expression()))->compile(); + + //choose default variant if no late context exists + if (!domain->size()) { + return funcDefault; + } + + //RUNTIME PART + llvm::BasicBlock *blockCurrent = llvm->builder.GetInsertBlock(); + llvm::BasicBlock *blockEnd = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ContextDeterminationEnd", functionOuter); + + llvm->builder.SetInsertPoint(blockEnd); + llvm::Type* tyFuncCallee = funcDefault->getType(); + llvm::PHINode *ret = llvm->builder.CreatePHI(tyFuncCallee, domain->size(), "callee"); + + + //check runtime context + for (const Expression& c: *domain){ + if (specializations.count(c)){ + ///if (domain[c]) return specialization.at(c) else + llvm->builder.SetInsertPoint(blockCurrent); + llvm::Value* cond; + llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ContextDeterminationNext", functionOuter); + llvm->builder.CreateCondBr(cond, blockEnd, blockNext); + ret->addIncoming(pass->getFunctionUnit(specializations.at(c))->compile(), blockCurrent); + blockCurrent = blockNext; + } + } + + //check default variant in runtime + llvm->builder.SetInsertPoint(blockCurrent); + llvm->builder.CreateBr(blockEnd); + ret->addIncoming(funcDefault, blockCurrent); + + llvm->builder.SetInsertPoint(blockEnd); + return ret; +} + +llvm::Value* +LateContext::compileArgument(const std::string& callee, ScopePacked scopeOuter){ + LLVMLayer* llvm = pass->man->llvm; + + std::unordered_set indexContextStatic; + list listContextStatic = pass->queryContext->getContext(scopeOuter); + const ContextDomain* calleeDomain = &pass->queryContext->getFunctionDomain(callee); + + llvm::Type* tyBool = llvm::Type::getInt1Ty(llvm::getGlobalContext()); + llvm::Type* tyInt32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + + llvm::Value* result = llvm->builder.CreateAlloca(tyBool, llvm::ConstantInt::get(tyInt32, calleeDomain->size())); + llvm::Value* valueTrue = llvm::ConstantInt::get(tyBool, 1); + llvm::Value* valueFalse = llvm::ConstantInt::get(tyBool, 0); + + for (const Expression& e: listContextStatic){ + auto i = calleeDomain->getExpressionId(e); + if (i){ + result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, *i), valueTrue); + indexContextStatic.insert(*i); + } + } + + for (size_t i=0, size=calleeDomain->size(); iget(i); + if (indexContextStatic.count(i)) + continue; + + auto posPrev = domain->getExpressionId(e); + if (posPrev){ + llvm::Value* element = llvm->builder.CreateExtractElement(raw, llvm::ConstantInt::get(tyInt32, *posPrev)); + result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, i), element); + continue; + } + + result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, i), valueFalse); + } + + return result; +} + +//void +//LateContext::set(const Expression& e){ +// PackedExpression representation = __context.pack(e); +// +// assert(__context.count(representation) == 0); +// __context.emplace(move(representation), __context.size()); +//} + +} /* namespace xreate */ diff --git a/cpp/src/compilation/latecontext.h b/cpp/src/compilation/latecontext.h new file mode 100644 index 0000000..2ccfe41 --- /dev/null +++ b/cpp/src/compilation/latecontext.h @@ -0,0 +1,43 @@ +/* + * LateContext.h + * + * Created on: Jan 8, 2016 + * Author: pgess + */ + +#ifndef SRC_COMPILATION_LATECONTEXT_H_ +#define SRC_COMPILATION_LATECONTEXT_H_ + +#include "ast.h" +#include "expressionserializer.h" + +namespace llvm { + class Value; +} + +namespace xreate { +typedef unsigned int ScopePacked; + +class CompilePass; +class ContextDomain; + +class LateContext{ + +public: + LateContext(const std::string& function, CompilePass* compilePass); + ~LateContext(); + + llvm::Value* compileCheckContext(const Expression& e); + llvm::Value* compileArgument(const std::string& callee, ScopePacked scopeOuter); + llvm::Value* findFunction(const std::string name, ScopePacked scopeOuter, llvm::Function* functionOuter); + + const ContextDomain* const domain; + llvm::Value* raw; + +private: + CompilePass* pass; +}; + +} /* namespace xreate */ + +#endif /* SRC_COMPILATION_LATECONTEXT_H_ */ diff --git a/cpp/src/contextrule.cpp b/cpp/src/contextrule.cpp new file mode 100644 index 0000000..cea1272 --- /dev/null +++ b/cpp/src/contextrule.cpp @@ -0,0 +1,52 @@ +/* + * contextrule.cpp + * + * Created on: Jan 2, 2016 + * Author: pgess + */ + +#include "contextrule.h" +#include "clasplayer.h" + +#include + +using namespace xreate; +using namespace std; + +ContextRule::ContextRule(const Expression& rule) { + assert(rule.op == Operator::CONTEXT_RULE); + assert(rule.operands.size() == 3); + + head = rule.operands.at(0); + guards = rule.operands.at(1); + body = rule.operands.at(2); +} + +std::string +ContextRule::compile(const ScopePacked& scopeId) const{ + + const string prolog = + " %context rule visibility implemenetation\n" + " context_rule_visibility(X, Y) :- X=Y, scope(X), scope(Y).\n" + " context_rule_visibility(X, Y) :- cfa_parent(X, scope(Y)), scope(X), scope(Y)."; + + listrepHead_ = ClaspLayer::compile(head); + assert(repHead_.size() == 1); + + listrepGuards_ = ClaspLayer::compile(guards); + assert(repGuards_.size() == 1); + + listrepBody_ = ClaspLayer::compile(body); + assert(repBody_.size() == 1); + + const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); + boost::format formatContextVisibility("context_rule_visibility(ScopeX, %1%)"); + boost::format formatScopeBind(atomBindingScope + "(ScopeX, %1%)"); + + const string& repHead = str(formatScopeBind % repHead_.front()); + const string& repGuards = str(formatScopeBind % repGuards_.front()); + const string& repVisibility = str(formatContextVisibility % scopeId); + + boost::format formatRule("%1%:- %2%, %3%, %4%."); + return prolog + str(formatRule % repHead % repGuards % repBody_.front() % repVisibility); +} diff --git a/cpp/src/contextrule.h b/cpp/src/contextrule.h new file mode 100644 index 0000000..7d06e3b --- /dev/null +++ b/cpp/src/contextrule.h @@ -0,0 +1,30 @@ +/* + * contextrule.h + * + * Created on: Jan 2, 2016 + * Author: pgess + */ + +#ifndef SRC_CONTEXTRULE_H_ +#define SRC_CONTEXTRULE_H_ + +#include "ast.h" +#include + +namespace xreate { + +typedef unsigned int ScopePacked; + +class ContextRule { + public: + ContextRule(const Expression& rule); + std::string compile(const ScopePacked& scopeId) const; + + private: + Expression head; + Expression guards; + Expression body; +}; +} + +#endif /* SRC_CONTEXTRULE_H_ */ diff --git a/cpp/src/expressionserializer.cpp b/cpp/src/expressionserializer.cpp new file mode 100644 index 0000000..34d67c2 --- /dev/null +++ b/cpp/src/expressionserializer.cpp @@ -0,0 +1,231 @@ +/* + * expressionserializer.cpp + * + * Created on: Jan 4, 2016 + * Author: pgess + */ + +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost::bimaps; +namespace xreate { + +struct Index { + string name; + size_t degree; //count of parameters + unsigned char level; //level in expression tree (depth of tree layer) + + bool operator< (const Index other) const{ + if (name != other.name) return name < other.name; + if (degree != other.degree) return degree < other.degree; + if (name != other.name) return level < other.level; + return false; + } +}; + +class ExpressionSerializerPrivate { + boost::bimap> __registry; + map __range; + +public: + void pack(const Expression& e, unsigned char level, OptionalPackedExpression& target){ + if (!target) return; + + switch (e.op){ + case Operator::NONE: { + switch (e.__state) { + case Expression::STRING: + case Expression::IDENT: { + Index index{e.getValueString(), 0, level}; + if (!__registry.left.count(index)){ + target = boost::none; + return; + } + + size_t id = __registry.left.at(index); + size_t range = __range[level]; + (*target) << make_pair(id, range); + return; + } + default: break; + } + break; + } + + case Operator::CALL: { + Index index{e.getValueString(), e.operands.size(), level}; + if(__registry.left.count(index)){ + target = boost::none; + return; + } + + size_t id = __registry.left.at(index); + size_t range = __range[level]; + (*target) << make_pair(id, range); + + for (const Expression& operand: e.operands){ + pack(operand, level+1, target); + } + return; + } + default: break; + } + + assert(false && "Expression too complicate for serialization"); + } + + void registerExpression(const Expression&e, unsigned char level){ + switch (e.op){ + case Operator::CALL: { + Index index{e.getValueString(), e.operands.size(), level}; + if (__registry.left.insert(make_pair(index, __range[level])).second){ + __range[level]++; + } + + for (const Expression& operand: e.operands){ + registerExpression(operand, level+1); + } + return; + } + + case Operator::NONE: { + switch (e.__state) { + case Expression::STRING: + case Expression::IDENT: { + Index index{e.getValueString(), 0, level}; + if (__registry.left.insert(make_pair(index, __range[level])).second){ + __range[level]++; + } + return; + } + default: break; + } + break; + } + + default: break; + } + + assert(false && "Expression too complicate for serialization"); + } +}; + +ExpressionSerializer::ExpressionSerializer() + : strategy(new ExpressionSerializerPrivate()){ +} + +ExpressionSerializer::~ExpressionSerializer() { + delete strategy; +} + +void +ExpressionSerializer::registerExpression(const Expression&e){ + strategy->registerExpression(e, 0); +} + +PackedExpression +ExpressionSerializer::pack(const Expression& e){ + OptionalPackedExpression result; + strategy->pack(e, 0, result); + assert(result); + return move(*result); +} + +OptionalPackedExpression +ExpressionSerializer::packOptional(const Expression& e) const{ + OptionalPackedExpression result; + strategy->pack(e, 0, result); + return result; +} + +void +PackedExpression::operator<< (const std::pair& value){ + static const size_t sizeSizeT = sizeof(size_t); + + const size_t& id = value.first; + const size_t& range = value.second; + + int countSufficientBits = range <=1? 0 : ceil(log2(range)); + + if (0 < countRemainedBits && countRemainedBits < countSufficientBits) { + size_t* tail = reinterpret_cast(__storage + size- sizeSizeT); + (*tail) += id >> (countSufficientBits - countRemainedBits); + countSufficientBits-=countRemainedBits; + countRemainedBits = 0; + } + + if (countRemainedBits == 0) { + if (countSufficientBits == 0) return; + + char* __storageNew = new char[size+sizeSizeT]; + std::memcpy (__storageNew, __storage, size); + std::memset(__storageNew + size, 0, sizeSizeT); + + delete[] __storage; + __storage = __storageNew; + + size += sizeSizeT; + countRemainedBits = 8 * sizeSizeT; + } + + if (countRemainedBits >= countSufficientBits) { + size_t* tail = reinterpret_cast(__storage + size- sizeSizeT); + (*tail) += id << (countRemainedBits - countSufficientBits); + countRemainedBits -= countSufficientBits; + return; + } + + assert("Unreachable block"); +} + +PackedExpression::PackedExpression(PackedExpression&& other){ + __storage = other.__storage; + size = other.size; + countRemainedBits = other.countRemainedBits; + + other.__storage = nullptr; +} + +bool +PackedExpression::operator==(const PackedExpression& other) const{ + if (size == other.size && countRemainedBits == other.countRemainedBits){ + return std::memcmp(__storage, other.__storage, size) == 0 ; + } + + return false; +} + +bool +PackedExpression::operator<(const PackedExpression& other) const{ + if (size < other.size) { return true; } + if (countRemainedBits < other.countRemainedBits) return true; + + if (size == other.size && countRemainedBits == other.countRemainedBits){ + return std::memcmp(__storage, other.__storage, size) < 0 ; + } + + return false; +} + +bool +PackedExpression::operator!=(const PackedExpression& other) const{ + return ! ((*this) == other); +} + +PackedExpression::~PackedExpression() { + delete[] __storage; +} + +//PackedExpression::PackedExpression (const PackedExpression& other) +// : size(other.size), countRemainedBits(other.countRemainedBits) +//{ +// __storage = new char[size]; +// std::memcpy (__storage, other.__storage, size); +//} + +} /* namespace xreate */ diff --git a/cpp/src/expressionserializer.h b/cpp/src/expressionserializer.h new file mode 100644 index 0000000..910fca9 --- /dev/null +++ b/cpp/src/expressionserializer.h @@ -0,0 +1,56 @@ +/* + * expressionserializer.h + * + * Created on: Jan 4, 2016 + * Author: pgess + */ + +#ifndef SRC_EXPRESSIONSERIALIZER_H_ +#define SRC_EXPRESSIONSERIALIZER_H_ + +#include "ast.h" +#include +#include + +namespace xreate { + +struct PackedExpression{ + PackedExpression(){}; + PackedExpression(PackedExpression&& other); + ~PackedExpression(); + void operator<< (const std::pair& value); + char* operator*(){return __storage;} + bool operator==(const PackedExpression& other) const; + bool operator!=(const PackedExpression& other) const; + bool operator<(const PackedExpression& other) const; + private: + PackedExpression (const PackedExpression&)=delete; + PackedExpression& operator=(const PackedExpression&)=delete; + PackedExpression& operator=(PackedExpression&&)=delete; + + char* __storage = nullptr; + size_t size =0; + unsigned char countRemainedBits =0; +}; +typedef boost::optional OptionalPackedExpression; + +class ExpressionSerializerPrivate; + +class ExpressionSerializer { +public: + ExpressionSerializer(); + ~ExpressionSerializer(); + ExpressionSerializer(ExpressionSerializer&& other) + : strategy(other.strategy), registry(std::move(other.registry)) {} + void registerExpression(const Expression&e); + PackedExpression pack(const Expression& e); + OptionalPackedExpression packOptional(const Expression& e) const; + +private: + ExpressionSerializerPrivate* strategy; + std::map registry; +}; + +} /* namespace xreate */ + +#endif /* SRC_EXPRESSIONSERIALIZER_H_ */ diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 0e34bb4..ca7ce01 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,246 +1,255 @@ #include "ast.h" #include "llvmlayer.h" #include "ExternLayer.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetSelect.h" #include +#include using namespace llvm; using namespace xreate; using namespace std; LLVMLayer::LLVMLayer(AST* root) : ast(root), builder(getGlobalContext()) { module = new llvm::Module(root->getModuleName(), llvm::getGlobalContext()); layerExtern = new ExternLayer(this); layerExtern->init(root); } void* LLVMLayer::getFunctionPointer(llvm::Function* function){ uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); return (void*) entryAddr; } void LLVMLayer::initJit(){ std::string ErrStr; LLVMInitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::EngineBuilder builder((std::unique_ptr(module))); jit = builder .setEngineKind(llvm::EngineKind::JIT) .setErrorStr(&ErrStr) .setVerifyModules(true) .create(); } void LLVMLayer::print(){ llvm::PassManager PM; PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); PM.run(*module); } llvm::BasicBlock* LLVMLayer::initExceptionBlock(llvm::BasicBlock* blockException){ initExceptionsSupport(); PointerType* tyInt8P = PointerType::getInt8PtrTy(llvm::getGlobalContext()); Value* nullInt8P = llvm::ConstantPointerNull::get(tyInt8P); builder.SetInsertPoint(blockException); llvm::Function* fAllocate = module->getFunction("__cxa_allocate_exception"); llvm::Function* fThrow = module->getFunction("__cxa_throw"); auto exception = builder.CreateCall(fAllocate, ConstantInt::get(IntegerType::getInt64Ty(getGlobalContext()), 4)); vector throwParams{exception, nullInt8P, nullInt8P}; builder.CreateCall(fThrow, ArrayRef(throwParams)); builder.CreateUnreachable(); return blockException; } void LLVMLayer::moveToGarbage(void *o) { __garbage.push_back(o); } llvm::Type* LLVMLayer:: toLLVMType(const ExpandedType& ty) const { std::map empty; return toLLVMType(ty, empty); } llvm::Type* LLVMLayer:: toLLVMType(const ExpandedType& ty, std::map& conjuctions) const { TypeAnnotation t = ty; switch (t.__operator) { case TypeOperator::ARRAY: { assert(t.__operands.size()==1); TypeAnnotation elTy = t.__operands.at(0); return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); } case TypeOperator::STRUCT: case TypeOperator::TUPLE: { assert(t.__operands.size()); std::vector pack_; pack_.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), [this, &conjuctions](const TypeAnnotation& t){ return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); }); llvm::ArrayRef pack(pack_); //process recursive types: if (conjuctions.count(t.conjuctionId)) { auto result = conjuctions[t.conjuctionId]; result->setBody(pack, false); return result; } return llvm::StructType::get(llvm::getGlobalContext(), pack, false); }; case TypeOperator::LINK: { llvm::StructType* conjuction = llvm::StructType::create(llvm::getGlobalContext()); int id = t.conjuctionId; conjuctions.emplace(id, conjuction); return conjuction; }; case TypeOperator::CALL: { assert(false); }; case TypeOperator::CUSTOM: { //Look in extern types clang::QualType qt = layerExtern->lookupType(t.__valueCustom); return layerExtern->toLLVMType(qt); }; + case TypeOperator::VARIANT: { + int size = t.fields.size(); + assert(size); + + int bitcount = ceil(log2(size)); + return llvm::Type::getIntNTy(llvm::getGlobalContext(), bitcount); + } + case TypeOperator::NONE: { switch (t.__value) { case TypePrimitive::Bool: return llvm::Type::getInt1Ty(llvm::getGlobalContext()); case TypePrimitive::I32: case TypePrimitive::Int: case TypePrimitive::Num: return llvm::Type::getInt32Ty(llvm::getGlobalContext()); case TypePrimitive::I8: return llvm::Type::getInt8Ty(llvm::getGlobalContext()); case TypePrimitive::Float: return llvm::Type::getDoubleTy(llvm::getGlobalContext()); case TypePrimitive::String: return llvm::Type::getInt8PtrTy(llvm::getGlobalContext()); default: assert(false); } } default: assert(false); } assert(false); return nullptr; } void LLVMLayer::initExceptionsSupport(){ Type* typInt8Ptr = PointerType::get(IntegerType::get(module->getContext(), 8), 0); if (!module->getFunction("__cxa_throw")) { std::vector fThrowSignature{typInt8Ptr, typInt8Ptr, typInt8Ptr}; FunctionType* tyFThrow = FunctionType::get( /*Result=*/Type::getVoidTy(module->getContext()), /*Params=*/fThrowSignature, /*isVarArg=*/false); llvm::Function::Create( /*Type=*/tyFThrow, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"__cxa_throw", module); // (external, no body) } if (!module->getFunction("__cxa_allocate_exception")) { std::vectorfAllocateSignature{IntegerType::get(module->getContext(), 64)}; FunctionType* tyFAllocate = FunctionType::get( /*Result=*/typInt8Ptr, /*Params=*/fAllocateSignature, /*isVarArg=*/false); llvm::Function::Create( /*Type=*/tyFAllocate, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"__cxa_allocate_exception", module); // (external, no body) } } bool TypeUtils::isStruct(const ExpandedType& ty){ const TypeAnnotation& t = ty.get(); if (t.__operator==TypeOperator::STRUCT) { return true; } if (t.__operator != TypeOperator::CUSTOM) { return false; } clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); // TODO skip ALL the pointers until non-pointer type found if (raw->isStructureType()) return true; if (!raw->isAnyPointerType()) return false; clang::QualType pointee = raw->getPointeeType(); return pointee->isStructureType(); } bool TypeUtils::isPointer(const ExpandedType &ty) { if (ty.get().__operator != TypeOperator::CUSTOM) return false; clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); return llvm->layerExtern->isPointer(qt); } std::vector TypeUtils::getStructFields(const ExpandedType &t) { return (t.get().__operator == TypeOperator::STRUCT) ? t.get().fields : llvm->layerExtern->getStructFields( llvm->layerExtern->lookupType(t.get().__valueCustom)); } diff --git a/cpp/src/main.cpp b/cpp/src/main.cpp deleted file mode 100644 index a43eeed..0000000 --- a/cpp/src/main.cpp +++ /dev/null @@ -1,5 +0,0 @@ -int main() -{ - return 0; -} - diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index 81667b4..8e4aef4 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,169 +1,176 @@ #ifndef ABSTRACTPASS_H #define ABSTRACTPASS_H #include "ast.h" #include "passmanager.h" #include using namespace std; namespace xreate { struct PassContext { CodeScope* scope = 0; ManagedFnPtr function; ManagedRulePtr rule; std::string varDecl; PassContext() {} PassContext&& updateScope(CodeScope* scopeNew) { PassContext context2{*this}; context2.scope = scopeNew; return std::move(context2); } ~PassContext(){} }; - class PassManager; - class AbstractPassBase { public: AbstractPassBase(PassManager* manager); virtual void run()=0; virtual void finish(); PassManager* man; }; template Output defaultValue(); template class SymbolCache: private std::map{ public: bool isCached(const Symbol& symbol){ return this->count(symbol); } Output setCachedValue(const Symbol& symbol, Output&& value){ this->emplace(symbol, value); 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 { private: SymbolCache __visitedSymbols; Output processSymbol(const std::string& ident, PassContext context){ const Symbol& symbol = context.scope->findSymbol(ident); if (__visitedSymbols.isCached(symbol)) return __visitedSymbols.getCachedValue(symbol); if (CodeScope::hasDeclaration(symbol)) { PassContext context2 = context; context2.scope = symbol.scope; Output&& result = process(CodeScope::findDeclaration(symbol), context2, ident); return __visitedSymbols.setCachedValue(symbol, std::move(result)); } return defaultValue(); } public: AbstractPass(PassManager* manager) : AbstractPassBase(manager){} //NOTE implement processFnCall virtual void processFnCall(ManagedFnPtr function, PassContext context) {} + 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 process(scope->__body, context); } virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ switch (expression.__state) { case Expression::COMPOUND: assert(expression.op != Operator::MAP || (expression.op == Operator::MAP && expression.blocks.size())); for (const Expression &op: expression.getOperands()) { process(op, context); } for (CodeScope* scope: expression.blocks) { process(scope, context); } if (expression.op == Operator::CALL) { const std::string &calleeName = expression.getValueString(); - ManagedFnPtr callee = man->root->findFunction(calleeName); - if (callee) processFnCall(callee, context); + list callees = man->root->getFunctionVariants(calleeName); + if (callees.size() == 1 && callees.front()){ + processFnCall(callees.front(), context); + } else { + for (const ManagedFnPtr& callee: callees){ + processFnCallUncertain(callee, context); + } + } } break; case Expression::IDENT: assert(context.scope); return processSymbol(expression.getValueString(), context); default: break; } return defaultValue(); } void run() { ManagedRulePtr rule = man->root->begin(); while (rule.isValid()) { process(rule); ++rule; } ManagedFnPtr f = man->root->begin(); while (f.isValid()) { process(f); ++f; } } }; template<> void AbstractPass::processSymbol(const std::string& ident, PassContext context); } #endif diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp new file mode 100644 index 0000000..61173cf --- /dev/null +++ b/cpp/src/pass/adhocpass.cpp @@ -0,0 +1,80 @@ +/* + * adhoc.cpp + * + * Created on: Nov 28, 2015 + * Author: pgess + */ + +#include "pass/adhocpass.h" +#include "query/context.h" + +namespace xreate { + AdhocScheme* + AdhocPass::determineForScope(CodeScope* entry){ + std::list contextStack = queryContext->getContext(man->clasp->pack(entry)); + AdhocScheme* scheme = nullptr; + + for (const Expression& context: contextStack){ + if (context.__state != Expression::IDENT) continue; + + if (__schemes.count(context.getValueString())){ + assert(!scheme && "ambiguous context"); + scheme = __schemes.at(context.getValueString()); + } + } + + assert(scheme && "Appropriate context not found"); + return scheme; + } + + const TypeAnnotation& + AdhocScheme::getResultType(){ + return __resultType; + } + + CodeScope* + AdhocScheme::getImplementationForCommand(const std::string& comm) { + assert(__commands.count(comm) && "Adhoc not defined"); + return __commands.at(comm); + } + + AdhocScheme::AdhocScheme(const Expression& scheme): + __resultType(scheme.type), __context(scheme.getValueString()) { + + Expression cases = scheme.getOperands()[0]; + for (const Expression& exprCase: cases.getOperands()){ + CodeScope* blockComm = exprCase.blocks.front(); + std::string nameCase = blockComm->__body.operands[0].getValueString(); + + CodeScope* blockImpl = *(++exprCase.blocks.begin()); + __commands.emplace(nameCase, blockImpl); + } + } + + const std::string& + AdhocScheme::getContext(){ + return __context; + } + + /* + void + AdhocPass::process(const Expression& expression, PassContext context, const std::string& varDecl=""){ + if (expression == Exp) + } + */ + + void + AdhocPass::run(){ + queryContext = reinterpret_cast(man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery)); + + auto range = man->root->__interfacesData.equal_range(ASTInterface::Adhoc); + for (auto i=range.first; i!= range.second; ++i){ + AdhocScheme* scheme = new AdhocScheme(i->second); + __schemes.emplace(scheme->getContext(), scheme); + } + } +} + + + + diff --git a/cpp/src/pass/adhocpass.h b/cpp/src/pass/adhocpass.h new file mode 100644 index 0000000..45877ad --- /dev/null +++ b/cpp/src/pass/adhocpass.h @@ -0,0 +1,50 @@ +/* + * adhoc.h + * + * Created on: Nov 28, 2015 + * Author: pgess + */ +//SECTIONTAG adhoc pass +#ifndef SRC_INSTRUCTIONS_ADHOC_H_ +#define SRC_INSTRUCTIONS_ADHOC_H_ + +#include "abstractpass.h" + +#ifndef FRIEND_ADHOC_UNITTESTS + #define FRIEND_ADHOC_UNITTESTS +#endif + +namespace xreate { + + class ContextQuery; + + class AdhocScheme { + public: + AdhocScheme(const Expression& scheme); + CodeScope* getImplementationForCommand(const std::string& comm); + const TypeAnnotation& getResultType(); + const std::string& getContext(); + + private: + TypeAnnotation __resultType; + std::string __context; + std::map __commands; + }; + + class AdhocPass: public AbstractPass { + FRIEND_ADHOC_UNITTESTS + + public: + AdhocPass(PassManager* manager): AbstractPass(manager) {} + AdhocScheme* determineForScope(CodeScope* entry); + + // virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); + void run() override; + + private: + std::map __schemes; + ContextQuery* queryContext; + }; +} + +#endif /* SRC_INSTRUCTIONS_ADHOC_H_ */ diff --git a/cpp/src/pass/cfgpass.cpp b/cpp/src/pass/cfgpass.cpp index 6c84981..84c62b3 100644 --- a/cpp/src/pass/cfgpass.cpp +++ b/cpp/src/pass/cfgpass.cpp @@ -1,73 +1,90 @@ #include "cfgpass.h" #include using namespace std; using namespace xreate; void CFGPass::initSignatures(){ auto range = man->root->__interfacesData.equal_range(CFA); for (auto i = range.first; i!= range.second; ++i){ __signatures.emplace(i->second.op, i->second); } } void CFGPass::run(){ initSignatures(); return AbstractPass::run(); } void CFGPass::finish() { man->clasp->setCFAData(move(__context.graph)); return AbstractPass::finish(); } void CFGPass::processFnCall(ManagedFnPtr function, PassContext context) { ClaspLayer* clasp = man->clasp; - __context.graph.addLink(clasp->pack(context.scope), function->getName()); + __context.graph.addCallConnection(clasp->pack(context.scope), function->getName()); return AbstractPass::processFnCall(function, context); } void CFGPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ + ClaspLayer* clasp = man->clasp; + + CodeScope* scopeParent = context.scope; + ScopePacked scopeId = clasp->pack(scope); + + if (scopeParent){ + __context.graph.addParentConnection(scopeId, clasp->pack(scopeParent)); + } else { + __context.graph.addParentConnection(scopeId, context.function->getName()); + } + + //TEST scope annotations + //SECTIONTAG context gather scope annotations + __context.graph.addScopeAnnotations(scopeId, scope->tags); + + __context.graph.addContextRules(scopeId, scope->contextRules); + return AbstractPass::process(scope, context, hintBlockDecl); } +//TEST scope annotations via scheme void CFGPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ ClaspLayer* clasp = man->clasp; if (expression.__state == Expression::COMPOUND){ Operator op= expression.op; if (__signatures.count(op)) { assert(expression.blocks.size()); for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { - __context.graph.addScopeNodeTags(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); + __context.graph.addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); } } } return AbstractPass::process(expression, context, varDecl); } void CFGPass::process(ManagedFnPtr function) { - __context.graph.addFunctionNodeTags(function->getName(), function->getAnnotations()); - + __context.graph.addFunctionAnnotations(function->getName(), function->getAnnotations()); return AbstractPass::process(function); } CFGPass::CFGPass(PassManager* manager) : AbstractPass(manager) {} diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 0fde4db..4466ae2 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,457 +1,550 @@ #include "compilepass.h" #include "clasplayer.h" #include #include #include "query/containers.h" -#include "instructions/instr-containers.h" +#include "query/context.h" +#include "compilation/instr-containers.h" #include "ExternLayer.h" +#include "pass/adhocpass.h" + +#include using namespace std; using namespace xreate; using namespace llvm; +//SECTIONTAG types/convert implementation +llvm::Value* +doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, LLVMLayer* llvm){ + if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) + { + llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); + llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); + + if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){ + return llvm->builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); + } + + if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){ + return llvm->builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); + } + } + + return source; +} + CompilePass::CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) : scope(codeScope), pass(compilePass), function(f) {} void CompilePass::CodeScopeUnit::bindArg(llvm::Value* var, std::string&& name) { assert(scope->__vartable.count(name)); VID id = scope->__vartable.at(name); __rawVars[id] = var; } -llvm::Value* -CompilePass::CodeScopeUnit::convertType(llvm::Value* source, llvm::Type* tyTarget){ - LLVMLayer* llvm = pass->man->llvm; - - if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) - { - llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); - llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); +//SECTIONTAG context-based function specialization +CompilePass::FunctionUnit* +CompilePass::CodeScopeUnit::findFunctionUnit(const std::string f){ + AST* ast = pass->man->root; - if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){ - return llvm->builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); - } + const ScopePacked& scopeId = pass->man->clasp->pack(scope); - if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){ - return llvm->builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); - } + const std::list& context = pass->queryContext->getContext(scopeId); + std::unordered_set contextIndex; + for (const Expression& c: context){ + if (c.__state != Expression::IDENT) continue; + contextIndex.insert(c.getValueString()); } - assert(false && "no automatic type conversion possible"); + ManagedFnPtr function = pass->man->root->findFunctionVariant(f, FunctionSpecializationQuery{contextIndex}); + if (!function.isValid()) return nullptr; + + return pass->getFunctionUnit(function); } llvm::Value* CompilePass::CodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ #define VARNAME(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; - CompilePass::Context context{function, this, pass}; - containers::Instructions instructions = containers::Instructions(context); + containers::Instructions instructions = containers::Instructions({function, this, pass}); switch (expr.op) { case Operator::ADD: case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); - if (left->getType()!= right->getType()) { - right = convertType(right, left->getType()); - } + //SECTIONTAG types/convert binary operation + right = doAutomaticTypeConversion(right, left->getType(), &l); break; default:; } switch (expr.op) { case Operator::ADD: return l.builder.CreateAdd(left, right, VARNAME("tmp_add")); break; case Operator::SUB: return l.builder.CreateSub(left, right, VARNAME("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, VARNAME("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, VARNAME("tmp_div")); break; case Operator::EQU: left->dump(); right->dump(); return l.builder.CreateICmpEQ(left, right, VARNAME("tmp_equ")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, VARNAME("tmp_lss")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, VARNAME("tmp_gtr")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, VARNAME("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); - std::string fname = expr.getValueString(); - + llvm::BasicBlock* blockCurrent = pass->man->llvm->builder.GetInsertBlock(); + std::string fname = expr.getValueString(); std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), - [this](const Expression &operand) { - return process(operand); - } + [this](const Expression &operand) { + return process(operand); + } ); - FunctionUnit* calleeUnit = pass->getFunctionUnit(string(fname)); + ScopePacked outerScopeId = pass->man->clasp->pack(this->scope); + llvm::Value* callee = this->function->lateContext.findFunction(fname, outerScopeId, function->raw); // external function - if (!calleeUnit) { + if (!callee) { llvm::Function* external = pass->man->llvm->layerExtern->lookupFunction(fname); return l.builder.CreateCall(external, args, hintVarDecl); } + //SECTIONTAG late-context propagation arg + size_t calleeDomSize = pass->queryContext->getFunctionDomain(fname).size(); + if (calleeDomSize){ + llvm::Value* argLateContext = function->lateContext.compileArgument(fname, outerScopeId); + args.push_back(argLateContext); + } + + //TODO implement inline functions + /* if (calleeUnit->isInline()) { return calleeUnit->compileInline(move(args), this->function); } + */ llvm::BasicBlock* blockPrev = pass->man->llvm->builder.GetInsertBlock(); - llvm::Value* callee = calleeUnit->compile(); - pass->man->llvm->builder.SetInsertPoint(blockPrev); + //llvm::Value* callee = calleeUnit->compile(); + pass->man->llvm->builder.SetInsertPoint(blockCurrent); return l.builder.CreateCall(callee, args, hintVarDecl); } case Operator::IF: { return instructions.compileIf(expr, hintVarDecl); } case Operator::SWITCH: { - return nullptr; //instructions.compileSwitch(); + return instructions.compileSwitch(expr, hintVarDecl); + } + + case Operator::LOOP_CONTEXT: + { + return instructions.compileLoopContext(expr, hintVarDecl); + } + + case Operator::LOGIC_AND: { + assert(expr.operands.size() == 1); + return process (expr.operands[0]); } case Operator::LIST: { return instructions.compileConstantArray(expr, hintVarDecl); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; ExpandedType tyRaw = l.ast->expandType(expr.type); const std::vector fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom)) : tyRaw.get().fields; std::map indexFields; for(size_t i=0, size = fields.size(); i(l.toLLVMType(tyRaw)); llvm::Value* record = llvm::UndefValue::get(tyRecord); for (size_t i=0; igetElementType(fieldId); - result = llvm::UndefValue::get(tyNullField); - - } else { +//TODO Null ad hoc Llvm implementation +// if (operand.isNone()){ +// llvm::Type* tyNullField = tyRecord->getElementType(fieldId); +// result = llvm::UndefValue::get(tyNullField); +// +// } else { result = process(operand); - } +// } assert (result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolid(expr, VARNAME("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, VARNAME("fold")); }; case Operator::INDEX: { //TODO allow multiindex assert(expr.operands.size()==1); const std::string &ident = expr.getValueString(); Symbol s = scope->findSymbol(ident); const TypeAnnotation& t = s.scope->findDefinition(s); const ExpandedType& t2 = pass->man->root->expandType(t); switch (t2.get().__operator) { case TypeOperator::STRUCT: case TypeOperator::CUSTOM: { Expression idx = expr.operands.at(0); assert(idx.__state == Expression::STRING); std::string idxField = idx.getValueString(); llvm::Value* aggr = compileSymbol(s, ident); return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression& op){return process(op);} ); return instructions.compileArrayIndex(s, indexes, VARNAME(string("el_") + ident)); }; default: assert(false); } }; + //SECTIONTAG adhoc actual compilation + case Operator::ADHOC: { + assert(function->adhocImplementation && "Adhoc implementation not found"); + string comm = expr.operands[0].getValueString(); + + CodeScope* scope = function->adhocImplementation->getImplementationForCommand(comm); + CodeScopeUnit* unitScope = function->getScopeUnit(scope); + return unitScope->compile(); + }; case Operator::NONE: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { const std::string &ident = expr.getValueString(); Symbol s = scope->findSymbol(ident); return compileSymbol(s, ident); } case Expression::NUMBER: { int literal = expr.getValueDouble(); return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), hintVarDecl); }; + case Expression::VARIANT: { + const ExpandedType& typVariant = pass->man->root->expandType(expr.type); + llvm::Type* typRaw = l.toLLVMType(typVariant); + int value = expr.getValueDouble(); + return llvm::ConstantInt::get(typRaw, value); + } + default: { break; } }; break; default: break; } assert(false); return 0; } llvm::Value* CompilePass::CodeScopeUnit::compile(const std::string& hintBlockDecl){ if (raw != nullptr) return raw; if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } raw = process(scope->__body); return raw; } llvm::Value* CompilePass::CodeScopeUnit::compileSymbol(const Symbol& s, std::string hintRetVar) { CodeScope* scope = s.scope; CodeScopeUnit* self = function->getScopeUnit(scope); if (self->__rawVars.count(s.identifier)) { return self->__rawVars[s.identifier]; } return self->__rawVars[s.identifier] = self->process(scope->findDeclaration(s), hintRetVar); } bool CompilePass::FunctionUnit::isInline(){ Symbol ret = Symbol{0, function->__entry}; bool flagOnTheFly = SymbolAttachments::get(ret, false); return flagOnTheFly; } llvm::Function* CompilePass::FunctionUnit::compile(){ if (raw != nullptr) return raw; std::vector types; LLVMLayer* llvm = pass->man->llvm; CodeScope* entry = function->__entry; + AST* ast = pass->man->root; std::transform(entry->__args.begin(), entry->__args.end(), std::inserter(types, types.end()), - [this, llvm, entry](const std::string &arg)->llvm::Type* { + [this, llvm, ast, entry](const std::string &arg)->llvm::Type* { assert(entry->__vartable.count(arg)); VID argid = entry->__vartable.at(arg); assert(entry->__definitions.count(argid)); - return llvm->toLLVMType(pass->man->root->expandType(entry->__definitions.at(argid))); + return llvm->toLLVMType(ast->expandType(entry->__definitions.at(argid))); }); - llvm::FunctionType *ft = llvm::FunctionType::get(llvm->toLLVMType(pass->man->root->expandType(entry->__definitions[0])), types, false); - raw = llvm::cast(llvm->module->getOrInsertFunction(function->__name, ft)); + //SECTIONTAG late-context signature type + size_t sizeDom = lateContext.domain->size(); + if (sizeDom) { + llvm::Type* tyBool = llvm::Type::getInt1Ty(llvm::getGlobalContext()); + llvm::Type* tyDom = llvm::ArrayType::get(tyBool, sizeDom); + types.push_back(tyDom); + } + + //SECTIONTAG adhoc func signature determination + llvm::Type* funcResultType; + if (function->isPrefunction){ + AdhocPass* adhocpass = reinterpret_cast(pass->man->getPassById(PassId::AdhocPass)); + + adhocImplementation = adhocpass->determineForScope(entry); + funcResultType = llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); + } else { + funcResultType = llvm->toLLVMType(ast->expandType(entry->__definitions[0])); + } + + llvm::FunctionType *ft = llvm::FunctionType::get(funcResultType, types, false); + + raw = llvm::cast(llvm->module->getOrInsertFunction(function->__name + std::to_string(function.id()), ft)); CodeScopeUnit* entryCompilation = getScopeUnit(entry); llvm::Function::arg_iterator fargsI = raw->arg_begin(); for (std::string &arg : entry->__args) { VID argid = entry->__vartable[arg]; entryCompilation->__rawVars[argid] = fargsI; fargsI->setName(arg); ++fargsI; } - const std::string blockName = "entry"; - llvm->builder.CreateRet(entryCompilation->compile(blockName)); + if (sizeDom){ + fargsI->setName("latecontext"); + lateContext.raw = fargsI; + } + + const std::string&blockName = "entry"; + + //SECTIONTAG types/convert function ret value + llvm->builder.CreateRet( + doAutomaticTypeConversion( + entryCompilation->compile(blockName), funcResultType, llvm)); llvm->moveToGarbage(ft); return raw; } llvm::Value* CompilePass::FunctionUnit::compileInline(std::vector &&args, CompilePass::FunctionUnit* outer){ CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__args.at(i))); } return entryCompilation->compile(); } CompilePass::CodeScopeUnit* CompilePass::FunctionUnit::getScopeUnit(CodeScope* scope){ if (!scopes.count(scope)){ CodeScopeUnit* unit = new CodeScopeUnit(scope, this, pass); scopes.emplace(scope, std::unique_ptr(unit)); } return scopes.at(scope).get(); } CompilePass::CodeScopeUnit* CompilePass::FunctionUnit::getEntry(){ return getScopeUnit(function->getEntryScope()); } CompilePass::CodeScopeUnit* CompilePass::FunctionUnit::getScopeUnit(ManagedScpPtr scope){ return getScopeUnit(&*scope); } CompilePass::FunctionUnit* -CompilePass::getFunctionUnit(const CompilePass::FunctionQuery& f){ - ManagedFnPtr fkey = man->root->findFunction(f.name); - - //external functions: - if (!fkey){ - return nullptr; - } +CompilePass::getFunctionUnit(const ManagedFnPtr& function){ + unsigned int id = function.id(); - if (!functions.count(&*fkey)){ - functions.emplace(&*fkey, std::unique_ptr(new FunctionUnit(fkey, this))); + if (!functions.count(id)){ + FunctionUnit* unit = new FunctionUnit(function, this); + functions.emplace(id, std::unique_ptr(unit)); + return unit; } - return functions.at(&*fkey).get(); + return functions.at(id).get(); } void CompilePass::run(){ + queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); + //Find out main function; ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry")); assert(model && "Error: No entry function found"); assert(model->first != model->second && "Error: Ambiguous entry function"); string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); - FunctionUnit* unitMain = getFunctionUnit(move(nameMain)); + FunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction(){ assert(entry); return entry; } +void +CompilePass::prepareQueries(ClaspLayer* clasp){ + clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); + clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); +} //CODESCOPE COMPILATION PHASE //FIND SYMBOL(compilation phase): //if (!forceCompile) //{ // return result; //} // //search in already compiled vars //if (__rawVars.count(vId)) //{ // return result; //} //if (!__declarations.count(vId)) { // //error: symbol is uncompiled scope arg // assert(false); //} //const Expression& e = __declarations.at(vId); //__rawVars[vId] = process(e, l, name); //FIND FUNCTION //llvm::Function* //CompilePass::findFunction(const std::string& name){ // ManagedFnPtr calleeFunc = man->root->findFunction(name); // assert(calleeFunc.isValid()); // return nullptr; //} diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index a135d6c..ab199a4 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,82 +1,85 @@ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" #include "llvm/IR/Function.h" +#include "compilation/latecontext.h" namespace xreate { +class AdhocScheme; +class ClaspLayer; +class ContextQuery; -class CompilePass : public AbstractPass -{ -public: +class CompilePass : public AbstractPass { + friend class LateContext; +public: class CodeScopeUnit; class FunctionUnit{ public: FunctionUnit(ManagedFnPtr f, CompilePass* p) - : function(f), pass(p) {} + : function(f), lateContext(f->getName(), p), pass(p) {} llvm::Value* compileInline(std::vector&& args, CompilePass::FunctionUnit* outer); bool isInline(); llvm::Function* compile(); CodeScopeUnit* getEntry(); CodeScopeUnit* getScopeUnit(CodeScope* scope); CodeScopeUnit* getScopeUnit(ManagedScpPtr scope); ManagedFnPtr function; llvm::Function* raw = nullptr; + AdhocScheme* adhocImplementation=nullptr; //SECTIONTAG adhoc prefunc scheme declaration + LateContext lateContext; + private: CompilePass* pass; std::map> scopes; }; class CodeScopeUnit { public: CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); void bindArg(llvm::Value* var, std::string&& name); std::map __rawVars; + void reset(){raw = nullptr;} llvm::Value* compile(const std::string& hintBlockDecl=""); llvm::Value* compileSymbol(const Symbol& s, std::string hintRetVar=""); llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); CodeScope* scope; private: CompilePass* pass; llvm::Value* raw = nullptr; FunctionUnit* function; - llvm::Value* convertType(llvm::Value* source, llvm::Type* tyTarget); + FunctionUnit* findFunctionUnit(const std::string f); }; struct Context{ FunctionUnit* function; CodeScopeUnit* scope; CompilePass* pass; }; - struct FunctionQuery{ - FunctionQuery(std::string&& functionName): name(functionName) {} - - std::string name; - }; - CompilePass(PassManager* manager): AbstractPass(manager) {} - FunctionUnit* getFunctionUnit(const FunctionQuery& f); + FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); void run() override; llvm::Function* getEntryFunction(); + static void prepareQueries(ClaspLayer* clasp); private: - std::map> functions; + std::map> functions; llvm::Function* entry = 0; - + ContextQuery* queryContext; }; } #endif // COMPILEPASS_H diff --git a/cpp/src/pass/dfgpass.cpp b/cpp/src/pass/dfgpass.cpp index 5520d2f..da501ad 100644 --- a/cpp/src/pass/dfgpass.cpp +++ b/cpp/src/pass/dfgpass.cpp @@ -1,187 +1,182 @@ #include "dfgpass.h" #include "passmanager.h" #include "clasplayer.h" #include using namespace std; namespace xreate{ DFGPass::DFGPass(PassManager* manager) : AbstractPass(manager), clasp(man->clasp) {} SymbolNode -DFGPass::process(ManagedFnPtr function){ - SymbolNode symbolRet = AbstractPass::process(function); - - if (SymbolPacked* symbolRetPacked = boost::get(&symbolRet)){ - Expression retExpr(Operator::CALL, {Atom(Config::get("clasp.ret.symbol")), - Atom(boost::str(boost::format("(%1%, %2%)") - %(symbolRetPacked->identifier) - % (symbolRetPacked->scope))) - }); - - const std::vector tag{{retExpr, TagModifier::NONE}}; - clasp->cfagraph.addFunctionNodeTags(function->getName(), tag); - - } else if (SymbolTransient* symbT = boost::get(&symbolRet)){ - std::vector tags; - tags.reserve(symbT->tags.size()); - - const std::string stmntRetTag = Config::get("clasp.ret.tag"); - std::transform(symbT->tags.begin(), symbT->tags.end(), std::inserter(tags, tags.begin()), - [&stmntRetTag](const Expression& e) { - Expression tag(Operator::CALL, {Atom(string(stmntRetTag)), e}); - return Tag{e, TagModifier::NONE}; - }); - - clasp->cfagraph.addFunctionNodeTags(function->getName(), tags); +DFGPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ + /* + if (SymbolTransient* symbT = boost::get(&symbolRet)){ + std::vector tags; + tags.reserve(symbT->tags.size()); + + const std::string stmntRetTag = Config::get("clasp.ret.tag"); + std::transform(symbT->tags.begin(), symbT->tags.end(), std::inserter(tags, tags.begin()), + [&stmntRetTag](const Expression& e) { + Expression tag(Operator::CALL, {Atom(string(stmntRetTag)), e}); + return Tag{e, TagModifier::NONE}; + }); + + clasp->cfagraph.addFunctionAnnotations(function->getName(), tags); } + */ - return SymbolInvalid(); + const SymbolNode& retActual = AbstractPass::process(scope, context, hintBlockDecl); + const SymbolPacked& retFormal{0, clasp->pack(scope)}; + __context.graph.addConnection(retFormal, retActual, DFGConnection::ALIAS); + + return retFormal; } SymbolNode DFGPass::process(const Expression& expression, PassContext context, const std::string& decl) { // write down adhoc expression tags: if (expression.tags.size() && decl.length()) { for (pair tag: expression.tags) { SymbolNode nodeThis = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); - __context.graph.addTag(nodeThis, Expression(tag.second)); + __context.graph.addAnnotation(nodeThis, Expression(tag.second)); } } switch(expression.__state) { case Expression::IDENT: { const string& ident = expression.getValueString(); SymbolNode nodeFrom = AbstractPass::process(expression, context, decl); SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(ident), context.function->getName() + ":" + ident); - __context.graph.addLink(nodeTo, nodeFrom, DFGConnection::ALIAS); + __context.graph.addConnection(nodeTo, nodeFrom, DFGConnection::ALIAS); return nodeTo; } default: break; } - //special case for NONE value: - if (expression.isNone()){ - return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; - } - +//TODO Null ad hoc DFG implementation +// if (expression.isNone()){ +// return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; +// } switch(expression.op) { case Operator::CALL: { const string &name = expression.getValueString(); std::vector operands; operands.reserve(expression.getOperands().size()); for (const Expression &op: expression.getOperands()) { operands.push_back(process(op, context)); } - ManagedFnPtr function = man->root->findFunction(name); - if (!function) return SymbolInvalid(); + //TODO implement processFnCall/Uncertain + list functions = man->root->getFunctionVariants(name); + if (functions.size()!=1) return SymbolInvalid(); + ManagedFnPtr function= functions.front(); // set calling relations: CodeScope *scopeRemote = function->getEntryScope(); std::vector::iterator nodeActual = operands.begin(); for (const std::string &identFormal: scopeRemote->__args) { const Symbol &symbolFormal = scopeRemote->findSymbol(identFormal); - __context.graph.addLink(clasp->pack(symbolFormal, name + ":" + identFormal), *nodeActual, DFGConnection::OPT); + __context.graph.addConnection(clasp->pack(symbolFormal, name + ":" + identFormal), *nodeActual, DFGConnection::OPT); ++nodeActual; } //TODO need SymbolTransient::connection mark in order to represent OPT connection return clasp->pack(Symbol{0, scopeRemote}, name + ": *retv"); } default: break; } SymbolNode result = AbstractPass::process(expression, context, decl); if (expression.__state != Expression::COMPOUND){ return result; } std::vector operands; if (__signatures.count(expression.op)) { const Expression &scheme = __signatures.at(expression.op); operands.reserve(expression.getOperands().size()); if (expression.op == Operator::CALL || expression.op == Operator::INDEX){ string caption = expression.getValueString(); operands.push_back(process(Expression(move(caption)), context, "")); } for (const Expression &op: expression.getOperands()) { operands.push_back(process(op, context)); } std::vector::iterator arg = operands.begin(); std::vector::const_iterator tag = ++scheme.getOperands().begin(); while (tag != scheme.getOperands().end()) { if (tag->__state != Expression::INVALID) { - __context.graph.addTag(*arg, Expression(*tag)); + __context.graph.addAnnotation(*arg, Expression(*tag)); } ++arg; ++tag; } Expression retTag = *scheme.getOperands().begin(); if (retTag.__state != Expression::INVALID) { - __context.graph.addTag(result, move(retTag)); + __context.graph.addAnnotation(result, move(retTag)); } } // adhoc for MAP case, TODO reorganize code in more clear manner if (expression.op == Operator::MAP) { SymbolNode nodeFrom; if (operands.size()) { nodeFrom = operands.at(0); } else { nodeFrom = process(expression.getOperands().at(0), context); } assert(!decl.empty()); SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); SymbolPacked* nodeFromPacked = boost::get(&nodeFrom); assert(nodeFromPacked); - __context.graph.addLink(move(nodeTo), *nodeFromPacked, DFGConnection::PROTO); + __context.graph.addConnection(move(nodeTo), *nodeFromPacked, DFGConnection::PROTO); } return result; } void DFGPass::run() { init(); return AbstractPass::run(); } void DFGPass::init() { for (const Expression& scheme: man->root->__dfadata) { __signatures.emplace(scheme.op, scheme); } } void DFGPass::finish() { man->clasp->addDFAData(move(__context.graph)); } template<> SymbolNode defaultValue(){return SymbolInvalid();}; } diff --git a/cpp/src/pass/dfgpass.h b/cpp/src/pass/dfgpass.h index fcf9cf1..d29ecf3 100644 --- a/cpp/src/pass/dfgpass.h +++ b/cpp/src/pass/dfgpass.h @@ -1,34 +1,34 @@ // Data Flow Graph determination pass #ifndef DFGPASS_H #define DFGPASS_H #include "abstractpass.h" #include "clasplayer.h" namespace xreate { class ClaspLayer; class DFGPass : public AbstractPass { public: - SymbolNode process(ManagedFnPtr function); + SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""); SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; DFGPass(PassManager* manager); void init(); void run(); void finish(); private: struct { DFAGraph graph; } __context; std::map __signatures; //DFA data for particular operators ClaspLayer* clasp; }; }; #endif diff --git a/cpp/src/pass/logging.cpp b/cpp/src/pass/loggerpass.cpp similarity index 76% rename from cpp/src/pass/logging.cpp rename to cpp/src/pass/loggerpass.cpp index 0daaf05..b6fe477 100644 --- a/cpp/src/pass/logging.cpp +++ b/cpp/src/pass/loggerpass.cpp @@ -1,106 +1,106 @@ /* * logging.cpp * * Created on: Jun 23, 2015 * Author: pgess */ -#include "logging.h" -#include "instructions/instr-containers.h" +#include +#include "compilation/instr-containers.h" #include "utils.h" using namespace std; using namespace llvm; namespace xreate { -void Logging::init(ClaspLayer* clasp){ +void LoggerPass::init(ClaspLayer* clasp){ auto model = clasp->query(Config::get("logging.id")); if(!model) return; for (ClaspLayer::ModelIterator rec = model->first; rec!=model->second; ++rec){ std::tuple _v =ClaspLayer::parse(rec->second); Symbol v = clasp->unpack(get<0>(_v)); SymbolAttachments::put(v, true); } } void -Logging::process(const Expression& expression, PassContext context, const std::string& varDecl){ +LoggerPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ if (varDecl.size()){ Symbol v = context.scope->findSymbol(varDecl); if (SymbolAttachments::get(v, false)){ - CompilePass::FunctionUnit* f = compiler->getFunctionUnit(CompilePass::FunctionQuery(string(context.function->getName()))); - CompilePass::CodeScopeUnit* u = f->getScopeUnit(context.scope); + CompilePass::FunctionUnit* func = compiler->getFunctionUnit(context.function); + CompilePass::CodeScopeUnit* scope = func->getScopeUnit(context.scope); - CompilePass::Context compilation{f, u, compiler}; - inject(v, compilation); + CompilePass::Context compilationContext{func, scope, compiler}; + inject(v, compilationContext); } } return AbstractPass::process(expression, context, varDecl); } -void Logging::inject(const Symbol& symbol, const CompilePass::Context& context){ +void LoggerPass::inject(const Symbol& symbol, const CompilePass::Context& context){ llvm::Value* source = context.scope->compileSymbol(symbol); ExpandedType typSource = man->root->expandType(CodeScope::findDefinition(symbol)); string format = ""; switch (typSource->__value) { case TypePrimitive::Int : case TypePrimitive::Num : case TypePrimitive::I32: case TypePrimitive::I8: format = "%d\n"; break; case TypePrimitive::String: format = "%s\n"; break; default: assert(false && "No appropriate type for logging"); } containers::Instructions compiler(context); LLVMLayer* llvm = context.pass->man->llvm; llvm->builder.SetInsertPoint(*source->use_begin()); llvm::Value* formatRaw = compiler.compileConstantStringAsPChar(format, "logformat"); llvm->builder.CreateCall2(refPrintf, formatRaw, source); } void -Logging::initOutput(){ +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); } } -Logging::Logging(PassManager* manager) +LoggerPass::LoggerPass(PassManager* manager) : AbstractPass(manager) { initOutput(); init(man->clasp); } void -Logging::initDependencies(CompilePass* pass){ +LoggerPass::initDependencies(CompilePass* pass){ compiler = pass; } } /* namespace xreate */ diff --git a/cpp/src/pass/logging.h b/cpp/src/pass/loggerpass.h similarity index 89% rename from cpp/src/pass/logging.h rename to cpp/src/pass/loggerpass.h index 4745a06..bfa3d0b 100644 --- a/cpp/src/pass/logging.h +++ b/cpp/src/pass/loggerpass.h @@ -1,44 +1,44 @@ /* * logging.h * * Created on: Jun 23, 2015 * Author: pgess */ #ifndef SRC_LOGGING_H_ #define SRC_LOGGING_H_ #include "ast.h" #include #include "pass/compilepass.h" #include "pass/abstractpass.h" #include "clasplayer.h" namespace xreate { -class Logging:public AbstractPass, public IQuery { +class LoggerPass:public AbstractPass, public IQuery { public: void inject(const Symbol& symbol, const CompilePass::Context& context); - Logging(PassManager* manager); + LoggerPass(PassManager* manager); virtual void init(ClaspLayer* clasp); void initDependencies(CompilePass* pass); virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); private: CompilePass* compiler = nullptr; llvm::Function* refPrintf; void initOutput(); }; struct IsLogging{}; template<> struct AttachmentsDict { typedef bool Data; static const unsigned int key = 5; }; } /* namespace xreate */ #endif /* SRC_LOGGING_H_ */ diff --git a/cpp/src/passmanager.cpp b/cpp/src/passmanager.cpp index 3bcfded..87d8b8d 100644 --- a/cpp/src/passmanager.cpp +++ b/cpp/src/passmanager.cpp @@ -1,93 +1,102 @@ #include +#include #include "query/containers.h" #include "passmanager.h" #include "pass/compilepass.h" +#include "pass/adhocpass.h" #include "Parser.h" #include "pass/cfgpass.h" #include "pass/dfgpass.h" -#include "pass/logging.h" #include using namespace xreate; using namespace std; PassManager* PassManager::prepareForCode(std::string&& code){ Scanner scanner(reinterpret_cast(code.c_str()), code.size()); return prepareForCode(scanner); } PassManager* PassManager::prepareForCode(Scanner& scanner){ Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager* man = new PassManager; AST* ast = new AST(parser.root); man->root = ast; man->clasp = new ClaspLayer(); man->clasp->ast = man->root; man->llvm = new LLVMLayer(man->root); CFGPass* passCFG = new CFGPass(man); - man->registerPass(new DFGPass(man), passCFG); - man->registerPass(passCFG); + //TODO is it really DFGPass needs CFGpass? + man->registerPass(new DFGPass(man), PassId::DFGPass, passCFG); + man->registerPass(passCFG, PassId::CFGPass); + man->registerPass(new AdhocPass(man), PassId::AdhocPass); + + CompilePass::prepareQueries(man->clasp); return man; } - - void -PassManager::registerPass(AbstractPassBase* pass, AbstractPassBase* parent) +PassManager::registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* parent) { - __passes.emplace(parent, pass); + __passes.emplace(id, pass); + __passDependencies.emplace(parent, pass); +} + +AbstractPassBase* +PassManager::getPassById(const PassId& id){ + assert(__passes.count(id)); + return __passes[id]; } void* PassManager::run() { runWithoutCompilation(); CompilePass* compiler = new CompilePass(this); compiler->run(); //Compiler Dependents: - Logging* logger = new Logging(this); + LoggerPass* logger = new LoggerPass(this); logger->initDependencies(compiler); logger->run(); llvm->print(); llvm->initJit(); return llvm->getFunctionPointer(compiler->getEntryFunction()); } void PassManager::runWithoutCompilation(){ std::list passes{nullptr}; while (passes.size()){ AbstractPassBase* parent = passes.front(); - auto range = __passes.equal_range(parent); + auto range = __passDependencies.equal_range(parent); for (auto i=range.first; i!=range.second; ++i){ AbstractPassBase* pass = i->second; pass->run(); pass->finish(); passes.push_back(pass); } passes.pop_front(); } - clasp->registerdQuery(new containers::Query()); clasp->run(); } PassManager::~PassManager(){} diff --git a/cpp/src/passmanager.h b/cpp/src/passmanager.h index 4c9e0de..389487f 100644 --- a/cpp/src/passmanager.h +++ b/cpp/src/passmanager.h @@ -1,33 +1,45 @@ #ifndef PASSMANAGER_H #define PASSMANAGER_H #include "Scanner.h" #include #include namespace xreate { class AbstractPassBase; class ClaspLayer; class LLVMLayer; class AST; +enum class PassId { + CFGPass, + CompilePass, + DFGPass, + EnvironmentTestsPass, + LoggerPass, + AdhocPass, + RulesPass +}; + class PassManager { public: ~PassManager(); - void* run(); + void*run(); void runWithoutCompilation(); - void registerPass(AbstractPassBase* pass, AbstractPassBase* prerequisite=nullptr); + void registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* prerequisite=nullptr); + AbstractPassBase* getPassById(const PassId& id); static PassManager* prepareForCode(std::string&& code); static PassManager* prepareForCode(Scanner& scanner); ClaspLayer* clasp; LLVMLayer* llvm; AST* root; private: //typedef std::multimap FILTERS_STORAGE; //FILTERS_STORAGE __filters; - std::multimap __passes; + std::map __passes; + std::multimap __passDependencies; }; } #endif diff --git a/cpp/src/query/context.cpp b/cpp/src/query/context.cpp new file mode 100644 index 0000000..0f4399b --- /dev/null +++ b/cpp/src/query/context.cpp @@ -0,0 +1,129 @@ +/* + * adhoc.cpp + * + * Created on: Dec 1, 2015 + * Author: pgess + */ + +#include +#include + +using namespace std; +namespace xreate { + +std::list +ContextQuery::getContext(const ScopePacked& scopeId){ + std::list result; + + for (auto i: boost::make_iterator_range(__modelContext.equal_range(scopeId))){ + result.push_back(i.second); + } + + for (auto i: boost::make_iterator_range(__modelForcedContext.equal_range(scopeId))){ + result.push_back(i.second); + } + + return result; +} + +void +ContextQuery::forceContext(const ScopePacked& scopeId, std::list context){ + // TODO remove forced context only of the same class, possibly + + //remove any previous forced context for this scopeId + __modelForcedContext.erase(scopeId); + + std::transform(context.begin(), context.end(), inserter(__modelForcedContext, __modelForcedContext.end()), + [scopeId](const Expression& context){return make_pair(scopeId, context);}); +} + +void +ContextQuery::init(ClaspLayer* clasp){ + const std::string& atomEarlyBinding = Config::get("clasp.bindings.scope"); + ClaspLayer::ModelFragment model = clasp->query(atomEarlyBinding); + + if (model){ + for (auto i = model->first; i!=model->second; ++i){ + ScopePacked idScope; + Expression context; + tie(idScope, context) = ClaspLayer::parse(i->second); + __modelContext.emplace(idScope, context); + } + } + + const std::string& atomLateBinding = Config::get("clasp.bindings.scope_weak"); + model = clasp->query(atomEarlyBinding); + + std::map> modelLateContext; + if (model){ + for (auto i = model->first; i!=model->second; ++i){ + string nameFunction; + Expression context; + tie(nameFunction, context) = ClaspLayer::parse(i->second); + modelLateContext.at(nameFunction).push_back(context); + } + + for(auto& entry: modelLateContext){ + __modelFunctionContext.emplace(entry.first, move(entry.second)); + } + } +} + +const ContextDomain& +ContextQuery::getFunctionDomain(const std::string& name) const { + static ContextDomain domainNULL({}); + + if (__modelFunctionContext.count(name)){ + return __modelFunctionContext.at(name); + } + + return domainNULL; +} + +ContextDomain::ContextDomain(const std::vector&& expressions) + : std::vector(move(expressions)){ + for (const Expression& e: expressions){ + serializer.registerExpression(e); + } + + size_t id =0; + for (const Expression& e: expressions){ + scheme.emplace(serializer.pack(e), id++); + } +} + +size_t +ContextDomain::size() const{ + return PARENT::size(); +} + + +ContextDomain::const_iterator +ContextDomain::begin() const { + return begin(); +} + +ContextDomain::const_iterator +ContextDomain::end() const { + return end(); +} + +boost::optional +ContextDomain::getExpressionId(const Expression& e) const{ + const auto& exprPacked = serializer.packOptional(e); + if (!exprPacked){ + return boost::none; + } + + if (scheme.count(*exprPacked)){ + return scheme.at(*exprPacked); + } + + return boost::none; +} + +const Expression& +ContextDomain::get(size_t id) const{ + return at(id); +} +} /* namespace xreate */ diff --git a/cpp/src/query/context.h b/cpp/src/query/context.h new file mode 100644 index 0000000..6da9f9d --- /dev/null +++ b/cpp/src/query/context.h @@ -0,0 +1,81 @@ +/* + * adhoc.h + * + * Created on: Dec 1, 2015 + * Author: pgess + */ + +#ifndef SRC_QUERY_CONTEXT_H_ +#define SRC_QUERY_CONTEXT_H_ + +#include "clasplayer.h" +#include "ast.h" +#include "expressionserializer.h" +#include +namespace xreate { + +class ContextDomain: private std::vector{ + typedef std::vector PARENT; + +public: + ContextDomain(const std::vector&& expressions); + ContextDomain(ContextDomain&& other) + : scheme(std::move(other.scheme)), serializer(std::move(serializer)){} + boost::optional getExpressionId(const Expression& e) const; + const Expression& get(size_t id) const; + size_t size() const; + ContextDomain::const_iterator begin() const; + ContextDomain::const_iterator end() const; + +private: + ContextDomain(const ContextDomain&)=delete; + + std::map scheme; + ExpressionSerializer serializer; +}; + +template +class ContextAttachments: private std::unordered_map { + typedef std::unordered_map PARENT; + +public: + size_t size() const { + return PARENT::size(); + } + + size_t count(const Expression& e) const { + return (domain.getExpressionId(e)? 1: 0); + } + + const ATTACHMENTS& at(const Expression& e) const{ + auto id = domain.getExpressionId(e); + assert(id); + return PARENT::at(*id); + } + +private: + ContextDomain domain; +}; +typedef ContextAttachments FunctionSpecializations ; + +class ContextQuery: public IQuery { +public: + //AdhocQuery(); + std::list getContext(const ScopePacked& scopeId); + void forceContext(const ScopePacked& scopeId, std::list context); + const ContextDomain& getFunctionDomain(const std::string& name) const; + const FunctionSpecializations& getFunctionSpecializations(const std::string& name) const; + + virtual void init(ClaspLayer* clasp); + virtual ~ContextQuery(){}; +private: + std::multimap __modelContext; + std::multimap __modelForcedContext; + std::map __modelFunctionContext; + std::map __modelFunctionSpecializations; + +}; + +} /* namespace xreate */ + +#endif /* SRC_QUERY_CONTEXT_H_ */ diff --git a/cpp/src/utils.h b/cpp/src/utils.h index 925023c..2778ad0 100644 --- a/cpp/src/utils.h +++ b/cpp/src/utils.h @@ -1,130 +1,134 @@ #ifndef UTILS_H #define UTILS_H #include "jeayeson/jeayeson.hpp" //TODO mark dirty members /* template struct DdesctructableClass { } */ /* template struct TagUpdatable{ TagUpdatable(const OriginalType& source) : __source(source) {} TagUpdatable() = delete; const OriginalType& __source; }; struct Updatable; template struct TagsDictionary {}; template struct TagsDictionary { typedef TagUpdatable TagName; }; template struct awareOf { awareOf(OT& dest) : __dest(dest) {} awareOf& operator= (const typename TagsDictionary::TagName& source) { __dest = source.__source; } private: OT& __dest; }; template> const OT& awareOf(const Tag& holder) { return std::forward(holder.__source); } */ namespace xreate { template struct AddTag { explicit - AddTag(const Source &&src) + 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(); } }; } #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 < +#include +#include +#include + + +#include "pass/adhocpass.h" +#include "pass/compilepass.h" +#include "llvmlayer.h" + +using namespace xreate; +using namespace std; + +TEST(Adhoc, ast_operatorAdhoc1){ + PassManager* man = PassManager::prepareForCode ( + " test = " + "function:: int {\n" + " ad hoc Exception(NonImplemented)\n" + " }" + ); + + Expression subject = man->root->findFunction("test")->getEntryScope()->__body; + ASSERT_EQ(Operator::ADHOC, subject.op); + ASSERT_EQ(1, subject.getOperands().size()); + + Expression exception = subject.getOperands()[0]; + ASSERT_EQ("Exception", exception.getValueString()); +} + +TEST(Adhoc, ast_schemeAdhoc1){ + PassManager* man = PassManager::prepareForCode ( + "interface(adhoc){\n" + " pre function expectNoErrors:: bool {\n" + " case Error {false}\n" + " case Success {true}\n" + " }\n" + " }"); + + assert(man->root->__interfacesData.count(ASTInterface::Adhoc)); + Expression adhocData = man->root->__interfacesData.find(ASTInterface::Adhoc)->second; + ASSERT_EQ(Operator::SWITCH, adhocData.operands[0].op); +} + +TEST(Adhoc, pass_Adhoc1){ + PassManager* man = PassManager::prepareForCode ( + "interface(adhoc){\n" + " pre function expectNoErrors:: bool {\n" + " case Error {false}\n" + " case Success {true}\n" + " }\n" + " }"); + + man->runWithoutCompilation(); + AdhocPass* pass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); + EXPECT_TRUE(pass->__schemes.size() > 0); + + AdhocScheme* scheme = pass->__schemes.begin()->second; + EXPECT_EQ("expectNoErrors", scheme->getContext()); +} + +TEST(Adhoc, full_1){ + PassManager* man = PassManager::prepareForCode ( + " import raw (\"core/control-context.lp\")" + + " interface(adhoc){\n" + " pre function expectNoErrors:: bool {\n" + " case Error {0}\n" + " case Success {1}\n" + " }\n" + " }" + + " test1 = pre function {\n" + " context:: expectNoErrors." + " ad hoc \"Success\"\n" + " }" + + "main = function::bool;entry {\n" + " test1()\n" + " }"); + + bool (*main)() = (bool (*)()) man->run(); + bool result = main(); + ASSERT_EQ(true, result); +} + +TEST(Adhoc, full_contextExpectNoErrrors){ + PassManager* man = PassManager::prepareForCode ( + " import raw (\"core/control-context.lp\")\n" + + "interface(extern-c){\n" + " xml2 = library:: pkgconfig(\"libxml-2.0\").\n" + " \n" + " include {\n" + " xml2 = [\"stdlib.h\"]\n" + " }.\n" + "}" + + " interface(adhoc){\n" + " pre function expectNoErrors:: bool {\n" + " case Error {0}\n" + " case Success {1}\n" + " }\n" + " }\n" + + " expectErrorCode = pre function(x::int){\n" + " if (x==0)::bool {ad hoc \"Success\"}\n" + " else {ad hoc \"Error\"}\n" + " }\n" + + " main = function::bool; entry {\n" + " context:: expectNoErrors." + " expectErrorCode(system(\"ls -la\"))\n" + " }" ); + + int (*main)() = (int (*)()) man->run(); + ASSERT_EQ(1, main()); +} + +TEST(Adhoc, ast_switchAdhoc1){ + PassManager* man = PassManager::prepareForCode ( + "test1 = function:: bool {\n" + " switch ad hoc (x:: errors)\n" + " case ERROR {0}\n" + " case SUCCESS {1}\n" + " \n" + " }" + ); + + Expression eSwitch = man->root->findFunction("test1")->getEntryScope()->__body; + 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/context.cpp b/cpp/tests/context.cpp new file mode 100644 index 0000000..485a7c1 --- /dev/null +++ b/cpp/tests/context.cpp @@ -0,0 +1,198 @@ +/* + * frame-context.cpp + * + * Created on: Dec 3, 2015 + * Author: pgess + */ + +#include "passmanager.h" +#include "query/context.h" + +#include "gtest/gtest.h" + +using namespace xreate; + +TEST(Context, frame_Context1){ + PassManager* man = PassManager::prepareForCode( + " import raw (\"core/control-context.lp\")\n" + " testC = function::int {\n" + " context:: testC.\n" + + " 0\n" + " }\n" + + " testA = function:: int {\n" + " context:: testA; test.\n" + + " testC()\n" + " }\n" + + " testB = function:: int {\n" + " context:: testB; test.\n" + + " testC()\n" + " }\n" + ); + + ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); + man->runWithoutCompilation(); + + CodeScope* scopeTestC = man->root->findFunction("testC")->getEntryScope(); + const std::list& context = query->getContext(man->clasp->pack(scopeTestC)); + + int contextSize = context.size(); + EXPECT_EQ(2, contextSize); +} + +TEST(Context, full_ContextBasedFunctionSpecialization){ + + PassManager* man = PassManager::prepareForCode( + " case context::toMillimeters {\n" + " convert = function(source:: num)::num {\n" + " 10 * source \n" + " }\n" + " }\n" + + " case context::toInches {\n" + " convert = function(source:: num)::num {\n" + " 2 * source \n" + " }\n" + " }\n" + + "test = function(vrnt:: int)::int; entry {\n" + " switch(vrnt):: int\n" + " case 0 {\n" + " context:: toMillimeters.\n" + " convert(1)\n" + " }\n" + "\n" + " case 1 {\n" + " context:: toInches.\n" + " convert(1)\n" + " }\n" + " case default {0}\n" + " }" ); + + int (*main)(int) = (int (*)(int)) man->run(); + ASSERT_EQ(10, main(0)); + ASSERT_EQ(2, main(1)); +} + +TEST(Context, full_LoopContext){ + + PassManager* man = PassManager::prepareForCode("case context:: a {\n" + " print = function:: string {\n" + " \"a\"\n" + " }}\n" + "\n" + " case context:: b {\n" + " print = function:: string {\n" + " \"b\"\n" + " }}\n" + "\n" + " case context:: c {\n" + " print = function:: string {\n" + " \"c\"\n" + " }}\n" + "\n" + " case context:: d {\n" + " print = function:: string {\n" + " \"d\"\n" + " }}\n" + "\n" + " start = function(command::int)::string; entry {\n" + " switch (command) :: string \n" + " case 0 {\n" + " context:: print(a); print(b); print(d).\n" + "\n" + " loop context (\"print\") {\n" + " print()\n" + " }\n" + " }\n" + "\n" + " case default {\n" + " context:: print(c).\n" + " loop context (\"print\") {\n" + " print()\n" + " }\n" + " }\n" + " }"); + + + char* (*main)(int) =(char* (*)(int)) man->run(); + ASSERT_STREQ("c", main(1)); + ASSERT_STREQ("a", main(0)); +} + +TEST(Context, full_RuleContext){ + /* + "rule context:: childs(Child)\n" + " case artefact(Item)\n" + " {\n" + " artefact_depends(Item, Child)\n" + " }"; + */ + + PassManager* man = PassManager::prepareForCode( + " case context:: toMilli {\n" + " convert = function(length::int)::int{\n" + " 10 * length\n" + " }\n" + " }\n" + "\n" + " case context:: toCenti {\n" + " convert = function(length::int)::int{\n" + " length\n" + " }\n" + " }\n" + "\n" + " main=function::int; entry {\n" + " context:: output(milli).\n" + "\n" + " rule context::toMilli\n" + " case output(milli) {true}\n" + "\n" + " convert(1)\n" + " }" ); + man->clasp->addRawScript("true."); + + int (*entry)() = (int (*)()) man->run(); + ASSERT_EQ(10, entry()); +} + +TEST(Context, full_InheritedRuleContext){ + PassManager* man = PassManager::prepareForCode( + " import raw (\"core/control-context.lp\") \n" + + " case context:: toMilli {\n" + " convert = function(length::int)::int{\n" + " 10 * length\n" + " }\n" + " }\n" + + " case context:: toCenti {\n" + " convert = function(length::int)::int{\n" + " length\n" + " }\n" + " }\n" + "\n" + + "main = function(comm:: num)::num; entry{\n" + " rule context::X case output(X) {true}\n" + "\n" + " switch (comm)::num \n" + " case 0 {\n" + " context:: output(toMilli).\n" + " convert(1)\n" + " }\n" + " case default {\n" + " context:: output(toCenti).\n" + " convert(1)\n" + " }\n" + " }"); + + man->clasp->addRawScript("true."); + int (*entry)(int) = (int (*)(int)) man->run(); + ASSERT_EQ(10, entry(0)); + ASSERT_EQ(1, entry(1)); +} diff --git a/cpp/tests/diagnostic-messages.cpp b/cpp/tests/diagnostic-messages.cpp index b46cdf0..5c7c946 100644 --- a/cpp/tests/diagnostic-messages.cpp +++ b/cpp/tests/diagnostic-messages.cpp @@ -1,28 +1,32 @@ /* * diagnostic-messages.cpp * * Created on: Oct 27, 2015 * Author: pgess */ +#include "passmanager.h" +#include "pass/dfgpass.h" + #include "gtest/gtest.h" using namespace std; +using namespace xreate; TEST(Diagnostic_DFA, DISABLED_recursion1){ - //Error while processing recursion, Should be some diagnostic complaints + //Error while processing recursion, There should be some diagnostic complaints std::string code = \ "test1 = function()::[int] {\n" " varRecursion = loop map(varRecursion->el:: int)::[int]{\n" " el\n" " }.\n" " \n" " varRecursion\n" "}"; - PassManager* man = PassManager::prepareForCode(code); + PassManager* man = PassManager::prepareForCode(move(code)); DFGPass* pass = new DFGPass(man); pass->run(); pass->finish(); } diff --git a/cpp/tests/expressions.cpp b/cpp/tests/expressions.cpp new file mode 100644 index 0000000..6b6e732 --- /dev/null +++ b/cpp/tests/expressions.cpp @@ -0,0 +1,31 @@ +/* + * expressions.cpp + * + * Created on: Dec 21, 2015 + * Author: pgess + */ + +#include "passmanager.h" +#include "gtest/gtest.h" + +using namespace std; +using namespace xreate; + +TEST(Expressions, switch1){ + string&& code = + " colors = type variant (RED, BLUE, GREEN).\n" + " test = function:: colors; entry {GREEN}" + + "main = function:: int; entry {\n" + " switch(test():: color)\n" + " case GREEN {0}\n" + " case default {1}\n" + "}"; + + PassManager* man = PassManager::prepareForCode(move(code)); + int (*main)() = (int (*)()) man->run(); + + EXPECT_EQ(0, main()); +} + + diff --git a/cpp/tests/tests.cpp b/cpp/tests/main.cpp similarity index 100% rename from cpp/tests/tests.cpp rename to cpp/tests/main.cpp diff --git a/cpp/tests/testLogging.cpp b/cpp/tests/pass-Logger.cpp similarity index 82% rename from cpp/tests/testLogging.cpp rename to cpp/tests/pass-Logger.cpp index a84026a..a1da4c7 100644 --- a/cpp/tests/testLogging.cpp +++ b/cpp/tests/pass-Logger.cpp @@ -1,87 +1,87 @@ /* * testLogging.cpp * * Created on: Jun 23, 2015 * Author: pgess */ +#include #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" #include "pass/compilepass.h" -#include "pass/logging.h" using namespace std; using namespace xreate; -TEST(Logging, simpleInjection){ +TEST(LoggerPass, simpleInjection){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int. return x}"); man->runWithoutCompilation(); - CompilePass* compilator = new CompilePass(man); - compilator->run(); + CompilePass* compiler = new CompilePass(man); + compiler->run(); - CompilePass::FunctionUnit* fTest = compilator->getFunctionUnit(CompilePass::FunctionQuery("test")); + CompilePass::FunctionUnit* fTest = compiler->getFunctionUnit(man->root->findFunction("test")); ASSERT_NE(fTest, nullptr); CompilePass::CodeScopeUnit* scopeUnitTest = fTest->getEntry(); CodeScope* scopeTest = scopeUnitTest->scope; Symbol symbX = scopeTest->findSymbol("x"); TypeAnnotation typX = scopeTest->findDefinition(symbX); llvm::Value* retRaw = scopeUnitTest->compile(); llvm::BasicBlock& blockTestRaw = fTest->raw->getEntryBlock(); LLVMLayer* llvm = man->llvm; //llvm->builder.SetInsertPoint(&blockTestRaw); - CompilePass::Context params{fTest, scopeUnitTest, compilator}; + CompilePass::Context params{fTest, scopeUnitTest, compiler}; - Logging l(man); + LoggerPass l(man); l.inject(symbX, params); llvm->initJit(); int (*f)() = (int(*)()) llvm->getFunctionPointer(fTest->raw); testing::internal::CaptureStdout(); f(); std::string&& output = testing::internal::GetCapturedStdout(); EXPECT_STREQ("10\n", output.c_str()); } -TEST(Logging, simpleInjection2){ +TEST(LoggerPass, simpleInjection2){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int; logging. x}"); man->runWithoutCompilation(); CompilePass* compiler= new CompilePass(man); compiler->run(); - Logging* logger = new Logging(man); + LoggerPass* logger = new LoggerPass(man); logger->initDependencies(compiler); logger->run(); man->llvm->initJit(); man->llvm->print(); int (*f)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); testing::internal::CaptureStdout(); f(); std::string&& output = testing::internal::GetCapturedStdout(); EXPECT_STREQ("10\n", output.c_str()); } -TEST(Logging, simpleInjection3){ +TEST(LoggerPass, simpleInjection3){ FILE* input = fopen("scripts/cases/log.xreate","r"); assert(input != nullptr); Scanner scanner(input); std::unique_ptr program(PassManager::prepareForCode(scanner)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); fclose(input); } diff --git a/cpp/tests/testExpressionSerializer.cpp b/cpp/tests/testExpressionSerializer.cpp new file mode 100644 index 0000000..9fd30f3 --- /dev/null +++ b/cpp/tests/testExpressionSerializer.cpp @@ -0,0 +1,50 @@ +/* + * testExpressionSerializer.cpp + * + * Created on: Jan 4, 2016 + * Author: pgess + */ + +#include "expressionserializer.h" +#include "ast.h" +#include "gtest/gtest.h" +using namespace xreate; +using namespace std; + +TEST(ExpressionSerializer, pack1){ + PackedExpression x; + + x << std::make_pair(0xA1, 0x100); + size_t* storage = reinterpret_cast (*x); + ASSERT_EQ(0xA100000000000000, *storage); + + x << std::make_pair(0x23456, 0x100000); + ASSERT_EQ(0xA123456000000000, *storage); + + x << std::make_pair(0x7654321, 0x10000000); + ASSERT_EQ(0xA123456765432100, *storage); + + + x << std::make_pair(0xABBA, 0x10000); + storage = reinterpret_cast (*x); + ASSERT_EQ(0xA1234567654321AB, *storage); + ASSERT_EQ(0xBA00000000000000, *(storage+1)); +} + +TEST(ExpressionSerializer, serialize1){ + Expression a(Operator::CALL, {Expression(string("a")), Expression(string("a"))}); + Expression b(Operator::CALL, {Expression(string("a")), Expression(string("b"))}); + + ExpressionSerializer serializer; + serializer.registerExpression(a); + serializer.registerExpression(b); + + PackedExpression packA = serializer.pack(a); + PackedExpression packB = serializer.pack(b); + PackedExpression packA2 = serializer.pack(a); + + ASSERT_EQ(packA, packA2); + ASSERT_NE(packA, packB); +} + + diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index 0967945..9801984 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,130 +1,149 @@ /* * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n"; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator); ASSERT_EQ(2, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value); } TEST(Types, DependantTypes2) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Template = type Template(Leaf) [Leaf, [Leaf[content]]]." "Concrete = type alias Template(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); ASSERT_EQ(typeConcrete->conjuctionId,typeLink.conjuctionId); } TEST(Types, TreeType1LLvm){ string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symb = body->findSymbol("childrenRaw"); const TypeAnnotation& t = CodeScope::findDefinition(symb); const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); } TEST(Types, ExternType1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symbTree = body->findSymbol("tree"); const TypeAnnotation& t = CodeScope::findDefinition(symbTree); const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } +TEST(Types, ast_VariantType1){ + string&& code = + " colors = type variant (RED, BLUE, GREEN).\n" + " test = function:: colors; entry {GREEN}"; + + std::unique_ptr program(PassManager::prepareForCode(move(code))); + + ExpandedType typ = program->root->findType("colors"); + EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); + + Expression eRed = program->root->findFunction("test")->getEntryScope()->__body; + EXPECT_EQ(Expression::VARIANT, eRed.__state); + + const ExpandedType& typ2 = program->root->expandType(eRed.type); + EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); + + program->run(); +} + //TEST string type diff --git a/problems/basket/dependencies.lp b/problems/basket/dependencies.lp new file mode 100644 index 0000000..abbe0c4 --- /dev/null +++ b/problems/basket/dependencies.lp @@ -0,0 +1,8 @@ +node(a; b; c; d). +depends(b,a). +depends(c,a). +depends(d, a). +depends(d, c). + +level(X, 0) :- not depends(X, _); node(X). +level(X, LEVEL):- LEVEL = #max{L+1, level(Y, L): level(Y, L), depends(X, Y)}; node(X); LEVEL > 0. diff --git a/problems/basket/kitchen.lp b/problems/basket/kitchen.lp new file mode 100644 index 0000000..f9f0fc9 --- /dev/null +++ b/problems/basket/kitchen.lp @@ -0,0 +1,13 @@ +room(bedroom; diningroom; kitchen). + +%location(bedroom). +door(bedroom, diningroom). +door(diningroom, kitchen). + +{move(A, B)} :- location(A); door(A, B); room(A); room(B). +{move(A, B)} :- move(_, A); door(A, B); room(A); room(B). + +goal:- location(kitchen). +goal:- move(_, kitchen). + +:- not goal. diff --git a/scripts/environment-tests/control-context.lp b/scripts/environment-tests/control-context.lp new file mode 120000 index 0000000..86bd292 --- /dev/null +++ b/scripts/environment-tests/control-context.lp @@ -0,0 +1 @@ +/private/prg/code/xreate/core/control-context.lp \ No newline at end of file diff --git a/scripts/environment-tests/dependencies.lp b/scripts/environment-tests/dependencies.lp new file mode 120000 index 0000000..7db9889 --- /dev/null +++ b/scripts/environment-tests/dependencies.lp @@ -0,0 +1 @@ +/private/prg/code/xreate/core/dependencies.lp \ No newline at end of file diff --git a/scripts/environment-tests/sequence b/scripts/environment-tests/sequence new file mode 100644 index 0000000..1fc241b --- /dev/null +++ b/scripts/environment-tests/sequence @@ -0,0 +1,62 @@ +include raw "core/dependencies.lp" +include raw "core/control-context.lp" +include raw "core/unit-tests.lp" + +start = function:: int; entry { + context:: goal(artefact(gcc)). + + provideGoals() +} + +provideGoals = function():: int { + loop context (goal) { + visit_artefact() + } +} + +visitArtefact = function(){ + switch (EXISTS()){ + case INSTALLED { + ad hoc NOACTION + } + + case NON_INSTALLED { + run [ + PROVIDE_DEPENDENCIES(), + PROVIDE()) + ] + } + } +} + +provideDependencies() = function() { + rule context { + childs(Child) <- artefact(Item); artefact_depends(Item, Child). + } + + loop context (childs) { + VISIT_ARTEFACT(). + } +} + +case context:: artefact(subversion) { + EXISTS = function() { + exec("svn --version"):: ExpectNoErrors; log("Check svn"). + } + + PROVIDE = function(){ + exec("sudo apt-get install subversion"):: log("[Subversion] Installation"). + } +} + + +// DRAFT +/* + flagIsProvided = if(dictProvided()) {true} else + dictProvided = dictProvided + + +expectErrorCode = pre function(x::int){ + if (x==0)::bool {ad hoc "Success"} + else {ad hoc "Error"} +} +*/ \ No newline at end of file diff --git a/scripts/environment-tests/tests-context.lp b/scripts/environment-tests/tests-context.lp new file mode 100644 index 0000000..8559a15 --- /dev/null +++ b/scripts/environment-tests/tests-context.lp @@ -0,0 +1,28 @@ +#include "control-context.lp". + +%body + function(a). + function(b). + function(c). + + scope(0..3). + cfa_call(0, c). + cfa_call(1, c). + cfa_parent(0, function(a)). + cfa_parent(1, function(b)). + cfa_parent(2, function(c)). + cfa_parent(3, scope(2)). + + bind_scope(0, weak(a)). + bind_scope(1, weak(b)). + + bind_scope(0, hard). + bind_scope(1, hard). + +%test weak and hard context + :- bind_scope(2, weak(_)). + :- not bind_scope(2, hard). + +%test rules: + bind_scope(X, rule) :- bind_scope(X, hard), context_rule_visibility(X, 2). + :- not bind_scope(3, rule). diff --git a/scripts/environment-tests/tests-early_late_binding.lp b/scripts/environment-tests/tests-early_late_binding.lp new file mode 100644 index 0000000..a59a8fe --- /dev/null +++ b/scripts/environment-tests/tests-early_late_binding.lp @@ -0,0 +1,21 @@ +%body + function(a). + function(b). + function(c). + function(d1). + function(d2). + + +scope(0..4). +cfa_parent(0, function(a)). +cfa_parent(1, function(b)). +cfa_parent(2, function(c)). +cfa_parent(3, function(d1)). +cfa_parent(4, function(d2)). + +cfa_call(0, function(c)). +cfa_call(1, function(c)). +cfa_call(2, function(d)). + +bind_scope(0, a). +bind_scope(1, b). \ No newline at end of file diff --git a/scripts/environment-tests/xreate-environment b/scripts/environment-tests/xreate-environment index f7428c8..149efed 100644 --- a/scripts/environment-tests/xreate-environment +++ b/scripts/environment-tests/xreate-environment @@ -1,60 +1,73 @@ // install cmake // install llvm // install gcc // install gtest -function():: TestEnvironment(exists(gcc)){ +EXISTS(gcc) = function(){ exec("gcc -v") :: ExpectNoErrors; log("Check gcc"). } function():: provide(gcc) { exec("sudo apt-get install gcc"):: log("[GCC] Installation"). } function():: TestEnvironment(exists(cmake)){ exec("cmake /V"):: ExpectNoErrors; log("Check cmake"). } function():: provide(cmake) { exec("sudo apt-get install cmake"):: log("[CMake] Installation"). } function():: TestEnvironment(exists(subversion)){ exec("svn --version"):: ExpectNoErrors; log("Check svn"). } function():: provide(subversion) { exec("sudo apt-get install subversion"):: log("[Subversion] Installation"). } function():: TestEnvironment(exists(scons)){ exec("scons -v"):: ExpectNoErrors; log("Check scons"). } function():: provide(scons) { exec("sudo apt-get install scons"):: log("[Scons] Installation"). } function():: TestEnvironment(exists(bison)){ exec("bison --version"):: ExpectNoErrors; log("Check bison"). } function():: provide(bison) { exec("sudo apt-get install bison"):: log("[Bison] Installation"). } //FEATURE dependent packages: Subversion function():: provide(gringo) { exec("cd /opt"). //FEATURE states: dir("/opt") exec("svn://svn.code.sf.net/p/potassco/code/trunk") :: log("[Potassco] cloning latest version"); require(svn); require(rights("/opt", WRITE)). //"sudo chown -R user ./potassco" // exec("scons --build-dir=release"):: require(scons) } -function()::{ +function()::depends(env(gringo)){ + +} + +exec(cmd::string) = procedure { + system(cmd)::ErrorCodeResult. } + +procedure :: EnvironmentTest(gcc) { + exec("gcc -v")::ExpectNoErrors. +} + +EnvironmentProvider(gcc) = procedure { + exec("sudo apt-get install gcc"):: log("[GCC] Installation"). +} \ No newline at end of file diff --git a/scripts/function-modifications/control-context.lp b/scripts/function-modifications/control-context.lp deleted file mode 100644 index 22d3247..0000000 --- a/scripts/function-modifications/control-context.lp +++ /dev/null @@ -1 +0,0 @@ -function_mod(func1, mod1):- %context condition diff --git a/scripts/testspass/Containers_Implementation_LinkedList1.xreate b/scripts/testspass/Containers_Implementation_LinkedList1.xreate index cbc893d..7721ddc 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"). +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 { +test= function:: num; entry { filename = "project/documentation.fodt" :: string. docRaw = xmlParseFile(filename) :: xmlDocPtr. tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. childrenRaw = tree["children"]:: [xmlNodePtr]; containers:linkedlist(next, null). size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count::int):: int { count +1::int }. size } diff --git a/scripts/trash/ftransform.li b/scripts/trash/ftransform.li new file mode 100644 index 0000000..d75c454 --- /dev/null +++ b/scripts/trash/ftransform.li @@ -0,0 +1,26 @@ +//преобразование параметров функции + +function(first-function, vars-list(var(x, i32), var(y, i32)), i32, + div(add(x, 5), y)) + +-------------------------------------------------------------------------------------------------- + +type(name(ListNode), struct( + field(name(caption), type(String)), + field(name(args), type(collection(ListNode))) +)) + + + +transform( + name(f-transform), guard(var(name(X), constraints(caption(simple-function)))), + body( + set (args, field(X, args), + + + wrap(extract(args, 0), caption(name)), + + wrap + name(field()) + ) +) diff --git a/scripts/trash/intersection.li2 b/scripts/trash/intersection.li2 new file mode 100644 index 0000000..6ce957a --- /dev/null +++ b/scripts/trash/intersection.li2 @@ -0,0 +1,93 @@ +// пример реализации процедуры определения пересечения двух множеств +// +// +// A, B - два множества + + +Iterator (Set set) : (Set set, int pos) + +next(Iterator Set i): action of Iterator{ + pos++; + + return i; +} + +written El_Type x = Iterator/Set/El_Type i : substitution{ + x = i.pos; +} + + +A overtake B: action of Iterator { + elB = current (B); //эта команда может превратиться просто в использование elA из вызывающей функции, используя аннотацию context или bag + + repeat-post elA elB) + elB = B overtake A; + else + elA = A overake B; + + if (elA == elB) + put(RESULT-SET, elA); + +return RESULT-SET +} + +// repeat - бесконечный повтор? +// repeat-pre - повтор с предусловием, repeat-post - повтор с постусловием + + + + + Работа с Map: + Пример отображения(view), пример №1: + +Map/(KEY, VALUE): type = [(KEY, VALUE)]; + +Map-T ([KEY], [VALUE]): view, pairs: Map/(KEY, VALUE) = { + keys = map pairs, pair + (key, ) = pair; + key + + values = map pairs, pair + (, value) = pair; + value + + return (keys, values) +} + +//(SELECT key, SELECT value) - возможно ли в функцию передавать названия поля, с кот. ей нужно работать.. ? + + Пример №2 (свести к поиску 6): + +find6: function = { +x: [int] = [1, 2, 3, 4, 5, 6, 7]; //эффективная инициализация! + +y = map x, el + 2 * el + +return exists(x, 12); +} + + +/** + * Построить: + * сортировка :- необходимо ordered-list(linked-list, tree-list) + * RA доступ :- желательно hash-list или желательно tree-list + * последовательный доступ :- желательно ordered-list + * + * +Necessarily and ◇ for Possibly \ No newline at end of file diff --git a/scripts/trash/opcode.comments b/scripts/trash/opcode.comments new file mode 100644 index 0000000..31c457b --- /dev/null +++ b/scripts/trash/opcode.comments @@ -0,0 +1,30 @@ + +/* + +ASTLispNode + + +transform( + + function(__name, __vars), function(name(__name), vars-list(__vars), body(function.body) +) +*/ + + +add(y, div(add(x, 5), 15)))) + + +opcode(add, LLVMAddInstruction) +opcode(div, LLVMDivideInstruction) + +function(name(first-function), + vars-list(var(name(x), type(i32)), var(name(y), type(i32))), + return(type(i32)), + body( + div(add(x, 5), y))) + +function (name(second-f), vars-list, return(type(i32)), body( + add(add (10, 20), first-function(11, 80)) +)) + +main(second-f) \ No newline at end of file diff --git a/scripts/trash/opcode.li b/scripts/trash/opcode.li new file mode 100644 index 0000000..5f62311 --- /dev/null +++ b/scripts/trash/opcode.li @@ -0,0 +1,14 @@ +opcode(add, LLVMAddInstruction) +opcode(div, LLVMDivideInstruction) + +function(name(first-function), + vars-list(var(name(x), type(i32)), var(name(y), type(i32))), + return(type(i32)), + body( + div(add(x, 5), y))) + +function (name(second-f), vars-list, return(type(i32)), body( + add(add (10, 20), first-function(80, 11)) +)) + +main(second-f) \ No newline at end of file