GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
fcn-info.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "file-ops.h"
31 #include "file-stat.h"
32 #include "lo-sysdep.h"
33 #include "oct-env.h"
34 
35 #include "defun.h"
36 #include "fcn-info.h"
37 #include "interpreter-private.h"
38 #include "interpreter.h"
39 #include "load-path.h"
40 #include "ov-fcn.h"
41 #include "ov-usr-fcn.h"
42 #include "parse.h"
43 #include "symscope.h"
44 #include "symtab.h"
45 #include "utils.h"
46 
47 // Should Octave always check to see if function files have changed
48 // since they were last compiled?
49 static int Vignore_function_time_stamp = 1;
50 
52 
54 fcn_info::fcn_info_rep::load_private_function (const std::string& dir_name)
55 {
56  octave_value retval;
57 
59 
60  std::string file_name = lp.find_private_fcn (dir_name, name);
61 
62  if (file_name.empty ())
63  return retval;
64 
65  octave_value ov_fcn = load_fcn_from_file (file_name, dir_name);
66 
67  if (ov_fcn.is_undefined ())
68  return retval;
69 
70  octave_function *tmpfcn = ov_fcn.function_value ();
71 
72  if (! tmpfcn)
73  return retval;
74 
75  std::string class_name;
76 
77  std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
78 
79  if (pos != std::string::npos)
80  {
81  std::string tmp = dir_name.substr (pos+1);
82 
83  if (tmp[0] == '@')
84  class_name = tmp.substr (1);
85  }
86 
87  tmpfcn->mark_as_private_function (class_name);
88 
89  private_functions[sys::canonicalize_file_name (dir_name)] = ov_fcn;
90 
91  return ov_fcn;
92 }
93 
95 fcn_info::fcn_info_rep::load_class_constructor ()
96 {
97  octave_value retval;
98 
99  std::string dir_name;
100 
101  load_path& lp = __get_load_path__ ();
102 
103  std::string file_name = lp.find_method (name, name, dir_name, package_name);
104 
105  if (! file_name.empty ())
106  {
107  octave_value ov_fcn
108  = load_fcn_from_file (file_name, dir_name, name,
109  package_name);
110 
111  if (ov_fcn.is_defined ())
112  {
113  // Note: ov_fcn may be an octave_classdef_meta object instead
114  // of the actual constructor function.
115 
116  retval = ov_fcn;
117 
118  class_constructors[name] = retval;
119  class_methods[name] = retval;
120  }
121  }
122  else
123  {
124  // Classdef constructors can be defined anywhere in the path, not
125  // necessarily in @-folders. Look for a normal function and load it.
126  // If the loaded function is a classdef constructor, store it as such
127  // and restore function_on_path to its previous value.
128 
129  octave_value old_function_on_path = function_on_path;
130 
131  octave_value maybe_cdef_ctor = find_user_function ();
132 
133  if (maybe_cdef_ctor.is_defined ())
134  {
135  octave_function *fcn = maybe_cdef_ctor.function_value (true);
136 
137  if (fcn && fcn->is_classdef_constructor ())
138  {
139  retval = maybe_cdef_ctor;
140 
141  class_constructors[name] = retval;
142  class_methods[name] = retval;
143 
144  function_on_path = old_function_on_path;
145  }
146  }
147  }
148 
149  return retval;
150 }
151 
153 fcn_info::fcn_info_rep::load_class_method (const std::string& dispatch_type)
154 {
155  octave_value retval;
156 
157  if (full_name () == dispatch_type)
158  retval = load_class_constructor ();
159  else
160  {
162 
163  retval = cdm.find_method_symbol (name, dispatch_type);
164 
165  if (! retval.is_defined ())
166  {
167  std::string dir_name;
168 
169  load_path& lp = __get_load_path__ ();
170 
171  std::string file_name = lp.find_method (dispatch_type, name,
172  dir_name);
173 
174  if (! file_name.empty ())
175  {
176  octave_value ov_fcn
177  = load_fcn_from_file (file_name, dir_name,
178  dispatch_type);
179 
180  if (ov_fcn.is_defined ())
181  {
182  octave_function *tmpfcn = ov_fcn.function_value ();
183 
184  if (tmpfcn && tmpfcn->is_class_method (dispatch_type))
185  {
186  retval = ov_fcn;
187 
188  class_methods[dispatch_type] = retval;
189  }
190  }
191  }
192 
193  if (retval.is_undefined ())
194  {
195  // Search parent classes
196 
197  symbol_table& symtab = __get_symbol_table__ ();
198 
199  const std::list<std::string>& plist
200  = symtab.parent_classes (dispatch_type);
201 
202  auto it = plist.begin ();
203 
204  while (it != plist.end ())
205  {
206  retval = find_method (*it);
207 
208  if (retval.is_defined ())
209  {
210  class_methods[dispatch_type] = retval;
211  break;
212  }
213 
214  it++;
215  }
216  }
217 
218  if (retval.is_undefined ())
219  {
220  // Search for built-in functions that are declared to
221  // handle specific types.
222 
223  if (built_in_function.is_defined ())
224  {
225  octave_function *fcn = built_in_function.function_value ();
226 
227  if (fcn && fcn->handles_dispatch_class (dispatch_type))
228  {
229  retval = built_in_function;
230 
231  class_methods[dispatch_type] = retval;
232  }
233  }
234  }
235  }
236  }
237 
238  return retval;
239 }
240 
241 // :-) JWE, can you parse this? Returns a 2D array with second dimension equal
242 // to btyp_num_types (static constant). Only the leftmost dimension can be
243 // variable in C/C++. Typedefs are boring.
244 
245 static builtin_type_t (* build_sup_table ())[btyp_num_types]
246 {
247  static builtin_type_t sup_table[btyp_num_types][btyp_num_types];
248  for (int i = 0; i < btyp_num_types; i++)
249  for (int j = 0; j < btyp_num_types; j++)
250  {
251  builtin_type_t ityp = static_cast<builtin_type_t> (i);
252  builtin_type_t jtyp = static_cast<builtin_type_t> (j);
253  // FIXME: Is this really right?
254  bool use_j
255  = (jtyp == btyp_func_handle || ityp == btyp_bool
256  || (btyp_isarray (ityp)
257  && (! btyp_isarray (jtyp)
258  || (btyp_isinteger (jtyp) && ! btyp_isinteger (ityp))
259  || ((ityp == btyp_double || ityp == btyp_complex
260  || ityp == btyp_char)
261  && (jtyp == btyp_float
262  || jtyp == btyp_float_complex)))));
263 
264  sup_table[i][j] = (use_j ? jtyp : ityp);
265  }
266 
267  return sup_table;
268 }
269 
270 std::string
272  builtin_type_t& builtin_type)
273 {
274  static builtin_type_t (*sup_table)[btyp_num_types] = build_sup_table ();
275  std::string dispatch_type;
276 
277  int n = args.length ();
278 
279  if (n > 0)
280  {
281  int i = 0;
282  builtin_type = args(0).builtin_type ();
283  if (builtin_type != btyp_unknown)
284  {
285  for (i = 1; i < n; i++)
286  {
287  builtin_type_t bti = args(i).builtin_type ();
288  if (bti != btyp_unknown)
289  builtin_type = sup_table[builtin_type][bti];
290  else
291  {
292  builtin_type = btyp_unknown;
293  break;
294  }
295  }
296  }
297 
298  if (builtin_type == btyp_unknown)
299  {
300  // There's a non-builtin class in the argument list.
301  dispatch_type = args(i).class_name ();
302 
303  symbol_table& symtab = __get_symbol_table__ ();
304 
305  for (int j = i+1; j < n; j++)
306  {
307  octave_value arg = args(j);
308 
309  if (arg.builtin_type () == btyp_unknown)
310  {
311  std::string cname = arg.class_name ();
312 
313  // Only switch to type of ARG if it is marked superior
314  // to the current DISPATCH_TYPE.
315  if (! symtab.is_superiorto (dispatch_type, cname)
316  && symtab.is_superiorto (cname, dispatch_type))
317  dispatch_type = cname;
318  }
319  }
320  }
321  else
322  dispatch_type = btyp_class_name[builtin_type];
323  }
324  else
325  builtin_type = btyp_unknown;
326 
327  return dispatch_type;
328 }
329 
330 std::string
332 {
333  builtin_type_t builtin_type;
334  return get_dispatch_type (args, builtin_type);
335 }
336 
337 // Find function definition according to the following precedence list:
338 //
339 // nested functions (and subfunctions)
340 // local functions in the current file
341 // private function
342 // class method
343 // class constructor
344 // command-line function
345 // autoload function
346 // functions on the load_path (current directory is always first)
347 // package (FIXME: does this belong here?)
348 // built-in function
349 
351 fcn_info::fcn_info_rep::find (const symbol_scope& scope,
352  const octave_value_list& args)
353 {
354  symbol_scope search_scope
355  = (scope
356  ? scope : __get_current_scope__ ());
357 
358  octave_value retval = xfind (search_scope, args);
359 
360  if (retval.is_undefined ())
361  {
362  // It is possible that the user created a file on the fly since
363  // the last prompt or chdir, so try updating the load path and
364  // searching again.
365 
366  load_path& lp = __get_load_path__ ();
367 
368  lp.update ();
369 
370  retval = xfind (search_scope, args);
371  }
372 
373  return retval;
374 }
375 
376 
377 static void
378 split_name_with_package (const std::string& name, std::string& fname,
379  std::string& pname)
380 {
381  std::size_t pos = name.rfind ('.');
382 
383  fname.clear ();
384  pname.clear ();
385 
386  if (pos != std::string::npos)
387  {
388  fname = name.substr (pos + 1);
389  pname = name.substr (0, pos);
390  }
391  else
392  fname = name;
393 }
394 
395 // Check the load path to see if file that defined this is still
396 // visible. If the file is no longer visible, then erase the
397 // definition and move on. If the file is visible, then we also
398 // need to check to see whether the file has changed since the
399 // function was loaded/parsed. However, this check should only
400 // happen once per prompt (for files found from relative path
401 // elements, we also check if the working directory has changed
402 // since the last time the function was loaded/parsed).
403 //
404 // FIXME: perhaps this should be done for all loaded functions when
405 // the prompt is printed or the directory has changed, and then we
406 // would not check for it when finding symbol definitions.
407 
408 static inline bool
409 load_out_of_date_fcn (const std::string& file_name,
410  const std::string& dir_name_arg,
411  octave_value& function,
412  const std::string& dispatch_type = "",
413  const std::string& package_name = "")
414 {
415  bool retval = false;
416 
417  std::string dir_name = dir_name_arg;
418 
419  if (dir_name.empty ())
420  {
421  std::size_t pos = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
422 
423  dir_name = file_name.substr (0, pos);
424  }
425 
426  // FIXME: do the following job of determining private status and
427  // class membership in a separate function?
428 
429  std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
430 
431  bool is_private_fcn
432  = pos != std::string::npos && dir_name.substr (pos+1) == "private";
433 
434  if (is_private_fcn)
435  dir_name = dir_name.substr (0, pos);
436 
437  std::string class_name;
438 
439  pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
440 
441  if (pos != std::string::npos)
442  {
443  std::string tmp = dir_name.substr (pos+1);
444 
445  if (tmp[0] == '@')
446  class_name = tmp.substr (1);
447  }
448 
449  octave_value ov_fcn
450  = load_fcn_from_file (file_name, dir_name, dispatch_type,
451  package_name);
452 
453  if (ov_fcn.is_defined ())
454  {
455  retval = true;
456 
457  octave_function *fcn = ov_fcn.function_value ();
458 
459  if (is_private_fcn)
460  fcn->mark_as_private_function (class_name);
461 
462  function = ov_fcn;
463  }
464  else
465  function = octave_value ();
466 
467  return retval;
468 }
469 
470 static bool
471 out_of_date_check (octave_value& function,
472  const std::string& dispatch_type = "",
473  bool check_relative = true)
474 {
475  bool retval = false;
476 
477  octave_function *fcn = function.function_value (true);
478 
479  if (fcn)
480  {
481  // FIXME: we need to handle subfunctions properly here.
482 
483  if (! (fcn->is_subfunction () || fcn->is_anonymous_function ()))
484  {
485  std::string ff = fcn->fcn_file_name ();
486 
487  if (! ff.empty ())
488  {
489  sys::time tc = fcn->time_checked ();
490 
491  bool relative = check_relative && fcn->is_relative ();
492 
493  if (tc <= Vlast_prompt_time
494  || (relative && tc < Vlast_chdir_time))
495  {
496  bool clear_breakpoints = false;
497  std::string nm = fcn->name ();
498  std::string pack = fcn->package_name ();
499  std::string canonical_nm = fcn->canonical_name ();
500 
501  bool is_same_file = false;
502 
503  std::string file;
504  std::string dir_name;
505 
506  if (check_relative)
507  {
508  int nm_len = nm.length ();
509 
510  if (sys::env::absolute_pathname (nm)
511  && ((nm_len > 4
512  && (nm.substr (nm_len-4) == ".oct"
513  || nm.substr (nm_len-4) == ".mex"))
514  || (nm_len > 2
515  && nm.substr (nm_len-2) == ".m")))
516  file = nm;
517  else
518  {
519  // We don't want to make this an absolute name,
520  // because load_fcn_file looks at the name to
521  // decide whether it came from a relative lookup.
522 
523  if (! dispatch_type.empty ())
524  {
525  load_path& lp = __get_load_path__ ();
526 
527  file = lp.find_method (dispatch_type, nm,
528  dir_name, pack);
529 
530  if (file.empty ())
531  {
532  std::string s_name;
533  std::string s_pack;
534 
535  symbol_table& symtab = __get_symbol_table__ ();
536 
537  const std::list<std::string>& plist
538  = symtab.parent_classes (dispatch_type);
539 
540  std::list<std::string>::const_iterator it
541  = plist.begin ();
542 
543  while (it != plist.end ())
544  {
545  split_name_with_package (*it, s_name,
546  s_pack);
547 
548  file = lp.find_method (*it, nm, dir_name,
549  s_pack);
550  if (! file.empty ())
551  {
552  pack = s_pack;
553  break;
554  }
555 
556  it++;
557  }
558  }
559  }
560 
561  // Maybe it's an autoload?
562  if (file.empty ())
563  {
565 
566  file = tw.lookup_autoload (nm);
567  }
568 
569  if (file.empty ())
570  {
571  load_path& lp = __get_load_path__ ();
572  file = lp.find_fcn (nm, dir_name, pack);
573  }
574  }
575 
576  if (! file.empty ())
577  is_same_file = sys::same_file (file, ff);
578  }
579  else
580  {
581  is_same_file = true;
582  file = ff;
583  }
584 
585  if (file.empty ())
586  {
587  // Can't see this function from current
588  // directory, so we should clear it.
589 
590  function = octave_value ();
591 
592  clear_breakpoints = true;
593  }
594  else if (is_same_file)
595  {
596  // Same file. If it is out of date, then reload it.
597 
598  sys::time ottp = fcn->time_parsed ();
599  OCTAVE_TIME_T tp = ottp.unix_time ();
600 
601  fcn->mark_fcn_file_up_to_date (sys::time ());
602 
603  if (! (Vignore_function_time_stamp == 2
604  || (Vignore_function_time_stamp
605  && fcn->is_system_fcn_file ())))
606  {
607  sys::file_stat fs (ff);
608 
609  if (fs)
610  {
611  if (fs.is_newer (tp))
612  {
613  retval = load_out_of_date_fcn (ff, dir_name,
614  function,
615  dispatch_type,
616  pack);
617 
618  clear_breakpoints = true;
619  }
620  }
621  else
622  {
623  function = octave_value ();
624 
625  clear_breakpoints = true;
626  }
627  }
628  }
629  else
630  {
631  // Not the same file, so load the new file in
632  // place of the old.
633 
634  retval = load_out_of_date_fcn (file, dir_name, function,
635  dispatch_type, pack);
636 
637  clear_breakpoints = true;
638  }
639 
640  // If the function has been replaced then clear any
641  // breakpoints associated with it
642  if (clear_breakpoints)
643  {
644  bp_table& bptab = __get_bp_table__ ();
645 
646  bptab.remove_all_breakpoints_from_function (canonical_nm,
647  true);
648  }
649  }
650  }
651  }
652  }
653 
654  return retval;
655 }
656 
658 fcn_info::fcn_info_rep::find_scoped_function (const symbol_scope& search_scope)
659 {
660  if (search_scope)
661  {
662  // Subfunction.
663 
664  octave_value fcn = search_scope.find_subfunction (name);
665 
666  if (fcn.is_defined ())
667  return fcn;
668 
669  // Local function.
670 
671  std::string fcn_file = search_scope.fcn_file_name ();
672 
673  // For anonymous functions we look at the parent scope so that if
674  // they were defined within class methods and use local functions
675  // (helper functions) we can still use those anonymous functions
676 
677  if (! fcn_file.empty ())
678  {
679  auto r = local_functions.find (fcn_file);
680 
681  if (r != local_functions.end ())
682  {
683  // We shouldn't need an out-of-date check here since
684  // local functions may ultimately be called only from
685  // a primary function or method defined in the same
686  // file.
687 
688  return r->second;
689  }
690  }
691 
692  // Private function.
693 
694  return find_private_function (search_scope.dir_name ());
695  }
696 
697  return octave_value ();
698 }
699 
701 fcn_info::fcn_info_rep::find_private_function (const std::string& dir_name)
702 {
703  if (! dir_name.empty ())
704  {
705  auto q = private_functions.find (dir_name);
706 
707  if (q == private_functions.end ())
708  {
709  octave_value val = load_private_function (dir_name);
710 
711  if (val.is_defined ())
712  return val;
713  }
714  else
715  {
716  octave_value& fval = q->second;
717 
718  if (fval.is_defined ())
719  out_of_date_check (fval, "", false);
720 
721  if (fval.is_defined ())
722  return fval;
723  else
724  {
725  octave_value val = load_private_function (dir_name);
726 
727  if (val.is_defined ())
728  return val;
729  }
730  }
731  }
732 
733  return octave_value ();
734 }
735 
737 fcn_info::fcn_info_rep::find_method (const octave_value_list& args)
738 {
739  if (! args.empty ())
740  {
741  std::string dispatch_type = get_dispatch_type (args);
742 
743  return find_method (dispatch_type);
744  }
745 
746  return octave_value ();
747 }
748 
750 fcn_info::fcn_info_rep::xfind (const symbol_scope& search_scope,
751  const octave_value_list& args)
752 {
753  // Subfunction, local function, or private function.
754 
755  octave_value fcn;
756 
757  fcn = find_scoped_function (search_scope);
758 
759  if (fcn.is_defined ())
760  return fcn;
761 
762  // Class methods.
763 
764  fcn = find_method (args);
765 
766  if (fcn.is_defined ())
767  return fcn;
768 
769  // Class constructors. The class name and function name are the same.
770 
771  auto q = class_constructors.find (name);
772 
773  if (q == class_constructors.end ())
774  {
775  octave_value val = load_class_constructor ();
776 
777  if (val.is_defined ())
778  return val;
779  }
780  else
781  {
782  octave_value& fval = q->second;
783 
784  if (fval.is_defined ())
785  out_of_date_check (fval, name);
786 
787  if (fval.is_defined ())
788  return fval;
789  else
790  {
791  octave_value val = load_class_constructor ();
792 
793  if (val.is_defined ())
794  return val;
795  }
796  }
797 
798  // Command-line function.
799 
800  if (cmdline_function.is_defined ())
801  return cmdline_function;
802 
803  // Autoload?
804 
805  fcn = find_autoload ();
806 
807  if (fcn.is_defined ())
808  return fcn;
809 
810  // Function on the path.
811 
812  fcn = find_user_function ();
813 
814  if (fcn.is_defined ())
815  return fcn;
816 
817  // Package
818 
819  fcn = find_package ();
820 
821  if (fcn.is_defined ())
822  return fcn;
823 
824  // Built-in function (might be undefined).
825 
826  return built_in_function;
827 }
828 
829 // Find the definition of NAME according to the following precedence
830 // list:
831 //
832 // built-in function
833 // function on the path
834 // autoload function
835 // command-line function
836 // private function
837 // subfunction
838 
839 // This function is used to implement the "builtin" function, which
840 // searches for "built-in" functions. In Matlab, "builtin" only
841 // returns functions that are actually built-in to the interpreter.
842 // But since the list of built-in functions is different in Octave and
843 // Matlab, we also search up the precedence list until we find
844 // something that matches. Note that we are only searching by name,
845 // so class methods and constructors are skipped.
846 
848 fcn_info::fcn_info_rep::builtin_find (const symbol_scope& scope)
849 {
850  symbol_scope search_scope
851  = (scope
852  ? scope : __get_current_scope__ ());
853 
854  octave_value retval = x_builtin_find (search_scope);
855 
856  if (! retval.is_defined ())
857  {
858  // It is possible that the user created a file on the fly since
859  // the last prompt or chdir, so try updating the load path and
860  // searching again.
861 
862  load_path& lp = __get_load_path__ ();
863 
864  lp.update ();
865 
866  retval = x_builtin_find (search_scope);
867  }
868 
869  return retval;
870 }
871 
873 fcn_info::fcn_info_rep::x_builtin_find (const symbol_scope& search_scope)
874 {
875  // Built-in function.
876  if (built_in_function.is_defined ())
877  return built_in_function;
878 
879  // Function on the path.
880 
881  octave_value fcn = find_user_function ();
882 
883  if (fcn.is_defined ())
884  return fcn;
885 
886  // Autoload?
887 
888  fcn = find_autoload ();
889 
890  if (fcn.is_defined ())
891  return fcn;
892 
893  // Command-line function.
894 
895  if (cmdline_function.is_defined ())
896  return cmdline_function;
897 
898  // Private function, local function, or subfunction.
899 
900  if (search_scope)
901  {
902  // Private function.
903 
904  std::string dir_name = search_scope.dir_name ();
905 
906  if (! dir_name.empty ())
907  {
908  auto q = private_functions.find (dir_name);
909 
910  if (q == private_functions.end ())
911  {
912  octave_value val = load_private_function (dir_name);
913 
914  if (val.is_defined ())
915  return val;
916  }
917  else
918  {
919  octave_value& fval = q->second;
920 
921  if (fval.is_defined ())
922  out_of_date_check (fval);
923 
924  if (fval.is_defined ())
925  return fval;
926  else
927  {
928  octave_value val = load_private_function (dir_name);
929 
930  if (val.is_defined ())
931  return val;
932  }
933  }
934  }
935 
936  // Local function.
937 
938  std::string fcn_file = search_scope.fcn_file_name ();
939 
940  if (! fcn_file.empty ())
941  {
942  auto r = local_functions.find (fcn_file);
943 
944  if (r != local_functions.end ())
945  {
946  // We shouldn't need an out-of-date check here since local
947  // functions may ultimately be called only from a primary
948  // function or method defined in the same file.
949 
950  return r->second;
951  }
952  }
953 
954  // Subfunction. I think it only makes sense to check for
955  // subfunctions if we are currently executing a function defined
956  // from a .m file.
957 
958  octave_value val = search_scope.find_subfunction (name);
959 
960  if (val.is_defined ())
961  return val;
962  }
963 
964  return octave_value ();
965 }
966 
968 fcn_info::fcn_info_rep::find_method (const std::string& dispatch_type)
969 {
970  octave_value retval;
971 
972  auto q = class_methods.find (dispatch_type);
973 
974  if (q == class_methods.end ())
975  retval = load_class_method (dispatch_type);
976  else
977  {
978  retval = q->second;
979 
980  if (retval.is_defined ())
981  out_of_date_check (retval, dispatch_type);
982 
983  if (! retval.is_defined ())
984  retval = load_class_method (dispatch_type);
985  }
986 
987  // Ignore any classdef constructors that were found by
988  // load_class_method above, either for dispatch_type or any
989  // superclasses of that class.
990 
991  // FIXME: Maybe there is a better way of managing classdef
992  // constructors (which may actually be octave_classdef_meta objects)
993  // so they don't appear in both the class_methods and
994  // class_constructors maps?
995 
996  if (retval.is_classdef_meta ())
997  {
998  octave_function *fcn = retval.function_value ();
999 
1000  if (fcn && fcn->is_classdef_constructor (dispatch_type))
1001  retval = octave_value ();
1002  }
1003 
1004  return retval;
1005 }
1006 
1008 fcn_info::fcn_info_rep::find_autoload ()
1009 {
1010  // Autoloaded function.
1011 
1012  if (autoload_function.is_defined ())
1013  out_of_date_check (autoload_function);
1014 
1015  if (! autoload_function.is_defined ())
1016  {
1018 
1019  std::string file_name = tw.lookup_autoload (name);
1020 
1021  if (! file_name.empty ())
1022  {
1023  std::size_t pos = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
1024 
1025  std::string dir_name = file_name.substr (0, pos);
1026 
1027  octave_value ov_fcn
1028  = load_fcn_from_file (file_name, dir_name, "", "", name, true);
1029 
1030  if (ov_fcn.is_defined ())
1031  autoload_function = octave_value (ov_fcn);
1032  }
1033  }
1034 
1035  return autoload_function;
1036 }
1037 
1039 fcn_info::fcn_info_rep::find_user_function ()
1040 {
1041  // Function on the path.
1042 
1043  if (function_on_path.is_defined ())
1044  out_of_date_check (function_on_path);
1045 
1046  if (function_on_path.is_undefined ())
1047  {
1048  std::string dir_name;
1049 
1050  load_path& lp = __get_load_path__ ();
1051 
1052 
1053  std::string file_name = lp.find_fcn (name, dir_name, package_name);
1054 
1055  if (! file_name.empty ())
1056  {
1057  octave_value ov_fcn
1058  = load_fcn_from_file (file_name, dir_name, "", package_name);
1059 
1060  if (ov_fcn.is_defined ())
1061  function_on_path = ov_fcn;
1062  }
1063  }
1064 
1065  return function_on_path;
1066 }
1067 
1069 fcn_info::fcn_info_rep::find_package ()
1070 {
1071  // FIXME: implement correct way to check out of date package
1072  //if (package.is_defined ())
1073  // out_of_date_check (package);
1074 
1075  if (package.is_undefined ())
1076  {
1078 
1079  package = cdm.find_package_symbol (full_name ());
1080  }
1081 
1082  return package;
1083 }
1084 
1085 void
1086 fcn_info::fcn_info_rep::install_built_in_dispatch (const std::string& klass)
1087 {
1088  if (built_in_function.is_defined ())
1089  {
1090  octave_function *fcn = built_in_function.function_value ();
1091 
1092  if (fcn)
1093  {
1094  if (fcn->handles_dispatch_class (klass))
1095  warning ("install_built_in_dispatch: '%s' already defined for class '%s'",
1096  name.c_str (), klass.c_str ());
1097  else
1098  fcn->push_dispatch_class (klass);
1099  }
1100  }
1101  else
1102  error ("install_built_in_dispatch: '%s' is not a built-in function",
1103  name.c_str ());
1104 }
1105 
1107 fcn_info::fcn_info_rep::dump () const
1108 {
1109  std::map<std::string, octave_value> m
1110  = {{ "name", full_name () },
1111  { "package", package.dump () },
1112  { "local_functions", dump_function_map (local_functions) },
1113  { "private_functions", dump_function_map (private_functions) },
1114  { "class_methods", dump_function_map (class_methods) },
1115  { "class_constructors", dump_function_map (class_constructors) },
1116  { "cmdline_function", cmdline_function.dump () },
1117  { "autoload_function", autoload_function.dump () },
1118  { "function_on_path", function_on_path.dump () },
1119  { "built_in_function", built_in_function.dump () }
1120  };
1121 
1122  return octave_value (m);
1123 }
1124 
1126 dump_function_map (const std::map<std::string, octave_value>& fcn_map)
1127 {
1128  if (fcn_map.empty ())
1129  return octave_value (Matrix ());
1130 
1131  std::map<std::string, octave_value> info_map;
1132 
1133  for (const auto& nm_fcn : fcn_map)
1134  {
1135  std::string nm = nm_fcn.first;
1136  const octave_value& fcn = nm_fcn.second;
1137  info_map[nm] = fcn.dump ();
1138  }
1139 
1140  return octave_value (info_map);
1141 }
1142 
1143 DEFUN (ignore_function_time_stamp, args, nargout,
1144  doc: /* -*- texinfo -*-
1145 @deftypefn {} {@var{val} =} ignore_function_time_stamp ()
1146 @deftypefnx {} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})
1147 Query or set the internal variable that controls whether Octave checks
1148 the time stamp on files each time it looks up functions defined in
1149 function files.
1150 
1151 If the internal variable is set to @qcode{"system"}, Octave will not
1152 automatically recompile function files in subdirectories of
1153 @file{@var{octave-home}/share/@var{version}/m} if they have changed since
1154 they were last compiled, but will recompile other function files in the
1155 search path if they change.
1156 
1157 If set to @qcode{"all"}, Octave will not recompile any function files
1158 unless their definitions are removed with @code{clear}.
1159 
1160 If set to @qcode{"none"}, Octave will always check time stamps on files
1161 to determine whether functions defined in function files need to
1162 recompiled.
1163 @end deftypefn */)
1164 {
1165  int nargin = args.length ();
1166 
1167  if (nargin > 1)
1168  print_usage ();
1169 
1170  octave_value retval;
1171 
1172  if (nargout > 0 || nargin == 0)
1173  {
1174  switch (Vignore_function_time_stamp)
1175  {
1176  case 1:
1177  retval = "system";
1178  break;
1179 
1180  case 2:
1181  retval = "all";
1182  break;
1183 
1184  default:
1185  retval = "none";
1186  break;
1187  }
1188  }
1189 
1190  if (nargin == 1)
1191  {
1192  std::string sval = args(0).xstring_value ("ignore_function_time_stamp: first argument must be a string");
1193 
1194  if (sval == "all")
1195  Vignore_function_time_stamp = 2;
1196  else if (sval == "system")
1197  Vignore_function_time_stamp = 1;
1198  else if (sval == "none")
1199  Vignore_function_time_stamp = 0;
1200  else
1201  error (R"(ignore_function_time_stamp: argument must be one of "all", "system", or "none")");
1202  }
1203 
1204  return retval;
1205 }
1206 
1207 /*
1208 %!shared old_state
1209 %! old_state = ignore_function_time_stamp ();
1210 %!test
1211 %! state = ignore_function_time_stamp ("all");
1212 %! assert (state, old_state);
1213 %! assert (ignore_function_time_stamp (), "all");
1214 %! state = ignore_function_time_stamp ("system");
1215 %! assert (state, "all");
1216 %! assert (ignore_function_time_stamp (), "system");
1217 %! ignore_function_time_stamp (old_state);
1218 
1219 ## Test input validation
1220 %!error ignore_function_time_stamp ("all", "all")
1221 %!error ignore_function_time_stamp ("UNKNOWN_VALUE")
1222 %!error ignore_function_time_stamp (42)
1223 */
1224 
1225 OCTAVE_END_NAMESPACE(octave)
Definition: dMatrix.h:42
bp_lines remove_all_breakpoints_from_function(const std::string &fcn_ident, bool silent=false)
Definition: bp-table.cc:1038
octave_value find_method_symbol(const std::string &method_name, const std::string &class_name)
std::string find_fcn(const std::string &fcn, std::string &dir_name, const std::string &pack_name="")
Definition: load-path.h:109
std::string find_private_fcn(const std::string &dir, const std::string &fcn, const std::string &pack_name="")
Definition: load-path.h:122
void update()
Definition: load-path.cc:417
std::string find_method(const std::string &class_name, const std::string &meth, std::string &dir_name, const std::string &pack_name="")
Definition: load-path.h:77
virtual bool is_anonymous_function() const
Definition: ov-base.h:527
virtual octave_function * function_value(bool silent=false)
Definition: ov-base.cc:940
virtual bool handles_dispatch_class(const std::string &) const
Definition: ov-fcn.h:143
virtual bool is_subfunction() const
Definition: ov-fcn.h:106
std::string canonical_name() const
Definition: ov-fcn.h:208
std::string package_name() const
Definition: ov-fcn.h:152
bool is_class_method(const std::string &cname="") const
Definition: ov-fcn.h:115
virtual octave::sys::time time_checked() const
Definition: ov-fcn.h:97
virtual void push_dispatch_class(const std::string &)
Definition: ov-fcn.h:141
virtual bool is_classdef_constructor(const std::string &="") const
Definition: ov-fcn.h:125
virtual void mark_fcn_file_up_to_date(const octave::sys::time &)
Definition: ov-fcn.h:90
bool is_relative() const
Definition: ov-fcn.h:204
virtual octave::sys::time time_parsed() const
Definition: ov-fcn.h:94
virtual std::string fcn_file_name() const
Definition: ov-fcn.h:75
virtual void mark_as_private_function(const std::string &cname="")
Definition: ov-fcn.h:155
virtual bool is_system_fcn_file() const
Definition: ov-fcn.h:73
std::string name() const
Definition: ov-fcn.h:206
bool empty() const
Definition: ovl.h:115
octave_idx_type length() const
Definition: ovl.h:113
bool is_undefined() const
Definition: ov.h:595
std::string class_name() const
Definition: ov.h:1347
bool is_classdef_meta() const
Definition: ov.h:652
octave_value dump() const
Definition: ov.h:1439
bool is_defined() const
Definition: ov.h:592
octave_function * function_value(bool silent=false) const
builtin_type_t builtin_type() const
Definition: ov.h:690
std::string fcn_file_name() const
Definition: symscope.h:648
octave_value find_subfunction(const std::string &name) const
Definition: symscope.h:526
std::string dir_name() const
Definition: symscope.h:653
bool is_superiorto(const std::string &a, const std::string &b)
Definition: symtab.cc:556
std::list< std::string > parent_classes(const std::string &dispatch_type)
Definition: symtab.cc:697
std::string lookup_autoload(const std::string &nm) const
Definition: pt-eval.cc:4653
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void warning(const char *fmt,...)
Definition: error.cc:1063
void() error(const char *fmt,...)
Definition: error.cc:988
octave_value dump_function_map(const std::map< std::string, octave_value > &fcn_map)
std::string dir_sep_chars()
octave::sys::time Vlast_prompt_time
Definition: input.cc:83
bp_table & __get_bp_table__()
symbol_scope __get_current_scope__()
cdef_manager & __get_cdef_manager__()
load_path & __get_load_path__()
tree_evaluator & __get_evaluator__()
symbol_table & __get_symbol_table__()
sys::time Vlast_chdir_time
bool same_file(const std::string &file1, const std::string &file2)
Definition: lo-sysdep.cc:437
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
T * r
Definition: mx-inlines.cc:781
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:798
std::string get_dispatch_type(const octave_value_list &args)
Definition: fcn-info.cc:331
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
std::string btyp_class_name[btyp_num_types+1]
Definition: ov-base.cc:91
bool btyp_isinteger(builtin_type_t btyp)
Definition: ov-base.h:110
bool btyp_isarray(builtin_type_t btyp)
Definition: ov-base.h:116
builtin_type_t
Definition: ov-base.h:83
@ btyp_float_complex
Definition: ov-base.h:87
@ btyp_func_handle
Definition: ov-base.h:100
@ btyp_double
Definition: ov-base.h:84
@ btyp_float
Definition: ov-base.h:85
@ btyp_bool
Definition: ov-base.h:96
@ btyp_unknown
Definition: ov-base.h:101
@ btyp_num_types
Definition: ov-base.h:102
@ btyp_char
Definition: ov-base.h:97
@ btyp_complex
Definition: ov-base.h:86
octave_value load_fcn_from_file(const std::string &file_name, const std::string &dir_name="", const std::string &dispatch_type="", const std::string &package_name="", const std::string &fcn_name="", bool autoload=false)