changeset 29349:6f6b5f2e5d4d stable

fix lookup of "caller" stack frame (bug #59847) * call-stack.cc (call_stack::goto_caller_frame): Use static_link of current user frame instead of dbup to find caller frame. Don't error if we are already at the top scope, just return the top scope. * eval-command.tst: New tests.
author John W. Eaton <jwe@octave.org>
date Wed, 03 Feb 2021 21:48:27 -0500
parents 72e75857a5c6
children 9ae39daf5ff5 bbbe4dcc7200
files libinterp/corefcn/call-stack.cc test/eval-command.tst
diffstat 2 files changed, 55 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/call-stack.cc	Wed Feb 03 09:43:00 2021 -0500
+++ b/libinterp/corefcn/call-stack.cc	Wed Feb 03 21:48:27 2021 -0500
@@ -618,11 +618,12 @@
   {
     size_t start = find_current_user_frame ();
 
-    // FIXME: is this supposed to be an error?
-    if (start == 0)
-      error ("already at top level");
+    std::shared_ptr<stack_frame> caller_frame = m_cs[start]->static_link ();
 
-    m_curr_frame = dbupdown (start, -1, false);
+    // Allow evalin ('caller', ...) to work when called from the
+    // top-level prompt.
+
+    m_curr_frame = caller_frame ? caller_frame->index () : 0;
   }
 
   void call_stack::goto_base_frame (void)
--- a/test/eval-command.tst	Wed Feb 03 09:43:00 2021 -0500
+++ b/test/eval-command.tst	Wed Feb 03 21:48:27 2021 -0500
@@ -159,3 +159,53 @@
 %! f4a ();
 %! assert (sigma_call, "function");
 %! clear -global sigma_call
+
+%!function r = f_eval_fun ()
+%!  evalin_value = "this is f_eval_fun";
+%!  r = evalin ("caller", "evalin_value");
+%!endfunction
+%!function r = g_eval_fun ()
+%!  evalin_value = "this is g_eval_fun";
+%!  r = evalin ("caller", "f_eval_fun ()");
+%!endfunction
+%!function r = h_eval_fun ()
+%!  evalin_value = "this is h_eval_fun";
+%!  r = f_eval_fun ();
+%!endfunction
+
+%!shared evalin_value
+%! evalin_value = "this is the caller";
+%!assert <59847> (f_eval_fun (), "this is the caller");
+%!assert <59847> (g_eval_fun (), "this is the caller");
+%!assert <59847> (h_eval_fun (), "this is h_eval_fun");
+
+%!function r = f_asgn_fun ()
+%!  asgnin_value = "this is f_asgn_fun";
+%!  assignin ("caller", "asgnin_value", "f value");
+%!  r = asgnin_value;
+%!endfunction
+%!function r = g_asgn_fun ()
+%!  asgnin_value = "this is g_asgn_fun";
+%!  evalin ("caller", "f_asgn_fun ();");
+%!  r = asgnin_value;
+%!endfunction
+%!function r = h_asgn_fun ()
+%!  asgnin_value = "this is h_asgn_fun";
+%!  f_asgn_fun ();
+%!  r = asgnin_value;
+%!endfunction
+
+%!test <59847>
+%! asgnin_value = "this is the caller";
+%! assert (f_asgn_fun (), "this is f_asgn_fun");
+%! assert (asgnin_value, "f value");
+
+%!test <59847>
+%! asgnin_value = "this is the caller";
+%! assert (g_asgn_fun (), "this is g_asgn_fun");
+%! assert (asgnin_value, "f value");
+
+%!test <59847>
+%! asgnin_value = "this is the caller";
+%! assert (h_asgn_fun (), "f value");
+%! assert (asgnin_value, "this is the caller");