|
|
@@ -1,139 +1,60 @@
|
|
|
-#!/usr/bin/env babel-node --stage 0
|
|
|
-/*jshint esnext:true*/
|
|
|
"use strict";
|
|
|
-//TODO: should be a lib not a test / binary
|
|
|
|
|
|
+module.exports = class Generator {
|
|
|
|
|
|
-let typeEnum = { //TODO: use Symbol for these?
|
|
|
- SYSTEM: Symbol("SYSTEM"),
|
|
|
- BEHAVIOR: Symbol("BEHAVIOR"),
|
|
|
- ALTERNATION: Symbol("ALTERNATION"),
|
|
|
-};
|
|
|
-
|
|
|
-let behaviors = {
|
|
|
- driving_a_car: {type:"BEHAVIOR", id:"driving_a_car", body:[
|
|
|
- {type:"BEHAVIOR", id:"go_straight"},
|
|
|
- {type:"ALTERNATION", id:"driving_a_car_alt1", scope:{min:0,max:1}, body:[
|
|
|
- {type:"BEHAVIOR", id:"go_straight"},
|
|
|
- {type:"BEHAVIOR", id:"turn_left"},
|
|
|
- {type:"BEHAVIOR", id:"turn_right"},
|
|
|
- ]},
|
|
|
- {type:"BEHAVIOR", id:"stop"},
|
|
|
- ]},
|
|
|
- go_straight: {type:"BEHAVIOR", id:"go_straight", body:[
|
|
|
- {type:"ALTERNATION", id:"go_straight_alt1", scope:{min:1,max:1}, body:[
|
|
|
- {type:"BEHAVIOR", id:"accelerate"},
|
|
|
- {type:"BEHAVIOR", id:"decelerate"},
|
|
|
- {type:"BEHAVIOR", id:"cruise"},
|
|
|
- ]},
|
|
|
- ]},
|
|
|
- turn_left: {type:"BEHAVIOR", id:"turn_left", body:[]},
|
|
|
- turn_right: {type:"BEHAVIOR", id:"turn_right", body:[]},
|
|
|
- accelerate: {type:"BEHAVIOR", id:"accelerate", body:[]},
|
|
|
- decelerate: {type:"BEHAVIOR", id:"decelerate", body:[]},
|
|
|
- cruise: {type:"BEHAVIOR", id:"cruise", body:[]},
|
|
|
- stop: {type:"BEHAVIOR", id:"stop", body:[]},
|
|
|
+ constructor(parsed) {
|
|
|
+ this.systems = parsed.systems;
|
|
|
+ this.behaviors = parsed.behaviors;
|
|
|
+ this.interactions = parsed.interactions;
|
|
|
+ this.triggers = parsed.triggers;
|
|
|
+ }
|
|
|
|
|
|
- foobarbaz: {type:"BEHAVIOR", id:"foobarbaz", body:[
|
|
|
- {type:"BEHAVIOR", id:"foo", scope:{max:1}},
|
|
|
- {type:"BEHAVIOR", id:"bar", scope:{max:1}},
|
|
|
- {type:"BEHAVIOR", id:"baz", scope:{max:1}},
|
|
|
- ]},
|
|
|
- foo: {type:"BEHAVIOR", id:"foo", body:[]},
|
|
|
- bar: {type:"BEHAVIOR", id:"bar", body:[]},
|
|
|
- baz: {type:"BEHAVIOR", id:"baz", body:[]},
|
|
|
-};
|
|
|
+ *generate(obj, min, max, scope=1, n=0, i=0) {
|
|
|
+ console.log(`t=${obj.type}, id=${obj.id || ""}, n=${n}, i=${i}`);
|
|
|
+
|
|
|
+ let nextMin = obj.scope && typeof obj.scope.min === "number" ? Math.max(0, obj.scope.min) : 1;
|
|
|
+ let nextMax = obj.scope && typeof obj.scope.max === "number" ? Math.min(scope, obj.scope.max) : scope;
|
|
|
+
|
|
|
+ let id;
|
|
|
+ switch (obj.type) {
|
|
|
+
|
|
|
+ case "Behavior":
|
|
|
+ if (!obj.body) { // Behavior reference
|
|
|
+ let realObj = this.behaviors[obj.id];
|
|
|
+ if (!realObj || !realObj.body) throw new Error(`Unable to find referenced behavior: ${obj.id}`);
|
|
|
+ obj = realObj;
|
|
|
+ if (obj.body.length === 0) { // Atomic Behavior
|
|
|
+ yield [obj.id];
|
|
|
+ return; //break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* falls through */
|
|
|
+ case "System": // or Behavior
|
|
|
+ if (!obj.body) throw new Error(`Unexpected empty ${obj.type}`);
|
|
|
+ id = `${obj.id}_${n + 1}of${max}`;
|
|
|
+ /* falls through */
|
|
|
+ case "Sequence": // or System or Behavior
|
|
|
+ let outs = [];
|
|
|
+ if (i === 0 && id) outs.push(id);
|
|
|
+ if (i < obj.body.length) {
|
|
|
+ for (let nextEvts of this.generate(obj, min, max, scope, n, i + 1)) {
|
|
|
+ for (let evts of this.generate(obj.body[i], nextMin, nextMax, scope)) {
|
|
|
+ yield outs.concat(evts, nextEvts);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (n >= min - 1) yield outs;
|
|
|
+ if (n < max - 1) {
|
|
|
+ for (let nextEvts of this.generate(obj, min, max, scope, n + 1, 0))
|
|
|
+ yield outs.concat(nextEvts);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ throw new Error(`UNIMPLEMENTED TYPE: ${obj.type}`);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-let systems = {
|
|
|
- car_race: {
|
|
|
- type: "SYSTEM",
|
|
|
- id: "car_race",
|
|
|
- body: [
|
|
|
- // {type:"BEHAVIOR", id:"driving_a_car", scope:{min:1, max:null}},
|
|
|
- // {type:"BEHAVIOR", id:"go_straight", scope:{min:1, max:null}},
|
|
|
- {type:"BEHAVIOR", id:"foobarbaz", scope:{min:1, max:null}},
|
|
|
- ],
|
|
|
- },
|
|
|
};
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-//SYSTEM: car_race = foobarbaz+;
|
|
|
-//BEHAVIOR: foobarbaz = foo bar baz;
|
|
|
-
|
|
|
-//car_race foobarbaz foo bar baz
|
|
|
-//car_race foobarbaz foo bar baz foobarbaz foo bar baz
|
|
|
-//car_race foobarbaz foo bar baz foobarbaz foo bar baz foobarbaz foo bar baz
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-const SCOPE_MAX = 3;
|
|
|
-
|
|
|
-function *getEventGenerator(obj, min, max, scope=SCOPE_MAX, i=0) {
|
|
|
-
|
|
|
- let nextMin = obj.scope && typeof obj.scope.min === "number" ? Math.max(0, obj.scope.min) : 1;
|
|
|
- let nextMax = obj.scope && typeof obj.scope.max === "number" ? Math.min(scope, obj.scope.max) : scope;
|
|
|
-
|
|
|
- switch (obj.type) {
|
|
|
-
|
|
|
- case "BEHAVIOR":
|
|
|
- if (!obj.body) {
|
|
|
- let realObj = behaviors[obj.id];
|
|
|
- if (!realObj || !realObj.body) throw new Error(`Unable to find: ${obj.id}`);
|
|
|
- obj = realObj;
|
|
|
- }
|
|
|
-
|
|
|
- case "SYSTEM":
|
|
|
-// console.log(i, obj);
|
|
|
- let id = `${obj.id}_${max}`;
|
|
|
- if (obj.body.length > 0) {
|
|
|
- if (i < obj.body.length) {
|
|
|
- yield* (
|
|
|
- for (nextEvt of getEventGenerator(obj, min, max, scope, i + 1))
|
|
|
- for (evt of getEventGenerator(obj.body[i], nextMin, nextMax, scope))
|
|
|
- i === 0 ? [].concat(id, evt, nextEvt) : [].concat(evt, nextEvt)
|
|
|
- );
|
|
|
- } else {
|
|
|
- yield [];
|
|
|
- if (min < max) {
|
|
|
- yield* getEventGenerator(obj, min + 1, max, scope, 0);
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- yield [id];
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case "ALTERNATION":
|
|
|
- let id = `${obj.id}_${max}`;
|
|
|
- if (obj.body.length > 0) {
|
|
|
- for (let bodyObj of obj.body) {
|
|
|
- for (let evt of getEventGenerator(bodyObj, nextMin, nextMax, scope)) {
|
|
|
- if (max > 1) {
|
|
|
- for (let evt2 of getEventGenerator(obj, min, max - 1)) {
|
|
|
- yield [].concat(evt, evt2);
|
|
|
- }
|
|
|
- } else {
|
|
|
- yield evt;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- yield id;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- throw new Error(`UNIMPLEMENTED TYPE: ${obj.type}`);
|
|
|
-
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-for (let systemId of Object.keys(systems)) {
|
|
|
- console.log(`START: ${systemId}`);
|
|
|
- for (let evt of getEventGenerator(systems[systemId], 1, 1)) {
|
|
|
- // console.log(`GOT:`, evt.map(x => JSON.stringify(x)).join("\n"))
|
|
|
- console.log(`GOT:`, evt)
|
|
|
- }
|
|
|
-}
|