// Copyright (c) 2010 Guillaume Lathoud
// MIT License
//
// tailcatch.js
// 
// Implement full tail-call optimization in Javascript through
// a throw/catch trampoline.
//
// Heavily inspired from Sjoed Visscher's work:
// http://w3future.com/weblog/2006/02/#tailCallEliminationInJavascript
// 
// Difference: I brought some speed improvements:
// - removed the caller search for self.
// - reduced the length of the throw/catch chain from n to 1.

/*jslint evil:false */

function tailcatch(g) {
    return (function (n) {

        return function()
        {
            if (n>5) {  // Jump off a small Empire State Building
                throw {tailCallArgs: arguments, tailCallThis: this};
            }
            
            var args = arguments;
            var me   = this;
            var ret;
            while (true)
            {
                if (n<1) {
                    try
                    {
                        n++;
                        ret = g.apply(me, args);
                        n--;
                        return ret;
                    }
                    catch(e) // Hit 33rd Street and bounce again
                    {
                        if (!e.tailCallArgs) {
                            throw e;
                        }
                        n=0;
                        args = e.tailCallArgs;
                        me   = e.tailCallThis;
                    }
                } else {
                    n++;
                    ret = g.apply(me, args);
                    n--;
                    return ret;
                    
                }
            }
        };

    })(0);
}

