<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE TIP SYSTEM "http://www.tcl.tk/cgi-bin/tct/tip/tipxml.dtd">
<!-- Converted at Sun Feb 12 12:02:27 GMT 2012 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='280'>
<header><title>Add Full Stack Trace Capability With Location Introspection</title><author address="mailto:andreas_kupries@users.sourceforge.net">Andreas Kupries</author><author address="mailto:andreask@activestate.com">Andreas Kupries</author><status type='project' state='final' tclversion="8.5" vote='after'>$Revision: 1.13 $</status><history></history><created day='10' month='aug' year='2004' /><keyword>Tcl</keyword><obsoletes tip='211'/></header>
<abstract>This TIP proposes adding a new subcommand to the <emph style="bold">info</emph> command to get a list of all the frames on the current stack, with additional information about command location, type of execution, etc., rather than the limited list returned by <emph style="bold">info level</emph>. It is also related to Peter MacDonald&apos;s <tipref type="text" tip="86"/>, or rather, to the <emph style="bold">info linenum</emph> feature proposed there. The base feature of providing location information for a command was extended, allowing the user to ask for the current location in all stack levels. Enough information is returned to consider this as an extended <tipref type="text" tip="211"/>.</abstract>
<body><section title="Rationale">
<para>The motivation for this feature is the debugging of scripts in situations where an error stack is wanted, to see where the problem occurred, but aborting the execution is not desired. To enable this a means of providing the essential information shown in an error stack is needed, which does not require an abort (and subsequent unwinding of the C stack) to assemble this information.</para>
<para>An example is the testing of scripts where an unexpected error should not fail the test case, nor the framework, yet still allow the recording of the problematic location and how it was reached in some log.</para>
<para>The original motivation for <tipref type="text" tip="211"/> was that there is currently no way to get a list of all the frames in the current stack managed by <emph style="bold">Tcl_PushCallFrame()</emph> and <emph style="bold">Tcl_PopCallFrame()</emph>. The <emph style="bold">info level</emph> command does not contain frames that are callers of <emph style="bold">uplevel</emph>, reporting only the frames that are accessible via another <emph style="bold">uplevel</emph> command. There are times when the lack of information can have a negative impact on code design.</para>
<para>This motivation asks in essence for an error stack as well, but limited itself to the returning commands themselves, and not the other information, like the line the command is on, its context, etc.</para>
<para>Other use cases, also found in <tipref type="text" tip="211"/>:</para>
<enumerate><item.e index='1'><para><emph style="bold">tcltest</emph>, and other testing frameworks.</para><para>The first case is with the core&apos;s Tcltest package, where the complete lack of ability to gain access to that information means it is impossible to gain information about a test without modifying the Tcltest code itself. Being able to find out the caller info would be very useful, especially for logging information. Currently, there is no way to get the caller&apos;s info, due to the fact that the code for the test is <emph style="italic">uplevel</emph>ed and, hence, not visible via <emph style="bold">info level</emph>.</para></item.e><item.e index='2'><para><emph style="bold">TestStubs Package</emph></para><para>The TestStubs package provides the ability to temporarily redefine commands, in particular for stubbing out or replacing functionality in a test case. There is a command in the package called <emph style="bold">chain</emph>, which is used within the code replacing a command (or part of a command) to call the original definition of the command. For example, one could do:</para><verbatim><vline encoding='base64'>c3R1YnM6OnN0dWIgZW5zZW1ibGUgYXJyYXkgbmFtZXMgew==</vline><vline encoding='base64'>ICAgIHJldHVybiBbbHNvcnQgW3VwbGV2ZWwgMSBjaGFpbiBuYW1lcyAkYXJnc11d</vline><vline encoding='base64'>fQ==</vline></verbatim><para>However, since the <emph style="bold">chain</emph> command is (and should be) limited to only running from within a stub definition, it needs to call <emph style="bold">info level</emph> to find out if its caller is one of the stubbed commands, and what the name of that command is. With <emph style="bold">info level</emph>, it would not have access to the level that is running inside the stubbed procedure. Hence, either it cannot check this constraint, or stubs cannot be allowed to use <emph style="bold">uplevel</emph> when calling it (which means things like the above either cannot work, or need to be rewritten in a considerably less clear manner).</para></item.e></enumerate>
</section>
<section title="Specification of the Proposed Change">

<subsection title="Tcl Level API">
<para>The builtin command <emph style="bold">info</emph> is extended to accept a new subcommand, <emph style="bold">frame</emph>. When this subcommand is called it returns information about the current command and its location. This information is available not only for the current stack level, but also the higher stack levels used to reach the current location.</para>
<para>The syntax of the new subcommand is</para>
<quote><emph style="bold">info frame</emph> ?<emph style="italic">level</emph>?</quote>
<para>The new functionality will provide access to all frames on the stack rather than the current limited subset. This TIP does <emph style="italic">not</emph> propose to alter <emph style="bold">uplevel</emph> or <emph style="bold">upvar</emph> so that they can see these hidden levels.</para>
<para>If <emph style="italic">level</emph> is not specified, this command returns a number giving the frame level of the command. This is 1 if the command is invoked at top-level.</para>
<para>If <emph style="italic">level</emph> is specified, then the result is a dictionary containing the location information for the command at the <emph style="italic">level</emph> on the stack.</para>
<para>If <emph style="italic">level</emph> is positive (&gt; 0) then it selects a particular stack level (1 refers to the top-most active command, i.e., <emph style="bold">info frame</emph> itself, 2 to the command it was called from, and so on); otherwise it gives a level relative to the current command (0 refers to the current command, i.e., <emph style="bold">info frame</emph> itself, -1 to its caller, and so on).</para>
<para>This is similar to how <emph style="bold">info level</emph> works, except that this subcommand reports all frames, like <emph style="bold">source</emph>&apos;d scripts, <emph style="bold">eval</emph>s, <emph style="bold">uplevel</emph>s, etc.</para>
<para>Note that for nested commands, like &quot;foo [bar [x]]&quot; only &quot;x&quot; will be seen by an <emph style="bold">info frame</emph> invoked within &quot;x&quot;. This is the same as for <emph style="bold">info level</emph> and error stack traces.</para>
<para>The result dictionary may contain the keys listed below, with the specified meanings for their values.</para>
<itemize><item.i><para><emph style="bold">type</emph></para><para>This entry is always present and describes the nature of the location for the command. The recognized values are <emph style="bold">source</emph>, <emph style="bold">proc</emph>, <emph style="bold">eval</emph>, and <emph style="bold">precompiled</emph>.</para><para>In some circumstances it makes sense to have this information extensible, i.e. to allow user-defined type names. For more about this topic see the discussion at the end of the document.</para><itemize><item.i><para><emph style="bold">source</emph> means that the command is found in a script loaded by the <emph style="bold">source</emph> command.</para></item.i><item.i><para><emph style="bold">proc</emph> means that the command is found in dynamically created procedure body.</para></item.i><item.i><para><emph style="bold">eval</emph> means that the command is executed by <emph style="bold">eval</emph> or <emph style="bold">uplevel</emph>.</para></item.i><item.i><para><emph style="bold">precompiled</emph> means that the command is found in a precompiled script (loadable by the package <emph style="italic">tbcload</emph>), and no further information will be available.</para></item.i></itemize></item.i><item.i><para><emph style="bold">line</emph></para><para>This entry provides the number of the line the command is at inside of the script it is a part of. This information is not present for type <emph style="bold">precompiled</emph>. For type <emph style="bold">source</emph> this information is counted relative to the beginning of the file, whereas for the last two types the line is counted relative to the start of the script.</para></item.i><item.i><para><emph style="bold">file</emph></para><para>This entry is present only for type <emph style="bold">source</emph>. It provides the normalized path of the file the command is in.</para></item.i><item.i><para><emph style="bold">cmd</emph></para><para>This entry provides the string representation of the command. This is usually the unsubstituted form, however for commands which are a pure list executed by eval it is the substituted form as they have no other string representation. Care is taken that the pure-List property of the latter is not spoiled.</para></item.i><item.i><para><emph style="bold">proc</emph></para><para>This entry is present only if the command is found in the body of a regular Tcl procedure. It then provides the name of that procedure.</para></item.i><item.i><para><emph style="bold">lambda</emph></para><para>This entry is present only if the command is found in the body of an anonymous Tcl procedure, i.e. a lambda. It then provides the entire definition of the lambda in question.</para></item.i><item.i><para><emph style="bold">level</emph></para><para>This entry is present only if the queried frame has a corresponding frame returned by <emph style="bold">info level</emph>. It provides the index of this frame, relative to the current level (0 and negative numbers).</para></item.i></itemize>
<para>A thing of note is that for procedures statically defined in files the locations of commands in their bodies will be reported with type <emph style="bold">source</emph> and absolute line numbers, and not as type <emph style="bold">proc</emph>. The same is true for procedures nested in statically defined procedures, and literal eval scripts in files or statically defined procedures.</para>
<para>In contrast, for a procedure definition or eval within a dynamically eval&apos;uated environment count linenumbers relative to the start of their script, even if they would be able to count relative to the start of the outer dynamic script. That type of number usually makes more sense.</para>
<para>A different way of describing this behaviour is that we track file based locations as deeply as we can, and where we cannot the lines are counted based on the smallest possible eval or procbody scope, as that scope is usually easier to find than any dynamic outer scope.</para>
<para>The syntactic form <emph style="bold">{expand}</emph> is handled like <emph style="bold">eval</emph>. This means that if it is given a literal list argument the system tracks the line-number within the list words as well, and otherwise all line-numbers are counted relative to the start of each word (smallest scope)</para>
<para>The following other builtin commands are changed as well to support the tracking of line numbers:</para>
<enumerate><item.e index='1'><para>catch</para></item.e><item.e index='2'><para>dict for</para></item.e><item.e index='3'><para>dict with</para></item.e><item.e index='4'><para>eval</para></item.e><item.e index='5'><para>for</para></item.e><item.e index='6'><para>foreach</para></item.e><item.e index='7'><para>if</para></item.e><item.e index='8'><para>interp eval</para></item.e><item.e index='9'><para>namespace eval</para></item.e><item.e index='10'><para>proc</para></item.e><item.e index='11'><para>source</para></item.e><item.e index='12'><para>switch</para></item.e><item.e index='13'><para>while</para></item.e></enumerate>
</subsection>
<subsection title="Public C API">
<para>No changes are made to the public C API.</para>
</subsection>
</section>
<section title="Examples">
<para>Note that this is not a complete set of examples covering all possible cases. Let us assume that the file is named EX. The &quot;cmd&quot; is always the &quot;info frame ...&quot; command, and &quot;level&quot; is 0 too, always, in this situation. This is left out of the result dictionaries to keep them small.</para>
<verbatim><vline encoding='base64'>IHB1dHMgW2luZm8gZnJhbWUgMF0gICAgICAgICAgIDsjIDAxKiAtIG91dHB1dDoge2NtZCB7aW5mbyBmcmFtZSAwfSBsaW5lIDEgZmlsZSBFWCB0eXBlIHNvdXJjZX0=</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDAy</vline><vline encoding='base64'>IHByb2MgZm9vIHt9IHsgICAgICAgICAgICAgICAgIDsjIDAzICAvZm9vIHJlbWVtYmVycyAz</vline><vline encoding='base64'>ICAgICBwdXRzIFtpbmZvIGZyYW1lIDBdICAgICAgIDsjIDA0Kg==</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDA1</vline><vline encoding='base64'>IGZvbyAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDA2ICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDQgZmlsZSBFWCB0eXBlIHNvdXJjZX0=</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDA3</vline><vline encoding='base64'>IHNldCBzY3JpcHQgeyAgICAgICAgICAgICAgICAgIDsjIDA4ICAx</vline><vline encoding='base64'>ICAgICBwdXRzIFtpbmZvIGZyYW1lIDBdICAgICAgIDsjIDA5ICAyKg==</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDEwICAz</vline><vline encoding='base64'>IGV2YWwgJHNjcmlwdCAgICAgICAgICAgICAgICAgIDsjIDExICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDIgdHlwZSBldmFsfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDEy</vline><vline encoding='base64'>IGV2YWwgeyAgICAgICAgICAgICAgICAgICAgICAgIDsjIDEzICAx</vline><vline encoding='base64'>ICAgICBwdXRzIFtpbmZvIGZyYW1lIDBdICAgICAgIDsjIDE0KiAyKg==</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDE1ICAzICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDE0IHR5cGUgc291cmNlfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDE2</vline><vline encoding='base64'>IHByb2MgZm94IHt9IHsgICAgICAgICAgICAgICAgIDsjIDE3ICAvZm94IHJlbWVtYmVycyAxNw==</vline><vline encoding='base64'>ICAgICBldmFsICQ6OnNjcmlwdCAgICAgICAgICAgIDsjIDE4</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDE5</vline><vline encoding='base64'>IGZveCAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDIwICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDIgdHlwZSBldmFsfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDIx</vline><vline encoding='base64'>IHByb2Mgc3F1aXJyZWwge30geyAgICAgICAgICAgIDsjIDIyICAvc3F1aXJyZWwgcmVtZW1iZXJzIDIy</vline><vline encoding='base64'>ICAgICBldmFsIHsgICAgICAgICAgICAgICAgICAgIDsjIDIzICAx</vline><vline encoding='base64'>ICAgICAgICAgcHV0cyBbaW5mbyBmcmFtZSAwXSAgIDsjIDI0KiAyKg==</vline><vline encoding='base64'>ICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDI1ICAz</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDI2</vline><vline encoding='base64'>IHNxdWlycmVsICAgICAgICAgICAgICAgICAgICAgIDsjIDI3ICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDI0IHR5cGUgc291cmNlfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDI4</vline><vline encoding='base64'>IHByb2MgZnVjaHMge30geyAgICAgICAgICAgICAgIDsjIDI5ICAgIC9mdWNocyByZW1lbWJlcnMgMjk=</vline><vline encoding='base64'>ICAgICBwcm9jIGRvZyB7fSB7ICAgICAgICAgICAgIDsjIDMwICAxIC9kb2cgICByZW1lbWJlcnMgMzA=</vline><vline encoding='base64'>ICAgICAgICAgcHV0cyBbaW5mbyBmcmFtZSAwXSAgIDsjIDMxKiAyKg==</vline><vline encoding='base64'>ICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDMyICAz</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDMz</vline><vline encoding='base64'>IGZ1Y2hzICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDM0</vline><vline encoding='base64'>IGRvZyAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDM1ICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDMxIHR5cGUgc291cmNlfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDM2</vline><vline encoding='base64'>IGV2YWwgeyAgICAgICAgICAgICAgICAgICAgICAgIDsjIDM3ICAx</vline><vline encoding='base64'>ICAgICBwcm9jIHdvbGYgeyAgICAgICAgICAgICAgIDsjIDM4ICAyIC93b2xmIHJlbWVtYmVycyAzOA==</vline><vline encoding='base64'>ICAgICAgICAgcHV0cyBbaW5mbyBmcmFtZSAwXSAgIDsjIDM5KiAzKg==</vline><vline encoding='base64'>ICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDQwICA0</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDQxICA1</vline><vline encoding='base64'>IHdvbGYgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDQyICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDM5IHR5cGUgc291cmNlfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDQz</vline><vline encoding='base64'>IHNldCBzY3JpcHRlZCB7ICAgICAgICAgICAgICAgIDsjIDQ0ICAx</vline><vline encoding='base64'>ICAgICBwcm9jIGRlZXIge30geyAgICAgICAgICAgIDsjIDQ1ICAyIC9kZWVyIHJlbWVtYmVycyAy</vline><vline encoding='base64'>ICAgICAgICAgcHV0cyBbaW5mbyBmcmFtZSAwXSAgIDsjIDQ2ICAzKg==</vline><vline encoding='base64'>ICAgICB9ICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDQ3ICA0</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDQ4ICA1</vline><vline encoding='base64'>IGV2YWwgJHNjcmlwdGVkICAgICAgICAgICAgICAgIDsjIDQ5</vline><vline encoding='base64'>IGRlZXIgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDUwICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDMgdHlwZSBldmFsfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDUx</vline><vline encoding='base64'>IHB1dHMgW3NldCBhIGIgICAgICAgICAgICAgICAgIDsjIDUy</vline><vline encoding='base64'>ICAgICAgIGluZm8gZnJhbWUgMF0gICAgICAgICAgIDsjIDUzKiAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDUzIHR5cGUgc291cmNlIGZpbGUgRVh9</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDU0</vline><vline encoding='base64'>IHB1dHMgW2luZm8gXA==</vline><vline encoding='base64'>ICAgICAgIGZyYW1lIDBdICAgICAgICAgICAgICAgIDsjIDU2ICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDU1IHR5cGUgc291cmNlIGZpbGUgRVh9</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDU3</vline><vline encoding='base64'>IHByb2Mgc2FsbW9uIHt9IFw=</vline><vline encoding='base64'>IHsgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDU5</vline><vline encoding='base64'>ICAgICBwdXRzIFtpbmZvIGZyYW1lIDBdICAgICAgIDsjIDYwKg==</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDYx</vline><vline encoding='base64'>IHNhbG1vbiAgICAgICAgICAgICAgICAgICAgICAgIDsjIDYyICAtIG91dHB1dDoge2NtZCB7Li4ufSBsaW5lIDYwIHR5cGUgc291cmNlIGZpbGUgRVh9</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDYz</vline><vline encoding='base64'>IHNldCBtZXRob2QgZnJhbWUgICAgICAgICAgICAgIDsjIDY0</vline><vline encoding='base64'>IHB1dHMgW2luZm8gJG1ldGhvZCAwXSAgICAgICAgIDsjIDY1KiAtIG91dHB1dDoge2NtZCB7aW5mbyAkbWV0aG9kIDB9IGxpbmUgNjUgdHlwZSBzb3VyY2UgZmlsZSBFWH0=</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDY2</vline><vline encoding='base64'>IHByb2MgdHJvdXQge30geyAgICAgICAgICAgICAgIDsjIDY3</vline><vline encoding='base64'>ICAgICBwdXRzIFtpbmZvICRtZXRob2QgMF0gICAgIDsjIDY4Kg==</vline><vline encoding='base64'>IH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDY5</vline><vline encoding='base64'>IHRyb3V0ICAgICAgICAgICAgICAgICAgICAgICAgIDsjIDcwICAtIG91dHB1dDoge2NtZCB7aW5mbyAkbWV0aG9kIDB9IGxpbmUgNjggdHlwZSBzb3VyY2UgZmlsZSBFWH0=</vline></verbatim>
<para>Another example showing how to query the whole stack of frames. It assumed that the file is named EX. The output shown after the example was manually reformatted to explicitly ordered the keys and the columns vertically aligned, for readability and better comparability of the lines. The returned level information was removed, and level numbers for <emph style="bold">info frame</emph> were added at the beginning of the lines.</para>
<verbatim><vline encoding='base64'>IHByb2Mgc2V0UmVzIHtyZXN1bHR9IHsgICAgICAgICAgICAgICA7IyAwMQ==</vline><vline encoding='base64'>ICAgaWYgeyRyZXN1bHQgPT0gImZhaWwifSB7ICAgICAgICAgICA7IyAwMg==</vline><vline encoding='base64'>ICAgICAgc2V0IGxldmVsIFtpbmZvIGZyYW1lXSAgICAgICAgICA7IyAwMw==</vline><vline encoding='base64'>ICAgICAgd2hpbGUgeyRsZXZlbH0geyAgICAgICAgICAgICAgICA7IyAwNA==</vline><vline encoding='base64'>ICAgICAgICAgICBwdXRzIFtpbmZvIGZyYW1lICRsZXZlbF0gICA7IyAwNQ==</vline><vline encoding='base64'>ICAgICAgICAgICBpbmNyIGxldmVsIC0xICAgICAgICAgICAgICA7IyAwNg==</vline><vline encoding='base64'>ICAgICAgIH0gOyMgZW5kIG9mIHdoaWxlICAgICAgICAgICAgICA7IyAwNw==</vline><vline encoding='base64'>ICAgfSA7IyBlbmQgb2YgaWYgICAgICAgICAgICAgICAgICAgICA7IyAwOA==</vline><vline encoding='base64'>IH0gOyMgZW5kIG9mIHByb2Mgc2V0UmVzICAgICAgICAgICAgICA7IyAwOQ==</vline><vline encoding='base64'>IHByb2MgcnVuVGVzdCB7dGN9IHsgICAgICAgICAgICAgICAgICA7IyAxMA==</vline><vline encoding='base64'>ICAgICAgIyBydW4gdGhlIHRlc3RjYXNlICAgICAgICAgICAgICA7IyAxMQ==</vline><vline encoding='base64'>ICAgICAgdXBsZXZlbCAxICBzZXRSZXMgZmFpbCAgICAgICAgICA7IyAxMg==</vline><vline encoding='base64'>IH0gOyMgZW5kIG9mIHByb2MgcnVuVGVzdCAgICAgICAgICAgICA7IyAxMw==</vline><vline encoding='base64'>IHJ1blRlc3QgVEMwMDAxICAgICAgICAgICAgICAgICAgICAgICA7IyAxNA==</vline></verbatim>
<para><emph style="bold">Output:</emph></para>
<verbatim><vline encoding='base64'>IDQge2NtZCB7cnVuVGVzdCBUQzAwMDF9ICAgICAgICBsaW5lIDE0IHR5cGUgc291cmNlIGZpbGUgRVh9</vline><vline encoding='base64'>IDMge2NtZCB7dXBsZXZlbCAxIHNldFJlcyBmYWlsfSBsaW5lIDEyIHR5cGUgc291cmNlIGZpbGUgRVggcHJvYyBydW5UZXN0fQ==</vline><vline encoding='base64'>IDIge2NtZCB7c2V0UmVzIGZhaWx9ICAgICAgICAgICBsaW5lICAxIHR5cGUgZXZhbH0=</vline><vline encoding='base64'>IDEge2NtZCB7aW5mbyBmcmFtZSAkbGV2ZWx9ICAgICBsaW5lICA1IHR5cGUgc291cmNlIGZpbGUgRVggcHJvYyBzZXRSZXN9</vline></verbatim>
<para>To see the connection between the new feature and error stack traces replace the <emph style="bold">info frame</emph> command on line 3 of <emph style="italic">setRes</emph> with &quot;<emph style="bold">return</emph> -code error X&quot;. This will generate an error trace and with a bit of reformatting the relationship can be seen easily:</para>
<para><emph style="bold">Stack trace:</emph></para>
<verbatim><vline encoding='base64'>CVg=</vline><vline encoding='base64'>CSAgICB3aGlsZSBleGVjdXRpbmc=</vline><vline encoding='base64'>CSJzZXRSZXMgZmFpbCI=</vline><vline encoding='base64'>CSAgICAoInVwbGV2ZWwiIGJvZHkgbGluZSAxKQ==</vline><vline encoding='base64'>CSAgICBpbnZva2VkIGZyb20gd2l0aGlu</vline><vline encoding='base64'>CSJ1cGxldmVsIDEgIHNldFJlcyBmYWlsIg==</vline><vline encoding='base64'>CSAgICAocHJvY2VkdXJlICJydW5UZXN0IiBsaW5lIDMp</vline><vline encoding='base64'>CSAgICBpbnZva2VkIGZyb20gd2l0aGlu</vline><vline encoding='base64'>CSJydW5UZXN0IFRDMDAwMSI=</vline><vline encoding='base64'>CSAgICAoZmlsZSAiRVgudGNsIiBsaW5lIDE0KQ==</vline></verbatim>
<para>Reformat the trace, with all output from a single command on one line, and some noise removed.</para>
<verbatim><vline encoding='base64'>CVg=</vline><vline encoding='base64'>CSJzZXRSZXMgZmFpbCIgKCJ1cGxldmVsIiBib2R5IGxpbmUgMSk=</vline><vline encoding='base64'>CSJ1cGxldmVsIDEgIHNldFJlcyBmYWlsIiAocHJvY2VkdXJlICJydW5UZXN0IiBsaW5lIDMp</vline><vline encoding='base64'>CSJydW5UZXN0IFRDMDAwMSIgKGZpbGUgIkVYLnRjbCIgbGluZSAxNCk=</vline></verbatim>
<para>Now revert the order of the lines, and add vertical alignment. Now have in essence the ouput of the unmodified example, with same difference in the line numbers. But that is only because the error stack trace always counts lines relative to the script, and doesn&apos;t attempt to determine an absolute location in a file.</para>
<verbatim><vline encoding='base64'>CSJydW5UZXN0IFRDMDAwMSIgICAgICAgICAoZmlsZSAiRVgudGNsIiBsaW5lIDE0KQ==</vline><vline encoding='base64'>CSJ1cGxldmVsIDEgIHNldFJlcyBmYWlsIiAocHJvY2VkdXJlICJydW5UZXN0IiBsaW5lIDMp</vline><vline encoding='base64'>CSJzZXRSZXMgZmFpbCIgICAgICAgICAgICAoInVwbGV2ZWwiIGJvZHkgbGluZSAxKQ==</vline><vline encoding='base64'>CVg=</vline></verbatim>
<subsection title="Child Interpreters">
<para>The current implementation of <emph style="bold">info level</emph> only returns levels up to the top of the stack for the current interpreter. Such an approach puts limitations on what information can be retrieved, but allows for a certain level of &quot;<emph style="italic">security</emph>&quot; when running code in child interps, especially safe interps.</para>
<para>Given the security considerations of safe interps, and consistancy with regards to what information is returned across multiple circumstances, the stack trace returned will only return information up to the top level of the current interp, the same limit <emph style="bold">info level</emph> is bound by.</para>
</subsection>
</section>
<section title="Discussion">
<para>A point noted by Lars Hellstrom is that this TIP makes the builtin <emph style="bold">source</emph> command special. It is not possible anymore to re-create <emph style="bold">source</emph> purely in Tcl, doing so will loose the name of the file. We are still tracking line numbers, but they are then relative to the start of the eval&apos;d script, withut a connection to the file.</para>
<para>In a similar way, user-defined control structures lose the ability of the builtin <emph style="italic">if</emph>, etc. to track line numbers in a literal code block relative to the enclosing file. The user-defined commands are again reduced to providing line numbers relative to the start of the code block.</para>
<para>To bring user-defined commands back to the same level as the builtins we need:</para>
<enumerate><item.e index='1'><para>An extension of <emph style="bold">info frame</emph> which delivers the line information for all words of the command we are inside of. As each word can start on a different line (because of continuation lines and preceding multi-line literals).</para><para>This information is actually already available internally. The current implementation needs it for the tracking into literals.</para></item.e><item.e index='2'><para>Extensions to the <emph style="italic">uplevel</emph> and <emph style="italic">eval</emph> commands which allow a script to provide them with location information for the script they are evaluating.</para></item.e></enumerate>
<para>For example:</para>
<verbatim><vline encoding='base64'>IHByb2MgbmV3c291cmNlIHtmb28gc2NyaXB0fSB7</vline><vline encoding='base64'>ICAgLi4uIHByZXByb2Nlc3Mgd2hhdGV2ZXIgLi4u</vline><vline encoding='base64'>ICAgc2V0IGxvYyBbaW5mbyBmcmFtZSBkYXRhIGZvciB3b3JkIDJd</vline><vline encoding='base64'>ICAgdXBsZXZlbCAtbG9jYXRpb24gJGxvYyAxICRzY3JpcHQ=</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>Internally we also need quite a bit more flexible data structures. The type names for example are defined through a C enum, and can be checked quickly and efficiently. The file information, i.e. path, is stored and used dependent on that, only for type <emph style="bold">source</emph>.</para>
<para>To keep this TIP and its implementation reasonably small the actual detailed specification and implementation of such extensibility is defered to a future TIP.</para>
</section>
<section title="Reference Implementation">
<para>An implementation patch is available on SourceForge[<url ref="http://sourceforge.net/support/tracker.php?aid=1571568"/>].</para>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain.</para>
<para>Please note that any correspondence to the author concerning this TIP is considered in the public domain unless otherwise specifically requested by the individual(s) authoring said correspondence. This is to allow information about the TIP to be placed in a public forum for discussion.</para>
</section>
</body></TIP>

