From 57b7b1cb196ea9f51aebaba1a838b9a86a9f83fe Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Wed, 16 Jan 2013 01:31:12 +0100 Subject: More work on Prolog datamodel --- config.h.in | 1 + contrib/cmake/FindSWI.cmake | 6 +- src/uscxml/Factory.h | 1 + src/uscxml/Interpreter.cpp | 11 +++- src/uscxml/Interpreter.h | 1 + src/uscxml/URL.cpp | 68 +++++++++++++++------- src/uscxml/URL.h | 9 +++ .../plugins/datamodel/prolog/swi/SWIDataModel.cpp | 59 ++++++++++++++++--- test/samples/uscxml/test-prolog.scxml | 26 +++++---- test/src/test-prolog-swi.cpp | 49 +++++++++++++--- test/src/test-url.cpp | 6 ++ 11 files changed, 181 insertions(+), 56 deletions(-) diff --git a/config.h.in b/config.h.in index 333b8a0..1bef782 100644 --- a/config.h.in +++ b/config.h.in @@ -48,6 +48,7 @@ /** miscellaneous */ #cmakedefine PROJECT_SOURCE_DIR "@PROJECT_SOURCE_DIR@" #cmakedefine DIST_PREPARE +#cmakedefine SWI_BINARY "@SWI_BINARY@" /** Optional libraries we found */ #cmakedefine UMUNDO_FOUND diff --git a/contrib/cmake/FindSWI.cmake b/contrib/cmake/FindSWI.cmake index 4c71ecd..fb30be4 100644 --- a/contrib/cmake/FindSWI.cmake +++ b/contrib/cmake/FindSWI.cmake @@ -63,10 +63,10 @@ if (SWI_PLATFORM_PATH OR SWI_INCLUDE_HINT) PATHS ${SWI_PLATFORM_PATH} HINTS ${SWI_LIBRARY_HINT} ) - + if (SWI_LIBRARY_RELEASE) list(APPEND SWI_LIBRARY optimized ${SWI_LIBRARY_RELEASE}) - add_definitions("-DSWI_LIBRARY_PATH=\"${SWI_PLATFORM_PATH}\"") + set(SWI_BINARY ${SWI_PLATFORM_PATH}) endif() @@ -84,5 +84,5 @@ if (SWI_PLATFORM_PATH OR SWI_INCLUDE_HINT) endif() INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SWI DEFAULT_MSG SWI_LIBRARY SWI_INCLUDE_DIR) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SWI DEFAULT_MSG SWI_LIBRARY SWI_INCLUDE_DIR SWI_BINARY) MARK_AS_ADVANCED(SWI_LIBRARY SWI_INCLUDE_DIR) diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index 29f7f9a..3cc8018 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -159,6 +159,7 @@ public: virtual void eval(const std::string& expr) { return _impl->eval(expr); } virtual std::string evalAsString(const std::string& expr) { return _impl->evalAsString(expr); } virtual bool evalAsBool(const std::string& expr) { return _impl->evalAsBool(expr); } + virtual void assign(const std::string& location, const std::string& expr) { return _impl->assign(location, expr); } virtual void assign(const std::string& location, const Data& data) { return _impl->assign(location, data); } diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 5449272..9063cef 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -33,6 +33,7 @@ Interpreter::Interpreter() : Arabica::SAX2DOM::Parser() { _thread = NULL; _sendQueue = NULL; _running = false; + _done = false; #ifdef _WIN32 WSADATA wsaData; @@ -172,6 +173,7 @@ Interpreter::~Interpreter() { } void Interpreter::start() { + _done = false; _thread = new tthread::thread(Interpreter::run, this); } @@ -180,10 +182,12 @@ void Interpreter::run(void* instance) { } bool Interpreter::runOnMainThread(int fps, bool blocking) { + if (_done) + return false; + if (fps > 0) { uint64_t nextRun = _lastRunOnMainThread + (1000 / fps); if (blocking) { - tthread::lock_guard lock(_mutex); while(nextRun > tthread::timeStamp()) { tthread::this_thread::sleep_for(tthread::chrono::milliseconds(nextRun - tthread::timeStamp())); } @@ -194,6 +198,7 @@ bool Interpreter::runOnMainThread(int fps, bool blocking) { _lastRunOnMainThread = tthread::timeStamp(); + tthread::lock_guard lock(_mutex); std::map::iterator ioProcessorIter = _ioProcessors.begin(); while(ioProcessorIter != _ioProcessors.end()) { ioProcessorIter->second.runOnMainThread(); @@ -1411,8 +1416,10 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet& enable } for (int i = 0; i < _configuration.size(); i++) { Arabica::DOM::Element stateElem = (Arabica::DOM::Element)_configuration[i]; - if (isFinal(stateElem) && parentIsScxmlState(stateElem)) + if (isFinal(stateElem) && parentIsScxmlState(stateElem)) { _running = false; + _done = true; + } } } diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index ab8cf6d..d5c719b 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -171,6 +171,7 @@ protected: std::string _nsPrefix; bool _running; + bool _done; Binding _binding; Arabica::XPath::NodeSet _configuration; Arabica::XPath::NodeSet _statesToInvoke; diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index ca3e8f7..db128ef 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -52,26 +52,13 @@ const bool URLImpl::toAbsoluteCwd() { return toAbsolute(std::string("file://" + std::string(currPath) + "/")); } -const bool URLImpl::toAbsolute(const std::string& baseUrl) { - if (_uri.is_absolute()) - return true; - _uri = Arabica::io::URI(baseUrl, _uri.as_string()); - if (!_uri.is_absolute()) - return false; - return true; -} - -const std::string URLImpl::asLocalFile(const std::string& suffix, bool reload) { - // this is already a local file - if (_uri.scheme().compare("file") == 0) - return _uri.path(); - - if (_localFile.length() > 0 && !reload) - return _localFile; - +std::string URLImpl::getLocalFilename(const std::string& suffix) { if (_localFile.length() > 0) - remove(_localFile.c_str()); + return _localFile; + if (_uri.scheme().compare("file") == 0) + return _uri.path(); + // try hard to find a temporary directory const char* tmpDir = NULL; if (tmpDir == NULL) @@ -106,10 +93,49 @@ const std::string URLImpl::asLocalFile(const std::string& suffix, bool reload) { _close(fd); #else close(fd); -#endif - _localFile = std::string(tmpl); +#endif + return std::string(tmpl); +} - std::ofstream file(tmpl, std::ios_base::out); +boost::shared_ptr URLImpl::toLocalFile(const std::string& content, const std::string& suffix) { + boost::shared_ptr urlImpl = boost::shared_ptr(new URLImpl()); + urlImpl->_localFile = urlImpl->getLocalFilename(suffix); + urlImpl->_uri = std::string("file://") + urlImpl->_localFile; + + std::ofstream file(urlImpl->_localFile.c_str(), std::ios_base::out); + if(file.is_open()) { + file << content; + file.close(); + } else { + return boost::shared_ptr(); + } + + return urlImpl; +} + +const bool URLImpl::toAbsolute(const std::string& baseUrl) { + if (_uri.is_absolute()) + return true; + _uri = Arabica::io::URI(baseUrl, _uri.as_string()); + if (!_uri.is_absolute()) + return false; + return true; +} + +const std::string URLImpl::asLocalFile(const std::string& suffix, bool reload) { + // this is already a local file + if (_uri.scheme().compare("file") == 0) + return _uri.path(); + + if (_localFile.length() > 0 && !reload) + return _localFile; + + if (_localFile.length() > 0) + remove(_localFile.c_str()); + + _localFile = getLocalFilename(suffix); + + std::ofstream file(_localFile.c_str(), std::ios_base::out); if(file.is_open()) { file << URL(this->shared_from_this()); file.close(); diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h index 07921f3..5bcbd27 100644 --- a/src/uscxml/URL.h +++ b/src/uscxml/URL.h @@ -22,6 +22,8 @@ public: const bool toAbsolute(const std::string& baseUrl); const std::string asLocalFile(const std::string& suffix, bool reload = false); + static boost::shared_ptr toLocalFile(const std::string& content, const std::string& suffix); + const bool isAbsolute() const { return _uri.is_absolute(); } const std::string scheme() const { return _uri.scheme(); } const std::string host() const { return _uri.host(); } @@ -30,6 +32,8 @@ public: const std::string asString() const { return _uri.as_string(); } private: + std::string getLocalFilename(const std::string& suffix); + Arabica::io::URI _uri; std::string _localFile; }; @@ -41,6 +45,11 @@ public: URL(boost::shared_ptr const impl) : _impl(impl) { } URL(const URL& other) : _impl(other._impl) { } virtual ~URL() {}; + + static URL toLocalFile(const std::string& content, const std::string& suffix) { + boost::shared_ptr impl = URLImpl::toLocalFile(content, suffix); + return URL(impl); + } operator bool() const { return _impl;} bool operator< (const URL& other) const { return _impl < other._impl; } diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index e753a32..ffb48f9 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -1,4 +1,5 @@ #include "uscxml/Common.h" +#include "uscxml/config.h" #include "SWIDataModel.h" #include "uscxml/Message.h" #include @@ -23,8 +24,24 @@ SWIDataModel::SWIDataModel() { boost::shared_ptr SWIDataModel::create(Interpreter* interpreter) { boost::shared_ptr dm = boost::shared_ptr(new SWIDataModel()); dm->_interpreter = interpreter; - const char* swiPath = "/foo"; - dm->_plEngine = new PlEngine((char*)swiPath); + + const char* swibin = getenv("SWI_BINARY"); + if (swibin == NULL) + swibin = SWI_BINARY; + const char* quiet = "--quiet"; + + static char * av[] = { + (char*)swibin, + (char*)quiet, + // "-s", + // "/Users/sradomski/Documents/TK/Code/pl-devel/demo/likes.pl", + NULL}; + if(!PL_initialise(2,av)) { + LOG(ERROR) << "Error intializing prolog engine"; + PL_halt(1); + return boost::shared_ptr(); + } + return dm; } @@ -79,25 +96,49 @@ uint32_t SWIDataModel::getLength(const std::string& expr) { } void SWIDataModel::eval(const std::string& expr) { - std::cout << "SWIDataModel::eval" << std::endl; + URL localPLFile = URL::toLocalFile(expr, ".pl"); + PlCall("user", "load_files", PlTermv(localPLFile.asLocalFile(".pl").c_str())) || LOG(ERROR) << "Could not execute prolog from file"; } bool SWIDataModel::evalAsBool(const std::string& expr) { - std::cout << "SWIDataModel::evalAsBool" << std::endl; - return true; + PlCompound compound(expr.c_str()); + PlTermv termv(compound.arity()); + for (int i = 0; i < compound.arity(); i++) { + termv[i] = compound[i + 1]; + } + PlQuery query(compound.name(), termv); + return query.next_solution() > 0; } std::string SWIDataModel::evalAsString(const std::string& expr) { - std::cout << "SWIDataModel::evalAsString" << std::endl; - return std::string(""); + PlCompound compound(expr.c_str()); + if (strlen(compound.name())) { + PlTermv termv(compound.arity()); + for (int i = 0; i < compound.arity(); i++) { + termv[i] = compound[i + 1]; + } + PlQuery query(compound.name(), termv); + + std::stringstream ss; + while (query.next_solution()) { + for (int i = 0; i < compound.arity(); i++) { + const char* separator = ""; + ss << separator << (char *)termv[i]; + separator = ", "; + } + ss << std::endl; + } + return ss.str(); + } + return std::string(compound); } void SWIDataModel::assign(const std::string& location, const Data& data) { - std::cout << "SWIDataModel::assign" << std::endl; + eval(data.atom); } void SWIDataModel::assign(const std::string& location, const std::string& expr) { - std::cout << "SWIDataModel::assign" << std::endl; + eval(expr); } } \ No newline at end of file diff --git a/test/samples/uscxml/test-prolog.scxml b/test/samples/uscxml/test-prolog.scxml index 85d45bc..266bd8d 100644 --- a/test/samples/uscxml/test-prolog.scxml +++ b/test/samples/uscxml/test-prolog.scxml @@ -1,20 +1,22 @@ - - + +% see http://www.swi-prolog.org/FAQ/Multifile.html +:- multifile animal/1. +cat(tom). +animal(X):- cat(X). + - + + + + + + \ No newline at end of file diff --git a/test/src/test-prolog-swi.cpp b/test/src/test-prolog-swi.cpp index 5fa1cb4..afe0754 100644 --- a/test/src/test-prolog-swi.cpp +++ b/test/src/test-prolog-swi.cpp @@ -1,13 +1,17 @@ #include #include #include +#include "uscxml/config.h" using namespace std; int main(void){ + const char* swibin = getenv("SWI_BINARY"); + if (swibin == NULL) + swibin = SWI_BINARY; static char * av[] = { - "/Users/sradomski/Documents/TK/Code/uscxml/contrib/prebuilt/darwin-i386/clang/lib/swipl-6.3.5/bin/x86_64-darwin12.2.0/swipl", + (char*)swibin, // "--quiet", // "-s", // "/Users/sradomski/Documents/TK/Code/pl-devel/demo/likes.pl", @@ -23,17 +27,44 @@ int main(void){ int rval; PlFrame frame; - rval = PlCall("system", "load_files", PlTermv("/Users/sradomski/Documents/TK/Code/pl-devel/demo/likes.pl")); - PlQuery query("user", "likes", PlTermv("sam", "chips")); - if (query.next_solution() > 0) { - std::cout << "Yes!" << std::endl; - } else { - std::cout << "No!" << std::endl; + rval = PlCall("user", "load_files", PlTermv("/Users/sradomski/Documents/TK/Code/pl-devel/demo/likes.pl")); + +// PlCompound compound("likes(sam, X)"); + PlCompound compound("listing"); + PlTermv termv(compound.arity()); +// termv[0] = PlTerm(); + for (int i = 0; i < compound.arity(); i++) { + termv[i] = compound[i + 1]; + } + + PlQuery q(compound.name(), termv); + bool solutionExists = false; + while( q.next_solution() ) { + solutionExists = true; + for (int i = 0; i < compound.arity(); i++) { + switch (compound[i + 1].type()) { + case PL_VARIABLE: + std::cout << (char *)termv[i] << ", "; + break; + case PL_FLOAT: + std::cout << (double)termv[i] << ", "; + break; + case PL_ATOM: + std::cout << (PlAtom)termv[i] << ", "; + break; + case PL_STRING: + std::cout << (char *)termv[i] << ", "; + break; + case PL_TERM: + std::cout << (char *)termv[i] << ", "; + break; + default: ; + } + } + std::cout << std::endl; } - PlQuery q("call", PlTermv(PlCompound("likes(sam,curry).")) -// PlCompound compound("likes(sam,curry)."); // PlQuery query2(compound.name(), PlTermv(compound)); // if (query2.next_solution() > 0) { // std::cout << "Yes!" << std::endl; diff --git a/test/src/test-url.cpp b/test/src/test-url.cpp index 239ff3c..a9a6594 100644 --- a/test/src/test-url.cpp +++ b/test/src/test-url.cpp @@ -40,4 +40,10 @@ int main(int argc, char** argv) { assert(iequals(url.scheme(), "file")); std::cout << url.asString() << std::endl; } + { + URL url = URL::toLocalFile("this is quite some content!", "txt"); + std::cout << url.asLocalFile("txt"); + assert(url.isAbsolute()); + assert(iequals(url.scheme(), "file")); + } } \ No newline at end of file -- cgit v0.12