197 lines
4.0 KiB
JavaScript
197 lines
4.0 KiB
JavaScript
define(() => {
|
|
'use strict';
|
|
|
|
function mergeSets(target, b) {
|
|
if(!b) {
|
|
return;
|
|
}
|
|
for(let i = 0; i < b.length; ++ i) {
|
|
if(target.indexOf(b[i]) === -1) {
|
|
target.push(b[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function lastElement(list) {
|
|
return list[list.length - 1];
|
|
}
|
|
|
|
return class Generator {
|
|
findAgents(stages) {
|
|
const agents = ['['];
|
|
stages.forEach((stage) => {
|
|
if(stage.agents) {
|
|
mergeSets(agents, stage.agents);
|
|
}
|
|
});
|
|
|
|
if(agents.indexOf(']') !== -1) {
|
|
agents.splice(agents.indexOf(']'), 1);
|
|
}
|
|
agents.push(']');
|
|
|
|
return agents;
|
|
}
|
|
|
|
generate({meta = {}, stages}) {
|
|
const agents = this.findAgents(stages);
|
|
|
|
const agentStates = new Map();
|
|
agents.forEach((agent) => {
|
|
agentStates.set(agent, {visible: false, locked: false});
|
|
});
|
|
agentStates.get('[').locked = true;
|
|
agentStates.get(']').locked = true;
|
|
|
|
const rootStages = [];
|
|
let currentSection = {
|
|
mode: 'global',
|
|
label: '',
|
|
stages: rootStages,
|
|
};
|
|
let currentNest = {
|
|
type: 'block',
|
|
agents: [],
|
|
root: true,
|
|
sections: [currentSection],
|
|
};
|
|
const nesting = [currentNest];
|
|
|
|
function beginNested(stage) {
|
|
currentSection = {
|
|
mode: stage.mode,
|
|
label: stage.label,
|
|
stages: [],
|
|
};
|
|
currentNest = {
|
|
type: 'block',
|
|
agents: [],
|
|
sections: [currentSection],
|
|
};
|
|
nesting.push(currentNest);
|
|
}
|
|
|
|
function splitNested(stage) {
|
|
if(currentNest.sections[0].mode !== 'if') {
|
|
throw new Error('Invalid block nesting');
|
|
}
|
|
currentSection = {
|
|
mode: stage.mode,
|
|
label: stage.label,
|
|
stages: [],
|
|
};
|
|
currentNest.sections.push(currentSection);
|
|
}
|
|
|
|
function addStage(stage) {
|
|
currentSection.stages.push(stage);
|
|
mergeSets(currentNest.agents, stage.agents);
|
|
}
|
|
|
|
function endNested() {
|
|
if(currentNest.root) {
|
|
throw new Error('Invalid block nesting');
|
|
}
|
|
const subNest = nesting.pop();
|
|
currentNest = lastElement(nesting);
|
|
currentSection = lastElement(currentNest.sections);
|
|
if(subNest.agents.length > 0) {
|
|
addStage(subNest);
|
|
}
|
|
}
|
|
|
|
function addAgentMod(stageAgents, markVisible, mode) {
|
|
if(stageAgents.length === 0) {
|
|
return;
|
|
}
|
|
stageAgents.forEach((agent) => {
|
|
agentStates.get(agent).visible = markVisible;
|
|
});
|
|
const type = (markVisible ? 'agent begin' : 'agent end');
|
|
const existing = lastElement(currentSection.stages) || {};
|
|
if(existing.type === type && existing.mode === mode) {
|
|
mergeSets(existing.agents, stageAgents);
|
|
mergeSets(currentNest.agents, stageAgents);
|
|
} else {
|
|
addStage({
|
|
type,
|
|
agents: stageAgents,
|
|
mode,
|
|
});
|
|
}
|
|
}
|
|
|
|
function filterVis(stageAgents, visible, implicit = false) {
|
|
return stageAgents.filter((agent) => {
|
|
const state = agentStates.get(agent);
|
|
if(!state.locked) {
|
|
return state.visible === visible;
|
|
} else if(!implicit) {
|
|
throw new Error('Cannot modify agent ' + agent);
|
|
} else {
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
stages.forEach((stage) => {
|
|
/* jshint -W074 */ // It's only a switch statement
|
|
switch(stage.type) {
|
|
case 'agent define':
|
|
break;
|
|
case 'agent begin':
|
|
addAgentMod(
|
|
filterVis(stage.agents, false),
|
|
true,
|
|
stage.mode
|
|
);
|
|
break;
|
|
case 'agent end':
|
|
addAgentMod(
|
|
filterVis(stage.agents, true),
|
|
false,
|
|
stage.mode
|
|
);
|
|
break;
|
|
case 'block begin':
|
|
beginNested(stage);
|
|
break;
|
|
case 'block split':
|
|
splitNested(stage);
|
|
break;
|
|
case 'block end':
|
|
endNested(stage);
|
|
break;
|
|
default:
|
|
addAgentMod(
|
|
filterVis(stage.agents, false, true),
|
|
true,
|
|
'box'
|
|
);
|
|
addStage(stage);
|
|
break;
|
|
}
|
|
});
|
|
|
|
if(nesting.length !== 1) {
|
|
throw new Error('Invalid block nesting');
|
|
}
|
|
|
|
addAgentMod(
|
|
filterVis(agents, true, true),
|
|
false,
|
|
meta.terminators || 'none'
|
|
);
|
|
|
|
return {
|
|
meta: {
|
|
title: meta.title,
|
|
},
|
|
agents,
|
|
stages: rootStages,
|
|
};
|
|
}
|
|
};
|
|
});
|
|
|