<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE TIP SYSTEM "http://www.tcl.tk/cgi-bin/tct/tip/tipxml.dtd">
<!-- Converted at Fri May 24 23:00:37 GMT 2013 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='348'>
<header><title>Substituted &apos;errorstack&apos; / &apos;traceback&apos;</title><author address="mailto:alexandre.ferrieux@gmail.com">Alexandre Ferrieux</author><status type='project' state='final' tclversion="8.6" vote='after'>$Revision: 1.17 $</status><history></history><created day='26' month='feb' year='2009' /><keyword>Tcl debugging</keyword></header>
<abstract>This TIP proposes to add an <emph style="bold">errorstack</emph> options dict entry and associated <emph style="bold">info</emph> subcommand, giving a &quot;substituted&quot; traceback similar to Python&apos;s or gdb&apos;s ones.</abstract>
<body><section title="Background">
<para>The <emph style="bold">::errorInfo</emph> variable is a valuable tool for debugging; however, it yields mostly static information regarding each level of procedure call, as it only gives the static text (extracted from the source) at the call site. This leads to frustrating situations, like when an error occurs at a deep level of a recursive function, <emph style="bold">::errorInfo</emph> repeatedly reporting &quot;f $x [foo [bar]]&quot; or similar un-substituted commands. In other languages, the traceback is more useful in that it contains the actual values passed as arguments.</para>
</section>
<section title="Proposed Change">
<para>This TIP proposes to create an <emph style="bold">-errorstack</emph> options dictionary entry, and an associated <emph style="bold">info errorstack</emph> ?<emph style="italic">interp</emph>? command returning a list containing the [<emph style="bold">info level</emph> 0] lists of command-and-args at each stack frame level at the time of error unwinding.</para>
</section>
<section title="Rationale">
<para>In a natural implementation, its construction is analogous to that of <emph style="bold">::errorInfo</emph>, which is built incrementally, one level at a time while popping back from the error site. The only differences are that:</para>
<enumerate><item.e index='1'><para>dynamic arglists (from [<emph style="bold">info level</emph> 0]) are stored,</para></item.e><item.e index='2'><para>the result is a true list built by (the equivalent of) <emph style="bold">lappend</emph>, and</para></item.e><item.e index='3'><para>the granularity is coarser than with <emph style="bold">::errorInfo</emph> since there is just one element per stack frame level (and not for intervening <emph style="bold">while</emph> or <emph style="bold">foreach</emph> constructs) and no adornment like &quot;... while executing ...&quot;</para></item.e></enumerate>
<para>Measurements show that the performance hit of maintaining the error stack is small, being under 5% for realistic error stack sizes, and hits only the error cases. To achieve this speed, the list-growing is done carefully, reusing earlier optimizations made on list operations for the in-place case, so that in routine use the allocated Tcl_Obj, internal representation, and element array storage backing the list never change. This way, even code heavily relying on <emph style="bold">catch</emph> across dozens of stack frame levels won&apos;t noticeably suffer from the error stack machinery.</para>
</section>
<section title="Definition">
<para>The error stack is an even-sized list alternating tokens and parameters. Tokens are currently either <emph style="bold">CALL</emph> or <emph style="bold">UP</emph>, but other values may be introduced in the future; <emph style="bold">CALL</emph> indicates a procedure call, and its parameter is the corresponding [<emph style="bold">info level</emph> 0]; <emph style="bold">UP</emph>&apos; indicates a shift in variable frames generated by <emph style="bold">uplevel</emph> or similar, and applies to the previous <emph style="bold">CALL</emph> item:</para>
<quote>CALL {foo a} UP 1 CALL {bar b} CALL {baz c} UP 2 CALL {gnu d} CALL {gnats e}</quote>
<para>The above value indicates that [foo a] was called by [bar b] through [uplevel 1]. Similarly, [baz c] was itself lifted to toplevel by an [uplevel 2] in [gnu d].</para>
</section>
<section title="Reference Implementation">
<para>The reference implementation can be found on SourceForge[<url ref="https://sourceforge.net/support/tracker.php?aid=2868499"/>].</para>
<para>An earlier, extremely slow, pure-Tcl proof of concept based on write traces on <emph style="bold">::errorInfo</emph> can be found on the Wiki[<url ref="http://wiki.tcl.tk/traceback"/>].</para>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain.</para>
</section>
</body></TIP>
