summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bindings/swig/php/uscxml.i1
-rw-r--r--src/uscxml/Interpreter.cpp125
-rw-r--r--src/uscxml/Interpreter.h12
-rw-r--r--src/uscxml/Message.cpp2
-rw-r--r--src/uscxml/Message.h200
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.cpp28
-rw-r--r--src/uscxml/interpreter/InterpreterDraft6.h6
-rw-r--r--src/uscxml/interpreter/InterpreterDraft7.cpp100
-rw-r--r--src/uscxml/interpreter/InterpreterDraft7.h16
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp126
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h2
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeList.h2
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeListCustom.cpp52
13 files changed, 458 insertions, 214 deletions
diff --git a/src/bindings/swig/php/uscxml.i b/src/bindings/swig/php/uscxml.i
index 6180d05..ba58678 100644
--- a/src/bindings/swig/php/uscxml.i
+++ b/src/bindings/swig/php/uscxml.i
@@ -31,6 +31,7 @@ void*** tsrm_ls;
%feature("director") uscxml::InterpreterMonitor;
%ignore uscxml::NumAttr;
+%ignore uscxml::SCXMLParser;
//***********************************************
// Parse the header file to generate wrappers
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index e59ef5f..089406d 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -108,7 +108,7 @@ Interpreter* Interpreter::fromURI(const std::string& uri) {
Interpreter* Interpreter::fromInputSource(Arabica::SAX::InputSource<std::string>& source) {
Interpreter* interpreter = new InterpreterDraft6();
-
+
SCXMLParser* parser = new SCXMLParser(interpreter);
if(!parser->parse(source) || !parser->getDocument().hasChildNodes()) {
if(parser->_errorHandler.errorsReported()) {
@@ -260,24 +260,24 @@ void Interpreter::init() {
NodeList<std::string> scxmls = _document.getElementsByTagNameNS(_nsURL, "scxml");
if (scxmls.getLength() > 0) {
_scxml = (Arabica::DOM::Element<std::string>)scxmls.item(0);
-
+
// setup xpath and check that it works
_xpath.setNamespaceContext(_nsContext);
Arabica::XPath::NodeSet<std::string> scxmls = _xpath.evaluate("/" + _xpathPrefix + "scxml", _document).asNodeSet();
assert(scxmls.size() > 0);
assert(scxmls[0] == _scxml);
-
+
if (_name.length() == 0)
_name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID());
-
+
normalize(_document);
-
+
if (_capabilities & CAN_GENERIC_HTTP)
_httpServlet = new InterpreterServlet(this);
-
+
_sendQueue = new DelayedEventQueue();
_sendQueue->start();
-
+
} else {
LOG(ERROR) << "Cannot find SCXML element" << std::endl;
}
@@ -552,6 +552,7 @@ void Interpreter::send(const Arabica::DOM::Node<std::string>& element) {
if (contents.size() > 0) {
if (HAS_ATTR(contents[0], "expr")) {
if (_dataModel) {
+ /// this is out of spec
std::string contentValue = _dataModel.evalAsString(ATTR(contents[0], "expr"));
sendReq.content = contentValue;
// sendReq.data.atom = contentValue;
@@ -560,9 +561,50 @@ void Interpreter::send(const Arabica::DOM::Node<std::string>& element) {
LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
}
} else if (contents[0].hasChildNodes()) {
- sendReq.content = contents[0].getFirstChild().getNodeValue();
-// sendReq.data.atom = sendReq.content;
-// sendReq.data.type = Data::VERBATIM;
+ bool presentAsDOM = false;
+ NodeList<std::string> contentChilds = contents[0].getChildNodes();
+ for (int i = 0; i < contentChilds.getLength(); i++) {
+ if (contentChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE) {
+ presentAsDOM = true;
+ break;
+ }
+ }
+ if (presentAsDOM) {
+ // use the whole dom
+ Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ sendReq.dom = domFactory.createDocument(contents[0].getNamespaceURI(), "", 0);
+ for (int i = 0; i < contentChilds.getLength(); i++) {
+ try {
+ Node<std::string> newNode = sendReq.dom.importNode(contentChilds.item(i), true);
+ sendReq.dom.appendChild(newNode);
+ } catch (...) {
+
+ }
+ }
+ std::cout << sendReq.dom << std::endl;
+ } else {
+ Node<std::string> textChild = contents[0].getFirstChild();
+ while(textChild && textChild.getNodeType() != Node_base::TEXT_NODE) {
+ textChild = textChild.getNextSibling();
+ }
+ if (textChild && textChild.getNodeType() == Node_base::TEXT_NODE) {
+ /// create space normalized string
+ std::istringstream iss(contents[0].getFirstChild().getNodeValue());
+ std::stringstream content;
+ std::string seperator;
+ do {
+ std::string token;
+ iss >> token;
+ if (token.length() > 0) {
+ content << seperator << token;
+ seperator = " ";
+ }
+ } while (iss);
+ sendReq.content = content.str();
+ } else {
+ LOG(ERROR) << "content element has neither text nor element children.";
+ }
+ }
} else {
LOG(ERROR) << "content element does not specify any content.";
}
@@ -587,6 +629,7 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) {
Interpreter* INSTANCE = data->first;
SendRequest sendReq = data->second;
+ // see http://www.w3.org/TR/scxml/#SendTargets
if (boost::iequals(sendReq.target, "#_parent")) {
// send to parent scxml session
if (INSTANCE->_parentQueue != NULL) {
@@ -611,7 +654,12 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) {
LOG(ERROR) << "Can not send to invoked component '" << invokeId << "', no such invokeId" << std::endl;
}
} else if (sendReq.target.length() == 0) {
- INSTANCE->receive(sendReq);
+ /**
+ * If neither the 'target' nor the 'targetexpr' attribute is specified, the
+ * SCXML Processor must add the event will be added to the external event
+ * queue of the sending session.
+ */
+ INSTANCE->_externalQueue.push(sendReq);
} else {
IOProcessor ioProc = INSTANCE->getIOProcessor(sendReq.type);
if (ioProc) {
@@ -628,7 +676,11 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) {
void Interpreter::invoke(const Arabica::DOM::Node<std::string>& element) {
InvokeRequest invokeReq;
- invokeReq.dom = element;
+
+ Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ invokeReq.dom = domFactory.createDocument(element.getNamespaceURI(), "", 0);
+ Node<std::string> newNode = invokeReq.dom.importNode(element, true);
+ invokeReq.dom.appendChild(newNode);
try {
// type
@@ -891,7 +943,7 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content)
if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE)
continue;
if (boost::iequals(TAGNAME(childs.item(i)), _xmlNSPrefix + "elseif") ||
- boost::iequals(TAGNAME(childs.item(i)), _xmlNSPrefix + "else")) {
+ boost::iequals(TAGNAME(childs.item(i)), _xmlNSPrefix + "else")) {
if (blockIsTrue) {
// last block was true, break here
break;
@@ -917,25 +969,34 @@ void Interpreter::executeContent(const Arabica::DOM::Node<std::string>& content)
std::string array = ATTR(content, "array");
std::string item = ATTR(content, "item");
std::string index = (HAS_ATTR(content, "index") ? ATTR(content, "index") : "");
- uint32_t iterations = _dataModel.getLength(array);
- _dataModel.pushContext(); // copy old and enter new context
- for (uint32_t iteration = 0; iteration < iterations; iteration++) {
- {
- // assign array element to item
- std::stringstream ss;
- ss << array << "[" << iteration << "]";
- _dataModel.assign(item, ss.str());
- }
- if (index.length() > 0) {
- // assign iteration element to index
- std::stringstream ss;
- ss << iteration;
- _dataModel.assign(index,ss.str());
+ uint32_t iterations = 0;
+ try {
+ iterations = _dataModel.getLength(array);
+ try {
+ _dataModel.pushContext(); // copy old and enter new context
+ for (uint32_t iteration = 0; iteration < iterations; iteration++) {
+ {
+ // assign array element to item
+ std::stringstream ss;
+ ss << array << "[" << iteration << "]";
+ _dataModel.assign(item, ss.str());
+ }
+ if (index.length() > 0) {
+ // assign iteration element to index
+ std::stringstream ss;
+ ss << iteration;
+ _dataModel.assign(index,ss.str());
+ }
+ if (content.hasChildNodes())
+ executeContent(content.getChildNodes());
+ }
+ _dataModel.popContext(); // leave stacked context
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in foreach element:" << std::endl << e << std::endl;
}
- if (content.hasChildNodes())
- executeContent(content.getChildNodes());
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in array attribute of foreach element:" << std::endl << e << std::endl;
}
- _dataModel.popContext(); // leave stacked context
} else {
LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl;
}
@@ -1225,7 +1286,7 @@ Arabica::XPath::NodeSet<std::string> Interpreter::getInitialStates(Arabica::DOM:
assert(isCompound(state) || isParallel(state));
Arabica::XPath::NodeSet<std::string> initialStates;
-
+
// initial attribute at element
Arabica::DOM::Element<std::string> stateElem = (Arabica::DOM::Element<std::string>)state;
if (stateElem.hasAttribute("initial")) {
@@ -1233,7 +1294,7 @@ Arabica::XPath::NodeSet<std::string> Interpreter::getInitialStates(Arabica::DOM:
}
Arabica::XPath::NodeSet<std::string> initStates;
-
+
// initial element as child - but not the implicit generated one
NodeSet<std::string> initElems = filterChildElements(_xmlNSPrefix + "initial", state);
if(initElems.size() == 1 && !boost::iequals(ATTR(initElems[0], "generated"), "true")) {
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 353233d..5d45e4c 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -77,7 +77,7 @@ public:
Arabica::SAX::CatchErrorHandler<std::string> _errorHandler;
Interpreter* _interpreter;
};
-
+
class Interpreter {
public:
enum Binding {
@@ -176,10 +176,10 @@ public:
void setConfiguration(const std::vector<std::string>& states) {
_userDefinedStartConfiguration = states;
}
-
+
Arabica::DOM::Node<std::string> getState(const std::string& stateId);
Arabica::XPath::NodeSet<std::string> getStates(const std::vector<std::string>& stateIds);
-
+
Arabica::DOM::Document<std::string>& getDocument() {
return _document;
}
@@ -213,7 +213,7 @@ public:
static bool isParallel(const Arabica::DOM::Node<std::string>& state);
static bool isCompound(const Arabica::DOM::Node<std::string>& state);
static bool isDescendant(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2);
-
+
static std::vector<std::string> tokenizeIdRefs(const std::string& idRefs);
bool isInitial(const Arabica::DOM::Node<std::string>& state);
@@ -256,7 +256,7 @@ protected:
Arabica::XPath::NodeSet<std::string> _configuration;
Arabica::XPath::NodeSet<std::string> _statesToInvoke;
std::vector<std::string> _userDefinedStartConfiguration;
-
+
DataModel _dataModel;
std::map<std::string, Arabica::XPath::NodeSet<std::string> > _historyValue;
@@ -309,7 +309,7 @@ protected:
/// TODO: We need to remember to adapt them when the DOM is operated upon
std::map<std::string, Arabica::DOM::Node<std::string> > _cachedStates;
std::map<std::string, URL> _cachedURLs;
-
+
friend class SCXMLParser;
};
diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp
index 845118b..3ada20c 100644
--- a/src/uscxml/Message.cpp
+++ b/src/uscxml/Message.cpp
@@ -182,7 +182,7 @@ Data Data::fromJSON(const std::string& jsonString) {
if (jsonString.length() == 0)
return data;
-
+
jsmn_parser p;
jsmntok_t* t = NULL;
diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h
index 2a49264..176ae86 100644
--- a/src/uscxml/Message.h
+++ b/src/uscxml/Message.h
@@ -40,19 +40,35 @@ public:
return ss.str();
}
- std::map<std::string, Data> getCompund() { return compound; }
- void setCompound(const std::map<std::string, Data>& compound) { this->compound = compound; }
+ std::map<std::string, Data> getCompund() {
+ return compound;
+ }
+ void setCompound(const std::map<std::string, Data>& compound) {
+ this->compound = compound;
+ }
- std::list<Data> getArray() { return array; }
- void setArray(const std::list<Data>& array) { this->array = array; }
+ std::list<Data> getArray() {
+ return array;
+ }
+ void setArray(const std::list<Data>& array) {
+ this->array = array;
+ }
+
+ std::string getAtom() {
+ return atom;
+ }
+ void setAtom(const std::string& atom) {
+ this->atom = atom;
+ }
- std::string getAtom() { return atom; }
- void setAtom(const std::string& atom) { this->atom = atom; }
+ Type getType() {
+ return type;
+ }
+ void setType(const Type type) {
+ this->type = type;
+ }
- Type getType() { return type; }
- void setType(const Type type) { this->type = type; }
-
#ifdef SWIGIMPORTED
protected:
#endif
@@ -84,29 +100,68 @@ public:
return this < &other;
}
- std::string getName() { return name; }
- void setName(const std::string& name) { this->name = name; }
+ std::string getName() {
+ return name;
+ }
+ void setName(const std::string& name) {
+ this->name = name;
+ }
+
+ Type getType() {
+ return type;
+ }
+ void setType(const Type type) {
+ this->type = type;
+ }
- Type getType() { return type; }
- void setType(const Type type) { this->type = type; }
+ std::string getOrigin() {
+ return origin;
+ }
+ void setOrigin(const std::string& origin) {
+ this->origin = origin;
+ }
- std::string getOrigin() { return origin; }
- void setOrigin(const std::string& origin) { this->origin = origin; }
+ std::string getOriginType() {
+ return origintype;
+ }
+ void setOriginType(const std::string& originType) {
+ this->origintype = originType;
+ }
- std::string getOriginType() { return origintype; }
- void setOriginType(const std::string& originType) { this->origintype = originType; }
+ Arabica::DOM::Document<std::string> getDOM() {
+ return dom;
+ }
+ void setDOM(const Arabica::DOM::Document<std::string>& dom) {
+ this->dom = dom;
+ }
- Arabica::DOM::Node<std::string> getDOM() { return dom; }
- void setDOM(const Arabica::DOM::Node<std::string>& dom) { this->dom = dom; }
+ std::string getContent() {
+ return content;
+ }
+ void setContent(const std::string& content) {
+ this->content = content;
+ }
- std::string getSendId() { return sendid; }
- void setSendId(const std::string& sendId) { this->sendid = sendId; }
+ std::string getSendId() {
+ return sendid;
+ }
+ void setSendId(const std::string& sendId) {
+ this->sendid = sendId;
+ }
- std::string getInvokeId() { return invokeid; }
- void setInvokeId(const std::string& invokeId) { this->invokeid = invokeId; }
+ std::string getInvokeId() {
+ return invokeid;
+ }
+ void setInvokeId(const std::string& invokeId) {
+ this->invokeid = invokeId;
+ }
- Data getData() { return data; }
- void setData(const Data& invokeId) { this->data = data; }
+ Data getData() {
+ return data;
+ }
+ void setData(const Data& invokeId) {
+ this->data = data;
+ }
static Event fromXML(const std::string& xmlString);
Arabica::DOM::Document<std::string> toDocument();
@@ -124,10 +179,11 @@ protected:
Type type;
std::string origin;
std::string origintype;
- Arabica::DOM::Node<std::string> dom;
+ Arabica::DOM::Document<std::string> dom;
std::string sendid;
std::string invokeid;
Data data;
+ std::string content;
#ifndef SWIG
friend std::ostream& operator<< (std::ostream& os, const Event& event);
@@ -138,22 +194,33 @@ class InvokeRequest : public Event {
public:
InvokeRequest(Event event) : Event(event) {}
InvokeRequest() {}
-
- std::string getType() { return type; }
- void setType(const std::string& type) { this->type = type; }
- std::string getSource() { return src; }
- void setSource(const std::string& src) { this->src = src; }
+ std::string getType() {
+ return type;
+ }
+ void setType(const std::string& type) {
+ this->type = type;
+ }
- std::string getContent() { return content; }
- void setContent(const std::string& content) { this->content = content; }
-
- bool isAutoForwarded() { return autoForward; }
- void setAutoForwarded(bool autoForward) { this->autoForward = autoForward; }
+ std::string getSource() {
+ return src;
+ }
+ void setSource(const std::string& src) {
+ this->src = src;
+ }
+
+ bool isAutoForwarded() {
+ return autoForward;
+ }
+ void setAutoForwarded(bool autoForward) {
+ this->autoForward = autoForward;
+ }
#ifdef SWIG
/// TODO: Do we want to set namelist and params as well?
- std::map<std::string, std::string> getNameList() { return namelist; }
+ std::map<std::string, std::string> getNameList() {
+ return namelist;
+ }
const std::vector<std::string> getNameListKeys() {
std::set<std::string> keys;
@@ -175,7 +242,7 @@ public:
}
return paramsMap;
}
-
+
const std::vector<std::string> getParamKeys() {
std::set<std::string> keys;
params_t::iterator paramIter = params.begin();
@@ -185,10 +252,14 @@ public:
}
return std::vector<std::string>(keys.begin(), keys.end());
}
-
+
#else
- std::map<std::string, std::string>& getNameList() { return namelist; }
- std::multimap<std::string, std::string>& getParams() { return params; }
+ std::map<std::string, std::string>& getNameList() {
+ return namelist;
+ }
+ std::multimap<std::string, std::string>& getParams() {
+ return params;
+ }
#endif
static InvokeRequest fromXML(const std::string& xmlString);
@@ -204,7 +275,6 @@ protected:
#endif
std::string type;
std::string src;
- std::string content;
bool autoForward;
std::map<std::string, std::string> namelist;
std::multimap<std::string, std::string> params;
@@ -223,21 +293,32 @@ public:
SendRequest() {}
SendRequest(Event event) : Event(event) {}
- std::string getTarget() { return target; }
- void setTarget(const std::string& target) { this->target = target; }
+ std::string getTarget() {
+ return target;
+ }
+ void setTarget(const std::string& target) {
+ this->target = target;
+ }
- std::string getType() { return type; }
- void setType(const std::string& type) { this->type = type; }
+ std::string getType() {
+ return type;
+ }
+ void setType(const std::string& type) {
+ this->type = type;
+ }
- uint32_t getDelayMs() { return delayMs; }
- void setDelayMs(uint32_t delayMs) { this->delayMs = delayMs; }
-
- std::string getContent() { return content; }
- void setContent(const std::string& content) { this->content = content; }
+ uint32_t getDelayMs() {
+ return delayMs;
+ }
+ void setDelayMs(uint32_t delayMs) {
+ this->delayMs = delayMs;
+ }
#ifdef SWIG
/// TODO: Do we want to set namelist and params as well?
- std::map<std::string, std::string> getNameList() { return namelist; }
+ std::map<std::string, std::string> getNameList() {
+ return namelist;
+ }
const std::vector<std::string> getNameListKeys() {
std::set<std::string> keys;
@@ -259,7 +340,7 @@ public:
}
return paramsMap;
}
-
+
const std::vector<std::string> getParamKeys() {
std::set<std::string> keys;
params_t::iterator paramIter = params.begin();
@@ -269,10 +350,14 @@ public:
}
return std::vector<std::string>(keys.begin(), keys.end());
}
-
+
#else
- std::map<std::string, std::string>& getNameList() { return namelist; }
- std::multimap<std::string, std::string>& getParams() { return params; }
+ std::map<std::string, std::string>& getNameList() {
+ return namelist;
+ }
+ std::multimap<std::string, std::string>& getParams() {
+ return params;
+ }
#endif
static SendRequest fromXML(const std::string& xmlString);
@@ -290,11 +375,10 @@ protected:
std::string target;
std::string type;
uint32_t delayMs;
- std::string content;
std::map<std::string, std::string> namelist;
std::multimap<std::string, std::string> params;
-
+
typedef std::map<std::string, std::string> namelist_t;
typedef std::multimap<std::string, std::string> params_t;
diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp
index d95ae4c..18a42fd 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.cpp
+++ b/src/uscxml/interpreter/InterpreterDraft6.cpp
@@ -67,12 +67,12 @@ void InterpreterDraft6::interpret() {
}
NodeSet<std::string> initialTransitions;
-
+
if (_userDefinedStartConfiguration.size() == 0) {
// try to get initial transition form initial element
- initialTransitions = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", _document).asNodeSet();
+ initialTransitions = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", _document).asNodeSet();
}
-
+
if (initialTransitions.size() == 0) {
Arabica::XPath::NodeSet<std::string> initialStates;
if (_userDefinedStartConfiguration.size() > 0) {
@@ -82,7 +82,7 @@ void InterpreterDraft6::interpret() {
// or fetch per draft
initialStates = getInitialStates();
}
-
+
assert(initialStates.size() > 0);
for (int i = 0; i < initialStates.size(); i++) {
Arabica::DOM::Element<std::string> initialElem = _document.createElementNS(_nsURL, "initial");
@@ -94,18 +94,18 @@ void InterpreterDraft6::interpret() {
initialTransitions.push_back(transitionElem);
}
}
-
+
assert(initialTransitions.size() > 0);
enterStates(initialTransitions);
-
- assert(hasLegalConfiguration());
+
+// assert(hasLegalConfiguration());
mainEventLoop();
if (_parentQueue) {
- // send one final event to unblock eventual listeners
- Event quit;
- quit.name = "done.state.scxml";
- _parentQueue->push(quit);
+ // send one final event to unblock eventual listeners
+ Event quit;
+ quit.name = "done.state.scxml";
+ _parentQueue->push(quit);
}
// set datamodel to null from this thread
@@ -234,7 +234,7 @@ void InterpreterDraft6::mainEventLoop() {
continue;
// assume that we have a legal configuration as soon as the internal queue is empty
- assert(hasLegalConfiguration());
+ assert(hasLegalConfiguration());
monIter = _monitors.begin();
// if (!_sendQueue || _sendQueue->isEmpty()) {
@@ -844,8 +844,8 @@ void InterpreterDraft6::enterStates(const Arabica::XPath::NodeSet<std::string>&
}
void InterpreterDraft6::addStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- Arabica::XPath::NodeSet<std::string>& statesToEnter,
- Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
+ Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
std::string stateId = ((Arabica::DOM::Element<std::string>)state).getAttribute("id");
#if VERBOSE
diff --git a/src/uscxml/interpreter/InterpreterDraft6.h b/src/uscxml/interpreter/InterpreterDraft6.h
index 10ff10a..476da05 100644
--- a/src/uscxml/interpreter/InterpreterDraft6.h
+++ b/src/uscxml/interpreter/InterpreterDraft6.h
@@ -8,17 +8,17 @@ namespace uscxml {
class InterpreterDraft6 : public Interpreter {
void interpret();
void mainEventLoop();
-
+
void initializeData(const Arabica::DOM::Node<std::string>& data);
void microstep(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
void enterStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
void addStatesToEnter(const Arabica::DOM::Node<std::string>& state,
Arabica::XPath::NodeSet<std::string>& statesToEnter,
Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
-
+
void exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
void exitInterpreter();
-
+
Arabica::XPath::NodeSet<std::string> selectEventlessTransitions();
Arabica::XPath::NodeSet<std::string> selectTransitions(const std::string& event);
Arabica::XPath::NodeSet<std::string> filterPreempted(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
diff --git a/src/uscxml/interpreter/InterpreterDraft7.cpp b/src/uscxml/interpreter/InterpreterDraft7.cpp
index 9542146..7af2d39 100644
--- a/src/uscxml/interpreter/InterpreterDraft7.cpp
+++ b/src/uscxml/interpreter/InterpreterDraft7.cpp
@@ -27,12 +27,12 @@ procedure interpret(doc):
void InterpreterDraft7::interpret() {
if (!_isInitialized)
init();
-
+
if (!_scxml)
return;
-
+
_sessionId = getUUID();
-
+
std::string datamodelName;
if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel"))
datamodelName = ATTR(_scxml, "datamodel");
@@ -43,7 +43,7 @@ void InterpreterDraft7::interpret() {
if(datamodelName.length() > 0 && !_dataModel) {
LOG(ERROR) << "No datamodel for " << datamodelName << " registered";
}
-
+
if (_dataModel) {
_dataModel.assign("_x.args", _cmdLineOptions);
if (_httpServlet) {
@@ -52,14 +52,14 @@ void InterpreterDraft7::interpret() {
_dataModel.assign("_ioprocessors['http']", data);
}
}
-
+
setupIOProcessors();
-
+
_running = true;
_binding = (HAS_ATTR(_scxml, "binding") && boost::iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY);
-
+
// @TODO: Reread http://www.w3.org/TR/scxml/#DataBinding
-
+
if (_dataModel && _binding == EARLY) {
// initialize all data elements
NodeSet<std::string> dataElems = _xpath.evaluate("//" + _xpathPrefix + "data", _document).asNodeSet();
@@ -73,14 +73,14 @@ void InterpreterDraft7::interpret() {
initializeData(topDataElems[i]);
}
}
-
+
// executeGlobalScriptElements
NodeSet<std::string> globalScriptElems = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "script", _document).asNodeSet();
for (unsigned int i = 0; i < globalScriptElems.size(); i++) {
if (_dataModel)
executeContent(globalScriptElems[i]);
}
-
+
// initial transition might be implict
NodeSet<std::string> initialTransitions = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", _document).asNodeSet();
if (initialTransitions.size() == 0) {
@@ -97,21 +97,21 @@ void InterpreterDraft7::interpret() {
}
}
enterStates(initialTransitions);
-
+
// assert(hasLegalConfiguration());
mainEventLoop();
-
+
if (_parentQueue) {
// send one final event to unblock eventual listeners
Event quit;
quit.name = "done.state.scxml";
_parentQueue->push(quit);
}
-
+
// set datamodel to null from this thread
if(_dataModel)
_dataModel = DataModel();
-
+
}
/**
@@ -127,7 +127,7 @@ void InterpreterDraft7::initializeData(const Arabica::DOM::Node<std::string>& da
LOG(ERROR) << "Data element has no id!";
return;
}
-
+
if (HAS_ATTR(data, "expr")) {
std::string value = ATTR(data, "expr");
_dataModel.assign(ATTR(data, "id"), value);
@@ -135,7 +135,7 @@ void InterpreterDraft7::initializeData(const Arabica::DOM::Node<std::string>& da
URL srcURL(ATTR(data, "src"));
if (!srcURL.isAbsolute())
toAbsoluteURI(srcURL);
-
+
std::stringstream ss;
if (_cachedURLs.find(srcURL.asString()) != _cachedURLs.end()) {
ss << _cachedURLs[srcURL.asString()];
@@ -144,7 +144,7 @@ void InterpreterDraft7::initializeData(const Arabica::DOM::Node<std::string>& da
_cachedURLs[srcURL.asString()] = srcURL;
}
_dataModel.assign(ATTR(data, "id"), ss.str());
-
+
} else if (data.hasChildNodes()) {
// search for the text node with the actual script
NodeList<std::string> dataChilds = data.getChildNodes();
@@ -156,7 +156,7 @@ void InterpreterDraft7::initializeData(const Arabica::DOM::Node<std::string>& da
}
}
}
-
+
} catch (Event e) {
LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl;
}
@@ -167,12 +167,12 @@ procedure mainEventLoop():
while running:
enabledTransitions = null
macrostepDone = false
- # Here we handle eventless transitions and transitions
+ # Here we handle eventless transitions and transitions
# triggered by internal events until macrostep is complete
while running and not macrostepDone:
enabledTransitions = selectEventlessTransitions()
if enabledTransitions.isEmpty():
- if internalQueue.isEmpty():
+ if internalQueue.isEmpty():
macrostepDone = true
else:
internalEvent = internalQueue.dequeue()
@@ -180,7 +180,7 @@ procedure mainEventLoop():
enabledTransitions = selectTransitions(internalEvent)
if not enabledTransitions.isEmpty():
microstep(enabledTransitions.toList())
- # either we're in a final state, and we break out of the loop
+ # either we're in a final state, and we break out of the loop
if not running:
break;
# or we've completed a macrostep, so we start a new macrostep by waiting for an external event
@@ -189,7 +189,7 @@ procedure mainEventLoop():
for inv in state.invoke:
invoke(inv)
statesToInvoke.clear()
- # Invoking may have raised internal error events and we iterate to handle them
+ # Invoking may have raised internal error events and we iterate to handle them
if not internalQueue.isEmpty():
continue
# A blocking wait for an external event. Alternatively, if we have been invoked
@@ -205,12 +205,12 @@ procedure mainEventLoop():
if inv.invokeid == externalEvent.invokeid:
applyFinalize(inv, externalEvent)
if inv.autoforward:
- send(inv.id, externalEvent)
+ send(inv.id, externalEvent)
enabledTransitions = selectTransitions(externalEvent)
if not enabledTransitions.isEmpty():
- microstep(enabledTransitions.toList())
- # End of outer while running loop. If we get here, we have reached a top-level final state or have been cancelled
- exitInterpreter()
+ microstep(enabledTransitions.toList())
+ # End of outer while running loop. If we get here, we have reached a top-level final state or have been cancelled
+ exitInterpreter()
*/
void InterpreterDraft7::mainEventLoop() {
}
@@ -224,7 +224,7 @@ procedure exitInterpreter():
for inv in s.invoke:
cancelInvoke(inv)
configuration.delete(s)
- if isFinalState(s) and isScxmlState(s.parent):
+ if isFinalState(s) and isScxmlState(s.parent):
returnDoneEvent(s.donedata)
*/
void InterpreterDraft7::exitInterpreter() {
@@ -246,7 +246,7 @@ function selectEventlessTransitions():
for state in atomicStates:
loop: for s in [state].append(getProperAncestors(state, null)):
for t in s.transition:
- if not t.event and conditionMatch(t):
+ if not t.event and conditionMatch(t):
enabledTransitions.add(t)
break loop
enabledTransitions = filterPreempted(enabledTransitions)
@@ -275,7 +275,7 @@ Arabica::XPath::NodeSet<std::string> InterpreterDraft7::selectTransitions(const
procedure enterStates(enabledTransitions):
statesToEnter = new OrderedSet()
statesForDefaultEntry = new OrderedSet()
- computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry)
+ computeEntrySet(enabledTransitions, statesToEnter, statesForDefaultEntry)
for s in statesToEnter.toList().sort(entryOrder):
configuration.add(s)
statesToInvoke.add(s)
@@ -302,14 +302,14 @@ void InterpreterDraft7::enterStates(const Arabica::XPath::NodeSet<std::string>&
/**
procedure exitStates(enabledTransitions):
- statesToExit = computeExitSet(enabledTransitions)
+ statesToExit = computeExitSet(enabledTransitions)
for s in statesToExit:
statesToInvoke.delete(s)
statesToExit = statesToExit.toList().sort(exitOrder)
for s in statesToExit:
for h in s.history:
if h.type == "deep":
- f = lambda s0: isAtomicState(s0) and isDescendant(s0,s)
+ f = lambda s0: isAtomicState(s0) and isDescendant(s0,s)
else:
f = lambda s0: s0.parent == s
historyValue[h.id] = configuration.toList().filter(f)
@@ -330,27 +330,27 @@ function computeExitSet(transitions)
domain = getTransitionDomain(t)
for s in configuration:
if isDescendant(s,domain):
- statesToExit.add(s)
- return statesToExit
+ statesToExit.add(s)
+ return statesToExit
*/
Arabica::XPath::NodeSet<std::string> InterpreterDraft7::computeExitSet(const Arabica::XPath::NodeSet<std::string>& enabledTransitions,
- const Arabica::XPath::NodeSet<std::string>& statesToExit) {
+ const Arabica::XPath::NodeSet<std::string>& statesToExit) {
}
/**
procedure computeEntrySet(transitions, statesToEnter, statesForDefaultEntry)
for t in transitions:
- statesToEnter.union(getTargetStates(t.target))
+ statesToEnter.union(getTargetStates(t.target))
for s in statesToEnter:
- addDescendentStatesToEnter(s,statesToEnter,statesForDefaultEntry)
- for t in transitions:
- ancestor = getTransitionDomain(t)
- for s in getTargetStates(t.target)):
+ addDescendentStatesToEnter(s,statesToEnter,statesForDefaultEntry)
+ for t in transitions:
+ ancestor = getTransitionDomain(t)
+ for s in getTargetStates(t.target)):
addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry)
*/
Arabica::XPath::NodeSet<std::string> InterpreterDraft7::computeEntrySet(const Arabica::XPath::NodeSet<std::string>& transitions,
- const Arabica::XPath::NodeSet<std::string>& statesToEnter,
- const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
+ const Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
}
/**
@@ -364,14 +364,14 @@ function removeConflictingTransitions(enabledTransitions):
if computeExitSet(t1).hasIntersection(computeExitSet(t2)):
if isDescendent(t1.source, t2.source):
transitionsToRemove.add(t2)
- else:
+ else:
t1Preempted = true
break
if not t1Preempted:
for t3 in transitionsToRemove.toList():
filteredTransitions.delete(t3)
filteredTransitions.add(t1)
-
+
return filteredTransitions
*/
Arabica::XPath::NodeSet<std::string> InterpreterDraft7::removeConflictingTransitions(const Arabica::XPath::NodeSet<std::string>& enabledTransitions) {
@@ -413,11 +413,11 @@ Arabica::DOM::Node<std::string> InterpreterDraft7::getTransitionDomain(const Ara
if isParallelState(state):
for child in getChildStates(state):
if not statesToEnter.some(lambda s: isDescendant(s,child)):
- addDescendentStatesToEnter(child,statesToEnter,statesForDefaultEntry)
+ addDescendentStatesToEnter(child,statesToEnter,statesForDefaultEntry)
*/
Arabica::XPath::NodeSet<std::string> InterpreterDraft7::addDescendentStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- const Arabica::XPath::NodeSet<std::string>& statesToEnter,
- const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
+ const Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
}
/**
@@ -427,12 +427,12 @@ Arabica::XPath::NodeSet<std::string> InterpreterDraft7::addDescendentStatesToEnt
if isParallelState(anc):
for child in getChildStates(anc):
if not statesToEnter.some(lambda s: isDescendant(s,child)):
- addStatesToEnter(child,statesToEnter,statesForDefaultEntry)
+ addStatesToEnter(child,statesToEnter,statesForDefaultEntry)
*/
Arabica::XPath::NodeSet<std::string> InterpreterDraft7::addAncestorsStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- const Arabica::DOM::Node<std::string>& ancestor,
- const Arabica::XPath::NodeSet<std::string>& statesToEnter,
- const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
+ const Arabica::DOM::Node<std::string>& ancestor,
+ const Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry) {
}
diff --git a/src/uscxml/interpreter/InterpreterDraft7.h b/src/uscxml/interpreter/InterpreterDraft7.h
index e784e84..1dc9350 100644
--- a/src/uscxml/interpreter/InterpreterDraft7.h
+++ b/src/uscxml/interpreter/InterpreterDraft7.h
@@ -19,23 +19,23 @@ class InterpreterDraft7 : public Interpreter {
void exitStates(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
Arabica::XPath::NodeSet<std::string> computeExitSet(const Arabica::XPath::NodeSet<std::string>& enabledTransitions,
- const Arabica::XPath::NodeSet<std::string>& statesToExit);
+ const Arabica::XPath::NodeSet<std::string>& statesToExit);
Arabica::XPath::NodeSet<std::string> computeEntrySet(const Arabica::XPath::NodeSet<std::string>& transitions,
- const Arabica::XPath::NodeSet<std::string>& statesToEnter,
- const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
+ const Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
Arabica::XPath::NodeSet<std::string> removeConflictingTransitions(const Arabica::XPath::NodeSet<std::string>& enabledTransitions);
Arabica::DOM::Node<std::string> getTransitionDomain(const Arabica::DOM::Node<std::string>& transition);
Arabica::XPath::NodeSet<std::string> addDescendentStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- const Arabica::XPath::NodeSet<std::string>& statesToEnter,
- const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
+ const Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
Arabica::XPath::NodeSet<std::string> addAncestorsStatesToEnter(const Arabica::DOM::Node<std::string>& state,
- const Arabica::DOM::Node<std::string>& ancestor,
- const Arabica::XPath::NodeSet<std::string>& statesToEnter,
- const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
+ const Arabica::DOM::Node<std::string>& ancestor,
+ const Arabica::XPath::NodeSet<std::string>& statesToEnter,
+ const Arabica::XPath::NodeSet<std::string>& statesForDefaultEntry);
void initializeData(const Arabica::DOM::Node<std::string>& data);
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
index 407988e..4072862 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -1,6 +1,8 @@
#include "uscxml/Common.h"
#include "V8DataModel.h"
+#include "dom/V8DOM.h"
#include "dom/V8Document.h"
+#include "dom/V8Node.h"
#include "dom/V8SCXMLEvent.h"
#include "uscxml/Message.h"
@@ -118,8 +120,23 @@ void V8DataModel::setEvent(const Event& event) {
privData->dom = _dom;
eventObj->SetInternalField(0, Arabica::DOM::V8DOM::toExternal(privData));
eventObj.MakeWeak(0, Arabica::DOM::V8SCXMLEvent::jsDestructor);
+ if (event.dom) {
+ v8::Handle<v8::Function> retCtor = Arabica::DOM::V8Document::getTmpl()->GetFunction();
+ v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance());
- eventObj->Set(v8::String::New("data"), getDataAsValue(event.data)); // set data part of _event
+ struct Arabica::DOM::V8Document::V8DocumentPrivate* retPrivData = new Arabica::DOM::V8Document::V8DocumentPrivate();
+ retPrivData->dom = privData->dom;
+ retPrivData->nativeObj = (Arabica::DOM::Document<std::string>*)&event.dom;
+
+ retObj->SetInternalField(0, Arabica::DOM::V8DOM::toExternal(retPrivData));
+ retObj.MakeWeak(0, Arabica::DOM::V8Document::jsDestructor);
+
+ eventObj->Set(v8::String::New("data"), retObj); // set data part of _event
+ } else if (event.content.length() > 0) {
+ eventObj->Set(v8::String::New("data"), v8::String::New(event.content.c_str())); // set data part of _event
+ } else {
+ eventObj->Set(v8::String::New("data"), getDataAsValue(event.data)); // set data part of _event
+ }
global->Set(v8::String::New("_event"), eventObj);
}
@@ -247,9 +264,18 @@ bool V8DataModel::validate(const std::string& location, const std::string& schem
uint32_t V8DataModel::getLength(const std::string& expr) {
v8::Locker locker;
v8::HandleScope handleScope;
+ v8::TryCatch tryCatch;
v8::Context::Scope contextScope(_contexts.back());
- v8::Handle<v8::Array> result = evalAsValue(expr).As<v8::Array>();
- return result->Length();
+ v8::Handle<v8::Value> result = evalAsValue(expr);
+ if (!result.IsEmpty() && result->IsArray())
+ return result.As<v8::Array>()->Length();
+
+ Event exceptionEvent;
+ exceptionEvent.name = "error.execution";
+ exceptionEvent.data.compound["exception"] = Data("'" + expr + "' does not evaluate to an array.", Data::VERBATIM);;
+
+ _interpreter->receiveInternal(exceptionEvent);
+ throw(exceptionEvent);
}
void V8DataModel::eval(const std::string& expr) {
@@ -280,6 +306,17 @@ std::string V8DataModel::evalAsString(const std::string& expr) {
return std::string(*data);
}
+double V8DataModel::evalAsNumber(const std::string& expr) {
+ v8::Locker locker;
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(_contexts.back());
+ v8::Handle<v8::Value> result = evalAsValue(expr);
+ if (result->IsNumber()) {
+ return result->ToNumber()->NumberValue();
+ }
+ return 0;
+}
+
void V8DataModel::assign(const std::string& location, const Data& data) {
v8::Locker locker;
v8::HandleScope handleScope;
@@ -308,49 +345,54 @@ v8::Handle<v8::Value> V8DataModel::evalAsValue(const std::string& expr) {
if (script.IsEmpty() || result.IsEmpty()) {
// throw an exception
- assert(tryCatch.HasCaught());
- Event exceptionEvent;
- exceptionEvent.name = "error.execution";
-
- std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception()));
- exceptionEvent.data.compound["exception"] = Data(exceptionString, Data::VERBATIM);;
-
- v8::Handle<v8::Message> message = tryCatch.Message();
- if (!message.IsEmpty()) {
- std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName()));
- exceptionEvent.data.compound["filename"] = Data(filename, Data::VERBATIM);
-
- std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine()));
- size_t startpos = sourceLine.find_first_not_of(" \t");
- if(std::string::npos != startpos) // removoe leading white space
- sourceLine = sourceLine.substr(startpos);
-
- exceptionEvent.data.compound["sourceline"] = Data(sourceLine, Data::VERBATIM);
-
- std::stringstream ssLineNumber;
- int lineNumber = message->GetLineNumber();
- ssLineNumber << lineNumber;
- exceptionEvent.data.compound["linenumber"] = Data(ssLineNumber.str());
-
- int startColumn = message->GetStartColumn();
- int endColumn = message->GetEndColumn();
- std::stringstream ssUnderline;
- for (int i = 0; i < startColumn; i++)
- ssUnderline << " ";
- for (int i = startColumn; i < endColumn; i++)
- ssUnderline << "^";
- exceptionEvent.data.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM);
-
- std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace()));
- exceptionEvent.data.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM);
+ if (tryCatch.HasCaught())
+ throwExceptionEvent(tryCatch);
+ }
- }
+ return result;
+}
+
+void V8DataModel::throwExceptionEvent(const v8::TryCatch& tryCatch) {
+ assert(tryCatch.HasCaught());
+ Event exceptionEvent;
+ exceptionEvent.name = "error.execution";
+
+ std::string exceptionString(*v8::String::AsciiValue(tryCatch.Exception()));
+ exceptionEvent.data.compound["exception"] = Data(exceptionString, Data::VERBATIM);;
+
+ v8::Handle<v8::Message> message = tryCatch.Message();
+ if (!message.IsEmpty()) {
+ std::string filename(*v8::String::AsciiValue(message->GetScriptResourceName()));
+ exceptionEvent.data.compound["filename"] = Data(filename, Data::VERBATIM);
+
+ std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine()));
+ size_t startpos = sourceLine.find_first_not_of(" \t");
+ if(std::string::npos != startpos) // removoe leading white space
+ sourceLine = sourceLine.substr(startpos);
+
+ exceptionEvent.data.compound["sourceline"] = Data(sourceLine, Data::VERBATIM);
+
+ std::stringstream ssLineNumber;
+ int lineNumber = message->GetLineNumber();
+ ssLineNumber << lineNumber;
+ exceptionEvent.data.compound["linenumber"] = Data(ssLineNumber.str());
+
+ int startColumn = message->GetStartColumn();
+ int endColumn = message->GetEndColumn();
+ std::stringstream ssUnderline;
+ for (int i = 0; i < startColumn; i++)
+ ssUnderline << " ";
+ for (int i = startColumn; i < endColumn; i++)
+ ssUnderline << "^";
+ exceptionEvent.data.compound["sourcemark"] = Data(ssUnderline.str(), Data::VERBATIM);
+
+ std::string stackTrace(*v8::String::AsciiValue(tryCatch.StackTrace()));
+ exceptionEvent.data.compound["stacktrace"] = Data(stackTrace, Data::VERBATIM);
- _interpreter->receiveInternal(exceptionEvent);
- throw(exceptionEvent);
}
- return result;
+ _interpreter->receiveInternal(exceptionEvent);
+ throw(exceptionEvent);
}
} \ No newline at end of file
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
index 18e1ea4..6d4ca63 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h
@@ -52,6 +52,7 @@ public:
virtual std::string evalAsString(const std::string& expr);
virtual bool evalAsBool(const std::string& expr);
+ virtual double evalAsNumber(const std::string& expr);
static v8::Handle<v8::Value> jsIn(const v8::Arguments& args);
static v8::Handle<v8::Value> jsPrint(const v8::Arguments& args);
@@ -63,6 +64,7 @@ protected:
v8::Handle<v8::Value> evalAsValue(const std::string& expr);
virtual v8::Handle<v8::Value> getDataAsValue(const Data& data);
+ void throwExceptionEvent(const v8::TryCatch& tryCatch);
};
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeList.h b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeList.h
index fb1b510..c454e65 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeList.h
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeList.h
@@ -43,6 +43,7 @@ public:
static v8::Handle<v8::Value> itemCallback(const v8::Arguments&);
static v8::Handle<v8::Value> lengthAttrGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> indexedPropertyCustomGetter(uint32_t, const v8::AccessorInfo&);
static v8::Persistent<v8::FunctionTemplate> Tmpl;
static v8::Handle<v8::FunctionTemplate> getTmpl() {
@@ -60,6 +61,7 @@ public:
instance->SetAccessor(v8::String::NewSymbol("length"), V8NodeList::lengthAttrGetter, 0,
v8::External::New(0), static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None));
+ instance->SetIndexedPropertyHandler(V8NodeList::indexedPropertyCustomGetter, 0);
prototype->Set(v8::String::NewSymbol("item"),
v8::FunctionTemplate::New(V8NodeList::itemCallback, v8::Undefined()), static_cast<v8::PropertyAttribute>(v8::DontDelete));
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeListCustom.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeListCustom.cpp
new file mode 100644
index 0000000..c05c5a4
--- /dev/null
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/dom/V8NodeListCustom.cpp
@@ -0,0 +1,52 @@
+#include "V8NodeList.h"
+#include "V8Element.h"
+#include "V8Node.h"
+
+namespace Arabica {
+namespace DOM {
+
+v8::Handle<v8::Value> V8NodeList::indexedPropertyCustomGetter(uint32_t index, const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> self = info.Holder();
+ V8NodeListPrivate* privData = V8DOM::toClassPtr<V8NodeListPrivate >(self->GetInternalField(0));
+
+ if (privData->nativeObj->getLength() >= index) {
+ switch(privData->nativeObj->item(index).getNodeType()) {
+ case Node_base::ELEMENT_NODE: {
+ Arabica::DOM::Element<std::string>* retVal = new Arabica::DOM::Element<std::string>(privData->nativeObj->item(index));
+
+ v8::Handle<v8::Function> retCtor = V8Element::getTmpl()->GetFunction();
+ v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance());
+
+ struct V8Element::V8ElementPrivate* retPrivData = new V8Element::V8ElementPrivate();
+ retPrivData->dom = privData->dom;
+ retPrivData->nativeObj = retVal;
+
+ retObj->SetInternalField(0, V8DOM::toExternal(retPrivData));
+
+ retObj.MakeWeak(0, V8Element::jsDestructor);
+ return retObj;
+ }
+ default: {
+ Arabica::DOM::Node<std::string>* retVal = new Arabica::DOM::Node<std::string>(privData->nativeObj->item(index));
+
+ v8::Handle<v8::Function> retCtor = V8Node::getTmpl()->GetFunction();
+ v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance());
+
+ struct V8Node::V8NodePrivate* retPrivData = new V8Node::V8NodePrivate();
+ retPrivData->dom = privData->dom;
+ retPrivData->nativeObj = retVal;
+
+ retObj->SetInternalField(0, V8DOM::toExternal(retPrivData));
+
+ retObj.MakeWeak(0, V8Node::jsDestructor);
+ return retObj;
+ }
+ }
+ }
+
+ return v8::Undefined();
+
+}
+
+}
+} \ No newline at end of file