On Wed, Nov 23, 2011 at 8:06 AM, Brock <awwa...@thelackthereof.org> wrote:
> On Sun, 20 Nov 2011 Rocky Bernstein wrote: > > I've briefly looked at PadWalker which can look at "my" and "our" > > variables on a call stack. And while this is very useful, it is not > > the same as being able to evaluate a string in the context of a stack > > frame. > > > > Has anyone tried to create such an eval? A simple suggested interface > > would be to pass it an integer which indicates the call stack frame to > > use. > > You might take a look at Eval::WithLexicals and how it is used in > Plack::Middleware::InteractiveDebugger (which, upon die(), lets the user > open a web-based REPL at any level of the call stack). Looks like there > is some manual work you have to do though. > Thanks! I think I now understand how it's done. Sort of. Devel::StrackTrace::WithLexicals uses PadWalker to create a hash of of all the lexical variables for a given call frame. Eval::WithLexicals is then passed that hash. By the way, this is similar to how Python's eval works. And then comes the complicated part, Eval::WithLexicals uses that hash somehow in a string eval. How this works is not obvious to me, but the next couple of days I'll probably figure this out as I have a good debugger that can track nicely through string evals which is used a bit here. Eval::WithLexicals (and Eval::WithLexicals::WithHintPersistence ) then needs to put changed values back someplace. (Perhaps this id done via B::svref_2object.) So one thing that needs to be checked in my use is that the values do indeed get put back into the right place in the call stack and not just say in the hash created by Devel::StackTrace::WithLexicals. Another thing that seems to be something that could go wrong is in handling local variables, because PadWaker doesn't handle local variables. Suppose I have a local variable $a defined in main and a couple of calls down I have another local $a --alsi in package main::. I am not sure how I would be able to access the outer or main-most $a to read the value. (Actually here is a bad way and one that is sort of used in the first Ruby debugger: On every call create a closure with all of the values. This is horrendously slow.) And looking at WithLexical.pm's code, there is this comment in _record_caller_data(): # PadWalker ignores eval block and eval string so we must do so too. So this could also be another source of discrepancy people may run into. Given all of this -- and I am sorry if this was a bit long -- it seems that life would be much simpler and more reliable if Perl just had a eval_n function which did the evaluations n levels down the call stack. Looking at the C code, one can get a PERL_CONTEXT from the call stack and somehow one just needs to make sure that this is what is used by this new eval_n routine.