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