summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins/datamodel/prolog/swi
diff options
context:
space:
mode:
authorStefan Radomski <sradomski@mintwerk.de>2015-07-08 20:03:03 (GMT)
committerStefan Radomski <sradomski@mintwerk.de>2015-07-08 20:03:03 (GMT)
commit57ba362eae6e8209cf560555fd4cc4bb76dbe2a1 (patch)
tree00a2e2c5fd6993a5ee118df147cae3ef6e9cca9a /src/uscxml/plugins/datamodel/prolog/swi
parentf02d7e5919f16d8396839fcff1e0588d6ccf3004 (diff)
downloaduscxml-57ba362eae6e8209cf560555fd4cc4bb76dbe2a1.zip
uscxml-57ba362eae6e8209cf560555fd4cc4bb76dbe2a1.tar.gz
uscxml-57ba362eae6e8209cf560555fd4cc4bb76dbe2a1.tar.bz2
done.event bug and prolog tests
Fixed the done.event bug and added first prolog transformed IRP tests
Diffstat (limited to 'src/uscxml/plugins/datamodel/prolog/swi')
-rw-r--r--src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp6
-rw-r--r--src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.new962
2 files changed, 966 insertions, 2 deletions
diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
index f6131f8..21b390a 100644
--- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
+++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp
@@ -689,7 +689,9 @@ bool SWIDataModel::evalAsBool(const Arabica::DOM::Element<std::string>& node, co
}
PlQuery query(compound.name(), termv);
return query.next_solution() > 0;
- } catch(...) {
+ }
+ RETHROW_PLEX_AS_EVENT
+ catch(...) {
return false;
}
}
@@ -823,7 +825,7 @@ void SWIDataModel::assign(const Element<std::string>& assignElem,
PlCall(dataInitStr.str().c_str());
} else {
// treat content as . seperated facts
- std::stringstream factStream(content);
+ std::stringstream factStream(expr);
std::string item;
while(std::getline(factStream, item, '.')) {
std::string fact = boost::trim_copy(item);
diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.new b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.new
new file mode 100644
index 0000000..8238577
--- /dev/null
+++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.new
@@ -0,0 +1,962 @@
+/**
+ * @file
+ * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de)
+ * @copyright Simplified BSD
+ *
+ * @cond
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the FreeBSD license as published by the FreeBSD
+ * project.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the FreeBSD license along with this
+ * program. If not, see <http://www.opensource.org/licenses/bsd-license>.
+ * @endcond
+ */
+
+#include <boost/algorithm/string.hpp>
+
+#include "uscxml/Common.h"
+#include "uscxml/config.h"
+#include "SWIDataModel.h"
+#include "uscxml/DOMUtils.h"
+#include "uscxml/Message.h"
+#include <glog/logging.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+// these are defined but not exported by swi-prolog 7
+extern "C" {
+ PL_EXPORT(int) PL_is_dict(term_t t);
+ PL_EXPORT(int) PL_for_dict(term_t dict, int (*func)(term_t key, term_t value, int last, void *closure), void *closure, int flags);
+}
+#define RETHROW_PLEX_AS_EVENT \
+catch (PlException plex) { \
+ ERROR_EXECUTION_THROW((char*)plex); \
+} \
+
+#define PL_MODULE \
+_interpreter.getSessionId().c_str() \
+
+#define SET_PL_ENGINE(dm) \
+assert(_swiEngines.find(dm) != _swiEngines.end()); \
+int rc = PL_set_engine(_swiEngines[dm], NULL); \
+assert(rc == PL_ENGINE_SET); \
+_dmPtr = dm;
+
+namespace uscxml {
+
+using namespace Arabica::XPath;
+using namespace Arabica::DOM;
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool pluginConnect(pluma::Host& host) {
+ host.add( new SWIDataModelProvider() );
+ return true;
+}
+#endif
+
+// SWI prolog does not support passing user data
+static SWIDataModel* _dmPtr;
+static std::map<SWIDataModel*, PL_engine_t> _swiEngines;
+
+PL_blob_t SWIDataModel::blobType = {
+ PL_BLOB_MAGIC,
+ PL_BLOB_NOCOPY,
+ (char*)"blob",
+ releaseBlob,
+ compareBlob,
+ writeBlob,
+ acquireBlob
+};
+
+SWIDataModel::SWIDataModel() {
+}
+
+SWIDataModel::~SWIDataModel() {
+ try {
+ if (_swiEngines.find(this) != _swiEngines.end()) {
+ PL_destroy_engine(_swiEngines[this]);
+ _swiEngines.erase(this);
+ }
+ }
+ RETHROW_PLEX_AS_EVENT;
+}
+
+boost::shared_ptr<DataModelImpl> SWIDataModel::create(InterpreterImpl* interpreter) {
+ try {
+ boost::shared_ptr<SWIDataModel> dm = boost::shared_ptr<SWIDataModel>(new SWIDataModel());
+ dm->_interpreter = interpreter;
+
+ const char* swibin = getenv("SWI_BINARY");
+ if (swibin == NULL)
+ swibin = SWI_BINARY;
+ const char* quiet = "--quiet";
+
+ int argc = 2;
+ static char * av[] = {
+ (char*)swibin,
+ (char*)quiet,
+ NULL
+ };
+
+ if (!PL_is_initialised(NULL, NULL)) {
+ if(!PL_initialise(argc,av)) {
+ LOG(ERROR) << "Error intializing prolog engine";
+ PL_halt(1);
+ return boost::shared_ptr<DataModelImpl>();
+ }
+
+ PL_set_engine(PL_ENGINE_CURRENT, &_engine);
+
+ // load SWI XML parser
+ try {
+ PlCall("use_module", PlCompound("library", PlTerm("sgml")));
+ } catch (PlException plex) {
+
+ LOG(ERROR) << "Cannot load prolog sgml module - make sure you have it installed in your prolog runtime: " << (char*)plex;
+ throw plex;
+ }
+
+ // load json parser
+ try {
+ PlCall("use_module", PlCompound("library", PlTerm("http/json")));
+ PlCall("use_module", PlCompound("library", PlTerm("http/json_convert")));
+ } catch (PlException plex) {
+ LOG(ERROR) << "Cannot load prolog json module or json_convert - make sure you have it installed in your prolog runtime: " << (char*)plex;
+ throw plex;
+ }
+
+ } else {
+ LOG(WARNING) << "Instantiating more than one SWI prolog datamodel will lead to weird effects as I cannot seperate the environments";
+// engine = PL_create_engine(NULL);
+ }
+
+// assert(engine);
+// _swiEngines[dm.get()] = engine;
+ _dmPtr = dm.get();
+
+// int rc = PL_set_engine(engine, NULL);
+// assert(rc == PL_ENGINE_SET);
+// (void)rc;
+
+ _plModule = boost::replace_all_copy(interpreter->getSessionId(), "-", "");
+ boost::replace_all(_plModule, "0", "g");
+ boost::replace_all(_plModule, "1", "h");
+ boost::replace_all(_plModule, "2", "i");
+ boost::replace_all(_plModule, "3", "j");
+ boost::replace_all(_plModule, "4", "k");
+ boost::replace_all(_plModule, "5", "l");
+ boost::replace_all(_plModule, "6", "m");
+ boost::replace_all(_plModule, "7", "n");
+ boost::replace_all(_plModule, "8", "o");
+ boost::replace_all(_plModule, "9", "p");
+
+ // use atoms for double quoted
+ PlCall("set_prolog_flag(double_quotes,atom).");
+
+ // set system variables
+ PlCall("assert", PlCompound("sessionid", PlTerm(PlString(dm->_interpreter->getSessionId().c_str()))));
+ PlCall("assert", PlCompound("name", PlTerm(PlString(dm->_interpreter->getName().c_str()))));
+
+ std::map<std::string, IOProcessor>::const_iterator ioProcIter = dm->_interpreter->getIOProcessors().begin();
+ while(ioProcIter != dm->_interpreter->getIOProcessors().end()) {
+ Data ioProcData = ioProcIter->second.getDataModelVariables();
+
+ if (ioProcIter->first.find_first_of(":/'") == std::string::npos) {
+ std::stringstream ioProcShortCall;
+ ioProcShortCall << "assert(ioprocessors(" << ioProcIter->first << "(location('" << ioProcData.compound["location"].atom << "'))))";
+ PlCall(ioProcShortCall.str().c_str());
+ }
+ std::stringstream ioProcCall;
+ ioProcCall << "assert(ioprocessors(name('" << ioProcIter->first << "'), location('" << ioProcData.compound["location"].atom << "')))";
+ PlCall(ioProcCall.str().c_str());
+
+ ioProcIter++;
+ }
+
+ // the in predicate
+ PlRegister("user", "in", 1, SWIDataModel::inPredicate);
+ PL_set_engine(NULL, NULL);
+ return dm;
+ }
+ RETHROW_PLEX_AS_EVENT;
+}
+
+foreign_t SWIDataModel::inPredicate(term_t a0, int arity, void* context) {
+ try {
+ char *s;
+ if ( PL_get_atom_chars(a0, &s) ) {
+ if (_dmPtr->_interpreter->isInState(s)) {
+ return true;
+ }
+ }
+ return FALSE;
+ }
+ RETHROW_PLEX_AS_EVENT;
+}
+
+void SWIDataModel::registerIOProcessor(const std::string& name, const IOProcessor& ioprocessor) {
+// std::cout << "SWIDataModel::registerIOProcessor" << std::endl;
+}
+
+void SWIDataModel::setSessionId(const std::string& sessionId) {
+// std::cout << "SWIDataModel::setSessionId" << std::endl;
+ _sessionId = sessionId;
+}
+
+void SWIDataModel::setName(const std::string& name) {
+// std::cout << "SWIDataModel::setName" << std::endl;
+ _name = name;
+}
+
+void SWIDataModel::pushContext() {
+// std::cout << "SWIDataModel::pushContext" << std::endl;
+}
+
+void SWIDataModel::popContext() {
+// std::cout << "SWIDataModel::popContext" << std::endl;
+}
+
+void SWIDataModel::initialize() {
+// std::cout << "SWIDataModel::initialize" << std::endl;
+}
+
+void SWIDataModel::setEvent(const Event& event) {
+ SWIEngineLock engineLock;
+
+ // remove old event
+ try {
+ PlCall("retractall(event(_))");
+
+ // simple values
+ PlCall("assert", PlCompound("event", PlCompound("name", PlTerm(event.name.c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("origin", PlString(event.origin.c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("origintype", PlString(event.invokeid.c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("invokeid", PlTerm(event.origintype.c_str()))));
+ PlCall("assert", PlCompound("event", PlCompound("raw", PlString(event.raw.c_str()))));
+
+ // event.type
+ std::string type;
+ switch (event.eventType) {
+ case Event::PLATFORM:
+ type = "platform";
+ break;
+ case Event::INTERNAL:
+ type = "internal";
+ break;
+ case Event::EXTERNAL:
+ type = "external";
+ break;
+ }
+ PlCall("assert", PlCompound("event", PlCompound("type", PlTerm(type.c_str()))));
+
+ // event.sendid
+ if (!event.hideSendId)
+ PlCall("assert", PlCompound("event", PlCompound("sendid", PlTerm(event.sendid.c_str()))));
+
+ // event.data
+ URL domUrl;
+ if (event.dom) {
+ std::stringstream dataInitStr;
+ std::stringstream xmlDoc;
+// xmlDoc << event.getFirstDOMElement();
+ xmlDoc << event.dom;
+ domUrl = URL::toLocalFile(xmlDoc.str(), ".pl");
+ dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), copy_term(XML,DATA), assert(event(data(DATA)))";
+ PlCall(dataInitStr.str().c_str());
+ } else if (event.content.size() > 0) {
+ PlCall("assert", PlCompound("event", PlCompound("data", PlString(InterpreterImpl::spaceNormalize(event.content).c_str()))));
+ } else if (!event.data.empty()) {
+ assertFromData(event.data, "event(data(", 2);
+ }
+
+ Event::params_t::const_iterator paramIter = event.params.begin();
+ while(paramIter != event.params.end()) {
+ assertFromData(paramIter->second, "event(param(" + paramIter->first + "(", 3);
+ paramIter++;
+ }
+
+ Event::namelist_t::const_iterator namelistIter = event.namelist.begin();
+ while(namelistIter != event.namelist.end()) {
+ assertFromData(paramIter->second, "event(param(" + namelistIter->first + "(", 3);
+ namelistIter++;
+ }
+
+#if 0
+ // event.params
+ size_t uniqueKeys = 0;
+ Event::params_t::const_iterator paramIter = event.params.begin();
+ while(paramIter != event.params.end()) {
+ uniqueKeys++;
+ paramIter = event.params.upper_bound(paramIter->first);
+ }
+ if (uniqueKeys > 0) {
+ paramIter = event.params.begin();
+ for(int i = 0; paramIter != event.params.end(); i++) {
+ std::stringstream paramArray;
+ Event::params_t::const_iterator lastValueIter = event.params.upper_bound(paramIter->first);
+
+ paramArray << paramIter->first << "([";
+ std::string termSep = "";
+
+ for (int j = 0; paramIter != lastValueIter; j++) {
+ paramArray << termSep << "'" << paramIter->second << "'";
+ termSep = ", ";
+ paramIter++;
+ }
+ paramArray << "])";
+ std::stringstream paramExpr;
+ paramExpr << "assert(event(param(" << paramArray.str() << ")))";
+ //std::cout << paramExpr.str() << std::endl;
+ PlCall(paramExpr.str().c_str());
+
+ paramIter = lastValueIter;
+ }
+ }
+#endif
+ }
+ RETHROW_PLEX_AS_EVENT;
+}
+
+void SWIDataModel::assertFromData(const Data& data, const std::string& expr, size_t nesting) {
+ if (data.atom.size() > 0) {
+ // terminal branch, this is where we assert
+
+ std::stringstream ss;
+ ss << expr;
+// nesting++;
+
+ if (data.type == Data::VERBATIM) {
+ ss << "\"" << data.atom << "\"";
+ } else {
+ ss << data.atom;
+ }
+
+ for (size_t i = 0; i < nesting; i++) {
+ ss << ")";
+ }
+
+// std::cout << ss.str() << std::endl;
+ PlCall("assert", PlCompound(ss.str().c_str()));
+ return;
+ }
+
+ if (data.compound.size() > 0) {
+ std::map<std::string, Data>::const_iterator compIter = data.compound.begin();
+ while(compIter != data.compound.end()) {
+// std::cout << compIter->first << std::endl;
+ std::stringstream prefix;
+ size_t prefixNesting = 0;
+ size_t oldPos = 0;
+ size_t pos = 0;
+ while((pos = compIter->first.find_first_of(",.(-", oldPos)) != std::string::npos) {
+ prefix << compIter->first.substr(oldPos, pos - oldPos) << "(";
+ prefixNesting++;
+ oldPos = pos + 1;
+ }
+ if (oldPos != compIter->first.size()) {
+ prefix << compIter->first.substr(oldPos, compIter->first.size() - oldPos) << "(";
+ prefixNesting++;
+ }
+ assertFromData(compIter->second, expr + prefix.str(), nesting + prefixNesting);
+ compIter++;
+ }
+ }
+
+ if (data.array.size() > 0) {
+ std::list<Data>::const_iterator arrIter = data.array.begin();
+ while(arrIter != data.array.end()) {
+ assertFromData(*arrIter, expr, nesting);
+ arrIter++;
+ }
+ }
+
+ if (data.node) {
+ std::stringstream dataInitStr;
+ std::stringstream xmlDoc;
+
+ xmlDoc << data.node;
+ URL domUrl = URL::toLocalFile(xmlDoc.str(), ".pl");
+ dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), ";
+ dataInitStr << "copy_term(XML,DATA), ";
+ dataInitStr << "assert(";
+ dataInitStr << expr << "(DATA)";
+
+ for (size_t i = 0; i < nesting; i++) {
+ dataInitStr << ")";
+ }
+
+ PlCall(dataInitStr.str().c_str());
+ return;
+ }
+}
+
+#if 0
+std::list<PlCompound> SWIDataModel::getSolutions(PlCompound compound) {
+ std::list<PlCompound> solutions;
+
+ PlTermv termv(compound.arity());
+ for (int i = 0; i < compound.arity(); i++) {
+ termv[i] = compound[i + 1];
+ }
+ PlQuery query(compound.name(), termv);
+ while(query.next_solution()) {
+// std::cout << (char*)compound << std::endl;
+ solutions.push_back(compound);
+ }
+ return solutions;
+}
+#endif
+
+Data SWIDataModel::getStringAsData(const std::string& content) {
+ SWIEngineLock engineLock;
+ try {
+ PlCompound compound(content.c_str());
+ PlCompound orig(content.c_str());
+ Data data;
+
+ PlTermv termv(compound.arity());
+ for (int i = 0; i < compound.arity(); i++) {
+ termv[i] = compound[i + 1];
+ }
+ PlQuery query(compound.name(), termv);
+
+ while(query.next_solution()) {
+ std::map<std::string, PlTerm> vars = resolveAtoms(compound, orig);
+ std::map<std::string, PlTerm>::const_iterator varIter = vars.begin();
+
+ while(varIter != vars.end()) {
+ data.merge(termAsData(varIter->second));
+ varIter++;
+ }
+
+ }
+// std::cout << Data::toJSON(data) << std::endl;
+ return data;
+ } catch (PlException plex) {
+ try {
+ // could not parse as compound, try term and type in termAsData
+ PlTerm term(content.c_str());
+ return(termAsData(term));
+ }
+ RETHROW_PLEX_AS_EVENT
+ }
+ return Data();
+}
+
+Data SWIDataModel::termAsData(PlTerm term) {
+
+ Data data;
+// std::cout << term.name() << (char*)term << std::endl;
+
+ switch (term.type()) {
+ case PL_TERM:
+ for (int i = 1; i <= term.arity(); i++) { // arguments start at 1
+ data.compound[term.name()] = termAsData(term[i]);
+ }
+ break;
+ case PL_VARIABLE:
+ case PL_INTEGER:
+ case PL_FLOAT:
+ case PL_SHORT:
+ case PL_INT:
+ case PL_LONG:
+ case PL_DOUBLE:
+ data.atom = std::string(term);
+ data.type = Data::INTERPRETED;
+ break;
+ case PL_STRING:
+ case PL_ATOM:
+ data.atom = std::string(term);
+ data.type = Data::VERBATIM;
+ break;
+#ifdef SWI_HAS_PL_NIL
+ case PL_NIL:
+ data.array.push_back(Data("", Data::VERBATIM));
+ break;
+#endif
+#ifdef SWI_HAS_PL_LIST_PAIR
+ case PL_LIST_PAIR: {
+ PlTail tail(term);
+ PlTerm item;
+ while(tail.next(item)) {
+ data.array.push_back(termAsData(item));
+ }
+ break;
+ }
+#endif
+#ifdef SWI_HAS_DICT
+ case PL_DICT: {
+ std::string key(term);
+ size_t curlyPos = key.find_first_of("{");
+ if (curlyPos == std::string::npos || curlyPos == 0) {
+ // no key given
+ PL_for_dict(term, SWIDataModel::dictCallBack, &data, 0);
+ } else {
+ // with key given
+ Data& tmp = data.compound[boost::trim_copy(key.substr(0, curlyPos))];
+ PL_for_dict(term, SWIDataModel::dictCallBack, &tmp, 0);
+ }
+ break;
+ }
+#endif
+ default:
+ LOG(ERROR) << "Prolog type " << term.type() << " at '" << (char*)term << "' not supported";
+ break;
+ }
+ return data;
+}
+
+int SWIDataModel::dictCallBack(term_t key, term_t value, int last, void *closure) {
+ Data* data = (Data*)closure;
+ PlTerm keyTerm(key);
+ data->compound[(char*)keyTerm] = termAsData(value);
+ return 0;
+}
+
+PlTerm SWIDataModel::dataAsTerm(Data data) {
+ if (data.atom.length() > 0) {
+ return PlTerm(data.atom.c_str());
+ }
+ if (data.array.size() > 0) {
+ PlTerm head;
+ PlTail list(head);
+
+ std::list<Data>::const_iterator arrIter = data.array.begin();
+ while(arrIter != data.array.end()) {
+ list.append(dataAsTerm(*arrIter));
+ arrIter++;
+ }
+ list.close();
+ return PlTail(head);
+ }
+ if (data.compound.size() > 0) {
+ if (data.compound.size() == 1 && data.compound.begin()->second.array.size() > 0) {
+ // this used to be a prolog compound
+ const Data& arr = data.compound.begin()->second;
+ PlTermv termv(arr.array.size());
+ int index = 0;
+
+ std::list<Data>::const_iterator arrIter = arr.array.begin();
+ while(arrIter != arr.array.end()) {
+ termv[index] = dataAsTerm(*arrIter);
+ index++;
+ arrIter++;
+ }
+ return PlCompound(data.compound.begin()->first.c_str(), termv);
+ } else if (data.compound.size() == 1 && data.compound.begin()->second.compound.size() > 0) {
+ // this used to be a named dict - until we have dict support in C/C++ use PL_chars_to_term
+ std::stringstream dictSS;
+ std::string seperator;
+ dictSS << data.compound.begin()->first << "{";
+
+ std::map<std::string, Data>::const_iterator keyIter = data.compound.begin()->second.compound.begin();
+ while(keyIter != data.compound.begin()->second.compound.end()) {
+ dictSS << seperator << keyIter->first << ":" << (char*)dataAsTerm(keyIter->second);
+ seperator = ",";
+ keyIter++;
+ }
+ dictSS << "}";
+ return PlCompound(dictSS.str().c_str());
+
+ } else {
+ // an array of dicts
+ PlTermv termv(data.compound.size());
+ int index = 0;
+
+ std::map<std::string, Data>::const_iterator compIter = data.compound.begin();
+ while(compIter != data.compound.end()) {
+ termv[index] = PlCompound(compIter->first.c_str(), dataAsTerm(compIter->second));
+ index++;
+ compIter++;
+ }
+ return PlCompound(data.compound.begin()->first.c_str(), termv);
+
+ }
+ }
+ if (data.binary) {
+ LOG(ERROR) << "Binary data with prolog datamodel still very experimental";
+// term_t binTerm = PL_new_term_ref();
+// PL_put_blob(binTerm, data.binary->data, data.binary->size, &blobType);
+// return binTerm;
+ }
+ if (data.node) {
+ LOG(ERROR) << "DOM in event with prolog datamodel still very experimental";
+ std::stringstream dataInitStr;
+ std::stringstream xmlDoc;
+ // xmlDoc << event.getFirstDOMElement();
+ xmlDoc << data.node;
+ URL domUrl = URL::toLocalFile(xmlDoc.str(), ".pl");
+ dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), copy_term(XML,DATA), assert(event(data(DATA)))";
+ PlCall(dataInitStr.str().c_str());
+ }
+
+ return PlTerm();
+}
+
+bool SWIDataModel::validate(const std::string& location, const std::string& schema) {
+ SWIEngineLock engineLock;
+// std::cout << "SWIDataModel::validate" << std::endl;
+ return true;
+}
+
+bool SWIDataModel::isLocation(const std::string& expr) {
+ return true;
+}
+
+uint32_t SWIDataModel::getLength(const std::string& expr) {
+ SWIEngineLock engineLock;
+ try {
+ 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);
+ uint32_t length = 0;
+ while(query.next_solution() > 0)
+ length++;
+ return length;
+ }
+ RETHROW_PLEX_AS_EVENT;
+}
+
+void SWIDataModel::setForeach(const std::string& item,
+ const std::string& array,
+ const std::string& index,
+ uint32_t iteration) {
+ SWIEngineLock engineLock;
+ try {
+ PlCompound compound(array.c_str());
+ PlCompound orig(array.c_str());
+ PlTermv termv(compound.arity());
+ for (int i = 0; i < compound.arity(); i++) {
+ termv[i] = compound[i + 1];
+ }
+ {
+ int tmp = iteration + 1;
+ PlQuery query(compound.name(), termv);
+ while (tmp) {
+ query.next_solution();
+ tmp--;
+ }
+ }
+ PlCall("retractall", PlCompound(index.c_str(), 1));
+ PlCall("retractall", PlCompound(item.c_str(), 1));
+ PlCall("assert", PlCompound(index.c_str(), PlTerm((long)iteration)));
+
+ std::map<std::string, PlTerm> vars = resolveAtoms(compound, orig);
+ std::map<std::string, PlTerm>::iterator varIter = vars.begin();
+ while(varIter != vars.end()) {
+ PlCall("assert", PlCompound(item.c_str(), varIter->second));
+ varIter++;
+ }
+ }
+ RETHROW_PLEX_AS_EVENT;
+}
+
+void SWIDataModel::eval(const Element<std::string>& scriptElem, const std::string& expr) {
+ SWIEngineLock engineLock;
+ try {
+ if (scriptElem && HAS_ATTR(scriptElem, "type") && iequals(ATTR(scriptElem, "type"), "query")) {
+ evalAsBool(expr);
+ } else {
+ URL localPLFile = URL::toLocalFile(expr, ".pl");
+ PlCall("user", "load_files", PlTermv(localPLFile.asLocalFile(".pl").c_str())) || LOG(ERROR) << "Could not execute prolog from file";
+ }
+ }
+ RETHROW_PLEX_AS_EVENT;
+}
+
+bool SWIDataModel::evalAsBool(const std::string& expr) {
+ return evalAsBool(Arabica::DOM::Element<std::string>(), expr);
+}
+
+bool SWIDataModel::evalAsBool(const Arabica::DOM::Element<std::string>& node, const std::string& expr) {
+ SWIEngineLock engineLock;
+ try {
+ 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;
+ }
+ RETHROW_PLEX_AS_EVENT
+ catch(...) {
+ return false;
+ }
+}
+
+std::string SWIDataModel::evalAsString(const std::string& expr) {
+ SWIEngineLock engineLock;
+ try {
+
+ PlCompound compound(expr.c_str());
+
+ if (strlen(compound.name())) {
+ PlCompound orig(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);
+
+ std::stringstream ss;
+ std::string solSeparator = "";
+ while (query.next_solution()) {
+ ss << solSeparator;
+ std::map<std::string, PlTerm> vars = resolveAtoms(compound, orig);
+ std::map<std::string, PlTerm>::const_iterator varIter = vars.begin();
+
+ std::string varSeparator = "";
+ while(varIter != vars.end()) {
+ ss << varSeparator << (char *)varIter->second;
+ varSeparator = ", ";
+ varIter++;
+ }
+ solSeparator = "\n";
+ }
+ return ss.str();
+ }
+ return std::string(compound);
+
+ } catch(PlException plex) {
+ // we got an exception while trying to evaluate as compound
+ PlTerm term(expr.c_str());
+ if (term.type() == PL_ATOM || term.type() == PL_CHARS || term.type() == PL_STRING) {
+ return std::string(term);
+ } else {
+ ERROR_EXECUTION_THROW((char*)plex);
+ }
+ }
+}
+
+
+// this is similar to http://etalis.googlecode.com/svn/eEtalis/src/term.c
+std::map<std::string, PlTerm> SWIDataModel::resolveAtoms(PlTerm& term, PlTerm& orig) {
+ try {
+ std::map<std::string, PlTerm> atoms;
+ switch (orig.type()) {
+ case PL_VARIABLE: {
+ atoms[(char *)orig] = term;
+ break;
+ }
+ case PL_ATOM:
+ break;
+ case PL_STRING:
+ break;
+ case PL_INTEGER:
+ break;
+ case PL_TERM:
+ for (int i = 1; i <= orig.arity(); i++) {
+ PlTerm newTerm = term[i];
+ PlTerm newOrig = orig[i];
+ std::map<std::string, PlTerm> result = resolveAtoms(newTerm, newOrig);
+ atoms.insert(result.begin(), result.end());
+ }
+ break;
+ default:
+ LOG(ERROR) << "Resolving variable of unknown type in query solution";
+ }
+ return atoms;
+ }
+ RETHROW_PLEX_AS_EVENT
+}
+
+void SWIDataModel::assign(const Element<std::string>& assignElem,
+ const Node<std::string>& node,
+ const std::string& content) {
+ SWIEngineLock engineLock;
+ try {
+ std::string callAssert = "assert";
+ std::string solution;
+ std::string expr = content;
+ std::string predicate;
+ if (HAS_ATTR(assignElem, "solution"))
+ solution = ATTR(assignElem, "solution");
+ if (HAS_ATTR(assignElem, "expr"))
+ expr = ATTR(assignElem, "expr");
+ if (HAS_ATTR(assignElem, "id"))
+ predicate = ATTR(assignElem, "id");
+ if (HAS_ATTR(assignElem, "location"))
+ predicate = ATTR(assignElem, "location");
+
+ if (solution.size() > 0 && expr.size() > 0 && predicate.size() > 0) {
+ // <assign location="var1" solution="Y" expr="var1(X), Y is X + 1, retractall(var1(_))"/>
+ std::cout << expr + ", " + callAssert + "(" + predicate + "(" + solution + "))" << std::endl;
+ PlCall((expr + ", " + callAssert + "(" + predicate + "(" + solution + "))").c_str());
+ return;
+ }
+
+ if (expr.size() > 0 && predicate.size()) {
+ Data json = Data::fromJSON(expr);
+ if (!json.empty()) {
+ std::cout << callAssert + "(" + predicate + ")" << std::endl;
+ PlCall((callAssert + "(" + predicate + ")").c_str());
+ // expression is a JSON structure!
+ std::stringstream dataInitStr;
+ // if (iequals(type, "retract"))
+ // PlCall("retractall", PlCompound(predicate.c_str(), 1));
+ dataInitStr << "json_to_prolog(" << expr << ", JSON), assert(" << predicate << "(JSON))";
+ PlCall(dataInitStr.str().c_str());
+ return;
+ }
+ }
+
+ if (expr.size() > 0 && predicate.size()) {
+ // treat content as . seperated facts
+ std::stringstream factStream(expr);
+ std::string item;
+ while(std::getline(factStream, item, '.')) {
+ std::string fact = boost::trim_copy(item);
+ if (fact.length() == 0)
+ continue;
+ std::cout << callAssert + "(" + predicate + "(" + fact + "))" << std::endl;
+ PlCall((callAssert + "(" + predicate + "(" + fact + "))").c_str());
+ }
+ return;
+ }
+
+ if (predicate.size() > 0) {
+ std::cout << callAssert + "(" + predicate + ")" << std::endl;
+ PlCall((callAssert + "(" + predicate + ")").c_str());
+ return;
+ }
+
+ abort();
+
+ if (expr.size() == 0) {
+ // no expression, just assert id or idlocation
+ std::cout << callAssert + "(" + predicate + ")" << std::endl;
+ PlCall((callAssert + "(" + predicate + ")").c_str());
+ return;
+ }
+
+
+ std::cout << expr + ", " + callAssert + "(" + predicate + ")" << std::endl;
+ PlCall((expr + ", " + callAssert + "(" + predicate + ")").c_str());
+
+
+ }
+#if 0
+ try {
+ std::string expr = content;
+ std::string predicate;
+ if (HAS_ATTR(assignElem, "expr")) {
+ expr = ATTR(assignElem, "expr");
+ }
+ if (HAS_ATTR(assignElem, "id"))
+ predicate = ATTR(assignElem, "id");
+ if (HAS_ATTR(assignElem, "location"))
+ predicate = ATTR(assignElem, "location");
+
+ if (predicate.size() > 0) {
+ std::string callAssert = "assert";
+ std::string type;
+ if (HAS_ATTR(assignElem, "type")) {
+ type = ATTR(assignElem, "type");
+ if(iequals(type, "append")) {
+ callAssert = "assertz";
+ } else if(iequals(type, "prepend")) {
+ callAssert = "asserta";
+ }
+ }
+
+ URL domUrl;
+ Data json;
+ if (!node)
+ json = Data::fromJSON(expr);
+ if (node) {
+ std::stringstream dataInitStr;
+ std::stringstream xmlDoc;
+ Node<std::string> child = node;
+ while(child) {
+ xmlDoc << child;
+ child = child.getNextSibling();
+ }
+ domUrl = URL::toLocalFile(xmlDoc.str(), ".pl");
+ if (iequals(type, "retract"))
+ PlCall("retractall", PlCompound(predicate.c_str(), 1));
+ dataInitStr << "load_xml_file('" << domUrl.asLocalFile(".pl") << "', XML), copy_term(XML,DATA), " << callAssert << "(" << predicate << "(DATA))";
+ PlCall(dataInitStr.str().c_str());
+ } else if (!json.empty()) {
+ std::stringstream dataInitStr;
+ if (iequals(type, "retract"))
+ PlCall("retractall", PlCompound(predicate.c_str(), 1));
+ dataInitStr << "json_to_prolog(" << expr << ", JSON), assert(" << predicate << "(JSON))";
+ PlCall(dataInitStr.str().c_str());
+ } else {
+ // treat content as . seperated facts
+ std::stringstream factStream(content);
+ std::string item;
+ while(std::getline(factStream, item, '.')) {
+ std::string fact = boost::trim_copy(item);
+ if (fact.length() == 0)
+ continue;
+ PlCall((callAssert + "(" + predicate + "(" + fact + "))").c_str());
+ }
+ }
+ } else if (expr.length() > 0) {
+ if (boost::equals(TAGNAME(assignElem), "data")) {
+ eval(assignElem, expr);
+ } else {
+ std::stringstream exprStream(expr);
+ std::string item;
+ while(std::getline(exprStream, item, '.')) {
+ std::string plExpr = boost::trim_copy(item);
+ if (plExpr.length() == 0)
+ continue;
+ PlCall(plExpr.c_str());
+ }
+ }
+ }
+ }
+#endif
+ RETHROW_PLEX_AS_EVENT
+}
+
+void SWIDataModel::assign(const std::string& location, const Data& data) {
+ eval(Element<std::string>(), data.atom);
+}
+
+void SWIDataModel::init(const Element<std::string>& dataElem,
+ const Node<std::string>& node,
+ const std::string& content) {
+ assign(dataElem, node, content);
+}
+void SWIDataModel::init(const std::string& location, const Data& data) {
+ assign(location, data);
+}
+
+bool SWIDataModel::isDeclared(const std::string& expr) {
+ return true;
+}
+
+void SWIDataModel::acquireBlob(atom_t symbol) {
+}
+
+
+int SWIDataModel::releaseBlob(atom_t symbol) {
+ return TRUE;
+}
+
+int SWIDataModel::compareBlob(atom_t a, atom_t b) {
+ return 0;
+}
+
+int SWIDataModel::writeBlob(void *s, atom_t symbol, int flags) {
+ return TRUE;
+}
+
+
+}