diff --git a/config/default.json b/config/default.json index 6b05add..1cf60ec 100644 --- a/config/default.json +++ b/config/default.json @@ -1,71 +1,70 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" }, }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "containers", + "template": "default", "templates": { "default": "*-", "adhocs": "Adhoc.*", "effects": "Effects.*", "basic": "Attachments.*", "ast": "AST.*", "cfa": "CFA.*", "dfa": "DFA.*", "compilation": "Compilation.*", "diagnostic": "Diagnostic.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "types": "Types.*-", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*", "dsl": "Interpretation.*", "context": "Context.*", - "containers": "Containers.ListAsArray2" - - "loops": "Loop.*", + "containers": "Containers.*", + "loops": "Loop.*" } } } diff --git a/core/containers.lp b/core/containers.lp index 63b7269..16b5432 100644 --- a/core/containers.lp +++ b/core/containers.lp @@ -1,58 +1,44 @@ %defines - impl(solid; on_the_fly; linked_list). - op(seqaccess; randaccess). + impl(llvm_array; llvm_const_array; on_the_fly). + op(seqaccess). op(randaccess). relation(recommends; satisfied; unsupported). relation_score(satisfied, 0). relation_score(recommends, 1). relation_score(unsupported, -1). score(-1..1). %domain facts: relation_op(seqaccess, on_the_fly, recommends). - - relation_op(randaccess, solid, recommends). + relation_op(randaccess, llvm_const_array, recommends). relation_op(randaccess, on_the_fly, unsupported). %dfa analysis: -%scheme: dfa_connection(Vto, Vfrom, proto); -%-- dfa_connection(VTo, VFrom, alias); -%-- dfa_connection(VFormal, VActual, arg); -%-- dfa_connection(VActual, VFormal, ret) +% -- %compilation: %-- %domain rules: - %aliases: - var_origin(VAR) :- not dfa_connection(VAR, _, alias), v(VAR). - var_alias(VAR0, VAR_TO) :- dfa_connection(VAR_TO, VAR0, alias), var_origin(VAR0). - var_alias(VAR0, VAR_TO2) :- dfa_connection(VAR_TO2, VAR_TO1, alias), var_alias(VAR0, VAR_TO1). - var_alias(VAR0, VAR0):- var_origin(VAR0). - - %prototypes: - var_proto(V0, Vproto) :- var_origin(V0); var_origin(Vproto); var_alias(Vproto, Vp); dfa_connection(V0, Vp, proto). - - %implementations: -impl_fulfill(OP, IMPL) :- relation_op(OP, IMPL, unsupported). impl_fulfill(OP, IMPL, SCORE):- SCORE = #sum{SCORE1, (OP, IMPL, RL): relation_op(OP, IMPL, RL),relation_score(RL, SCORE1)} ; op(OP); impl(IMPL); not -impl_fulfill(OP, IMPL). - -var_impl_fulfill(Var0, Impl) :- var_alias(Var0, Var_Any); bind(Var_Any, op(Op)); -impl_fulfill(Op, Impl). - var_impl_fulfill(VAR0, IMPL, Score) :- - Score = #sum{SCORE, (OP, IMPL, VAR_ANY): impl_fulfill(OP, IMPL, SCORE), var_alias(VAR0, VAR_ANY), bind(VAR_ANY, op(OP))} - ; bind(VAR0, impl(IMPL)); var_origin(VAR0); not -var_impl_fulfill(VAR0, IMPL). + cluster_root(VAR) :- not dfa_connection(VAR, _, strong), v(VAR). + var_cluster(VAR0, VAR_TO) :- dfa_connection(VAR_TO, VAR0, strong), cluster_root(VAR0). + var_cluster(VAR0, VAR_TO2) :- dfa_connection(VAR_TO2, VAR_TO1, strong), var_cluster(VAR0, VAR_TO1). + var_cluster(VAR0, VAR0):- cluster_root(VAR0). - %transfunction implementation: - %bind(Vactual, op(Op)) :- var_alias(Vformal, V1); bind(V1, op(Op)); dfa_connection(Vformal, Vactual, arg); op(Op). + -impl_fulfill_cluster(Var0, Impl) :- var_cluster(Var0, Var_Any); bind(Var_Any, op(Op)); -impl_fulfill(Op, Impl). + impl_fulfill_cluster(VAR0, IMPL, Score) :- + Score = #sum{SCORE, (OP, IMPL, VAR_ANY): impl_fulfill(OP, IMPL, SCORE), var_cluster(VAR0, VAR_ANY), bind(VAR_ANY, op(OP))} + ; bind(VAR0, impl(IMPL)); cluster_root(VAR0); not -impl_fulfill_cluster(VAR0, IMPL). + - %bind(Vactual, op(Op)) :- var_alias(VO, Vformal); var_alias(VO, V); bind(V, op(Op)); dfa_connection(Vactual,Vformal, ret); op(Op). - % --uncomment to add possible implementations(impl) to an actual var - %bind(Vres, op(Op)) :- var_alias(VO, VA); bind(VA, op(Op)); dfa_connection(VArg,VO, result); op(Op). + proto_cluster(V0, Vproto) :- cluster_root(V0); cluster_root(Vproto); var_cluster(Vproto, Vp); dfa_connection(V0, Vp, proto). %optimization -% #maximize {SCORE, (VAR0, IMPL) : var_impl_fulfill(VAR0, IMPL, SCORE)}. +% #maximize {SCORE, (VAR0, IMPL) : impl_fulfill_cluster(VAR0, IMPL, SCORE)}. -#show var_alias/2. -#show var_impl_fulfill/3. -#show proto_alias2. +#show var_cluster/2. +#show impl_fulfill_cluster/3. diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index d7dde42..1243cff 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,165 +1,165 @@ // // Created by pgess on 3/14/15. // #include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { if (Attachments::exists(s)) { return Attachments::get(s); } return Implementation::create(s); } Query::Query(){ Attachments::init(); } void Query::init(ClaspLayer* clasp) { if (flagIsDataLoaded) return; map prototypes; map roots; //read all proto data auto range = clasp->query(Config::get("containers.id.prototypes")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0> (data)); Symbol prototype = clasp->unpack(get<1> (data)); prototypes[root] = prototype; } // fill implementation data for a data sources: range = clasp->query(Config::get("containers.id.implementations")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol var = clasp->unpack(get<0>(data)); string implSerialized = get<1>(data); //data source, has no prototypes: if (!prototypes.count(var)) { Implementation impl = Implementation::create(var); Attachments::put(var, move(impl)); continue; } roots.emplace(move(var), move(implSerialized)); } //fill implementation data for a cluster roots for (const pair & root: roots) { Symbol prototype = prototypes[root.first]; while (prototypes.count(prototype)) { prototype = prototypes.at(prototype); } Attachments::put(root.first, Implementation(Attachments::get(prototype))); } // read cluster data and fill implementation data for cluster members range = clasp->query(Config::get("containers.id.clusters")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto info = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0>(info)); Symbol child = clasp->unpack(get<1>(info)); - if (!(child == root)) { + if (!(child == root) && (Attachments::exists(root))) { Implementation rootImpl = Attachments::get(root); Attachments::put(child, move(rootImpl)); } } flagIsDataLoaded = true; } //static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); Implementation Implementation::create(const Symbol &var) { //TODO review implementation determination strategy Expression varDecl = CodeScope::getDeclaration(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } default: break; }; ImplementationLinkedList ill(var); if (ill){ return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); } Implementation Implementation::create(const Symbol& var, const std::string& implSerialized) { Expression varDecl = CodeScope::getDeclaration(var); if (implSerialized == Config::get("containers.impl.solid")) { return {SOLID, ImplementationRec{varDecl.operands.size()}}; } else if (implSerialized == Config::get("containers.impl.onthefly")) { return {ON_THE_FLY, ImplementationRec{var}}; } assert(false && "unable to determine proper implementation for the symbol"); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source){ const Expression& sourceExpr = CodeScope::getDeclaration(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList:: operator bool () const{ return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/tests/adhoc.cpp b/cpp/tests/adhoc.cpp index 80d9ec5..55b586e 100644 --- a/cpp/tests/adhoc.cpp +++ b/cpp/tests/adhoc.cpp @@ -1,195 +1,196 @@ /* * adhoc-exceptions.cpp * * Created on: Nov 19, 2015 * Author: pgess */ class Adhoc_pass_Adhoc1_Test; #define FRIENDS_ADHOC \ friend class ::Adhoc_pass_Adhoc1_Test; #include "ast.h" #include "passmanager.h" #include "gtest/gtest.h" #include #include #include #include #include "pass/adhocpass.h" #include "pass/compilepass.h" #include "llvmlayer.h" using namespace xreate; using namespace std; TEST(Adhoc, ast_operatorAdhoc1){ PassManager* man = PassManager::prepareForCode ( "test = function:: int {\n" " ad hoc exception(nonImplemented)\n" "}"); Expression subject = man->root->findFunction("test")->getEntryScope()->getBody(); ASSERT_EQ(Operator::ADHOC, subject.op); Expression exception = AdhocExpression(subject).getCommand(); ASSERT_EQ("exception", exception.getValueString()); } TEST(Adhoc, ast_schemeAdhoc1){ PassManager* man = PassManager::prepareForCode ( "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (Error) {false}\n" " case (Success) {true}\n" " }\n" " }"); assert(man->root->__interfacesData.count(ASTInterface::Adhoc)); Expression adhocData = man->root->__interfacesData.find(ASTInterface::Adhoc)->second; ASSERT_EQ(Operator::SWITCH, adhocData.operands[0].op); } TEST(Adhoc, pass_Adhoc1){ PassManager* man = PassManager::prepareForCode ( "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (Error) {false}\n" " case (Success) {true}\n" " }\n" "}\n" "main = function::int; entry {0} \n" ); man->runWithoutCompilation(); AdhocPass* pass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); EXPECT_TRUE(pass->__schemes.size() > 0); AdhocScheme* scheme = pass->__schemes.begin()->second; EXPECT_EQ("expectNoErrors", scheme->getName()); } TEST(Adhoc, full_1){ PassManager* man = PassManager::prepareForCode ( " import raw (\"core/control-context.lp\")\n" " interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" " }\n" " test1 = pre function {\n" " context:: expectNoErrors." " ad hoc success\n" " }" "main = function::bool;entry {\n" " test1()\n" " }"); bool (*main)() = (bool (*)()) man->run(); bool result = main(); ASSERT_EQ(true, result); } TEST(Adhoc, full_2){ PassManager* man = PassManager::prepareForCode ( " import raw (\"core/control-context.lp\")\n" " interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" " pre function expectErrors:: bool {\n" " case (error) {true}\n" " case (success) {false}\n" " }\n" " }\n" " test1 = pre function {\n" " context:: expectNoErrors." " ad hoc success\n" " }\n" " test2 = pre function {\n" " context:: expectErrors." " ad hoc success\n" " }" "main = function::bool;entry {\n" " test1() != test2()\n" "}"); bool (*main)() = (bool (*)()) man->run(); bool result = main(); ASSERT_EQ(true, result); } //TODO adhoc type. FDecl sets wrong type in prefunc case(invalid type)) TEST(Adhoc, full_contextExpectNoErrrors){ PassManager* man = PassManager::prepareForCode ( "import raw (\"core/control-context.lp\")\n" "interface(extern-c){\n" " xml2 = library:: pkgconfig(\"libxml-2.0\").\n" " \n" " include {\n" " xml2 = [\"stdlib.h\"]\n" " }.\n" "}" "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" "}\n" "expectErrorCode = pre function(x::int){\n" " if (x==0)::undef {ad hoc success}\n" " else {ad hoc error}\n" "}\n" "main = function::bool; entry {\n" " context:: expectNoErrors." " expectErrorCode(system(\"ls -la\"))\n" "}" ); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(1, main()); } +//DEBT Implement compilation of switch adhoc TEST(Adhoc, ast_switchAdhoc1){ PassManager* man = PassManager::prepareForCode ( "test1 = function:: bool {\n" " x = 0. \n" " switch ad hoc (x:: errors)\n" " case (error) {0}\n" " case (success) {1}\n" "\n" "}" ); Expression eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody(); EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op); EXPECT_EQ(3, eSwitch.operands.size()); EXPECT_EQ(1, eSwitch.tags.size()); EXPECT_EQ("errors", eSwitch.tags.begin()->first); Expression eCondition = eSwitch.getOperands()[0]; EXPECT_EQ("x", eCondition.getValueString()); } diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index ba9d06c..a9f3c2b 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,96 +1,109 @@ /* * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ #include "passmanager.h" #include "query/containers.h" #include "Parser.h" #include "gtest/gtest.h" using namespace std; using namespace xreate; using namespace containers; TEST(Containers, ListAsArray){ PassManager* man = PassManager::prepareForCode( R"Code( main = function(x:: int):: int;entry { a = [1, 2, 3]:: [int]. a[x] } )Code" ); void* mainPtr = man->run(); int (*main)(int) = (int (*)(int))mainPtr; ASSERT_EQ(2, main(1)); delete man; } TEST(Containers, ListAsArray2){ PassManager* man = PassManager::prepareForCode( R"Code( + // 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)). + } + + import raw("core/containers.lp") + main = function:: int;entry { + + a= [1, 2, 3]:: [int]. b= loop map(a->el:: int):: [int]{ 2 * el }. sum = loop fold(b->el:: int, 0->acc):: int { acc + el }. sum } )Code" ); void* mainPtr = man->run(); int (*main)() = (int (*)())mainPtr; - ASSERT_EQ(0, main()); + ASSERT_EQ(12, main()); delete man; } TEST(Containers, ContanierLinkedList1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body}; containers::ImplementationLinkedList iLL(symb_chilrenRaw); ASSERT_EQ(true, static_cast(iLL)); ASSERT_EQ("next", iLL.fieldPointer); Implementation impl = Implementation::create(symb_chilrenRaw); ASSERT_NO_FATAL_FAILURE(impl.extract()); ImplementationRec recOnthefly = impl.extract(); ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); } TEST(Containers, Implementation_LinkedListFull){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); std::unique_ptr program(PassManager::prepareForCode(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); ASSERT_EQ(17, answer); fclose(input); } diff --git a/scripts/testspass/Containers_Implementation_LinkedList1.xreate b/scripts/testspass/Containers_Implementation_LinkedList1.xreate index 7a7a039..8340f56 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 index:: (op(randaccess)). - BREAKS THE ANALYSIS. MAKE tree VIEWED AS COLLECTION */ /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ } import raw("core/containers.lp") // PROGRAM XmlNode = type alias { tag:: string, /* attrs:: [string],*/ content:: string }. Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. XmlTree = type alias Tree(XmlNode). test= function:: num; entry { filename = "scripts/testspass/Containers_Implementation_LinkedList1-data.xml" :: string. docRaw = xmlParseFile(filename) :: xmlDocPtr. tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. childrenRaw = tree["children"]:: [xmlNodePtr]; linkedlist(next, null). size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count):: int { count +1::int }. size }