Add activate/deactivate syntax [#26]
This commit is contained in:
parent
827a94d712
commit
4cdb4ad584
|
@ -1854,6 +1854,22 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
function checkActivationConflicts(allStages) {
|
||||
const seen = new Set();
|
||||
for(const stage of allStages) {
|
||||
if(stage.type !== 'agent activation') {
|
||||
continue;
|
||||
}
|
||||
for(const agentID of stage.agentIDs) {
|
||||
if(seen.has(agentID)) {
|
||||
return 'Conflicting agent activation';
|
||||
}
|
||||
seen.add(agentID);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const PARALLEL_STAGES = [
|
||||
'agent begin',
|
||||
'agent end',
|
||||
|
@ -1884,7 +1900,8 @@
|
|||
return (
|
||||
checkAgentConflicts(allStages) ||
|
||||
checkReferenceConflicts(allStages) ||
|
||||
checkDelayedConflicts(allStages)
|
||||
checkDelayedConflicts(allStages) ||
|
||||
checkActivationConflicts(allStages)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1949,6 +1966,7 @@
|
|||
this.currentNest = null;
|
||||
|
||||
this.stageHandlers = {
|
||||
'agent activation': this.handleAgentActivation.bind(this),
|
||||
'agent begin': this.handleAgentBegin.bind(this),
|
||||
'agent define': this.handleAgentDefine.bind(this),
|
||||
'agent end': this.handleAgentEnd.bind(this),
|
||||
|
@ -2777,6 +2795,14 @@
|
|||
});
|
||||
}
|
||||
|
||||
handleAgentActivation({agents, activated, parallel}) {
|
||||
const gAgents = agents.map(this.toGAgent);
|
||||
this.validateGAgents(gAgents);
|
||||
this.defineGAgents(gAgents);
|
||||
this.addImpStage(this.setGAgentVis(gAgents, true, 'box'), {parallel});
|
||||
this.addStage(this.setGAgentActivation(gAgents, activated), {parallel});
|
||||
}
|
||||
|
||||
handleAgentBegin({agents, mode, parallel}) {
|
||||
const gAgents = agents.map(this.toGAgent);
|
||||
this.validateGAgents(gAgents);
|
||||
|
@ -3326,7 +3352,9 @@
|
|||
];
|
||||
|
||||
const PARALLEL_TASKS = [
|
||||
'activate',
|
||||
'begin',
|
||||
'deactivate',
|
||||
'end',
|
||||
'note',
|
||||
'state',
|
||||
|
@ -3635,6 +3663,8 @@
|
|||
'as': CM_ERROR,
|
||||
'\n': end,
|
||||
}},
|
||||
'activate': {type: 'keyword', then: {'': agentListTo({'\n': end})}},
|
||||
'deactivate': {type: 'keyword', then: {'': agentListTo({'\n': end})}},
|
||||
'if': commonGroup,
|
||||
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
||||
'if': {type: 'keyword', suggest: ['if: '], then: {
|
||||
|
@ -4661,6 +4691,16 @@
|
|||
AGENT_MANIPULATION_TYPES.set('begin', {mode: 'box', type: 'agent begin'});
|
||||
AGENT_MANIPULATION_TYPES.set('end', {mode: 'cross', type: 'agent end'});
|
||||
|
||||
const AGENT_ACTIVATION_TYPES = new Map();
|
||||
AGENT_MANIPULATION_TYPES.set('activate', {
|
||||
activated: true,
|
||||
type: 'agent activation',
|
||||
});
|
||||
AGENT_MANIPULATION_TYPES.set('deactivate', {
|
||||
activated: false,
|
||||
type: 'agent activation',
|
||||
});
|
||||
|
||||
function makeError(message, token = null) {
|
||||
let suffix = '';
|
||||
if(token) {
|
||||
|
@ -4957,6 +4997,16 @@
|
|||
}, type);
|
||||
}},
|
||||
|
||||
{begin: [], fn: (line) => { // Activation
|
||||
const type = AGENT_ACTIVATION_TYPES.get(tokenKeyword(line[0]));
|
||||
if(!type || line.length <= 1) {
|
||||
return null;
|
||||
}
|
||||
return Object.assign({
|
||||
agents: readAgentList(line, 1, line.length, {aliases: false}),
|
||||
}, type);
|
||||
}},
|
||||
|
||||
{begin: ['simultaneously'], fn: (line) => { // Async
|
||||
if(tokenKeyword(last(line)) !== ':') {
|
||||
return null;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1854,6 +1854,22 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
function checkActivationConflicts(allStages) {
|
||||
const seen = new Set();
|
||||
for(const stage of allStages) {
|
||||
if(stage.type !== 'agent activation') {
|
||||
continue;
|
||||
}
|
||||
for(const agentID of stage.agentIDs) {
|
||||
if(seen.has(agentID)) {
|
||||
return 'Conflicting agent activation';
|
||||
}
|
||||
seen.add(agentID);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const PARALLEL_STAGES = [
|
||||
'agent begin',
|
||||
'agent end',
|
||||
|
@ -1884,7 +1900,8 @@
|
|||
return (
|
||||
checkAgentConflicts(allStages) ||
|
||||
checkReferenceConflicts(allStages) ||
|
||||
checkDelayedConflicts(allStages)
|
||||
checkDelayedConflicts(allStages) ||
|
||||
checkActivationConflicts(allStages)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1949,6 +1966,7 @@
|
|||
this.currentNest = null;
|
||||
|
||||
this.stageHandlers = {
|
||||
'agent activation': this.handleAgentActivation.bind(this),
|
||||
'agent begin': this.handleAgentBegin.bind(this),
|
||||
'agent define': this.handleAgentDefine.bind(this),
|
||||
'agent end': this.handleAgentEnd.bind(this),
|
||||
|
@ -2777,6 +2795,14 @@
|
|||
});
|
||||
}
|
||||
|
||||
handleAgentActivation({agents, activated, parallel}) {
|
||||
const gAgents = agents.map(this.toGAgent);
|
||||
this.validateGAgents(gAgents);
|
||||
this.defineGAgents(gAgents);
|
||||
this.addImpStage(this.setGAgentVis(gAgents, true, 'box'), {parallel});
|
||||
this.addStage(this.setGAgentActivation(gAgents, activated), {parallel});
|
||||
}
|
||||
|
||||
handleAgentBegin({agents, mode, parallel}) {
|
||||
const gAgents = agents.map(this.toGAgent);
|
||||
this.validateGAgents(gAgents);
|
||||
|
@ -3326,7 +3352,9 @@
|
|||
];
|
||||
|
||||
const PARALLEL_TASKS = [
|
||||
'activate',
|
||||
'begin',
|
||||
'deactivate',
|
||||
'end',
|
||||
'note',
|
||||
'state',
|
||||
|
@ -3635,6 +3663,8 @@
|
|||
'as': CM_ERROR,
|
||||
'\n': end,
|
||||
}},
|
||||
'activate': {type: 'keyword', then: {'': agentListTo({'\n': end})}},
|
||||
'deactivate': {type: 'keyword', then: {'': agentListTo({'\n': end})}},
|
||||
'if': commonGroup,
|
||||
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
||||
'if': {type: 'keyword', suggest: ['if: '], then: {
|
||||
|
@ -4661,6 +4691,16 @@
|
|||
AGENT_MANIPULATION_TYPES.set('begin', {mode: 'box', type: 'agent begin'});
|
||||
AGENT_MANIPULATION_TYPES.set('end', {mode: 'cross', type: 'agent end'});
|
||||
|
||||
const AGENT_ACTIVATION_TYPES = new Map();
|
||||
AGENT_MANIPULATION_TYPES.set('activate', {
|
||||
activated: true,
|
||||
type: 'agent activation',
|
||||
});
|
||||
AGENT_MANIPULATION_TYPES.set('deactivate', {
|
||||
activated: false,
|
||||
type: 'agent activation',
|
||||
});
|
||||
|
||||
function makeError(message, token = null) {
|
||||
let suffix = '';
|
||||
if(token) {
|
||||
|
@ -4957,6 +4997,16 @@
|
|||
}, type);
|
||||
}},
|
||||
|
||||
{begin: [], fn: (line) => { // Activation
|
||||
const type = AGENT_ACTIVATION_TYPES.get(tokenKeyword(line[0]));
|
||||
if(!type || line.length <= 1) {
|
||||
return null;
|
||||
}
|
||||
return Object.assign({
|
||||
agents: readAgentList(line, 1, line.length, {aliases: false}),
|
||||
}, type);
|
||||
}},
|
||||
|
||||
{begin: ['simultaneously'], fn: (line) => { // Async
|
||||
if(tokenKeyword(last(line)) !== ':') {
|
||||
return null;
|
||||
|
|
|
@ -36,7 +36,9 @@ const AGENT_INFO_TYPES = [
|
|||
];
|
||||
|
||||
const PARALLEL_TASKS = [
|
||||
'activate',
|
||||
'begin',
|
||||
'deactivate',
|
||||
'end',
|
||||
'note',
|
||||
'state',
|
||||
|
@ -345,6 +347,8 @@ const makeCommands = ((() => {
|
|||
'as': CM_ERROR,
|
||||
'\n': end,
|
||||
}},
|
||||
'activate': {type: 'keyword', then: {'': agentListTo({'\n': end})}},
|
||||
'deactivate': {type: 'keyword', then: {'': agentListTo({'\n': end})}},
|
||||
'if': commonGroup,
|
||||
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
||||
'if': {type: 'keyword', suggest: ['if: '], then: {
|
||||
|
|
|
@ -270,6 +270,22 @@ function checkDelayedConflicts(allStages) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function checkActivationConflicts(allStages) {
|
||||
const seen = new Set();
|
||||
for(const stage of allStages) {
|
||||
if(stage.type !== 'agent activation') {
|
||||
continue;
|
||||
}
|
||||
for(const agentID of stage.agentIDs) {
|
||||
if(seen.has(agentID)) {
|
||||
return 'Conflicting agent activation';
|
||||
}
|
||||
seen.add(agentID);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const PARALLEL_STAGES = [
|
||||
'agent begin',
|
||||
'agent end',
|
||||
|
@ -300,7 +316,8 @@ function errorForParallel(existing, latest) {
|
|||
return (
|
||||
checkAgentConflicts(allStages) ||
|
||||
checkReferenceConflicts(allStages) ||
|
||||
checkDelayedConflicts(allStages)
|
||||
checkDelayedConflicts(allStages) ||
|
||||
checkActivationConflicts(allStages)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -365,6 +382,7 @@ export default class Generator {
|
|||
this.currentNest = null;
|
||||
|
||||
this.stageHandlers = {
|
||||
'agent activation': this.handleAgentActivation.bind(this),
|
||||
'agent begin': this.handleAgentBegin.bind(this),
|
||||
'agent define': this.handleAgentDefine.bind(this),
|
||||
'agent end': this.handleAgentEnd.bind(this),
|
||||
|
@ -1193,6 +1211,14 @@ export default class Generator {
|
|||
});
|
||||
}
|
||||
|
||||
handleAgentActivation({agents, activated, parallel}) {
|
||||
const gAgents = agents.map(this.toGAgent);
|
||||
this.validateGAgents(gAgents);
|
||||
this.defineGAgents(gAgents);
|
||||
this.addImpStage(this.setGAgentVis(gAgents, true, 'box'), {parallel});
|
||||
this.addStage(this.setGAgentActivation(gAgents, activated), {parallel});
|
||||
}
|
||||
|
||||
handleAgentBegin({agents, mode, parallel}) {
|
||||
const gAgents = agents.map(this.toGAgent);
|
||||
this.validateGAgents(gAgents);
|
||||
|
|
|
@ -25,6 +25,17 @@ describe('Sequence Generator', () => {
|
|||
const [PARSED_SOURCE] = makeParsedAgents([{flags: ['source']}]);
|
||||
|
||||
const PARSED = {
|
||||
agentActivation: (agents, activated, {
|
||||
ln = 0,
|
||||
parallel = false,
|
||||
} = {}) => ({
|
||||
activated,
|
||||
agents: makeParsedAgents(agents),
|
||||
ln,
|
||||
parallel,
|
||||
type: 'agent activation',
|
||||
}),
|
||||
|
||||
agentBegin: (agents, {
|
||||
ln = 0,
|
||||
mode = 'box',
|
||||
|
@ -227,15 +238,6 @@ describe('Sequence Generator', () => {
|
|||
};
|
||||
|
||||
const GENERATED = {
|
||||
activation: (agentIDs, activated, {
|
||||
ln = any(),
|
||||
} = {}) => ({
|
||||
activated,
|
||||
agentIDs,
|
||||
ln,
|
||||
type: 'agent activation',
|
||||
}),
|
||||
|
||||
agent: (id, {
|
||||
anchorRight = any(),
|
||||
formattedLabel = any(),
|
||||
|
@ -249,6 +251,15 @@ describe('Sequence Generator', () => {
|
|||
options,
|
||||
}),
|
||||
|
||||
agentActivation: (agentIDs, activated, {
|
||||
ln = any(),
|
||||
} = {}) => ({
|
||||
activated,
|
||||
agentIDs,
|
||||
ln,
|
||||
type: 'agent activation',
|
||||
}),
|
||||
|
||||
agentBegin: (agentIDs, {
|
||||
mode = any(),
|
||||
ln = any(),
|
||||
|
@ -860,6 +871,68 @@ describe('Sequence Generator', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('propegates activation stages', () => {
|
||||
const sequence = invoke([
|
||||
PARSED.agentActivation(['A', 'B'], true),
|
||||
]);
|
||||
|
||||
expect(sequence.stages).toEqual([
|
||||
any(),
|
||||
GENERATED.agentActivation(['A', 'B'], true),
|
||||
any(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('adds implicit begin stages for activation', () => {
|
||||
const sequence = invoke([
|
||||
PARSED.agentActivation(['A', 'B'], true),
|
||||
]);
|
||||
|
||||
expect(sequence.stages).toEqual([
|
||||
GENERATED.agentBegin(['A', 'B']),
|
||||
any(),
|
||||
any(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('implicitly combines compatible activation stages', () => {
|
||||
const sequence = invoke([
|
||||
PARSED.agentBegin(['A', 'B']),
|
||||
PARSED.agentActivation(['A'], true),
|
||||
PARSED.agentActivation(['B'], true),
|
||||
]);
|
||||
|
||||
expect(sequence.stages).toEqual([
|
||||
any(),
|
||||
GENERATED.agentActivation(['A', 'B'], true),
|
||||
any(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('maintains separation of incompatible activation stages', () => {
|
||||
const sequence = invoke([
|
||||
PARSED.agentBegin(['A']),
|
||||
PARSED.agentActivation(['A'], true),
|
||||
PARSED.agentActivation(['A'], false),
|
||||
]);
|
||||
|
||||
expect(sequence.stages).toEqual([
|
||||
any(),
|
||||
GENERATED.agentActivation(['A'], true),
|
||||
GENERATED.agentActivation(['A'], false),
|
||||
any(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('rejects conflicting parallel activation stages', () => {
|
||||
expect(() => invoke([
|
||||
PARSED.agentActivation(['A'], true),
|
||||
PARSED.agentActivation(['A'], false, {parallel: true}),
|
||||
])).toThrow(new Error(
|
||||
'Conflicting agent activation at line 1'
|
||||
));
|
||||
});
|
||||
|
||||
it('adds parallel activation stages to self connections', () => {
|
||||
const sequence = invoke([
|
||||
PARSED.connect([
|
||||
|
@ -871,12 +944,12 @@ describe('Sequence Generator', () => {
|
|||
expect(sequence.stages).toEqual([
|
||||
any(),
|
||||
GENERATED.parallel([
|
||||
GENERATED.activation(['A'], true),
|
||||
GENERATED.agentActivation(['A'], true),
|
||||
GENERATED.connectBegin(['A', 'A'], {label: 'woo!'}),
|
||||
]),
|
||||
GENERATED.parallel([
|
||||
GENERATED.connectEnd(),
|
||||
GENERATED.activation(['A'], false),
|
||||
GENERATED.agentActivation(['A'], false),
|
||||
]),
|
||||
any(),
|
||||
]);
|
||||
|
@ -1194,12 +1267,12 @@ describe('Sequence Generator', () => {
|
|||
expect(sequence.stages).toEqual([
|
||||
any(),
|
||||
GENERATED.parallel([
|
||||
GENERATED.activation(['B'], true),
|
||||
GENERATED.agentActivation(['B'], true),
|
||||
GENERATED.connect(['A', 'B']),
|
||||
]),
|
||||
GENERATED.parallel([
|
||||
GENERATED.connect(['A', 'B']),
|
||||
GENERATED.activation(['B'], false),
|
||||
GENERATED.agentActivation(['B'], false),
|
||||
]),
|
||||
any(),
|
||||
]);
|
||||
|
@ -1246,7 +1319,7 @@ describe('Sequence Generator', () => {
|
|||
any(),
|
||||
GENERATED.parallel([
|
||||
GENERATED.connect(['A', 'B']),
|
||||
GENERATED.activation(['B'], false),
|
||||
GENERATED.agentActivation(['B'], false),
|
||||
GENERATED.agentEnd(['B']),
|
||||
]),
|
||||
GENERATED.agentEnd(['A']),
|
||||
|
@ -1285,7 +1358,7 @@ describe('Sequence Generator', () => {
|
|||
any(),
|
||||
any(),
|
||||
GENERATED.parallel([
|
||||
GENERATED.activation(['B'], false),
|
||||
GENERATED.agentActivation(['B'], false),
|
||||
GENERATED.agentEnd(['A', 'B']),
|
||||
]),
|
||||
]);
|
||||
|
@ -1301,7 +1374,7 @@ describe('Sequence Generator', () => {
|
|||
any(),
|
||||
any(),
|
||||
GENERATED.parallel([
|
||||
GENERATED.activation(['B'], false),
|
||||
GENERATED.agentActivation(['B'], false),
|
||||
GENERATED.agentEnd(['A', 'B']),
|
||||
]),
|
||||
]);
|
||||
|
@ -1321,7 +1394,7 @@ describe('Sequence Generator', () => {
|
|||
any(),
|
||||
any(),
|
||||
GENERATED.parallel([
|
||||
GENERATED.activation(['A', 'B'], false),
|
||||
GENERATED.agentActivation(['A', 'B'], false),
|
||||
GENERATED.agentEnd(['A', 'B']),
|
||||
]),
|
||||
]);
|
||||
|
|
|
@ -154,6 +154,16 @@ AGENT_MANIPULATION_TYPES.set('define', {type: 'agent define'});
|
|||
AGENT_MANIPULATION_TYPES.set('begin', {mode: 'box', type: 'agent begin'});
|
||||
AGENT_MANIPULATION_TYPES.set('end', {mode: 'cross', type: 'agent end'});
|
||||
|
||||
const AGENT_ACTIVATION_TYPES = new Map();
|
||||
AGENT_MANIPULATION_TYPES.set('activate', {
|
||||
activated: true,
|
||||
type: 'agent activation',
|
||||
});
|
||||
AGENT_MANIPULATION_TYPES.set('deactivate', {
|
||||
activated: false,
|
||||
type: 'agent activation',
|
||||
});
|
||||
|
||||
function makeError(message, token = null) {
|
||||
let suffix = '';
|
||||
if(token) {
|
||||
|
@ -450,6 +460,16 @@ const PARSERS = [
|
|||
}, type);
|
||||
}},
|
||||
|
||||
{begin: [], fn: (line) => { // Activation
|
||||
const type = AGENT_ACTIVATION_TYPES.get(tokenKeyword(line[0]));
|
||||
if(!type || line.length <= 1) {
|
||||
return null;
|
||||
}
|
||||
return Object.assign({
|
||||
agents: readAgentList(line, 1, line.length, {aliases: false}),
|
||||
}, type);
|
||||
}},
|
||||
|
||||
{begin: ['simultaneously'], fn: (line) => { // Async
|
||||
if(tokenKeyword(last(line)) !== ':') {
|
||||
return null;
|
||||
|
|
|
@ -19,6 +19,18 @@ describe('Sequence Parser', () => {
|
|||
const any = () => jasmine.anything();
|
||||
|
||||
const PARSED = {
|
||||
agentActivation: (agents, {
|
||||
ln = any(),
|
||||
activated = any(),
|
||||
parallel = false,
|
||||
} = {}) => ({
|
||||
activated,
|
||||
agents: makeParsedAgents(agents),
|
||||
ln,
|
||||
parallel,
|
||||
type: 'agent activation',
|
||||
}),
|
||||
|
||||
agentBegin: (agents, {
|
||||
ln = any(),
|
||||
mode = any(),
|
||||
|
@ -689,12 +701,16 @@ describe('Sequence Parser', () => {
|
|||
const parsed = parser.parse(
|
||||
'define A, B\n' +
|
||||
'begin A, B\n' +
|
||||
'activate A, B\n' +
|
||||
'deactivate A, B\n' +
|
||||
'end A, B\n'
|
||||
);
|
||||
|
||||
expect(parsed.stages).toEqual([
|
||||
PARSED.agentDefine(['A', 'B']),
|
||||
PARSED.agentBegin(['A', 'B'], {mode: 'box'}),
|
||||
PARSED.agentActivation(['A', 'B'], {activated: true}),
|
||||
PARSED.agentActivation(['A', 'B'], {activated: false}),
|
||||
PARSED.agentEnd(['A', 'B'], {mode: 'cross'}),
|
||||
]);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue