3

I have a proc MYPROC which is called from slave interpreter (with name MYPRO) using alias and unknown mechanisms.

#include <tcl.h>
#include <iostream>

int main()
{
    Tcl_Interp* interp0 = Tcl_CreateInterp();
    Tcl_Interp* interp1 = Tcl_CreateSlave(interp0, "sl", false);
    const char* script1 =
       "proc MYPROC {a} {                              \n"
       "    puts [info frame]                          \n"
       "    global tcl_version                         \n"
       "    if { $tcl_version >= \"8.5\" } {           \n"
       "        puts \"frame 0 [info frame 0]\"        \n"
       "        puts \"frame 1 [info frame 1]\"        \n"
       "        puts \"frame 2 [info frame 2]\"        \n"
       "        puts \"frame 3 [info frame 3]\"        \n"
       "    }                                          \n"
       "}                                              \n"
       "proc m_unknown {cmd args} {                    \n"
       "    ${cmd}C $args                              \n"
       "}                                              \n";

    Tcl_Eval(interp0, script1);

    Tcl_CreateAlias(interp1, "unknown", interp0, "m_unknown", NULL, NULL);
    const char* script2 =
       "set a 1       \n"
       "set b 2       \n"
       "MYPRO {""}    \n";

    if (Tcl_Eval(interp1, script2) == TCL_ERROR) {
        Tcl_Eval(interp1, "puts $errorInfo");
        Tcl_Eval(interp0, "puts $errorInfo");
    }

    return 0;
}

Inside body of MYPROC I need to get line number of MYPRO invocation (I.e. line number of “MYPRO {""}” in script2 which is 3)

Here is an output of this sample

2
frame 0 type proc line 5 cmd {info frame 0} proc ::MYPROC level 0
frame 1 type proc line -1 cmd {${cmd}C $args                              } proc ::m_unknown level 1
frame 2 type proc line 7 cmd {info frame 2} proc ::MYPROC level 0
bad level "3"
    while executing
"info frame 3"
    (procedure "MYPROC" line 8)
    invoked from within
"${cmd}C $args                              "
    (procedure "m_unknown" line 2)
    invoked from within
"MYPRO {}    "
bad level "3"
    while executing
"info frame 3"
    (procedure "MYPROC" line 8)
    invoked from within
"${cmd}C $args                              "
    (procedure "m_unknown" line 2)

Here there is no any frame information about MYPRO invocation line since frame count is 2. Also from error trace of interp1 you can see that proc and line information is missing for MYPRO {} entry.

Vikash Pandey
  • 5,073
  • 6
  • 36
  • 41
ArmanHunanyan
  • 695
  • 2
  • 9
  • 21
  • This is an interesting problem actually, and not entirely trivial. _Context matters;_ readers should be aware that there are multiple interpreters in use, and that this strongly affects the results. – Donal Fellows May 31 '16 at 09:35

1 Answers1

2

The problem (for you) is that info frame doesn't describe anything about stack frames in other interpreters. This is by design; interpreters are strongly walled off from each other.

I've reproduced your issue without any of that C code. The interpreters are named foo and bar, but you could replace those names with anything else.

% interp create foo
foo
% interp eval foo {
  proc MYPROC {a} {
    puts [info frame]   
    global tcl_version
    if { $tcl_version >= "8.5" } {
      puts "frame 1 [info frame 1]"
      puts "frame 2 [info frame 2]"
      puts "frame 3 [info frame 3]"
    }
  }
  proc m_unknown {cmd args} {
    ${cmd}C {*}$args
  }
}
% interp create bar
bar
% interp alias  bar unknown  foo m_unknown
unknown
% interp eval bar {
  set a 1
  set b 2 
  MYPRO {""}
}
2
frame 1 type proc line -1 cmd {${cmd}C {*}$args} proc ::m_unknown level 1
frame 2 type proc line 7 cmd {info frame 2} proc ::MYPROC level 0
bad level "3"

That appears to be functioning correctly. (BTW info frame 0 isn't useful output here; it's counting the frame stack from the other end, just as info level 0 does. I've removed it.)

You'll need to try asking the info frame questions in the interpreter that can answer them. Let's do that (in this case using an alias, but I think interp eval would also be a suitable mechanism):

% interp alias  foo what  bar info frame
what
% interp eval foo {
  proc MYPROC {a} {
    puts [what]
    puts "frame 1 [what 1]"   
    puts "frame 2 [what 2]"
    puts "frame 3 [what 3]"
  }
}
% interp eval bar {
  set a 1
  set b 2
  MYPRO ""
}
1
frame 1 type eval line 4 cmd {MYPRO ""} level 0
bad level "2"

There we go, we're now able to see the correct line number. I assume you'll be able to sort things out from there.

Donal Fellows
  • 120,022
  • 18
  • 134
  • 199