I am in trouble. :)
I have 2 SCXML files : input and output. My program creates output file. Now I have to show: both files are semantically equivalent, somehow.
Input File: <ccdl:wait> means "wait for 100ms" then continue execution
<?xml version="1.0" encoding="UTF-8"?>
<scxml
xmlns="http://www.w3.org/2005/07/scxml"
xmlns:ccdl="http://www.NotRealURL.de"
xmlns:cs="http://commons.apache.org/scxml" version="1.0" initial="startup" datamodel="ecmascript" name="TestCase">
<datamodel>
<data id= "var1" expr="{'name':' var1','type':'Integer', 'value':8}"/>
<data id="dummyVariable" expr="0"/>
</datamodel>
<state id="startup">
<onentry>
<assign location="dummyVariable" expr="110"/>
<assign location="dummyVariable" expr="120"/>
<ccdl:wait duration="100 ms" />
<assign location="dummyVariable" expr="310"/>
<assign location="dummyVariable" expr="410"/>
</onentry>
<transition target="logic" />
<transition event="TestCase.error" target="teardown" />
<onexit>
<assign location="dummyVariable" expr="10"/>
<assign location="dummyVariable" expr="10"/>
</onexit>
</state>
<parallel id="logic">
<state id="logic_c0" />
<state id="logic_c1" />
<transition target="teardown" />
</parallel>
<state id="teardown">
<transition target="final" />
</state>
<final id="final" />
</scxml>
<?xml version="1.0" encoding="UTF-8"?>
<scxml
xmlns="http://www.w3.org/2005/07/scxml"
xmlns:ccdl="http://www.NotRealURL.de"
xmlns:cs="http://commons.apache.org/scxml" version="1.0" initial="startup" datamodel="ecmascript" name="TestCase">
<!--https://commons.apache.org/scxml-->
<datamodel>
<data id="var1" expr="{'name':' var1','type':'Integer', 'value':8}"/>
<data id="dummyVariable" expr="0"/>
<data id="duration" expr="0"/>
<data id="startTime" expr="0"/>
</datamodel>
<state id="startup" initial="child">
<transition target="logic"/>
<transition event="TestCase.error" target="teardown"/>
<state id="child" initial="hold">
<onentry>
<assign location="dummyVariable" expr="110"/>
<assign location="dummyVariable" expr="120"/>
<assign location="startTime" expr="Date.now()"/>
</onentry>
<state id="hold">
<onentry>
<assign location="duration" expr="Date.now()- startTime"/>
</onentry>
<transition cond="duration!=100" target="hold"/>
<transition cond="duration==100" target="child_Final"/>
</state>
<final id="child_Final"/>
<onexit>
<assign location="dummyVariable" expr="310"/>
<assign location="dummyVariable" expr="410"/>
</onexit>
</state>
<onexit>
<assign location="dummyVariable" expr="10"/>
<assign location="dummyVariable" expr="10"/>
</onexit>
</state>
<parallel id="logic">
<transition target="teardown"/>
<state id="logic_c0"/>
<state id="logic_c1"/>
</parallel>
<state id="teardown">
<transition target="final"/>
</state>
<final id="final"/>
</scxml>
Hi @Mumbasms,
First, here is how you can add custom action tags to SCION:
Use the scion.scxml.registerCustomActionTags
API. This takes a data structure of the form { <xml namespace> -> { <tag name> -> compiler function } }
. This API is used internally to implement the core action tags, so you can use that as an example:
https://gitlab.com/scion-scxml/scion/-/blob/main/projects/libraries/scxml/lib/runtime/facade.js#L44
https://gitlab.com/scion-scxml/scion/-/blob/main/projects/libraries/scxml/lib/compiler/coreActionTags.js
Next, here is how you might implement ccdl:wait
(untested, but should plausibly work):
{
"http://www.NotRealURL.de" : {
"wait": function(action, builder){
return ```
const tic = new Date()
while(true){
const toc = new Date()
const duration = toc - tic
if(duration >= getDelayInMs("${action.duration}")){
break
}
}
```
}
}
}
Big disclaimer: this solution is appropriate for research purposes only. This is not a practical solution, as Node.js is single-threaded, and the while loop would block the main thread, and any other asynchronous actions. A more appropriate solution is to use SCXML's <send>
tag with @delay
attribute. But this does require breaking the state machine into two states. Something like this:
<state id="startup">
<onentry>
<assign location="dummyVariable" expr="110"/>
<assign location="dummyVariable" expr="120"/>
<send event="ccdl_wait" delay="100ms"/>
</onentry>
<transition target="after_delay" event="ccdl_wait"/>
</state>
<state id="after_delay">
<onentry>
<assign location="dummyVariable" expr="310"/>
<assign location="dummyVariable" expr="410"/>
</onentry>
<transition target="logic" />
<transition event="TestCase.error" target="teardown" />
<onexit>
<assign location="dummyVariable" expr="10"/>
<assign location="dummyVariable" expr="10"/>
</onexit>
</state>
Hope this helps.
For some reason ramp function in <transition> is not updating datamodel. Otherwise our solution works
index.js
const scxml = require("@scion-scxml/scxml");
const core = require("@scion-scxml/core");
let action = {
"http://www.NotRealURL.de": {
wait: function (action, builder) {
const tic = new Date();
while (true) {
const toc = new Date();
const duration = toc - tic;
if (duration >= parseInt(action.duration.replace("ms", ""))) {
console.log(duration + "here");
break;
}
}
return "something";
},
expect: function (action, builder) {
let expr = builder.generateFnCall(
builder.generateAttributeExpression(action, "expr")
);
return `if(${expr}){
this.log('Expect Action Success');
} else {
this.log('Expect Action Failed');
}`;
},
ramp: function (action, builder) {
return `this.log(${action.dataid}.value);
for (let i =0 ; i < 10; i++) {
let temp=${action.dataid}.value + parseInt(${action.slope});
${action.dataid}.value = temp;
// this.log(${action.dataid}.value);
}
this.log(${action.dataid}.value);
`;
}
}
};
scxml.registerCustomActionTags(action);
scxml.pathToModel(
"rampINPUT.scxml",
function (err, model) {
if (err) throw err;
model.prepare(function (err, fnModel) {
if (err) throw err;
//instantiate the interpreter
var sc = new core.Statechart(fnModel);
//start the interpreter
sc.start();
});
}
);
Input File below rampINPUT.scxml
<?xml version="1.0" encoding="UTF-8"?>
<scxml
xmlns="http://www.w3.org/2005/07/scxml"
xmlns:ccdl="http://www.NotRealURL.de"
xmlns:cs="http://commons.apache.org/scxml" version="1.0" initial="startup" datamodel="ecmascript" name="TestCase">
<datamodel>
<data id= "var1" expr="{'name':' var1','type':'Integer', 'value':2}"/>
<data id= "var2" expr="{'name':' var2','type':'Integer', 'value':10}"/>
<data id= "var3" expr="{'name':' var3','type':'Integer', 'value':5}"/>
<data id="dummyVariable" expr="0"/>
</datamodel>
<state id="startup">
<onentry>
<assign location="dummyVariable" expr="10"/>
<assign location="dummyVariable" expr="20"/>
<ccdl:ramp id="ramp1" dataid="var1" slope="4"/>
<assign location="dummyVariable" expr="30"/>
<assign location="dummyVariable" expr="40"/>
</onentry>
<transition target="logic" >
<assign location="dummyVariable" expr="605"/>
<ccdl:ramp id="ramp2" dataid="var2" slope="400"/>
<assign location="dummyVariable" expr="750"/>
<log label="dummyVariable here" expr="dummyVariable"/>
</transition>
<transition event="TestCase.error" target="teardown" />
<onexit>
<assign location="dummyVariable" expr="60"/>
<ccdl:ramp id="ramp3" dataid="var3" slope="8"/>
<assign location="dummyVariable" expr="70"/>
<log label="var1" expr="var1.value"/>
<log label="var2" expr="var2.value"/>
<log label="var3" expr="var3.value"/>
<log label="dummyVariable last" expr="dummyVariable"/>
</onexit>
</state>
<parallel id="logic">
<state id="logic_c0" />
<state id="logic_c1" />
<transition target="teardown" />
</parallel>
<state id="teardown">
<transition target="final" />
</state>
<final id="final" />
</scxml>
console output
2
42
5
85
var1 42
var2 10
var3 85
dummyVariable last 70
10
4010
dummyVariable here 750
dummyVariable here
shoudl occur after dummyVariable last
registerCustomActionTags
and I will plan to fix this soon
@jbeard4 Oh understand. So far everything worked out.
1) "dummyVariable last" in <onexit> and "dummyVariable here" inside <transition> so as per SCXML rule, if I am not wrong,
while transitioning out from the state , sequence of execution : <onexit> of source state, <transition> executatable content
and then <onentry> of target state..
2) We wanted to use the ramp in parallel to the main execution i.e. in a separate thread.But it was pointed out to me that javascript is a single thread framework. Hence I decided to use uscxml- SCXML interpreter and transformer/compiler written in C/C++,
just to compare input and output files in the ramp. All credit goes to Korel for this :)
@Mumbasms Yes, in 2010 I developed an early version of SCION (then called scxml-js) as a project for the Apache Software Foundation as a part of Google Summer of Code, and this was implemented as an XSLT pipeline, such that it transformed SCXML to Javascript. I wrote a paper about it, which you can read here:
Slides are here:
Here is the source code:
http://svn.apache.org/repos/asf/commons/sandbox/gsoc/2010/scxml-js/trunk/
Hope this helps.
I feel like there were some pretty good ideas in that project. It would be neat to extend it to support multiple language compilation targets, like Ragel:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2005/07/scxml
https://www.w3.org/2011/04/SCXML/scxml.xsd"
xmlns:conf="http://www.w3.org/2005/scxml-conformance"
<script>
, @expr
, etc), or validate referenced javascript variables against variables declared in your <datamodel>
Hi @AbdallahNasser, here is a rough outline of the approach I would recommend taking to bring the @scion-scxml/eslint-plugin up-to-date. @scion-scxml/eslint-plugin is based on eslint-plugin-html:
https://github.com/BenoitZugmeyer/eslint-plugin-html/
@scion-scxml/eslint-plugin should be brought up to date with the changes in the latest eslint-plugin-html version. I would recommend diffing eslint-plugin-html version v4.0.6 to latest tagged release v6.2.0, then applying the relevant changes to @scion-scxml/eslint-plugin. Then the @scion-scxml/eslint-plugin can be tested locally with eslint. I would recommend using the command line version of eslint, rather than trying to use vscode integration for this.
I looked at this some time ago, and this seemed like a good approach, but did not have time to finish it. Let me know if you have any questions and I will attempt to help answer them.