/** * @author Martin Karkowski * @email m.karkowski@zema.de * @create date 2020-02-20 19:46:19 * @modify date 2020-03-09 16:55:12 * @desc [description] */ import * as handlebars from "handlebars"; import { ILogicNetwork } from "../../ZISS-Network/type/ILogicNetwork"; import { IArcExpression } from '../../ZISS-Petri-Net/types/IArcAnnotation'; import { IJsonSchema } from '../../ZISS-TypeScript-Library/src/JSON'; import { deepClone, rsetattr } from "../../ZISS-TypeScript-Library/src/Object-Methods"; import { replaceAll } from "../../ZISS-TypeScript-Library/src/String-Methods"; import { IParseableTransitionDescription, IParsedLogic } from "../types/interface"; import { AbstractParser } from "./default.parser"; export class JsParser extends AbstractParser { public variableDefinition(context: IParsedLogic): string { throw new Error("Method not implemented."); } /** * Function which will generate Parameters for the desired Function * @param task The Taskobject. */ protected _generateParameters(task: IParseableTransitionDescription) { // Only Adapt a Copy let ret = deepClone(task.params); const pair = new Map(); // Adapt the Parameters. for (const updateDefinition of task.dynamicParams) { pair.set(updateDefinition.usedVariable, '"' + updateDefinition.usedVariable + '"'); rsetattr( ret, updateDefinition.parameterPointer, updateDefinition.usedVariable ); } let obj = JSON.stringify(ret, undefined, 4); // Create The Text which will be used for the Parameters for (const [key, value] of pair.entries()) { replaceAll(obj, value, key); } return obj; } // Array, containing all Elements which should be replaced. protected _replace: { regex: RegExp; replacer: string; }[] = [ { regex: /(?<=[ \]\)])or(?=[ \[\(])/g, replacer: "||" }, { regex: /(?<=[ \]\)])and(?=[ \[\(])/g, replacer: "&&" }, { regex: /(?<=[ \]\)])sin(?=[ \[\(])/g, replacer: "Math.sin" }, { regex: /(?<=[ \]\)])cos(?=[ \[\(])/g, replacer: "Math.cos" }, { // (?<=[ \]\)]) regex: /not(?=[ \[\(])/g, replacer: "!" }, { regex: /(?<=[ \]\)])\|(?=[ \[\(])/g, replacer: "||" }, { regex: /(?<=[ \]\)])\&(?=[ \[\(])/g, replacer: "&&" } ]; /** * Function, which will be used to adapt the Path. * @param value */ protected _adaptGuard(guard: string, simplifiedGuard: string, OriginalScope: { [index: string]: { source: string; schema: IJsonSchema; }; }, simplifiedScope: { [index: string]: { source: string; schema: IJsonSchema; }; }, mappingOriginalToSimplified: Map, mappingSimplifiedToOriginal: Map, mappingSimplifiedToAdapted: Map, mappingAdaptedToSimplified: Map, mappingVariableToRoot: Map) { let adaptedGuard = simplifiedGuard; // Firstly get rid off the Elements (Chars, ot replace in the Equation) for (const data of this._replace) { adaptedGuard = adaptedGuard.replace(data.regex, data.replacer); } // Adapt the used Names for (const [simple, adapted] of mappingSimplifiedToAdapted) { adaptedGuard = replaceAll(adaptedGuard, simple, adapted); } return adaptedGuard; } /** * Function, which will be used to adapt a Variable Name. * @param value The original Variable Name */ protected _adaptVariableName( variable: string, simplifiedName: string, path: string ) { return "vars['" + simplifiedName + "']"; } /** * Function, which will be used to generate Function Code. * @param taskData */ protected _getFunctionTriggerCode(_taskData: IParseableTransitionDescription) { const taskData = deepClone(_taskData); taskData.params = this._generateParameters(taskData); const updateTaskResult = `` + ` _memoryInterface.set('{{id}}.function.output', { done: false, error: false, result: null, errorObject: null }); _broker.performTask('{{functionName}}', {{{params}}}, '{{id}}', 'async', (error, parameters, result) => { _memoryInterface.set('{{id}}.function.output', { result: result, done: error ? false : true, error: error ? true : false, errorObject: error }); }); `; const render = handlebars.compile(updateTaskResult); return render(taskData); } protected _convertInput(definition: { // Amount of Tokens that will be consumed (Result must be greater the minTokens) consumed: IArcExpression; placeId: string; type: | "expression" | "inhibitor" | "multiexpression" | "test" | "value" | "variable"; minTokens: number; }) { return { placeId: definition.placeId, minTokens: definition.minTokens, tokensToRemove: 1, } } protected _convertOutput(definition: { // Amount of Tokens that will be produced produced: IArcExpression; placeId: string; type: | "expression" | "inhibitor" | "multiexpression" | "test" | "value" | "variable"; maxTokens: number; }): { // Amount of Tokens that will be produced placeId: string; maxTokens: number; tokensToAdd: number; } { return { placeId: definition.placeId, maxTokens: definition.maxTokens, tokensToAdd: 1, } } protected _templates: { [index: string]: string; } = { ifHeaderTemplate: `{{#unless isFirst}}else {{/unless}}if ({{> testPrePlaces}}{{> testPostPlaces}}{{> testGuard}}) {`, testPrePlaces: `{{#each inputs}} ((tokens['{{placeId}}']{{#if minTokens}} - {{minTokens}}{{/if}}) >= {{tokensToRemove}}) &&{{/each}}`, testPostPlaces: `{{#each testOutputs}} ((tokens['{{placeId}}'] + {{tokensToAdd}}) <= {{maxTokens}}) &&{{/each}}`, testGuard: ` {{{ externalGuard }}}`, removeTokens: `{{#each inputs}}tokens['{{placeId}}'] -= {{tokensToRemove}};{{/each}}`, addTokens: `{{#each outputs}}tokens['{{placeId}}'] += {{tokensToAdd}};{{/each}}`, mainTemplate: `` + ` import { ZISSLogger, DEFAULT_LOGGER } from '../modules/ZISS-Logger/src/Unique.Logger'; const _logger = ZISSLogger.logger.getLogger(); /** Add Console Logger. */ ZISSLogger.logger.addStream(DEFAULT_LOGGER); _logger.info('started'); import 'reflect-metadata'; import * as BROKERFILEBASE from '../modules/ZISS-Broker/assembly/manual-assembly'; import * as BROKER from '../modules/ZISS-Broker/assembly/manual-assembly'; import * as MEMORYINTERFACE from '../modules/ZISS-Memory-Interface/assembly/manual-assembly'; import * as PUBSUB from '../modules/ZISS-Publish-And-Subscribe-System/assembly/manual-assembly'; import { Builder } from '../modules/ZISS-Assembly-Builder/src/Container-Builder.FileLoader'; import { ArgumentParser } from 'argparse'; const parser = new ArgumentParser({ version: '1.0.0', addHelp: true, description: 'Main Starter For the Kernel Tool' }); parser.addArgument( ['-l', '--level'], { help: 'The Loglevel. Defaults to Debug', defaultValue: 'info', choices: ['debug', 'error', 'fatal', 'info', 'trace', 'warn'], dest: 'level', } ); const args = parser.parseArgs(); ZISSLogger.logger.level = args.level; Builder.load(); Builder.on('loaded', () => { const _loader = Builder.instance.container.get(BROKERFILEBASE.TYPES.BrokerFilebased); const _broker = Builder.instance.container.get(BROKER.TYPES.Broker); const _memoryInterface = Builder.instance.container.get(MEMORYINTERFACE.TYPES.Storage); const _pubSub = Builder.instance.container.get(PUBSUB.TYPES.PubSubSystem); const vars: {[index:string]:any} = { 'true':true }; const tokens: {[index:string]:number} = { {{#each places}} '{{id}}' : {{tokens.length}}, {{/each}} }; function mainLoop(){ let checkTransitions = true; // Main Loop, which will iterate, until no action is left. while (checkTransitions) { checkTransitions = false; {{#each transitions}} // Test Transtion {{{label}}} {{> ifHeaderTemplate}} {{#if inputs}} // Removing Tokens from Pre-Places. {{> removeTokens}} {{/if}} {{#if outputs}} // Adding Tokens to the Post-Places. {{> addTokens}} {{/if}} {{#if functionName}} // Execute the desired Function {{#getFunctionCode this}}{{/getFunctionCode}} {{/if}} // Make shure the System Loops over again. checkTransitions = true; } {{/each}} } } // Define the Variables {{#each subscribedVariables}} Object.defineProperty(vars, '{{simplifiedName}}', { get: () => _memoryInterface.get('{{path}}'), set: (value) => _memoryInterface.set('{{path}}', value), enumerable: true }); _pubSub.createSubscription('{{path}}', (data) => { mainLoop(); }); {{/each}} {{#each variables}} {{#if hasValue}} _memoryInterface.set('{{path}}', {{data}}); {{/if}} {{/each}} const _func = async function () { try { await _loader.loadModules(); // Perform autostart await _loader.performAutostartConfig(); ZISSLogger.logger.level = args.level; ZISSLogger.logger.setLoglevel('delimiter', 'info'); ZISSLogger.logger.setLoglevel('logic.functions', 'info'); // Start the Task mainLoop(); } catch (e) { _logger.error(e, 'Error during Loading the Content'); } }; _func(); }); ` }; /** * Function, which will generate the MainLoop. * @param network */ mainLoop(network: ILogicNetwork): string { // Reference to the Own Object. const _this = this; handlebars.registerHelper("getFunctionCode", (taskData) => _this._getFunctionTriggerCode(taskData) ); this.linkTemplates(); const render = handlebars.compile(this._templates.mainTemplate); return render(this.getParseableLogic(network)) } instanceCreation(context: IParsedLogic): string { throw new Error("Method not implemented."); } }