Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #13 from mattoshry/system_vars

add _ioprocessors and _x described in 5.10 of SCXML
  • Loading branch information...
commit 46a77d05b9b9adc53ddb86e6ee6dda333c3bb08a 2 parents ccf9af2 + 62957d4
@jbeard4 authored
Showing with 66 additions and 62 deletions.
  1. +33 −29 lib/core/scxml/SCXML.js
  2. +33 −33 lib/core/util/code-gen.js
View
62 lib/core/scxml/SCXML.js
@@ -53,6 +53,8 @@ function SCXMLInterpreter(model, opts){
this.opts.priorityComparisonFn = this.opts.priorityComparisonFn || getTransitionWithHigherSourceChildPriority(this.opts.model);
this._sessionid = this.opts.sessionid || "";
+ this._platformvars = this.opts.platformvars || {};
+ this._ioprocessors = this.opts.ioprocessors || {};
this._configuration = new this.opts.BasicStateSet();
this._historyValue = {};
@@ -76,13 +78,13 @@ SCXMLInterpreter.prototype = {
//the require of the module importing SCION
//the require of the main module
//this module's require
- var actionCodeRequire =
- this.opts.require ||
- (module.parent &&
- module.parent.parent &&
+ var actionCodeRequire =
+ this.opts.require ||
+ (module.parent &&
+ module.parent.parent &&
module.parent.parent.require &&
- module.parent.parent.require.bind(module.parent.parent)) ||
- (require.main &&
+ module.parent.parent.require.bind(module.parent.parent)) ||
+ (require.main &&
require.main.require &&
require.main.require.bind(require.main)) ||
require;
@@ -96,7 +98,9 @@ SCXMLInterpreter.prototype = {
this.isIn.bind(this),
actionCodeRequire,
pm.platform.parseDocumentFromString,
- this._sessionid);
+ this._sessionid,
+ this._ioprocessors,
+ this._platformvars);
this._actions = tmp.actions;
this._datamodel = tmp.datamodel;
@@ -175,12 +179,12 @@ SCXMLInterpreter.prototype = {
//filter out targetless transitions here - we will only use these to execute transition actions
var selectedTransitionsWithTargets = new this.opts.TransitionSet(selectedTransitions.iter().filter(function(t){return t.targets;}));
- var exitedTuple = this._getStatesExited(selectedTransitionsWithTargets),
- basicStatesExited = exitedTuple[0],
+ var exitedTuple = this._getStatesExited(selectedTransitionsWithTargets),
+ basicStatesExited = exitedTuple[0],
statesExited = exitedTuple[1];
- var enteredTuple = this._getStatesEntered(selectedTransitionsWithTargets),
- basicStatesEntered = enteredTuple[0],
+ var enteredTuple = this._getStatesEntered(selectedTransitionsWithTargets),
+ basicStatesEntered = enteredTuple[0],
statesEntered = enteredTuple[1];
if (printTrace) pm.platform.log("basicStatesExited ", basicStatesExited);
@@ -199,7 +203,7 @@ SCXMLInterpreter.prototype = {
//invoke listeners
this._listeners.forEach(function(l){
- if(l.onExit) l.onExit(state.id);
+ if(l.onExit) l.onExit(state.id);
});
if(state.onexit !== undefined) this._evaluateAction(state.onexit,eventSet, datamodelForNextStep, eventsToAddToInnerQueue);
@@ -235,12 +239,12 @@ SCXMLInterpreter.prototype = {
var targetIds = transition.targets && transition.targets.map(function(target){return target.id;});
this._listeners.forEach(function(l){
- if(l.onTransition) l.onTransition(transition.source.id,targetIds);
+ if(l.onTransition) l.onTransition(transition.source.id,targetIds);
});
if(transition.actions !== undefined) this._evaluateAction(transition.actions,eventSet, datamodelForNextStep, eventsToAddToInnerQueue);
},this);
-
+
if (printTrace) pm.platform.log("executing state enter actions");
statesEntered.forEach(function(state){
@@ -248,7 +252,7 @@ SCXMLInterpreter.prototype = {
if (printTrace || this.opts.logStatesEnteredAndExited) pm.platform.log("entering", state.id);
this._listeners.forEach(function(l){
- if(l.onEntry) l.onEntry(state.id);
+ if(l.onEntry) l.onEntry(state.id);
});
if(state.onentry !== undefined) this._evaluateAction(state.onentry, eventSet, datamodelForNextStep, eventsToAddToInnerQueue);
@@ -262,7 +266,7 @@ SCXMLInterpreter.prototype = {
this._configuration.union(basicStatesEntered);
if (printTrace) pm.platform.log("new configuration ", this._configuration);
-
+
//add set of generated events to the innerEventQueue -> Event Lifelines: Next small-step
if (!eventsToAddToInnerQueue.isEmpty()) {
if (printTrace) pm.platform.log("adding triggered events to inner queue ", eventsToAddToInnerQueue);
@@ -270,7 +274,7 @@ SCXMLInterpreter.prototype = {
}
if (printTrace) pm.platform.log("updating datamodel for next small step :");
-
+
//update the datamodel
for (var key in datamodelForNextStep) {
this._setData(key,datamodelForNextStep[key]);
@@ -310,7 +314,7 @@ SCXMLInterpreter.prototype = {
//States exited are defined to be active states that are
//descendants of the scope of each priority-enabled transition.
//Here, we iterate through the transitions, and collect states
- //that match this condition.
+ //that match this condition.
transitions.iter().forEach(function(transition){
var lca = transition.lca,
scope = transition.scope,
@@ -360,7 +364,7 @@ SCXMLInterpreter.prototype = {
}else{
//everything else can just be passed through as normal
processState(s);
- }
+ }
});
}).bind(this);
@@ -384,13 +388,13 @@ SCXMLInterpreter.prototype = {
statesToProcess.push.apply(statesToProcess,
s.children.filter(function(s){return s.kind !== stateKinds.HISTORY;}));
} else if (s.kind === stateKinds.COMPOSITE) {
- statesToProcess.push(s.initial);
+ statesToProcess.push(s.initial);
} else if (s.kind === stateKinds.INITIAL || s.kind === stateKinds.BASIC || s.kind === stateKinds.FINAL) {
basicStatesToEnter.add(s);
}
}
- statesProcessed.add(s);
+ statesProcessed.add(s);
}).bind(this);
@@ -426,7 +430,7 @@ SCXMLInterpreter.prototype = {
//get full configuration, unordered
//this means we may select transitions from parents before children
-
+
this._configuration.iter().forEach(function(basicState){
statesAndParents.add(basicState);
this.opts.model.getAncestors(basicState).forEach(function(ancestor){
@@ -457,7 +461,7 @@ SCXMLInterpreter.prototype = {
var priorityEnabledTransitions = this._selectPriorityEnabledTransitions(enabledTransitions);
if (printTrace) pm.platform.log("priorityEnabledTransitions", priorityEnabledTransitions);
-
+
return priorityEnabledTransitions;
},
@@ -465,8 +469,8 @@ SCXMLInterpreter.prototype = {
_selectPriorityEnabledTransitions : function(enabledTransitions) {
var priorityEnabledTransitions = new this.opts.TransitionSet();
- var tuple = this._getInconsistentTransitions(enabledTransitions),
- consistentTransitions = tuple[0],
+ var tuple = this._getInconsistentTransitions(enabledTransitions),
+ consistentTransitions = tuple[0],
inconsistentTransitionsPairs = tuple[1];
priorityEnabledTransitions.union(consistentTransitions);
@@ -475,13 +479,13 @@ SCXMLInterpreter.prototype = {
if (printTrace) pm.platform.log("consistentTransitions", consistentTransitions);
if (printTrace) pm.platform.log("inconsistentTransitionsPairs", inconsistentTransitionsPairs);
if (printTrace) pm.platform.log("priorityEnabledTransitions", priorityEnabledTransitions);
-
+
while (!inconsistentTransitionsPairs.isEmpty()) {
enabledTransitions = new this.opts.TransitionSet(
inconsistentTransitionsPairs.iter().map(function(t){return this.opts.priorityComparisonFn(t);},this));
tuple = this._getInconsistentTransitions(enabledTransitions);
- consistentTransitions = tuple[0];
+ consistentTransitions = tuple[0];
inconsistentTransitionsPairs = tuple[1];
priorityEnabledTransitions.union(consistentTransitions);
@@ -490,7 +494,7 @@ SCXMLInterpreter.prototype = {
if (printTrace) pm.platform.log("consistentTransitions", consistentTransitions);
if (printTrace) pm.platform.log("inconsistentTransitionsPairs", inconsistentTransitionsPairs);
if (printTrace) pm.platform.log("priorityEnabledTransitions", priorityEnabledTransitions);
-
+
}
return priorityEnabledTransitions;
},
@@ -541,7 +545,7 @@ SCXMLInterpreter.prototype = {
registerListener provides a generic mechanism to subscribe to state change notifications.
Can be used for logging and debugging. For example, can attache a logger that simply logs the state changes.
Or can attach a network debugging client that sends state change notifications to a debugging server.
-
+
listener is of the form:
{
onEntry : function(stateId){},
View
66 lib/core/util/code-gen.js
@@ -33,7 +33,7 @@ function actionTagToFnBody(action){
if(!(generator && generatorFn)) throw new Error("Element " + pm.platform.dom.namespaceURI(action) + ':' + pm.platform.dom.localName(action) + " not yet supported");
- return generatorFn(action);
+ return generatorFn(action);
}
var actionTags = {
@@ -55,7 +55,7 @@ var actionTags = {
for(var i = 0; i < childNodes.length; i++){
var child = childNodes[i];
- if(pm.platform.dom.localName(child) === "elseif" || pm.platform.dom.localName(child) === "else"){
+ if(pm.platform.dom.localName(child) === "elseif" || pm.platform.dom.localName(child) === "else"){
break;
}else{
s += actionTagToFnBody(child) + "\n;;\n";
@@ -118,26 +118,26 @@ var actionTags = {
"send" : function(action){
var target = (pm.platform.dom.hasAttribute(action,"targetexpr") ? pm.platform.dom.getAttribute(action,"targetexpr") : JSON.stringify(pm.platform.dom.getAttribute(action,"target"))),
- targetVariableName = '_scionTargetRef',
+ targetVariableName = '_scionTargetRef',
targetDeclaration = 'var ' + targetVariableName + ' = ' + target + ';\n';
- var event = "{\n" +
+ var event = "{\n" +
"target: " + targetVariableName + ",\n" +
- "name: " + (pm.platform.dom.hasAttribute(action,"eventexpr") ? pm.platform.dom.getAttribute(action,"eventexpr") : JSON.stringify(pm.platform.dom.getAttribute(action,"event"))) + ",\n" +
+ "name: " + (pm.platform.dom.hasAttribute(action,"eventexpr") ? pm.platform.dom.getAttribute(action,"eventexpr") : JSON.stringify(pm.platform.dom.getAttribute(action,"event"))) + ",\n" +
"type: " + (pm.platform.dom.hasAttribute(action,"typeexpr") ? pm.platform.dom.getAttribute(action,"typeexpr") : JSON.stringify(pm.platform.dom.getAttribute(action,"type"))) + ",\n" +
"data: " + constructSendEventData(action) + ",\n" +
"origin: $origin\n" +
"}";
- var send =
+ var send =
targetDeclaration +
- "if(" + targetVariableName + " === '#_internal'){\n" +
- "$raise(" + event + ");\n" +
+ "if(" + targetVariableName + " === '#_internal'){\n" +
+ "$raise(" + event + ");\n" +
"}else{\n" +
- "$send(" + event + ", {\n" +
- "delay: " + (pm.platform.dom.hasAttribute(action,"delayexpr") ? pm.platform.dom.getAttribute(action,"delayexpr") : getDelayInMs(pm.platform.dom.getAttribute(action,"delay"))) + ",\n" +
- "sendId: " + (pm.platform.dom.hasAttribute(action,"idlocation") ? pm.platform.dom.getAttribute(action,"idlocation") : JSON.stringify(pm.platform.dom.getAttribute(action,"id"))) + "\n" +
- "});" +
+ "$send(" + event + ", {\n" +
+ "delay: " + (pm.platform.dom.hasAttribute(action,"delayexpr") ? pm.platform.dom.getAttribute(action,"delayexpr") : getDelayInMs(pm.platform.dom.getAttribute(action,"delay"))) + ",\n" +
+ "sendId: " + (pm.platform.dom.hasAttribute(action,"idlocation") ? pm.platform.dom.getAttribute(action,"idlocation") : JSON.stringify(pm.platform.dom.getAttribute(action,"id"))) + "\n" +
+ "});" +
"}";
return send;
@@ -150,18 +150,18 @@ var actionTags = {
arr = pm.platform.dom.getAttribute(action,"array"),
foreachBody = pm.platform.dom.getElementChildren(action).map(actionTagToFnBody).join("\n;;\n");
- return "(function(){\n" +
+ return "(function(){\n" +
"if(Array.isArray(" + arr + ")){\n" +
arr + ".forEach(function(" + item + "," + index + "){\n" +
foreachBody +
- "\n});\n" +
+ "\n});\n" +
"}else{\n" +
//assume object
"Object.keys(" + arr + ").forEach(function(" + index + "){\n" +
- item + " = " + arr + "[" + index + "];\n" +
+ item + " = " + arr + "[" + index + "];\n" +
foreachBody +
- "\n});\n" +
- "}\n" +
+ "\n});\n" +
+ "}\n" +
"})();";
}
}
@@ -190,13 +190,13 @@ function getDatamodelExpression(id, datamodelObject){
s += ' = ';
switch(datamodelObject.type){
- case 'xml' :
+ case 'xml' :
s += '$parseXml(' + JSON.stringify(datamodelObject.content) + ')';
break;
- case 'json' :
+ case 'json' :
s += 'JSON.parse(' + JSON.stringify(datamodelObject.content) + ')';
break;
- case 'expr' :
+ case 'expr' :
s += datamodelObject.content;
break;
default :
@@ -224,9 +224,9 @@ function makeDatamodelDeclaration(datamodel){
function makeDatamodelClosures(datamodel){
var vars = [];
for(var id in datamodel){
- vars.push( '"' + id + '" : {\n' +
- '"set" : function(v){ return ' + id + ' = v; },\n' +
- '"get" : function(){ return ' + id + ';}' +
+ vars.push( '"' + id + '" : {\n' +
+ '"set" : function(v){ return ' + id + ' = v; },\n' +
+ '"get" : function(){ return ' + id + ';}' +
'\n}');
}
return '{\n' + vars.join(',\n') + '\n}';
@@ -234,29 +234,29 @@ function makeDatamodelClosures(datamodel){
function wrapFunctionBodyInDeclaration(action,isExpression){
return "function(getData,setData,_events,$raise){var _event = _events[0];\n" +
- (isExpression ? "return" : "") + " " + action +
+ (isExpression ? "return" : "") + " " + action +
"\n}";
}
function makeTopLevelFunctionBody(datamodelDeclaration,topLevelScripts,datamodelClosures,actionStrings){
- return datamodelDeclaration +
- (topLevelScripts.length ? topLevelScripts.join("\n") : "") +
- "var $datamodel = " + datamodelClosures + ";\n" +
- "return {\n" +
- "datamodel:$datamodel,\n" +
+ return datamodelDeclaration +
+ (topLevelScripts.length ? topLevelScripts.join("\n") : "") +
+ "var $datamodel = " + datamodelClosures + ";\n" +
+ "return {\n" +
+ "datamodel:$datamodel,\n" +
"actions:[\n" + actionStrings.join(",\n") + "\n]" + //return all functions which get called during execution
"\n};";
}
function wrapTopLevelFunctionBodyInDeclaration(fnBody){
- return "function($log,$cancel,$send,$origin,In,require,$parseXml,_sessionid){\n" + fnBody + "\n}";
+ return "function($log,$cancel,$send,$origin,In,require,$parseXml,_sessionid,_ioprocessors,_x){\n" + fnBody + "\n}";
}
//this function ensures that the code in each SCXML document will run in "document scope".
//SCXML embeds js code as strings in the document, hence the use of "eval" to dynamically evaluate things.
//This function ensures that eval() is only called once, when the model is parsed. It will not be called during execution of the statechart.
-//However, each SCXML interpreter instance will have its own copies of the functions declared in the document.
+//However, each SCXML interpreter instance will have its own copies of the functions declared in the document.
//This is similar to the way HTML works - each page has its own copies of evaluated scripts.
function makeActionFactory(topLevelScripts,actionStrings,datamodel){
var datamodelDeclaration = makeDatamodelDeclaration(datamodel);
@@ -264,7 +264,7 @@ function makeActionFactory(topLevelScripts,actionStrings,datamodel){
var topLevelFnBody = makeTopLevelFunctionBody(datamodelDeclaration,topLevelScripts,datamodelClosures,actionStrings);
var fnStr = wrapTopLevelFunctionBodyInDeclaration(topLevelFnBody);
//require('fs').writeFileSync('out.js',fnStr);
- return fnStr;
+ return fnStr;
}
@@ -273,7 +273,7 @@ function constructSendEventData(action){
var namelist = pm.platform.dom.hasAttribute(action,"namelist") ? pm.platform.dom.getAttribute(action,"namelist").trim().split(/ +/) : null,
params = pm.platform.dom.getChildren(action).filter(function(child){return pm.platform.dom.localName(child) === 'param';}),
content = pm.platform.dom.getChildren(action).filter(function(child){return pm.platform.dom.localName(child) === 'content';});
-
+
if(content.length){
//TODO: instead of using textContent, serialize the XML
content = content[0];
Please sign in to comment.
Something went wrong with that request. Please try again.