GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
fcn-info.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1993-2025 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?
49static int Vignore_function_time_stamp = 1;
50
52
54fcn_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
95fcn_info::fcn_info_rep::load_class_constructor ()
96{
97 octave_value retval;
98
99 std::string dir_name;
100
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
153fcn_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
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
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
245static builtin_type_t (* build_sup_table ())[btyp_num_types]
246{
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
270std::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
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
330std::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
351fcn_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
367
368 lp.update ();
369
370 retval = xfind (search_scope, args);
371 }
372
373 return retval;
374}
375
376
377static void
378split_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
408static inline bool
409load_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
470static bool
471out_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 {
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
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 {
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
658fcn_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
701fcn_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
737fcn_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
750fcn_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
848fcn_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
863
864 lp.update ();
865
866 retval = x_builtin_find (search_scope);
867 }
868
869 return retval;
870}
871
873fcn_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
968fcn_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
1008fcn_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
1039fcn_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
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
1069fcn_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
1085void
1086fcn_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
1107fcn_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
1126dump_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
1143DEFUN (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})
1147Query or set the internal variable that controls whether Octave checks
1148the time stamp on files each time it looks up functions defined in
1149function files.
1150
1151If the internal variable is set to @qcode{"system"}, Octave will not
1152automatically recompile function files in subdirectories of
1153@file{@var{octave-home}/share/@var{version}/m} if they have changed since
1154they were last compiled, but will recompile other function files in the
1155search path if they change.
1156
1157If set to @qcode{"all"}, Octave will not recompile any function files
1158unless their definitions are removed with @code{clear}.
1159
1160If set to @qcode{"none"}, Octave will always check time stamps on files
1161to determine whether functions defined in function files need to
1162recompiled.
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
1225OCTAVE_END_NAMESPACE(octave)
bp_lines remove_all_breakpoints_from_function(const std::string &fcn_ident, bool silent=false)
Definition bp-table.cc:1119
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:107
std::string find_private_fcn(const std::string &dir, const std::string &fcn, const std::string &pack_name="")
Definition load-path.h:120
void update()
Definition load-path.cc:425
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:75
virtual bool is_anonymous_function() const
Definition ov-base.h:539
virtual octave_function * function_value(bool silent=false)
Definition ov-base.cc:935
virtual bool handles_dispatch_class(const std::string &) const
Definition ov-fcn.h:145
virtual bool is_subfunction() const
Definition ov-fcn.h:108
std::string canonical_name() const
Definition ov-fcn.h:210
std::string package_name() const
Definition ov-fcn.h:154
bool is_class_method(const std::string &cname="") const
Definition ov-fcn.h:117
virtual octave::sys::time time_checked() const
Definition ov-fcn.h:99
virtual void push_dispatch_class(const std::string &)
Definition ov-fcn.h:143
virtual bool is_classdef_constructor(const std::string &="") const
Definition ov-fcn.h:127
virtual void mark_fcn_file_up_to_date(const octave::sys::time &)
Definition ov-fcn.h:92
bool is_relative() const
Definition ov-fcn.h:206
virtual octave::sys::time time_parsed() const
Definition ov-fcn.h:96
virtual std::string fcn_file_name() const
Definition ov-fcn.h:74
virtual void mark_as_private_function(const std::string &cname="")
Definition ov-fcn.h:157
virtual bool is_system_fcn_file() const
Definition ov-fcn.h:72
std::string name() const
Definition ov-fcn.h:208
bool empty() const
Definition ovl.h:113
octave_idx_type length() const
Definition ovl.h:111
bool is_undefined() const
Definition ov.h:595
std::string class_name() const
Definition ov.h:1362
octave_function * function_value(bool silent=false) const
bool is_classdef_meta() const
Definition ov.h:652
octave_value dump() const
Definition ov.h:1454
bool is_defined() const
Definition ov.h:592
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:4740
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
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:1078
void error(const char *fmt,...)
Definition error.cc:1003
std::string get_dispatch_type(const octave_value_list &args, builtin_type_t &builtin_type)
Definition fcn-info.cc:271
octave_value dump_function_map(const std::map< std::string, octave_value > &fcn_map)
Definition fcn-info.cc:1126
octave::sys::time Vlast_prompt_time
Definition input.cc:82
tree_evaluator & __get_evaluator__()
cdef_manager & __get_cdef_manager__()
symbol_table & __get_symbol_table__()
symbol_scope __get_current_scope__()
bp_table & __get_bp_table__()
load_path & __get_load_path__()
sys::time Vlast_chdir_time
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)
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