Turing machine - JavaScript implementation

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Turing machine - JavaScript implementation</title>
    <style>
        body { font-family: monospace; white-space: pre; }
    </style>
    <script src="tm.js"></script>
    <script>
        window.onload = function () {
            // this simple machine prints "Hello" and stops
            var instance = new Machine({
                        // a finite, non-empty set of states
                        states : [0, 1, 2, 3, 5],
                        // a finite, non-empty set of the tape alphabet/symbols
                        alphabet : ['_', 'H', 'e', 'l', 'o'],
                        // the blank symbol (the only symbol allowed to occur on the
                        // tape infinitely often at any step during the computation)
                        blank : '_',
                        // the set of input symbols
                        input : 'abcdef',
                        // the initial state
                        initial : 0,
                        // the set of final or accepting states
                        finals : [5],
                        // transition function
                        transitions : new Transitions([
                            { criteria : { state : 0, symbol : '_' },
                                action : { state : 1, symbol : 'H', move : 'right' } },
                            { criteria : { state : 1, symbol : '_' },
                                action : { state : 2, symbol : 'e', move : 'right' } },
                            { criteria : { state : 2, symbol : '_' },
                                action : { state : 3, symbol : 'l', move : 'right' } },
                            { criteria : { state : 3, symbol : '_' },
                                action : { state : 4, symbol : 'l', move : 'right' } },
                            { criteria : { state : 4, symbol : '_' },
                                action : { state : 5, symbol : 'o', move : 'right' } }
                        ])
                    },
                    { length : 100, position: 50, interval: 300 }
                ),
                body = document.getElementsByTagName('body')[0];

            instance.starting = instance.stepping = function (head, register, tape) {
                body.innerText = [ tape.join(''), 'register: ' + register,
                    'head: ' + head, 'working' ].join('\n');
            };

            instance.stopping = function (head, register, tape) {
                body.innerText = [ tape.join(''), 'register: ' + register,
                    'head: ' + head, 'stopped'].join('\n');
            };

            instance.run();
        };
    </script>
</head>
<body><body>
</html>

tm.js

/**
 * Turing machine - JavaScript implementation
 * Based on http://en.wikipedia.org/wiki/Turing_machine
 * (C) 2012, Alex Netkachov. Public domain.
 */

/**
 * A finite table (occasionally called an action table or transition 
 * function) of instructions.
 */
function Transitions(transitions) {
    var actions = transitions.reduce(function (actions, transition) {
        var criteria = transition.criteria;
        if (undefined === actions[criteria.state]) {
            actions[criteria.state] = {};
        }
        actions[criteria.state][criteria.symbol] = transition.action;
        return actions;
    }, {});
    return {
        action : function (state, symbol) {
            var symbols = actions[state], action;
            if (undefined === symbols) {
                throw new Error('Transition table does not contain' +
                    ' entry for the ' + state + ' state');
            }
            action = symbols[symbol];
            if (undefined === action) {
                throw new Error('Transition table does not contain' +
                    ' entry for the ' + state + ' state and the' +
                    ' ' + symbol + ' symbol');
            }
            return action;
        }
    };
}

/**
 * Turing machine
 */
function Machine(definition, options) {
    var tape = new Array(options.length),
        head = options.position,
        register = definition.initial,
        read = function () { return tape[head]; },
        write = function (value) { return tape[head] = value; },
        move = function (direction) {
            switch (direction) {
            case 'left':
                head -= 1;
                break;
            case 'right':
                head += 1;
                break;
            default:
                throw new Error('Unsupported move');
            }
        };

    (function () {
        var index = 0; limit = tape.length;
        for (; index < limit; index += 1) {
            tape[index] = definition.blank;
        }
    }());

    return {
        // actions
        writing : function (head, value) { },
        moving : function (head, direction) { },
        stepping : function (head, register, tape) { },
        starting : function (head, register, tape) { },
        stopping : function (head, register, tape) { },
        // performs action
        step : function () {
            var action = definition.transitions.action(register, read());
            this.stepping(head, register, tape);
            register = action.state;
            write(action.symbol);
            move(action.move);
            if (-1 !== definition.finals.indexOf(register)) {
                this.stopping(head, register, tape)
                return false;
            }
            return true;
        },
        // runs machine till its final state or error
        run : function () {
            this.starting(head, register, tape);
            var interval = setInterval(function () {
                if (!this.step()) {
                    clearInterval(interval);
                }
            }.bind(this), options.interval);
        }
    };
}