import * as _ from 'lodash'; import { Transition, TransitionObject, PetriNet, Move, InFlowIntermediate, OutFlowIntermediate, TransitionExtensions } from './coloredPetriNets'; import { Expression, Pattern } from './types'; import { parseExpression, parsePattern, parseInteger } from './colorExpressionsParser'; class TransitionPlusPlus extends Transition { private static readonly commands: { [command: string]: { type: typeof TransitionPlusPlus } } = {}; public static registerType = (command: string, type: typeof TransitionPlusPlus): void => { TransitionPlusPlus.commands[command] = { type }; } static fromObject(net: PetriNet, data: TransitionObject): TransitionPlusPlus { const plusplusExtensions = data.extensions.plusplus; if (!plusplusExtensions) throw new Error("The extension data for a plusplus transition is missing."); const command = plusplusExtensions.command; if (!command) throw new Error("The command is unspecified."); if (!TransitionPlusPlus.commands[command]) throw new Error("The command is invalid."); if (_.some(data.inFlows, (inFlow) => inFlow.pattern)) throw new Error("Patterns are not allowed in plusplus transitions."); if (_.some(data.outFlows, (outFlow) => outFlow.expression)) throw new Error("Expressions are not allowed in plusplus transitions."); if (data.guard) throw new Error("Guards are not allowed in plusplus transitions."); return new TransitionPlusPlus.commands[command].type(data.key, data.displayName, data.guard, _.map(data.inFlows, (inFlow) => { const source = net.places[inFlow.source]; if (!source) throw new Error(`Source ${inFlow.source} not found while hydrating transition ${data.key}`); return { source, pattern: null }; }), _.map(data.outFlows, (outFlow) => { const target = net.places[outFlow.target]; if (!target) throw new Error(`Target ${outFlow.target} not found while hydrating transition ${data.key}`); return { target, expression: null }; }), data.extensions); } enabledMovesForMarking(): Move[] { throw new Error("enabledMovesForMarking() is not implemented for TransitionPlusPlus"); } } class PrintLnTransitionPlusPlus extends TransitionPlusPlus { public readonly expression: string; private readonly compiledExpression: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.expression = extensions.plusplus.arguments; this.compiledExpression = parseExpression(this.expression); } } TransitionPlusPlus.registerType('println', PrintLnTransitionPlusPlus); class CallTransitionPlusPlus extends TransitionPlusPlus { public readonly return: string; public readonly arguments: { name: string; expression: string; compiledExpression: Expression; }[]; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.return = extensions.plusplus.arguments.return; this.arguments = _.map(extensions.plusplus.arguments.arguments, ({ name, expression }) => ({ name, expression, compiledExpression: parseExpression(expression) })); } } TransitionPlusPlus.registerType('call', CallTransitionPlusPlus); class ReturnTransitionPlusPlus extends TransitionPlusPlus { public readonly expression: string; private readonly compiledExpression: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.expression = extensions.plusplus.arguments; this.compiledExpression = parseExpression(this.expression); } } TransitionPlusPlus.registerType('return', ReturnTransitionPlusPlus); class StartAgentTransitionPlusPlus extends TransitionPlusPlus { public readonly name: string; private readonly compiledName: Pattern; public readonly arguments: { name: string; expression: string; compiledExpression: Expression; }[]; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.name = extensions.plusplus.arguments.name; this.compiledName = parsePattern(this.name); this.arguments = _.map(extensions.plusplus.arguments.arguments, ({ name, expression }) => ({ name, expression, compiledExpression: parseExpression(expression) })); } } TransitionPlusPlus.registerType('start-agent', StartAgentTransitionPlusPlus); class JoinTransitionPlusPlus extends TransitionPlusPlus { public readonly agent: string; private readonly compiledAgent: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.agent = extensions.plusplus.arguments; this.compiledAgent = parseExpression(this.agent); } } TransitionPlusPlus.registerType('join', JoinTransitionPlusPlus); class InitChanTransitionPlusPlus extends TransitionPlusPlus { public readonly channel: string; private readonly compiledChannel: Expression; public readonly capacity: string; public readonly compiledCapacity: number; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.channel = extensions.plusplus.arguments.channel; this.compiledChannel = parseExpression(this.channel); this.capacity = extensions.plusplus.arguments.capacity; this.compiledCapacity = parseInteger(this.capacity); } } TransitionPlusPlus.registerType('init-chan', InitChanTransitionPlusPlus); class SendTransitionPlusPlus extends TransitionPlusPlus { public readonly channel: string; private readonly compiledChannel: Expression; public readonly value: string; private readonly compiledValue: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.channel = extensions.plusplus.arguments.channel; this.compiledChannel = parseExpression(this.channel); this.value = extensions.plusplus.arguments.value; this.compiledValue = parseExpression(this.value); } } TransitionPlusPlus.registerType('send', SendTransitionPlusPlus); class ReceiveTransitionPlusPlus extends TransitionPlusPlus { public readonly channel: string; private readonly compiledChannel: Expression; public readonly target: string; private readonly compiledTarget: Pattern; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.channel = extensions.plusplus.arguments.channel; this.compiledChannel = parseExpression(this.channel); this.target = extensions.plusplus.arguments.target; this.compiledTarget = parsePattern(this.target); } } TransitionPlusPlus.registerType('receive', ReceiveTransitionPlusPlus); class DefaultTransitionPlusPlus extends TransitionPlusPlus { constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); } } TransitionPlusPlus.registerType('default', DefaultTransitionPlusPlus); class GlobalReadTransitionPlusPlus extends TransitionPlusPlus { public readonly variable: string; private readonly compiledVariable: Expression; public readonly path: string[]; private readonly compiledPaths: Expression[]; public readonly target: string; private readonly compiledTarget: Pattern; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.variable = extensions.plusplus.arguments.variable; this.compiledVariable = parseExpression(this.variable); this.path = extensions.plusplus.arguments.path ? _.castArray(extensions.plusplus.arguments.path) : []; this.compiledPaths = _.map(this.path, (path) => parseExpression(path)); this.target = extensions.plusplus.arguments.target; this.compiledTarget = parsePattern(this.target); } } TransitionPlusPlus.registerType('read-global', GlobalReadTransitionPlusPlus); class GlobalWriteTransitionPlusPlus extends TransitionPlusPlus { public readonly variable: string; private readonly compiledVariable: Expression; public readonly path: string[]; private readonly compiledPaths: Expression[]; public readonly value: string; private readonly compiledValue: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.variable = extensions.plusplus.arguments.variable; this.compiledVariable = parseExpression(this.variable); this.path = extensions.plusplus.arguments.path ? _.castArray(extensions.plusplus.arguments.path) : []; this.compiledPaths = _.map(this.path, (path) => parseExpression(path)); this.value = extensions.plusplus.arguments.value; this.compiledValue = parseExpression(this.value); } } TransitionPlusPlus.registerType('write-global', GlobalWriteTransitionPlusPlus); class GlobalUpdateTransitionPlusPlus extends TransitionPlusPlus { public readonly variable: string; private readonly compiledVariable: Expression; public readonly path: string[]; private readonly compiledPaths: Expression[]; public readonly target: string | null; private readonly compiledTarget: Pattern | null; public readonly update: string; private readonly compiledUpdate: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.variable = extensions.plusplus.arguments.variable; this.compiledVariable = parseExpression(this.variable); this.path = extensions.plusplus.arguments.path ? _.castArray(extensions.plusplus.arguments.path) : []; this.compiledPaths = _.map(this.path, (path) => parseExpression(path)); this.target = extensions.plusplus.arguments.target; this.compiledTarget = this.target ? parsePattern(this.target) : null; this.update = extensions.plusplus.arguments.update; this.compiledUpdate = parseExpression(this.update); } } TransitionPlusPlus.registerType('update-global', GlobalUpdateTransitionPlusPlus); class MutexInitTransitionPlusPlus extends TransitionPlusPlus { public readonly mutex: string; private readonly compiledMutex: Pattern; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.mutex = extensions.plusplus.arguments; this.compiledMutex = parsePattern(this.mutex); } } TransitionPlusPlus.registerType('init-mutex', MutexInitTransitionPlusPlus); class MutexLockTransitionPlusPlus extends TransitionPlusPlus { public readonly mutex: string; private readonly compiledMutex: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.mutex = extensions.plusplus.arguments; this.compiledMutex = parseExpression(this.mutex); } } TransitionPlusPlus.registerType('lock-mutex', MutexLockTransitionPlusPlus); class MutexUnlockTransitionPlusPlus extends TransitionPlusPlus { public readonly mutex: string; private readonly compiledMutex: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.mutex = extensions.plusplus.arguments; this.compiledMutex = parseExpression(this.mutex); } } TransitionPlusPlus.registerType('unlock-mutex', MutexUnlockTransitionPlusPlus); class ConditionInitTransitionPlusPlus extends TransitionPlusPlus { public readonly condition: string; private readonly compiledCondition: Pattern; public readonly mutex: string; private readonly compiledMutex: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.condition = extensions.plusplus.arguments.condition; this.compiledCondition = parsePattern(this.condition); this.mutex = extensions.plusplus.arguments.mutex; this.compiledMutex = parseExpression(this.mutex); } } TransitionPlusPlus.registerType('init-condition', ConditionInitTransitionPlusPlus); class ConditionAwaitTransitionPlusPlus extends TransitionPlusPlus { public readonly condition: string; private readonly compiledCondition: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.condition = extensions.plusplus.arguments; this.compiledCondition = parseExpression(this.condition); } } TransitionPlusPlus.registerType('await-condition', ConditionAwaitTransitionPlusPlus); class ConditionSignalTransitionPlusPlus extends TransitionPlusPlus { public readonly condition: string; private readonly compiledCondition: Expression; public readonly signalAll: string; private readonly compiledSignalAll: Expression; constructor(key: string, displayName: string, guard: string | null, inFlows: InFlowIntermediate[], outFlows: OutFlowIntermediate[], extensions: TransitionExtensions) { super(key, displayName, guard, inFlows, outFlows, extensions); this.condition = extensions.plusplus.arguments.condition; this.compiledCondition = parseExpression(this.condition); this.signalAll = extensions.plusplus.arguments.signalAll; this.compiledSignalAll = parseExpression(this.signalAll); } } TransitionPlusPlus.registerType('signal-condition', ConditionSignalTransitionPlusPlus); Transition.registerTransitionType('plusplus', TransitionPlusPlus); export { TransitionPlusPlus, PrintLnTransitionPlusPlus, CallTransitionPlusPlus, ReturnTransitionPlusPlus, StartAgentTransitionPlusPlus, JoinTransitionPlusPlus, InitChanTransitionPlusPlus, SendTransitionPlusPlus, ReceiveTransitionPlusPlus, DefaultTransitionPlusPlus, GlobalReadTransitionPlusPlus, GlobalWriteTransitionPlusPlus, GlobalUpdateTransitionPlusPlus, MutexInitTransitionPlusPlus, MutexLockTransitionPlusPlus, MutexUnlockTransitionPlusPlus, ConditionInitTransitionPlusPlus, ConditionAwaitTransitionPlusPlus, ConditionSignalTransitionPlusPlus };