diff --git a/libinterp/corefcn/fcn-info.cc b/libinterp/corefcn/fcn-info.cc --- a/libinterp/corefcn/fcn-info.cc +++ b/libinterp/corefcn/fcn-info.cc @@ -86,7 +86,7 @@ namespace octave tmpfcn->mark_as_private_function (class_name); - private_functions[dir_name] = ov_fcn; + private_functions[octave::sys::canonicalize_file_name (dir_name)] = ov_fcn; return ov_fcn; } @@ -628,26 +628,20 @@ namespace octave fcn_info::fcn_info_rep::xfind (const symbol_scope& search_scope, const octave_value_list& args) { - octave_user_code *curr_code - = search_scope ? search_scope.user_code () : nullptr; - - // Subfunction. I think it only makes sense to check for - // subfunctions if we are currently executing a function defined - // from a .m file. + // Subfunction, local function, or private function. if (search_scope) { + // Subfunction. + octave_value fcn = search_scope.find_subfunction (name); if (fcn.is_defined ()) return fcn; - } - - // Local function. - if (curr_code) - { - std::string fcn_file = curr_code->fcn_file_name (); + // Local function. + + std::string fcn_file = search_scope.fcn_file_name (); // For anonymous functions we look at the parent scope so that if // they were defined within class methods and use local functions @@ -667,13 +661,10 @@ namespace octave return r->second; } } - } - - // Private function. - if (curr_code) - { - std::string dir_name = curr_code->dir_name (); + // Private function. + + std::string dir_name = search_scope.dir_name (); if (! dir_name.empty ()) { @@ -847,14 +838,13 @@ namespace octave if (cmdline_function.is_defined ()) return cmdline_function; - // Private function. + // Private function, local function, or subfunction. - octave_user_code *curr_code - = search_scope ? search_scope.user_code () : nullptr; + if (search_scope) + { + // Private function. - if (curr_code) - { - std::string dir_name = curr_code->dir_name (); + std::string dir_name = search_scope.dir_name (); if (! dir_name.empty ()) { @@ -885,13 +875,10 @@ namespace octave } } } - } - - // Local function. - if (curr_code) - { - std::string fcn_file = curr_code->fcn_file_name (); + // Local function. + + std::string fcn_file = search_scope.fcn_file_name (); if (! fcn_file.empty ()) { @@ -906,14 +893,11 @@ namespace octave return r->second; } } - } - // Subfunction. I think it only makes sense to check for - // subfunctions if we are currently executing a function defined - // from a .m file. + // Subfunction. I think it only makes sense to check for + // subfunctions if we are currently executing a function defined + // from a .m file. - if (search_scope) - { octave_value val = search_scope.find_subfunction (name); if (val.is_defined ()) diff --git a/libinterp/corefcn/load-path.cc b/libinterp/corefcn/load-path.cc --- a/libinterp/corefcn/load-path.cc +++ b/libinterp/corefcn/load-path.cc @@ -185,6 +185,46 @@ namespace octave return retval; } + static std::string find_private_fcn_file (const std::string& dir, + const std::string& fcn, + int type) + { + std::string nm + = sys::file_ops::concat (sys::file_ops::concat (dir, "private"), fcn); + + if (type & load_path::OCT_FILE) + { + std::string fnm = nm + ".oct"; + + sys::file_stat fs (fnm); + + if (fs.exists () && fs.is_reg ()) + return fnm; + } + + if (type & load_path::MEX_FILE) + { + std::string fnm = nm + ".mex"; + + sys::file_stat fs (fnm); + + if (fs.exists () && fs.is_reg ()) + return fnm; + } + + if (type & load_path::M_FILE) + { + std::string fnm = nm + ".m"; + + sys::file_stat fs (fnm); + + if (fs.exists () && fs.is_reg ()) + return fnm; + } + + return ""; + } + // True if a path is contained in a path list separated by path_sep_char static bool @@ -1525,7 +1565,7 @@ namespace octave remove_fcn_map (dir, fcn_files); - remove_private_fcn_map (dir); + remove_private_fcn_map (sys::canonicalize_file_name (dir)); remove_method_map (dir); } @@ -1656,25 +1696,28 @@ namespace octave std::string retval; // update (); - - const_private_fcn_map_iterator q = private_fcn_map.find (dir); + std::string canon_dir = sys::canonicalize_file_name (dir); + + const_private_fcn_map_iterator q = private_fcn_map.find (canon_dir); if (q != private_fcn_map.end ()) { - const dir_info::fcn_file_map_type& m = q->second; - - dir_info::const_fcn_file_map_iterator p = m.find (fcn); - - if (p != m.end ()) + const dir_info::fcn_file_map_type& fcn_file_map = q->second; + + dir_info::const_fcn_file_map_iterator p = fcn_file_map.find (fcn); + + if (p != fcn_file_map.end ()) { std::string fname - = sys::file_ops::concat (sys::file_ops::concat (dir, "private"), fcn); + = sys::file_ops::concat (sys::file_ops::concat (canon_dir, "private"), fcn); if (check_file_type (fname, type, p->second, fcn, "load_path::find_private_fcn")) retval = fname; } } + else + retval = find_private_fcn_file (canon_dir, fcn, type); return retval; } @@ -1892,7 +1935,8 @@ namespace octave dir_info::fcn_file_map_type private_file_map = di.private_file_map; if (! private_file_map.empty ()) - private_fcn_map[di.dir_name] = private_file_map; + private_fcn_map[sys::canonicalize_file_name (di.dir_name)] + = private_file_map; } void @@ -1955,7 +1999,8 @@ namespace octave dir_info::fcn_file_map_type private_file_map = ci.private_file_map; if (! private_file_map.empty ()) - private_fcn_map[full_dir_name] = private_file_map; + private_fcn_map[sys::canonicalize_file_name (full_dir_name)] + = private_file_map; } } @@ -2094,7 +2139,7 @@ namespace octave void load_path::package_info::remove_private_fcn_map (const std::string& dir) { - auto p = private_fcn_map.find (dir); + auto p = private_fcn_map.find (sys::canonicalize_file_name (dir)); if (p != private_fcn_map.end ()) private_fcn_map.erase (p); diff --git a/libinterp/corefcn/load-path.h b/libinterp/corefcn/load-path.h --- a/libinterp/corefcn/load-path.h +++ b/libinterp/corefcn/load-path.h @@ -209,12 +209,12 @@ namespace octave std::string system_path (void) const { return sys_path; } - private: - static const int M_FILE = 1; static const int OCT_FILE = 2; static const int MEX_FILE = 4; + private: + class dir_info { public: diff --git a/libinterp/corefcn/symscope.cc b/libinterp/corefcn/symscope.cc --- a/libinterp/corefcn/symscope.cc +++ b/libinterp/corefcn/symscope.cc @@ -29,6 +29,8 @@ #include +#include "file-ops.h" + #include "fcn-info.h" #include "interpreter-private.h" #include "interpreter.h" @@ -158,6 +160,12 @@ namespace octave } void + symbol_scope_rep::set_user_code (octave_user_code *code) + { + m_code = code; + } + + void symbol_scope_rep::set_parent (const std::shared_ptr& parent) { m_parent = std::weak_ptr (parent); @@ -169,6 +177,30 @@ namespace octave m_primary_parent = std::weak_ptr (parent); } + void + symbol_scope_rep::cache_fcn_file_name (const std::string& name) + { + m_fcn_file_name = name; + } + + void + symbol_scope_rep::cache_dir_name (const std::string& name) + { + m_dir_name = octave::sys::canonicalize_file_name (name); + } + + std::string + symbol_scope_rep::fcn_file_name (void) const + { + return m_fcn_file_name; + } + + std::string + symbol_scope_rep::dir_name (void) const + { + return m_dir_name; + } + bool symbol_scope_rep::is_relative (const std::shared_ptr& scope) const { diff --git a/libinterp/corefcn/symscope.h b/libinterp/corefcn/symscope.h --- a/libinterp/corefcn/symscope.h +++ b/libinterp/corefcn/symscope.h @@ -40,7 +40,7 @@ #include "oct-refcount.h" class tree_argument_list; -class octave_user_function; +class octave_user_code; #include "ov.h" #include "ovl.h" @@ -67,9 +67,9 @@ namespace octave symbol_scope_rep (const std::string& name = "") : m_name (name), m_symbols (), m_subfunctions (), - m_persistent_values (), m_code (nullptr), m_parent (), - m_primary_parent (), m_children (), m_nesting_depth (0), - m_is_static (false) + 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) { // All scopes have ans as the first symbol, initially undefined. @@ -126,6 +126,8 @@ namespace octave 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_file_name = m_fcn_file_name; + new_sid->m_dir_name = m_dir_name; new_sid->m_parent = m_parent; new_sid->m_primary_parent = m_primary_parent; new_sid->m_children = m_children; @@ -246,12 +248,20 @@ namespace octave octave_user_code *user_code (void) const { return m_code; } - void set_user_code (octave_user_code *code) { m_code = code; } + void set_user_code (octave_user_code *code); void set_parent (const std::shared_ptr& parent); void set_primary_parent (const std::shared_ptr& parent); + void cache_fcn_file_name (const std::string& name); + + void cache_dir_name (const std::string& name); + + std::string fcn_file_name (void) const; + + std::string dir_name (void) const; + bool is_relative (const std::shared_ptr& scope) const; void update_nest (void); @@ -300,6 +310,14 @@ namespace octave octave_user_code *m_code; + //! The file name associated with m_code. + + std::string m_fcn_file_name; + + //! The directory associated with m_code. + + std::string m_dir_name; + //! Parent of nested function (may be null). std::weak_ptr m_parent; @@ -550,6 +568,28 @@ namespace octave m_rep->set_primary_parent (p.get_rep ()); } + void cache_fcn_file_name (const std::string& name) + { + if (m_rep) + m_rep->cache_fcn_file_name (name); + } + + void cache_dir_name (const std::string& name) + { + if (m_rep) + m_rep->cache_dir_name (name); + } + + std::string fcn_file_name (void) const + { + return m_rep ? m_rep->fcn_file_name () : ""; + } + + std::string dir_name (void) const + { + return m_rep ? m_rep->dir_name () : ""; + } + bool is_relative (const symbol_scope& scope) const { return m_rep ? m_rep->is_relative (scope.get_rep ()) : false; diff --git a/libinterp/parse-tree/oct-parse.yy b/libinterp/parse-tree/oct-parse.yy --- a/libinterp/parse-tree/oct-parse.yy +++ b/libinterp/parse-tree/oct-parse.yy @@ -3424,6 +3424,8 @@ namespace octave symbol_scope script_scope = m_lexer.m_symtab_context.curr_scope (); script_scope.cache_name (m_lexer.m_fcn_file_full_name); + script_scope.cache_fcn_file_name (m_lexer.m_fcn_file_full_name); + script_scope.cache_dir_name (m_lexer.m_dir_name); octave_user_script *script = new octave_user_script (m_lexer.m_fcn_file_full_name, @@ -3666,6 +3668,8 @@ namespace octave symbol_scope fcn_scope = fcn->scope (); fcn_scope.cache_name (tmp); + fcn_scope.cache_fcn_file_name (file); + fcn_scope.cache_dir_name (m_lexer.m_dir_name); if (lc) fcn->stash_leading_comment (lc); diff --git a/libinterp/parse-tree/pt-fcn-handle.cc b/libinterp/parse-tree/pt-fcn-handle.cc --- a/libinterp/parse-tree/pt-fcn-handle.cc +++ b/libinterp/parse-tree/pt-fcn-handle.cc @@ -158,6 +158,9 @@ namespace octave af->stash_parent_fcn_name (curr_fcn->name ()); af->stash_dir_name (curr_fcn->dir_name ()); + new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ()); + new_scope.cache_dir_name (curr_fcn->dir_name ()); + // The following is needed so that class method dispatch works // properly for anonymous functions that wrap class methods.