diff src/toplev.cc @ 7901:3e4c9b69069d

call stack changes
author John W. Eaton <jwe@octave.org>
date Tue, 08 Jul 2008 12:00:32 -0400
parents 73ef513855e7
children 8018e10d2b87
line wrap: on
line diff
--- a/src/toplev.cc	Sat Jun 28 05:15:02 2008 -0400
+++ b/src/toplev.cc	Tue Jul 08 12:00:32 2008 -0400
@@ -167,6 +167,43 @@
   return retval;
 }
 
+size_t
+octave_call_stack::do_num_user_code_frames (octave_idx_type& curr_user_frame) const
+{
+  size_t retval = 0;
+
+  curr_user_frame = 0;
+
+  // Look for the caller of dbstack.
+  size_t frame = cs[curr_frame].prev;
+
+  bool found = false;
+
+  size_t k = cs.size ();
+
+  for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++)
+    {
+      octave_function *f = (*p).fcn;
+
+      if (--k == frame)
+	found = true;
+
+      if (f && f->is_user_code ())
+	{
+	  if (! found)
+	    curr_user_frame++;
+
+	  retval++;
+	}
+    }
+
+  // We counted how many user frames were not the one, in reverse.
+  // Now set curr_user_frame to be the index in the other direction.
+  curr_user_frame = retval - curr_user_frame - 1;
+
+  return retval;
+}
+
 octave_user_script *
 octave_call_stack::do_caller_user_script (difference_type q) const
 {
@@ -237,72 +274,76 @@
 }
 
 Octave_map
-octave_call_stack::do_backtrace (int nframes) const
+octave_call_stack::do_backtrace (size_t nskip,
+				 octave_idx_type& curr_user_frame) const
 {
   Octave_map retval;
 
-  if (nframes > 0 && nframes <= cs.size ())
-    {
-      Cell keys (6, 1);
+  size_t user_code_frames = do_num_user_code_frames (curr_user_frame);
+
+  size_t nframes = nskip <= user_code_frames ? user_code_frames - nskip : 0;
 
-      keys(0) = "file";
-      keys(1) = "name";
-      keys(2) = "line";
-      keys(3) = "column";
-      keys(4) = "scope";
-      keys(5) = "context";
+  // Our list is reversed.
+  curr_user_frame = nframes - curr_user_frame - 1;
+
+  Cell keys (6, 1);
 
-      Cell file (nframes, 1);
-      Cell name (nframes, 1);
-      Cell line (nframes, 1);
-      Cell column (nframes, 1);
-      Cell scope (nframes, 1);
-      Cell context (nframes, 1);
-
-      octave_idx_type k = nframes - 1;
+  keys(0) = "file";
+  keys(1) = "name";
+  keys(2) = "line";
+  keys(3) = "column";
+  keys(4) = "scope";
+  keys(5) = "context";
 
-      const_iterator p = cs.begin ();
+  Cell file (nframes, 1);
+  Cell name (nframes, 1);
+  Cell line (nframes, 1);
+  Cell column (nframes, 1);
+  Cell scope (nframes, 1);
+  Cell context (nframes, 1);
 
-      while (k >= 0)
+  if (nframes > 0)
+    {
+      int k = 0;
+
+      for (const_reverse_iterator p = cs.rbegin (); p != cs.rend (); p++)
 	{
-	  const call_stack_elt& elt = *p++;
-
-	  scope(k) = elt.scope;
-	  context(k) = elt.context;
+	  const call_stack_elt& elt = *p;
 
 	  octave_function *f = elt.fcn;
 
-	  if (f)
+	  if (f && f->is_user_code ())
 	    {
-	      file(k) = f->fcn_file_name ();
-	      std::string parent_fcn_name = f->parent_fcn_name ();
-	      if (parent_fcn_name == std::string ())
-		name(k) = f->name ();
-	      else
-		name(k) = f->parent_fcn_name () + Vfilemarker + f->name ();
-
-	      tree_statement *stmt = elt.stmt;
-
-	      if (stmt)
-		{
-		  line(k) = stmt->line ();
-		  column(k) = stmt->column ();
-		}
+	      if (nskip > 0)
+		nskip--;
 	      else
 		{
-		  line(k) = -1;
-		  column(k) = -1;
+		  scope(k) = elt.scope;
+		  context(k) = elt.context;
+
+		  file(k) = f->fcn_file_name ();
+		  std::string parent_fcn_name = f->parent_fcn_name ();
+		  if (parent_fcn_name == std::string ())
+		    name(k) = f->name ();
+		  else
+		    name(k) = f->parent_fcn_name () + Vfilemarker + f->name ();
+
+		  tree_statement *stmt = elt.stmt;
+
+		  if (stmt)
+		    {
+		      line(k) = stmt->line ();
+		      column(k) = stmt->column ();
+		    }
+		  else
+		    {
+		      line(k) = -1;
+		      column(k) = -1;
+		    }
+
+		  k++;
 		}
 	    }
-	  else
-	    {
-	      file(k) = "<unknown>";
-	      name(k) = "<unknown>";
-	      line(k) = -1;
-	      column(k) = -1;
-	    }
-
-	  k--;
 	}
 
       retval.assign ("file", file);
@@ -356,26 +397,126 @@
 }
 
 bool
-octave_call_stack::do_goto_frame_relative (int n, bool verbose)
+octave_call_stack::do_goto_frame_relative (int nskip, bool verbose)
 {
   bool retval = false;
 
-  size_t sz = cs.size ();
-
-  if (n == 0)
+  if (nskip == 0)
     retval = true;
   else
     {
-      size_t frame = static_cast<size_t> (n) + curr_frame;
+      int incr = nskip < 0 ? -1 : 1;
+
+      // Start looking with the caller of dbup/dbdown.
+      size_t frame = cs[curr_frame].prev;
+
+      while (true)
+	{
+	  if ((incr < 0 && frame == 0) || (incr > 0 && frame == cs.size () - 1))
+	    break;
+
+	  frame += incr;
+
+	  const call_stack_elt& elt = cs[frame];
+
+	  octave_function *f = elt.fcn;
+
+	  if (f && f->is_user_code ())
+	    {
+	      if (nskip > 0)
+		nskip--;
+	      else if (nskip < 0)
+		nskip++;
+
+	      if (nskip == 0)
+		{
+		  curr_frame = frame;
+		  cs[cs.size () - 1].prev = curr_frame;
 
-      if ((n > 0 && frame < sz) || (n < 0 && frame >= 0))
-	retval = goto_frame (frame, verbose);
+		  if (verbose)
+		    {
+		      tree_statement *s = elt.stmt;
+		      int l = -1;
+		      int c = -1;
+		      if (s)
+			{
+			  l = s->line ();
+			  c = s->column ();
+			}
+
+		      std::ostringstream buf;
+		      buf << f->name () << ": " << " line " << l
+			  << ", column " << c << std::endl;
+
+		      octave_stdout << buf.str ();
+		    }
+
+		  retval = true;
+		  break;
+		}
+	    }
+	}
+
+      // There is no need to set scope and context here.  That will
+      // happen when the dbup/dbdown frame is popped and we jump to
+      // the new "prev" frame set above.
     }
 
   return retval;
 }
 
 void
+octave_call_stack::do_goto_caller_frame (void)
+{
+  size_t frame = curr_frame;
+
+  bool skipped = false;
+
+  while (frame != 0)
+    {
+      frame = cs[frame].prev;
+
+      const call_stack_elt& elt = cs[frame];
+
+      octave_function *f = elt.fcn;
+
+      if (f && f->is_user_code ())
+	{
+	  if (! skipped)
+	    // We found the current user code frame, so skip it.
+	    skipped = true;
+	  else
+	    {
+	      // We found the caller user code frame.
+	      call_stack_elt tmp (elt);
+	      tmp.prev = curr_frame;
+
+	      curr_frame = cs.size ();
+
+	      cs.push_back (tmp);
+
+	      symbol_table::set_scope_and_context (tmp.scope, tmp.context);
+
+	      break;
+	    }
+	}
+    }
+}
+
+void
+octave_call_stack::do_goto_base_frame (void)
+{
+  call_stack_elt tmp (cs[0]);
+  tmp.prev = curr_frame;
+
+  curr_frame = cs.size ();
+
+  cs.push_back (tmp);
+
+  symbol_table::set_scope_and_context (tmp.scope, tmp.context);
+}
+
+void
 recover_from_exception (void)
 {
   can_interrupt = true;