Subscribe to
Posts
Comments

I like finite state machines and I wanted to try metaprogramming in JavaScript ever since I’d seen Adam McCrea presentation on the topic.

The result is an FSM builder in JavaScript. Machine descriptions look like my test machine here:

var Machine = FSM.build(function(fsm) { with (fsm) {
  onUnexpectedEvent(function() { ... });

  state('start', 'initial')
    .event('go')
      .goesTo('middle')
      .doing(function() { ... })
      .doing('phew')
    .event('run')
      .goesTo('finish')
    .onExiting(function() { ... });

  state('middle')
    .onUnexpectedEvent(function() { ... })
    .onEntering(function() { ... })
    .event('back')
      .goesTo('start')
      .onlyIf(function() { return true_or_false })
    .event('go')
      .goesTo('finish');

  state('finish', 'final');
}});

function TestMachine() {}
// amend TestMachine.prototype here all the way you want
TestMachine.prototype.phew = function() { ... };
TestMachine.prototype = new Machine(TestMachine.prototype);

There’s no documentation yet, but thorough unit testsspecs
using Nicolás Sanguinetti’s very nice js-spec framework.

Something to look at:

The script is meant to be usable independently of and play nicely with any other libraries.

The manner in which an FSM is attached to classes/objects is still rather convoluted. The general idea is that it (a) should be possible to insert the FSM as the first link in the prototype chain and (b) should be possible to directly attach it to an existing object. I’d appreciate suggestions how to make this nice and shiny.

5 Responses to “Finite State Machines in JavaScript”

  1. on 23 Dec 2007 at 01:23Nicolás Sanguinetti

    Good stuff! :) I’ll see what I can do for the specs so they look a bit nicer, as the results are pretty rough right now :P

    Regarding the code used to initialize a FSM, most of it is repetitive, so you could extract it into a static method of FSM. And for the declaration of events and states in your machine, you could “yield” the machine description object to a “block”:

    var Machine = FSM.build(function(m) {
    m.onUnexpectedEvent(…);
    m.state(‘start’, …);

    });

    Thing.prototype = new Machine(Thing.prototype);

    Then, the FSM.build function would look something like this:

    FSM.build = function(block) {
    var fsm = new FSM;
    block(fsm);
    return fsm.buildMachine();
    }

    (And you can still use with(m) in the “block” if calling methods explicitly bothers you :))

  2. on 23 Dec 2007 at 11:02michael

    Nicolás, thanks for the suggestion. I’ve updated the script accordingly.

  3. [...] I’m going to leave the discussion of what constitutes metaprogramming to another day (read: never), but what I will say is that I’m becoming more interested in DSLs and fluent interfaces. I want the code I write to work at a very high level, where it describes what I’m trying to achieve in terms that anyone else (read: me, six months later) can understand. I particularly like this example of a JavaScript DSL for describing state machines: [...]

  4. on 01 Jan 2014 at 03:04Kevin Prichard

    How does a state machine of this type handle complex events?

    Events that are triggered as the result of, say, the accumulation of multiple events or signals. Say there are five events that each need to be received before the FSM sends a sixth event.

    Do these JS FSMs provide direct support for that sort of thing, or do I have to piece it together with bit fields and a guard expression?

    Cheers,
    Kevin Prichard

  5. on 01 Jan 2014 at 11:05michael

    Kevin, I’m not sure we are on the same page regarding how an FSM is supposed to work. In your example, you’d have to create a specific state the machine is in after receiving each of the events. That’s no problem if these events are supposed to occur in a given order. If they can occur in any order this won’t work well; in that case, you are better of with bit fields and a guard.

Leave a Reply

Fork me on GitHub