UNPKG

@lf-lang/reactor-ts

Version:

A reactor-oriented programming framework in TypeScript

174 lines 6.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Mutation = exports.Procedure = exports.Reaction = void 0; const internal_1 = require("./internal"); /** * Generic base class for reactions. The type parameter `T` denotes the type of * the argument list of the `react` function that that is applied to when this * reaction gets triggered. * * @author Marten Lohstroh <marten@berkeley.edu> */ class Reaction { reactor; sandbox; trigs; args; react; deadline; late; /** * Priority derived from this reaction's location in the dependency graph * that spans the entire hierarchy of components inside the top-level reactor * that this reaction is also embedded in. */ priority = 0; // Number.MAX_SAFE_INTEGER; /** * Pointer to the next reaction, used by the runtime when this reaction is staged * for execution at the current logical time. */ next; /** * Construct a new reaction by passing in a reference to the reactor that * will own it, an object to execute the its `react` and `late` functions * on, a list of triggers, the arguments to pass into `react` and `late`, * an implementation of this reaction's `react` function, an optional * deadline to be observed, and an optional custom implementation of the * `late` function that is invoked when logical time lags behind physical time * with a margin that exceeds the time interval denoted by the deadline. * @param reactor The owner of this reaction. * @param sandbox The `this` object for `react` and `late`. * @param trigs The ports, actions, or timers, which, when they receive * values, will trigger this reaction. * @param args The arguments to be passed to `react` and `late`. * @param react Function that gets execute when triggered and "on time." * @param deadline The maximum amount by which logical time may lag behind * physical time when `react` has been triggered and is ready to execute. * @param late Function that gets execute when triggered and "late." */ constructor(reactor, sandbox, trigs, args, react, deadline, late = () => { internal_1.Log.globalLogger.warn("Deadline violation occurred!"); }) { this.reactor = reactor; this.sandbox = sandbox; this.trigs = trigs; this.args = args; this.react = react; this.deadline = deadline; this.late = late; } /** * Indicates whether or not this reaction is active. A reaction become * active when its container starts up, inactive when its container * shuts down. */ active = false; /** * Return true if this reaction is triggered immediately (by startup or a * timer with zero offset). */ isTriggeredImmediately() { return (this.trigs.filter((trig) => trig instanceof internal_1.Startup || (trig instanceof internal_1.Timer && trig.offset.isZero())).length > 0); } /** * Return the priority of this reaction. It determines the execution order among * reactions staged for execution at the same logical time. */ getPriority() { return this.priority; } /** * Return whether or not this reaction has priority over another. * @param another Reaction to compare this reaction's priority against. */ hasPriorityOver(another) { if (another != null && this.getPriority() < another.getPriority()) { return true; } else { return false; } } /** * Return whether another, newly staged reaction is equal to this one. * Because reactions are just object references, no updating is necessary. * Returning true just signals that the scheduler shouldn't stage it twice. * @param node */ updateIfDuplicateOf(node) { return Object.is(this, node); } /** * Invoke the react function in the appropriate sandbox and with the argument * list that was specified upon the construction of this reaction object. */ doReact() { internal_1.Log.debug(this, () => ">>> Reacting >>> " + this.constructor.name + " >>> " + this.toString()); internal_1.Log.debug(this, () => `Reaction deadline: ${this.deadline}`); // If this reaction was loaded onto the reaction queue but the trigger(s) // absorbed by a mutation that routed the value(s) elsewhere, then return // without invoking the reaction. if (!this.active) { return; } // Test if this reaction has a deadline which has been violated. // This is the case if the reaction has a defined timeout and // logical time + timeout < physical time if (this.deadline != null && this.sandbox.util .getCurrentTag() .getLaterTag(this.deadline) .isSmallerThan(new internal_1.Tag(this.sandbox.util.getCurrentPhysicalTime(), 0))) { this.late.apply(this.sandbox, this.args); // late } else { this.react.apply(this.sandbox, this.args); // on time } } /** * Set a deadline for this reaction. The given time value denotes the maximum * allowable amount by which logical time may lag behind physical time at the * point that this reaction is ready to execute. If this maximum lag is * exceeded, the `late` function is executed instead of the `react` function. * @param deadline The deadline to set to this reaction. */ setDeadline(deadline) { this.deadline = deadline; return this; } /** * Set for reaction priority, to be used only by the runtime environment. * The priority of each reaction is determined on the basis of its * dependencies on other reactions. * @param priority The priority for this reaction. */ setPriority(priority) { this.priority = priority; } /** * Return string representation of the reaction. */ toString() { return `${this.reactor._getFullyQualifiedName()}[R${this.reactor._getReactionIndex(this)}]`; } } exports.Reaction = Reaction; class Procedure extends Reaction { } exports.Procedure = Procedure; class Mutation extends Reaction { parent; constructor(__parent__, sandbox, trigs, args, react, deadline, late) { super(__parent__, sandbox, trigs, args, react, deadline, late); this.parent = __parent__; } /** * @override */ toString() { return `${this.parent._getFullyQualifiedName()}[M${this.parent._getReactionIndex(this)}]`; } } exports.Mutation = Mutation; //# sourceMappingURL=reaction.js.map