changeset 28432:71c34141cc2d stable

refactor handling of parent functions and localfunctions * help.cc (Flocalfunctions): Simply call symbol_scope::localfunctions for the current user function. * symscope.h, symscope.cc (symbol_scope_rep::m_fcn_name, symbol_scope_rep::m_parent_fcn_names, symbol_scope_rep::m_is_primary_fcn_scope): New data members. (symbol_scope_rep::localfunctions, symbol_scope_rep::fcn_name, symbol_scope_rep::cache_fcn_name, symbol_scope_rep::parent_fcn_names, symbol_scope_rep::cache_parent_fcn_names, symbol_scope_rep::mark_primary_fcn_scope, symbol_scope_rep::is_primary_fcn_scope, symbol_scope::localfunctions, symbol_scope::fcn_name, symbol_scope::cache_fcn_name, symbol_scope::parent_fcn_names, symbol_scope::cache_parent_fcn_names, symbol_scope::mark_primary_fcn_scope, symbol_scope::is_primary_fcn_scope): New functions. (symbol_scope_rep): Also cache parent function names. * oct-parse.yy (base_parser::push_fcn_symtab): Mark primary_fcn_scope as primary. (base_parser::finish_function): If parsing subfunction, set primary parent scope in subfunction scope. Cache parent function names in current scope. * ov-fcn.h (octave_function::parent_fcn_names): New virtual function. * ov-usr-fcn.h (octave_user_function::parent_fcn_names): New function.
author John W. Eaton <jwe@octave.org>
date Fri, 03 Apr 2020 22:00:06 -0400
parents 0ffae065ca03
children d05a4194f1ad
files libinterp/corefcn/help.cc libinterp/corefcn/symscope.cc libinterp/corefcn/symscope.h libinterp/octave-value/ov-class.cc libinterp/octave-value/ov-fcn-handle.cc libinterp/octave-value/ov-fcn.h libinterp/octave-value/ov-usr-fcn.h libinterp/parse-tree/oct-parse.yy
diffstat 8 files changed, 177 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/help.cc	Fri Apr 03 21:59:15 2020 -0400
+++ b/libinterp/corefcn/help.cc	Fri Apr 03 22:00:06 2020 -0400
@@ -814,30 +814,14 @@
 
   // Find the main function we are in.
   octave::tree_evaluator& tw = interp.get_evaluator ();
-  octave_user_code *parent_fcn = tw.debug_user_code ();
+  octave_user_code *caller = tw.debug_user_code ();
 
-  if (! parent_fcn)
+  if (! caller)
     return ovl (retval);
 
-  // Find the subfunctions of this function.
-  // 1) subfunction_names contains only valid subfunctions
-  // 2) subfunctions contains both nested functions and subfunctions
-  const std::list<std::string> names = parent_fcn->subfunction_names ();
-  const std::map<std::string, octave_value> h = parent_fcn->subfunctions ();
-
-  size_t sz = names.size ();
-  retval.resize (dim_vector (sz, 1));
+  octave::symbol_scope scope = caller->scope ();
 
-  // loop over them.
-  size_t i = 0;
-  for (const auto& nm : names)
-    {
-      std::map<std::string, octave_value>::const_iterator nm_fcn = h.find (nm);
-      if (nm_fcn != h.end ())
-        retval(i++) = octave_value (new octave_fcn_handle (nm_fcn->second, nm));
-    }
-
-  return ovl (retval);
+  return ovl (Cell (scope.localfunctions ()));
 }
 
 /*
--- a/libinterp/corefcn/symscope.cc	Fri Apr 03 21:59:15 2020 -0400
+++ b/libinterp/corefcn/symscope.cc	Fri Apr 03 22:00:06 2020 -0400
@@ -92,6 +92,43 @@
       return p->second;
   }
 
+  std::list<octave_value> symbol_scope_rep::localfunctions (void) const
+  {
+    std::list<octave_value> retval;
+
+    // Find the subfunctions of this function (which should be the
+    // primary parent function for this scope).
+
+    // 1) m_subfunction_names contains only valid subfunctions
+    // 2) m_subfunctions contains both nested functions and subfunctions
+
+    // loop over them.
+
+    for (const auto& nm : m_subfunction_names)
+      {
+        auto nm_fcn_iter = m_subfunctions.find (nm);
+
+        if (nm_fcn_iter != m_subfunctions.end ())
+          {
+            octave_value ov_fcn = nm_fcn_iter->second;
+            octave_user_code *fcn = ov_fcn.user_code_value ();
+
+            if (! fcn)
+              continue;
+
+            octave::symbol_scope scope = fcn->scope ();
+
+            std::list<std::string> plst = scope.parent_fcn_names ();
+
+            octave_fcn_handle *fh = new octave_fcn_handle (ov_fcn, nm, plst);
+
+            retval.push_back (octave_value (fh));
+          }
+      }
+
+    return retval;
+  }
+
   octave_value
   symbol_scope_rep::dump (void) const
   {
@@ -243,8 +280,14 @@
         m_is_static = true;
       }
 
+    std::list<std::string> plst = parent_fcn_names ();
+    plst.push_front (m_fcn_name);
+
     for (auto& scope_obj : m_children)
-      scope_obj.update_nest ();
+      {
+        scope_obj.cache_parent_fcn_names (plst);
+        scope_obj.update_nest ();
+      }
   }
 
   bool symbol_scope_rep::look_nonlocal (const std::string& name,
@@ -280,4 +323,21 @@
 
     return false;
   }
+
+  std::list<octave_value> symbol_scope::localfunctions (void) const
+  {
+    if (! m_rep)
+      return std::list<octave_value> ();
+
+    if (is_primary_fcn_scope ())
+      return m_rep->localfunctions ();
+
+    std::shared_ptr<symbol_scope_rep> ppsr
+      = m_rep->primary_parent_scope_rep ();
+
+    if (! ppsr)
+      return std::list<octave_value> ();
+
+    return ppsr->localfunctions ();
+  }
 }
--- a/libinterp/corefcn/symscope.h	Fri Apr 03 21:59:15 2020 -0400
+++ b/libinterp/corefcn/symscope.h	Fri Apr 03 22:00:06 2020 -0400
@@ -66,10 +66,11 @@
     subfunctions_iterator;
 
     symbol_scope_rep (const std::string& name = "")
-      : m_name (name), m_symbols (), m_subfunctions (),
-        m_persistent_values (), m_code (nullptr), m_fcn_file_name (),
-        m_dir_name (), m_parent (), m_primary_parent (), m_children (),
-        m_nesting_depth (0), m_is_static (false)
+      : m_name (name), m_symbols (), m_subfunctions (), m_persistent_values (),
+        m_code (nullptr), m_fcn_name (), m_parent_fcn_names (),
+        m_fcn_file_name (), m_dir_name (), m_parent (), m_primary_parent (),
+        m_children (), m_nesting_depth (0), m_is_static (false),
+        m_is_primary_fcn_scope (false)
     {
       // All scopes have ans as the first symbol, initially undefined.
 
@@ -126,6 +127,8 @@
       new_sid->m_persistent_values = m_persistent_values;
       new_sid->m_subfunction_names = m_subfunction_names;
       new_sid->m_code = m_code;
+      new_sid->m_fcn_name = m_fcn_name;
+      new_sid->m_parent_fcn_names = m_parent_fcn_names;
       new_sid->m_fcn_file_name = m_fcn_file_name;
       new_sid->m_dir_name = m_dir_name;
       new_sid->m_parent = m_parent;
@@ -133,6 +136,7 @@
       new_sid->m_children = m_children;
       new_sid->m_nesting_depth = m_nesting_depth;
       new_sid->m_is_static = m_is_static;
+      new_sid->m_is_primary_fcn_scope = m_is_primary_fcn_scope;
 
       return new_sid;
     }
@@ -213,6 +217,7 @@
         nm_sf.second.unlock ();
     }
 
+    // Pairs of name, function objects.
     std::map<std::string, octave_value> subfunctions (void) const
     {
       return m_subfunctions;
@@ -240,12 +245,28 @@
       return m_subfunction_names;
     }
 
+    std::list<octave_value> localfunctions (void) const;
+
     octave_value dump (void) const;
 
     std::string name (void) const { return m_name; }
 
     void cache_name (const std::string& name) { m_name = name; }
 
+    std::string fcn_name (void) const { return m_fcn_name; }
+
+    void cache_fcn_name (const std::string& name) { m_fcn_name = name; }
+
+    std::list<std::string> parent_fcn_names (void) const
+    {
+      return m_parent_fcn_names;
+    }
+
+    void cache_parent_fcn_names (const std::list<std::string>& names)
+    {
+      m_parent_fcn_names = names;
+    }
+
     octave_user_code *user_code (void) const { return m_code; }
 
     void set_user_code (octave_user_code *code) { m_code = code; }
@@ -259,11 +280,15 @@
       m_fcn_file_name = name;
     }
 
+    std::string fcn_file_name (void) const { return m_fcn_file_name; }
+
     void cache_dir_name (const std::string& name);
 
-    std::string fcn_file_name (void) const { return m_fcn_file_name; }
+    std::string dir_name (void) const { return m_dir_name; }
 
-    std::string dir_name (void) const { return m_dir_name; }
+    void mark_primary_fcn_scope (void) { m_is_primary_fcn_scope = true; }
+
+    bool is_primary_fcn_scope (void) const { return m_is_primary_fcn_scope; }
 
     bool is_relative (const std::shared_ptr<symbol_scope_rep>& scope) const;
 
@@ -313,6 +338,14 @@
 
     octave_user_code *m_code;
 
+    //! Simple name of the function corresponding to this scope.
+
+    std::string m_fcn_name;
+
+    //! List Simple names of the parent functions corresponding to this scope.
+
+    std::list<std::string> m_parent_fcn_names;
+
     //! The file name associated with m_code.
 
     std::string m_fcn_file_name;
@@ -341,6 +374,9 @@
     //! If true then no variables can be added.
 
     bool m_is_static;
+
+    //! If true, this is the scope of a primary function.
+    bool m_is_primary_fcn_scope;
   };
 
   class symbol_scope
@@ -532,6 +568,9 @@
       return m_rep ? m_rep->subfunction_names () : std::list<std::string> ();
     }
 
+    // List of function handle objects.
+    std::list<octave_value> localfunctions (void) const;
+
     octave_value dump (void) const
     {
       return m_rep ? m_rep->dump () : octave_value ();
@@ -548,6 +587,28 @@
         m_rep->cache_name (name);
     }
 
+    std::string fcn_name (void) const
+    {
+      return m_rep ? m_rep->fcn_name () : "";
+    }
+
+    void cache_fcn_name (const std::string& name)
+    {
+      if (m_rep)
+        m_rep->cache_fcn_name (name);
+    }
+
+    std::list<std::string> parent_fcn_names (void) const
+    {
+      return m_rep ? m_rep->parent_fcn_names () : std::list<std::string> ();
+    }
+
+    void cache_parent_fcn_names (const std::list<std::string>& names)
+    {
+      if (m_rep)
+        m_rep->cache_parent_fcn_names (names);
+    }
+
     octave_user_code * user_code (void) const
     {
       return m_rep ? m_rep->user_code () : nullptr;
@@ -593,6 +654,17 @@
       return m_rep ? m_rep->dir_name () : "";
     }
 
+    void mark_primary_fcn_scope (void)
+    {
+      if (m_rep)
+        m_rep->mark_primary_fcn_scope ();
+    }
+
+    bool is_primary_fcn_scope (void) const
+    {
+      return m_rep ? m_rep->is_primary_fcn_scope () : false;
+    }
+
     bool is_relative (const symbol_scope& scope) const
     {
       return m_rep ? m_rep->is_relative (scope.get_rep ()) : false;
--- a/libinterp/octave-value/ov-class.cc	Fri Apr 03 21:59:15 2020 -0400
+++ b/libinterp/octave-value/ov-class.cc	Fri Apr 03 22:00:06 2020 -0400
@@ -2141,7 +2141,6 @@
 Internal function.
 
 Implements final construction for inline objects.
-@seealso{inline}
 @end deftypefn */)
 {
   // Input validation has already been done in input.m.
--- a/libinterp/octave-value/ov-fcn-handle.cc	Fri Apr 03 21:59:15 2020 -0400
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Fri Apr 03 22:00:06 2020 -0400
@@ -2016,7 +2016,7 @@
 Previous versions of Octave accepted an optional second argument,
 @qcode{"global"}, that caused str2func to ignore locally visible
 functions.  This option is no longer supported.
-@seealso{func2str, inline, functions}
+@seealso{func2str, functions}
 @end deftypefn */)
 {
   int nargin = args.length ();
--- a/libinterp/octave-value/ov-fcn.h	Fri Apr 03 21:59:15 2020 -0400
+++ b/libinterp/octave-value/ov-fcn.h	Fri Apr 03 22:00:06 2020 -0400
@@ -87,6 +87,11 @@
   virtual octave::symbol_scope parent_fcn_scope (void) const
   { return octave::symbol_scope (); }
 
+  virtual std::list<std::string> parent_fcn_names (void) const
+  {
+    return std::list<std::string> ();
+  }
+
   virtual void mark_fcn_file_up_to_date (const octave::sys::time&) { }
 
   virtual octave::symbol_scope scope (void) { return octave::symbol_scope (); }
--- a/libinterp/octave-value/ov-usr-fcn.h	Fri Apr 03 21:59:15 2020 -0400
+++ b/libinterp/octave-value/ov-usr-fcn.h	Fri Apr 03 22:00:06 2020 -0400
@@ -273,6 +273,11 @@
     return m_scope.parent_scope ();
   }
 
+  std::list<std::string> parent_fcn_names (void) const
+  {
+    return m_scope.parent_fcn_names ();
+  }
+
   void mark_as_system_fcn_file (void);
 
   bool is_system_fcn_file (void) const { return system_fcn_file; }
--- a/libinterp/parse-tree/oct-parse.yy	Fri Apr 03 21:59:15 2020 -0400
+++ b/libinterp/parse-tree/oct-parse.yy	Fri Apr 03 22:00:06 2020 -0400
@@ -2489,7 +2489,10 @@
 
     if (! m_lexer.m_reading_script_file && m_curr_fcn_depth == 0
         && ! m_parsing_subfunctions)
-      m_primary_fcn_scope = m_lexer.m_symtab_context.curr_scope ();
+        {
+          m_primary_fcn_scope = m_lexer.m_symtab_context.curr_scope ();
+          m_primary_fcn_scope.mark_primary_fcn_scope ();
+        }
 
     if (m_lexer.m_reading_script_file && m_curr_fcn_depth > 0)
       {
@@ -3681,15 +3684,16 @@
 
     if (fcn)
       {
-        std::string nm = fcn->name ();
+        std::string fcn_nm = fcn->name ();
         std::string file = fcn->fcn_file_name ();
 
-        std::string tmp = nm;
+        std::string tmp = fcn_nm;
         if (! file.empty ())
           tmp += ": " + file;
 
         symbol_scope fcn_scope = fcn->scope ();
         fcn_scope.cache_name (tmp);
+        fcn_scope.cache_fcn_name (fcn_nm);
         fcn_scope.cache_fcn_file_name (file);
         fcn_scope.cache_dir_name (m_lexer.m_dir_name);
 
@@ -3713,14 +3717,27 @@
                 symbol_scope pscope = m_function_scopes.parent_scope ();
                 fcn_scope.set_parent (pscope);
                 fcn_scope.set_primary_parent (m_primary_fcn_scope);
-                pscope.install_nestfunction (nm, ov_fcn, fcn_scope);
+                pscope.install_nestfunction (fcn_nm, ov_fcn, fcn_scope);
+
+                // For nested functions, the list of parent functions is
+                // set in symbol_scope::update_nest.
               }
             else
               {
                 fcn->mark_as_subfunction ();
-                m_subfunction_names.push_back (nm);
+                m_subfunction_names.push_back (fcn_nm);
                 fcn_scope.set_parent (m_primary_fcn_scope);
-                m_primary_fcn_scope.install_subfunction (nm, ov_fcn);
+                if (m_parsing_subfunctions)
+                  fcn_scope.set_primary_parent (m_primary_fcn_scope);
+                m_primary_fcn_scope.install_subfunction (fcn_nm, ov_fcn);
+
+                // Prepend name of primary fucntion to list of parent
+                // functions (if any) for subfunction.
+
+                std::list<std::string> plst
+                  = fcn_scope.parent_fcn_names ();
+                plst.push_front (m_primary_fcn_scope.fcn_name ());
+                fcn_scope.cache_parent_fcn_names (plst);
               }
           }