Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 62 lines (62 sloc) 20.448 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
<!DOCTYPE html> <html> <head> <title>reentrant-exceptions.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> <script type="text/javascript"> if (window.location.hostname != '6a68.net') { return; } var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-32602307-1']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); </script> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="code-equals-data-equals-code.html"> code-equals-data-equals-code.js </a> <a class="source" href="fontbomb.html"> fontbomb.js </a> <a class="source" href="frontend-architecture-patterns.html"> frontend-architecture-patterns.js </a> <a class="source" href="functional-programming.html"> functional-programming.js </a> <a class="source" href="index.html"> index.js </a> <a class="source" href="interview-problems-dependency-manager.html"> interview-problems-dependency-manager.js </a> <a class="source" href="js-flow-control.html"> js-flow-control.js </a> <a class="source" href="meebo-jquery.html"> meebo-jquery.js </a> <a class="source" href="reentrant-exceptions.html"> reentrant-exceptions.js </a> <a class="source" href="rsvp.html"> rsvp.js </a> <a class="source" href="theres-a-bluebird-in-my-heart.html"> theres-a-bluebird-in-my-heart.js </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <h2>Reentrant exceptions in JavaScript</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <ol>
<li>control the call stack using thunks/trampolines.
<ul><li>refer reader to nathansuniversity for great overview.</li></ul></li>
<li>given thunks with dual exception and regular program flow,
update trampoline code to switch between contexts.</li>
<li>given re-entrant exceptions, we can test-drive code and handle missing methods:
<ul><li>write a failing test for an undefined method</li>
<li>give the user a prompt to handle the undefined method or break</li>
<li>after the user creates the undefined method, resume</li>
<li>test passes</li></ul></li>
</ol> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>let's start with a basic thunk and trampoline implementation.
we'll just use what's provided by nathansuniversity.</p> </td> <td class="code"> <div class="highlight"><pre><span class="cm">/* thunks are of the form</span>
<span class="cm"> { tag: &#39;value&#39;, val: value }</span>
<span class="cm"> or</span>
<span class="cm"> { tag: &#39;thunk&#39;, func: f, args: arguments }</span>
<span class="cm">*/</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>so, given a thunk t,</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">trampoline</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>dangerously assume t.tag is always defined and either 'value' or 'thunk'</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>if it's a value, return the value. this is the base case of the recursion.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">tag</span> <span class="o">==</span> <span class="s1">&#39;value&#39;</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nx">t</span><span class="p">.</span><span class="nx">val</span><span class="p">;</span>
        <span class="p">}</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>otherwise, it's a thunk. so, recurse.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">tag</span> <span class="o">==</span> <span class="s1">&#39;thunk&#39;</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">t</span> <span class="o">=</span> <span class="nx">t</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">args</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>but I want re-entrant exceptions. that means the trampoline must persist
the values of stack frames after they are executed, and each thunk must
include the 'success callback' and the 'error callback'.</p> </td> <td class="code"> <div class="highlight"><pre><span class="cm">/* thunks, revised:</span>
<span class="cm"> { tag: &#39;value&#39;, val: value }</span>
<span class="cm"> or </span>
<span class="cm"> { tag: &#39;thunk&#39;, func: f, args: arguments, err_func: f, err_args: arguments }</span>
<span class="cm">*/</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>so, for starters, let's just hang on to the last thunk.
I suppose we could try to go more than one step back through the stack
using something like "arguments.callee.caller.caller". but anyway.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">prev_thunk</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">supr_tramp</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="p">{</span>
    <span class="cm">/* still assumes t.tag == &#39;thunk&#39; || &#39;value&#39; */</span>
    <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>if you've hit a value, return it.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">tag</span> <span class="o">==</span> <span class="s1">&#39;value&#39;</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">t</span><span class="p">.</span><span class="nx">val</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>else, if you hit a thunk,</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">tag</span> <span class="o">==</span> <span class="s1">&#39;thunk&#39;</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>record the thunk in order to backtrack.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">prev_thunk</span> <span class="o">=</span> <span class="nx">t</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>try to call the function.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">try</span> <span class="p">{</span>
                <span class="nx">t</span> <span class="o">=</span> <span class="nx">t</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">args</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>if something goes wrong, </p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">ex</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>call the error callback.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">t</span> <span class="o">=</span> <span class="nx">t</span><span class="p">.</span><span class="nx">err_func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">err_args</span><span class="p">)</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>this isn't perfect. it seems like you should probably pass the exception
into the error callback, and you also need a way to switch back to the
mainline of execution: t.func --> t.err_func --> t.func again</p> </td> <td class="code"> <div class="highlight"><pre><span class="cm">/* thunks, revised again:</span>
<span class="cm"> { tag: &#39;value&#39;, val: value }</span>
<span class="cm"> or </span>
<span class="cm"> { tag: &#39;thunk&#39;, func: f, args: arguments, err_func: f }</span>
<span class="cm">*/</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>let's say, if the exception type is 'resume', we'll resume the
previous thunk. that means that you can have your exception handler
code throw an exception of its own in order to get back to the
original flow.</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">supr_supr_tramp</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">tag</span> <span class="o">==</span> <span class="s1">&#39;value&#39;</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">t</span><span class="p">.</span><span class="nx">val</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">tag</span> <span class="o">==</span> <span class="s1">&#39;thunk&#39;</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">prev_thunk</span> <span class="o">=</span> <span class="nx">t</span><span class="p">;</span>
            <span class="k">try</span> <span class="p">{</span>
                <span class="nx">t</span> <span class="o">=</span> <span class="nx">t</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">args</span><span class="p">)</span>
            <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">ex</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>if the exception's type is 'resume', backtrack.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">ex</span><span class="p">.</span><span class="nx">type</span> <span class="o">!==</span> <span class="s1">&#39;undefined&#39;</span> <span class="o">&amp;&amp;</span> <span class="nx">ex</span><span class="p">.</span><span class="nx">type</span> <span class="o">==</span> <span class="s1">&#39;resume&#39;</span><span class="p">)</span> <span class="p">{</span>
                    <span class="nx">t</span> <span class="o">=</span> <span class="nx">prev_thunk</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">prev_thunk</span><span class="p">.</span><span class="nx">args</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>otherwise, something really did go wrong</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                    <span class="nx">t</span> <span class="o">=</span> <span class="nx">t</span><span class="p">.</span><span class="nx">err_func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">err_args</span><span class="p">)</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>I really think this should work, but I ought to write some code with it.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>what's up next?
maybe TDD a little object to see this in action.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
Something went wrong with that request. Please try again.