diff --git a/cpp/src/modules.cpp b/cpp/src/modules.cpp index 5866c8a..c5e87fe 100644 --- a/cpp/src/modules.cpp +++ b/cpp/src/modules.cpp @@ -1,164 +1,175 @@ /* * modules.cpp * * Author: pgess * Created on July 22, 2017, 5:13 PM */ #include "modules.h" #include "modules/Parser.h" #include "analysis/aux.h" #include #include #include #include #include namespace fs = boost::filesystem; namespace xreate { void ModuleRecord::addModuleQuery(const Expression& query){ __queries.push_back(query); } void ModuleRecord::addControllerPath(const std::string& path){ __controllers.push_back(path); } void ModuleRecord::addDiscoveryPath(const std::string& path){ __discoveries.push_back(path); } void ModuleRecord::addProperty(const Expression& prop){ __properties.push_back(prop); } void ModulesSolver::loadControllers(const ModuleRecord& module){ for (const std::string& pathController: module.__controllers){ std::fstream fileContent(pathController); __program << fileContent.rdbuf(); } } void ModulesSolver::extractProperties(const ModuleRecord& module){ unsigned int moduleId = __registry->getModuleHash(module.__path); const std::string atomProperty = "bind_module"; boost::format formatProperty(atomProperty + "(%1%, %2%)."); for (const Expression& property: module.__properties){ std::list reprProp = xreate::analysis::compile(property); assert(reprProp.size()== 1); __program << (formatProperty % moduleId % reprProp.front()) << std::endl; } } void ModulesSolver::discoverModules(const ModuleRecord& moduleClient){ std::regex extXreate("\\.xreate$", std::regex::basic); for(const std::string& path: moduleClient.__discoveries){ for(fs::directory_entry e: fs::recursive_directory_iterator(path)) { if (fs::is_regular_file(e.status())){ if (!std::regex_search(e.path().string(), extXreate)) continue; FILE* script = fopen(e.path().c_str(), "r"); grammar::modules::Scanner scanner(script); grammar::modules::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Discovery errors"); parser.module.__path = e.path().c_str(); extractProperties(parser.module); fclose(script); } } } } void ModulesSolver::extractRequirements(const ModuleRecord& module){ const std::string atomQuery = "module_require"; boost::format formatProperty(atomQuery + "(%1%, %2%)."); unsigned int moduleId = __registry->getModuleHash(module.__path); for (const Expression& query: module.__queries){ std::list reprQuery = xreate::analysis::compile(query); assert(reprQuery.size()== 1); __program << (formatProperty % moduleId % reprQuery.front()) << std::endl; } } void ModulesSolver::add(const std::string& base){ __program << base; } void ModulesSolver::init(const std::string& programBase, const ModuleRecord& module){ add(programBase); extractRequirements(module); extractProperties(module); loadControllers(module); discoverModules(module); std::cout << __program.str() << std::endl; } std::list ModulesSolver::run(const ModuleRecord& module){ const std::string atomDecision = "module_include"; unsigned int moduleId = __registry->getModuleHash(module.__path); std::list result; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); ctl.add("base", {}, __program.str()); ctl.ground({{"base", {}}}, nullptr); ctl.solve([&atomDecision, this, &result, moduleId](Gringo::Model const &model) { for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { - atom.print(std::cout); + std::cout << atom << std::endl; if (std::strcmp(atom.name().c_str(), atomDecision.c_str())==0){ - auto rowDecision = ClaspLayer::parse(atom); + auto rowDecision = ClaspLayer::parse(atom); unsigned int moduleIdActual = std::get<0>(rowDecision); if (moduleIdActual == moduleId){ - result.push_back(__registry->getModuleNameByHash(std::get<1>(rowDecision))); + Gringo::Symbol moduleDecided = std::get<1>(rowDecision); + switch (moduleDecided.type()) { + case Gringo::SymbolType::Str: + result.push_back(moduleDecided.string().c_str()); + break; + + case Gringo::SymbolType::Num: + result.push_back(__registry->getModuleNameByHash(moduleDecided.num())); + break; + + default: assert(false && "Inappropriate symbol type"); + } } } } return true; }, {}); return result; } const std::string& ModulesRegistry::getModuleNameByHash(unsigned int hash){ auto result = __registry.right.find(hash); assert(result != __registry.right.end()); return result->second; } unsigned int ModulesRegistry::getModuleHash(const std::string& moduleName){ auto result = __registry.left.insert(Hash::left_value_type(moduleName, __registry.size())); return result.first->second; } } //namespace xreate diff --git a/cpp/tests/modules.cpp b/cpp/tests/modules.cpp index 10c1ead..d8e76b1 100644 --- a/cpp/tests/modules.cpp +++ b/cpp/tests/modules.cpp @@ -1,271 +1,320 @@ /* * modules.cpp * * Author: pgess * Created on June 18, 2017, 8:25 PM */ class Modules_AST2_Test; class Modules_Discovery1_Test; class Modules_Solve1_Test; #define FRIENDS_MODULES_TESTS \ friend class ::Modules_AST2_Test; \ friend class ::Modules_Discovery1_Test; \ friend class ::Modules_Solve1_Test; #include "modules.h" #include "misc/xreatemanager-decorators.h" #include "misc/xreatemanager-modules.h" #include "xreatemanager.h" #include "modules/Parser.h" #include "gtest/gtest.h" #include #include #include namespace fs = boost::filesystem; using namespace std; using namespace xreate::grammar::modules; TEST(Modules, AST1) { FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); ASSERT_EQ(parser.errors->count, 0); } TEST(Modules, AST2){ string code = R"Code( module { name(test1). status(untested). require provides(logging). include controller("/tmp/test-controller.ls"). discover("/tmp/root/"). } )Code"; Scanner scanner(reinterpret_cast(code.c_str()), code.size()); Parser parser(&scanner); parser.Parse(); xreate::ModuleRecord module = parser.module; ASSERT_EQ(2, module.__properties.size()); ASSERT_EQ("name", module.__properties.front().getValueString()); ASSERT_EQ("status", module.__properties.back().getValueString()); ASSERT_EQ(1, module.__queries.size()); ASSERT_EQ("provides", module.__queries.front().getValueString()); ASSERT_EQ(1, module.__controllers.size()); ASSERT_EQ("/tmp/test-controller.ls", module.__controllers.front()); ASSERT_EQ(1, module.__discoveries.size()); ASSERT_EQ("/tmp/root/", module.__discoveries.front()); } TEST(Modules, Discovery1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54723/"; string codeA = R"Code(module { name(testA). status(needToTestMore). })Code"; string codeB = R"Code(module { name(testB). status(needToTestEvenMore). })Code"; string codeMain = string("module{discover \"") + dirModulesRoot + "\".}"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); Parser parser(&scanner); parser.Parse(); xreate::ModulesRegistry registry; xreate::ModulesSolver solver(®istry); solver.discoverModules(parser.module); fs::remove_all(dirModulesRoot); std::string output = solver.__program.str(); cout << output << endl; ASSERT_NE(string::npos, output.find("bind_module(0, name(testA)).")); ASSERT_NE(string::npos, output.find("bind_module(1, status(needToTestEvenMore)).")); } TEST(Modules, Requests1){ } TEST(Modules, Solve1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54724/"; string codeA = R"Code(module { name(testA). provide(superService). status(needToTestMore). })Code"; string codeB = R"Code(module { name(testB). provide(superService). status(needToTestEvenMore). })Code"; string codeMain = R"Code(module { discover("/tmp/testModulesDiscovery1_t54724/") include controller ("/tmp/testModulesDiscovery1_t54724/controller") require (superService) })Code"; string codeController = R"Code( status_score(0, needToTestEvenMore). status_score(1, needToTestMore). module_include_candidate(X, Y, Request):- module_require(X, Request); bind_module(Y, provide(Request)). module_include_winner(X, Request, MaxScore) :- MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; module_require(X, Request). module_include(X, Y) :- module_include_winner(X, Request, MaxScore); bind_module(Y, provide(Request)); bind_module(Y, status(Status)); status_score(MaxScore, Status). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); Parser parser(&scanner); parser.Parse(); xreate::ModulesRegistry registry; xreate::ModulesSolver solver(®istry); solver.init("", parser.module); fs::remove_all(dirModulesRoot); cout << solver.__program.str() << endl; std::list modulesRequired = solver.run(parser.module); ASSERT_EQ(1, modulesRequired.size()); string moduleActualRequired = modulesRequired.front(); string moduleExpected = dirModulesRoot + "a.xreate"; ASSERT_EQ(moduleExpected, moduleActualRequired); } TEST(Modules, Compilation1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54725/"; string codeMain = R"Code( module { discover("/tmp/testModulesDiscovery1_t54725/") include controller("/tmp/testModulesDiscovery1_t54725/controller") require (superService) } test = function:: int; entry { getYourNumber() } )Code"; string codeA = R"Code(module { name(testA). provide(superService). status(needToTestEvenMore). } getYourNumber= function:: int {0} )Code"; string codeB = R"Code(module { name(testB). provide(superService). status(needToTestMore). } getYourNumber= function:: int {1} )Code"; string codeController = R"Code( status_score(0, needToTestEvenMore). status_score(1, needToTestMore). module_include_candidate(X, Y, Request):- module_require(X, Request); bind_module(Y, provide(Request)). module_include_winner(X, Request, MaxScore) :- MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; module_require(X, Request). module_include(X, Y) :- module_include_winner(X, Request, MaxScore); bind_module(Y, provide(Request)); bind_module(Y, status(Status)); status_score(MaxScore, Status). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); auto man = new XreateManagerImpl>(); man->prepareCode(std::move(codeMain)); fs::remove_all(dirModulesRoot); int (*funcMain)() = (int (*)()) man->run(); int result = funcMain(); ASSERT_EQ(1, result); } + +TEST(Modules, Compilation_AssignModulePath1){ + const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54725/"; + string codeMain = +R"Code( +module { + discover("/tmp/testModulesDiscovery1_t54725/") + include controller("/tmp/testModulesDiscovery1_t54725/controller") + + require (superService) +} + +test = function:: int; entry { + getYourNumber() +} +)Code"; + + string codeA = +R"Code(module { + name(testA). + provide(superService). + status(needToTestEvenMore). +} + +getYourNumber= function:: int {0} +)Code"; + + string codeController = +R"Code( +module_include(X, "/tmp/testModulesDiscovery1_t54725/a.xreate") :- module_require(X, superService). +)Code"; + + fs::create_directories(dirModulesRoot); + fs::ofstream fileA(dirModulesRoot + "a.xreate"); + fileA << codeA; + fileA.close(); + + fs::ofstream fileController(dirModulesRoot + "controller"); + fileController << codeController; + fileController.close(); + + auto man = new XreateManagerImpl>(); + man->prepareCode(std::move(codeMain)); + fs::remove_all(dirModulesRoot); + + int (*funcMain)() = (int (*)()) man->run(); + int result = funcMain(); + ASSERT_EQ(0, result); +} \ No newline at end of file