GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
symtab.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1993-2013 John W. Eaton
4 Copyright (C) 2009 VZLU Prague, a.s.
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <sstream>
29 
30 #include "file-ops.h"
31 #include "file-stat.h"
32 #include "oct-env.h"
33 #include "oct-time.h"
34 #include "singleton-cleanup.h"
35 
36 #include "debug.h"
37 #include "defun.h"
38 #include "dirfns.h"
39 #include "input.h"
40 #include "load-path.h"
41 #include "ov-fcn.h"
42 #include "ov-usr-fcn.h"
43 #include "pager.h"
44 #include "parse.h"
45 #include "pt-arg-list.h"
46 #include "symtab.h"
47 #include "unwind-prot.h"
48 #include "utils.h"
49 
51 
53 
54 std::map<symbol_table::scope_id, symbol_table*> symbol_table::all_instances;
55 
56 std::map<std::string, octave_value> symbol_table::global_table;
57 
58 std::map<std::string, symbol_table::fcn_info> symbol_table::fcn_table;
59 
60 std::map<std::string, std::set<std::string> >
62 
63 std::map<std::string, std::list<std::string> > symbol_table::parent_map;
64 
67 
69 
71 
72 // Should Octave always check to see if function files have changed
73 // since they were last compiled?
75 
76 void
78 {
79  instance = new scope_id_cache ();
80 
82 }
83 
86 {
88 
89  // FIXME: If active_context () == -1, then it does not make much
90  // sense to use this symbol_record. This means an attempt at accessing
91  // a variable from a function that has not been called yet is
92  // happening. This should be cleared up when an implementing closures.
93 
94  return fcn && fcn->active_context () != static_cast<context_id> (-1)
95  ? fcn->active_context () : xcurrent_context;
96 }
97 
98 void
100  (std::ostream& os, const std::string& prefix) const
101 {
102  octave_value val = varval ();
103 
104  os << prefix << name;
105 
106  if (val.is_defined ())
107  {
108  os << " ["
109  << (is_local () ? "l" : "")
110  << (is_automatic () ? "a" : "")
111  << (is_formal () ? "f" : "")
112  << (is_hidden () ? "h" : "")
113  << (is_inherited () ? "i" : "")
114  << (is_global () ? "g" : "")
115  << (is_persistent () ? "p" : "")
116  << "] ";
117  val.dump (os);
118  }
119 
120  os << "\n";
121 }
122 
125 {
126  octave_value retval;
127 
128  if (is_global ())
129  retval = symbol_table::global_varval (name ());
130  else
131  {
132  retval = varval ();
133 
134  if (retval.is_undefined ())
135  {
136  // Use cached fcn_info pointer if possible.
137  if (rep->finfo)
138  retval = rep->finfo->find (args);
139  else
140  {
141  retval = symbol_table::find_function (name (), args);
142 
143  if (retval.is_defined ())
144  rep->finfo = get_fcn_info (name ());
145  }
146  }
147  }
148 
149  return retval;
150 }
151 
152 // Check the load path to see if file that defined this is still
153 // visible. If the file is no longer visible, then erase the
154 // definition and move on. If the file is visible, then we also
155 // need to check to see whether the file has changed since the the
156 // function was loaded/parsed. However, this check should only
157 // happen once per prompt (for files found from relative path
158 // elements, we also check if the working directory has changed
159 // since the last time the function was loaded/parsed).
160 //
161 // FIXME: perhaps this should be done for all loaded functions when
162 // the prompt is printed or the directory has changed, and then we
163 // would not check for it when finding symbol definitions.
164 
165 static inline bool
166 load_out_of_date_fcn (const std::string& ff, const std::string& dir_name,
167  octave_value& function,
168  const std::string& dispatch_type = std::string ())
169 {
170  bool retval = false;
171 
172  octave_function *fcn = load_fcn_from_file (ff, dir_name, dispatch_type);
173 
174  if (fcn)
175  {
176  retval = true;
177 
178  function = octave_value (fcn);
179  }
180  else
181  function = octave_value ();
182 
183  return retval;
184 }
185 
186 bool
188  const std::string& dispatch_type,
189  bool check_relative)
190 {
191  bool retval = false;
192 
193  octave_function *fcn = function.function_value (true);
194 
195  if (fcn)
196  {
197  // FIXME: we need to handle subfunctions properly here.
198 
199  if (! fcn->is_subfunction ())
200  {
201  std::string ff = fcn->fcn_file_name ();
202 
203  if (! ff.empty ())
204  {
205  octave_time tc = fcn->time_checked ();
206 
207  bool relative = check_relative && fcn->is_relative ();
208 
209  if (tc < Vlast_prompt_time
210  || (relative && tc < Vlast_chdir_time))
211  {
212  bool clear_breakpoints = false;
213  std::string nm = fcn->name ();
214 
215  bool is_same_file = false;
216 
217  std::string file;
218  std::string dir_name;
219 
220  if (check_relative)
221  {
222  int nm_len = nm.length ();
223 
225  ((nm_len > 4 && (nm.substr (nm_len-4) == ".oct"
226  || nm.substr (nm_len-4) == ".mex"))
227  || (nm_len > 2 && nm.substr (nm_len-2) == ".m")))
228  file = nm;
229  else
230  {
231  // We don't want to make this an absolute name,
232  // because load_fcn_file looks at the name to
233  // decide whether it came from a relative lookup.
234 
235  if (! dispatch_type.empty ())
236  {
237  file = load_path::find_method (dispatch_type, nm,
238  dir_name);
239 
240  if (file.empty ())
241  {
242  const std::list<std::string>& plist
243  = symbol_table::parent_classes (dispatch_type);
244  std::list<std::string>::const_iterator it
245  = plist.begin ();
246 
247  while (it != plist.end ())
248  {
249  file = load_path::find_method (*it, nm,
250  dir_name);
251  if (! file.empty ())
252  break;
253 
254  it++;
255  }
256  }
257  }
258 
259  // Maybe it's an autoload?
260  if (file.empty ())
261  file = lookup_autoload (nm);
262 
263  if (file.empty ())
264  file = load_path::find_fcn (nm, dir_name);
265  }
266 
267  if (! file.empty ())
268  is_same_file = same_file (file, ff);
269  }
270  else
271  {
272  is_same_file = true;
273  file = ff;
274  }
275 
276  if (file.empty ())
277  {
278  // Can't see this function from current
279  // directory, so we should clear it.
280 
281  function = octave_value ();
282 
283  clear_breakpoints = true;
284  }
285  else if (is_same_file)
286  {
287  // Same file. If it is out of date, then reload it.
288 
289  octave_time ottp = fcn->time_parsed ();
290  time_t tp = ottp.unix_time ();
291 
293 
294  if (! (Vignore_function_time_stamp == 2
295  || (Vignore_function_time_stamp
296  && fcn->is_system_fcn_file ())))
297  {
298  file_stat fs (ff);
299 
300  if (fs)
301  {
302  if (fs.is_newer (tp))
303  {
304  retval = load_out_of_date_fcn (ff, dir_name,
305  function,
306  dispatch_type);
307 
308  clear_breakpoints = true;
309  }
310  }
311  else
312  {
313  function = octave_value ();
314 
315  clear_breakpoints = true;
316  }
317  }
318  }
319  else
320  {
321  // Not the same file, so load the new file in
322  // place of the old.
323 
324  retval = load_out_of_date_fcn (file, dir_name, function,
325  dispatch_type);
326 
327  clear_breakpoints = true;
328  }
329 
330  // If the function has been replaced then clear any
331  // breakpoints associated with it
332  if (clear_breakpoints)
334  }
335  }
336  }
337  }
338 
339  return retval;
340 }
341 
344  (const std::string& dir_name)
345 {
346  octave_value retval;
347 
348  std::string file_name = load_path::find_private_fcn (dir_name, name);
349 
350  if (! file_name.empty ())
351  {
352  octave_function *fcn = load_fcn_from_file (file_name, dir_name);
353 
354  if (fcn)
355  {
356  std::string class_name;
357 
358  size_t pos = dir_name.find_last_of (file_ops::dir_sep_chars ());
359 
360  if (pos != std::string::npos)
361  {
362  std::string tmp = dir_name.substr (pos+1);
363 
364  if (tmp[0] == '@')
365  class_name = tmp.substr (1);
366  }
367 
368  fcn->mark_as_private_function (class_name);
369 
370  retval = octave_value (fcn);
371 
372  private_functions[dir_name] = retval;
373  }
374  }
375 
376  return retval;
377 }
378 
381 {
382  octave_value retval;
383 
384  std::string dir_name;
385 
386  std::string file_name = load_path::find_method (name, name, dir_name);
387 
388  if (! file_name.empty ())
389  {
390  octave_function *fcn = load_fcn_from_file (file_name, dir_name, name);
391 
392  if (fcn)
393  {
394  retval = octave_value (fcn);
395 
396  class_constructors[name] = retval;
397  }
398  }
399 
400  return retval;
401 }
402 
405  (const std::string& dispatch_type)
406 {
407  octave_value retval;
408 
409  if (name == dispatch_type)
410  retval = load_class_constructor ();
411  else
412  {
413  std::string dir_name;
414 
415  std::string file_name = load_path::find_method (dispatch_type, name,
416  dir_name);
417 
418  if (! file_name.empty ())
419  {
420  octave_function *fcn = load_fcn_from_file (file_name, dir_name,
421  dispatch_type);
422 
423  if (fcn)
424  {
425  retval = octave_value (fcn);
426 
427  class_methods[dispatch_type] = retval;
428  }
429  }
430 
431  if (retval.is_undefined ())
432  {
433  // Search parent classes
434 
435  const std::list<std::string>& plist = parent_classes (dispatch_type);
436 
437  std::list<std::string>::const_iterator it = plist.begin ();
438 
439  while (it != plist.end ())
440  {
441  retval = find_method (*it);
442 
443  if (retval.is_defined ())
444  {
445  class_methods[dispatch_type] = retval;
446  break;
447  }
448 
449  it++;
450  }
451  }
452  }
453 
454  return retval;
455 }
456 
457 void
459  (scope_id scope, const std::string& class_name)
460 {
461  scope_val_iterator p = subfunctions.find (scope);
462 
463  if (p != subfunctions.end ())
464  {
465  octave_function *fcn = p->second.function_value ();
466 
467  if (fcn)
468  fcn->mark_as_private_function (class_name);
469  }
470 }
471 
472 void
474 {
475  if (dispatch_map.empty ())
476  os << "dispatch: " << name << " is not overloaded" << std::endl;
477  else
478  {
479  os << "Overloaded function " << name << ":\n\n";
480 
481  for (dispatch_map_const_iterator p = dispatch_map.begin ();
482  p != dispatch_map.end (); p++)
483  os << " " << name << " (" << p->first << ", ...) -> "
484  << p->second << " (" << p->first << ", ...)\n";
485 
486  os << std::endl;
487  }
488 }
489 
490 std::string
492 {
493  std::string retval;
494 
495  if (! dispatch_map.empty ())
496  {
497  retval = "Overloaded function:\n\n";
498 
499  for (dispatch_map_const_iterator p = dispatch_map.begin ();
500  p != dispatch_map.end (); p++)
501  retval += " " + p->second + " (" + p->first + ", ...)\n\n";
502  }
503 
504  return retval;
505 }
506 
507 // :-) JWE, can you parse this? Returns a 2D array with second dimension equal
508 // to btyp_num_types (static constant). Only the leftmost dimension can be
509 // variable in C/C++. Typedefs are boring.
510 
512 {
513  static builtin_type_t sup_table[btyp_num_types][btyp_num_types];
514  for (int i = 0; i < btyp_num_types; i++)
515  for (int j = 0; j < btyp_num_types; j++)
516  {
517  builtin_type_t ityp = static_cast<builtin_type_t> (i);
518  builtin_type_t jtyp = static_cast<builtin_type_t> (j);
519  // FIXME: Is this really right?
520  bool use_j =
521  (jtyp == btyp_func_handle || ityp == btyp_bool
522  || (btyp_isarray (ityp)
523  && (! btyp_isarray (jtyp)
524  || (btyp_isinteger (jtyp) && ! btyp_isinteger (ityp))
525  || ((ityp == btyp_double || ityp == btyp_complex
526  || ityp == btyp_char)
527  && (jtyp == btyp_float
528  || jtyp == btyp_float_complex)))));
529 
530  sup_table[i][j] = use_j ? jtyp : ityp;
531  }
532 
533  return sup_table;
534 }
535 
536 std::string
538  builtin_type_t& builtin_type)
539 {
540  static builtin_type_t (*sup_table)[btyp_num_types] = build_sup_table ();
541  std::string dispatch_type;
542 
543  int n = args.length ();
544 
545  if (n > 0)
546  {
547  int i = 0;
548  builtin_type = args(0).builtin_type ();
549  if (builtin_type != btyp_unknown)
550  {
551  for (i = 1; i < n; i++)
552  {
553  builtin_type_t bti = args(i).builtin_type ();
554  if (bti != btyp_unknown)
555  builtin_type = sup_table[builtin_type][bti];
556  else
557  {
558  builtin_type = btyp_unknown;
559  break;
560  }
561  }
562  }
563 
564  if (builtin_type == btyp_unknown)
565  {
566  // There's a non-builtin class in the argument list.
567  dispatch_type = args(i).class_name ();
568 
569  for (int j = i+1; j < n; j++)
570  {
571  octave_value arg = args(j);
572 
573  if (arg.builtin_type () == btyp_unknown)
574  {
575  std::string cname = arg.class_name ();
576 
577  // Only switch to type of ARG if it is marked superior
578  // to the current DISPATCH_TYPE.
579  if (! symbol_table::is_superiorto (dispatch_type, cname)
580  && symbol_table::is_superiorto (cname, dispatch_type))
581  dispatch_type = cname;
582  }
583  }
584  }
585  else
586  dispatch_type = btyp_class_name[builtin_type];
587  }
588  else
589  builtin_type = btyp_unknown;
590 
591  return dispatch_type;
592 }
593 
594 std::string
596 {
597  builtin_type_t builtin_type;
598  return get_dispatch_type (args, builtin_type);
599 }
600 
601 // Find the definition of NAME according to the following precedence
602 // list:
603 //
604 // variable
605 // subfunction
606 // private function
607 // class method
608 // class constructor
609 // legacy dispatch
610 // command-line function
611 // autoload function
612 // function on the path
613 // built-in function
614 //
615 // Matlab documentation states that constructors have higher precedence
616 // than methods, but that does not seem to be the case.
617 
620  bool local_funcs)
621 {
622  octave_value retval = xfind (args, local_funcs);
623 
624  if (! (error_state || retval.is_defined ()))
625  {
626  // It is possible that the user created a file on the fly since
627  // the last prompt or chdir, so try updating the load path and
628  // searching again.
629 
631 
632  retval = xfind (args, local_funcs);
633  }
634 
635  return retval;
636 }
637 
640  bool local_funcs)
641 {
642  if (local_funcs)
643  {
644  // Subfunction. I think it only makes sense to check for
645  // subfunctions if we are currently executing a function defined
646  // from a .m file.
647 
649 
650  for (scope_id scope = xcurrent_scope; scope >= 0;)
651  {
652  scope_val_iterator r = subfunctions.find (scope);
653  if (r != subfunctions.end ())
654  {
655  // FIXME: out-of-date check here.
656 
657  return r->second;
658  }
659 
660  octave_user_function *scope_curr_fcn = get_curr_fcn (scope);
661  if (scope_curr_fcn)
662  scope = scope_curr_fcn->parent_fcn_scope ();
663  else
664  scope = -1;
665  }
666 
667  // Private function.
668 
669  if (curr_fcn)
670  {
671  std::string dir_name = curr_fcn->dir_name ();
672 
673  if (! dir_name.empty ())
674  {
675  str_val_iterator q = private_functions.find (dir_name);
676 
677  if (q == private_functions.end ())
678  {
679  octave_value val = load_private_function (dir_name);
680 
681  if (val.is_defined ())
682  return val;
683  }
684  else
685  {
686  octave_value& fval = q->second;
687 
688  if (fval.is_defined ())
689  out_of_date_check (fval, "", false);
690 
691  if (fval.is_defined ())
692  return fval;
693  else
694  {
695  octave_value val = load_private_function (dir_name);
696 
697  if (val.is_defined ())
698  return val;
699  }
700  }
701  }
702  }
703  }
704 
705  // Class methods.
706 
707  if (! args.empty ())
708  {
709  std::string dispatch_type = get_dispatch_type (args);
710 
711  octave_value fcn = find_method (dispatch_type);
712 
713  if (fcn.is_defined ())
714  return fcn;
715  }
716 
717  // Class constructors. The class name and function name are the same.
718 
719  str_val_iterator q = class_constructors.find (name);
720 
721  if (q == class_constructors.end ())
722  {
723  octave_value val = load_class_constructor ();
724 
725  if (val.is_defined ())
726  return val;
727  }
728  else
729  {
730  octave_value& fval = q->second;
731 
732  if (fval.is_defined ())
733  out_of_date_check (fval, name);
734 
735  if (fval.is_defined ())
736  return fval;
737  else
738  {
739  octave_value val = load_class_constructor ();
740 
741  if (val.is_defined ())
742  return val;
743  }
744  }
745 
746  // Legacy dispatch.
747 
748  if (! args.empty () && ! dispatch_map.empty ())
749  {
750  std::string dispatch_type = args(0).type_name ();
751 
752  std::string fname;
753 
754  dispatch_map_iterator p = dispatch_map.find (dispatch_type);
755 
756  if (p == dispatch_map.end ())
757  p = dispatch_map.find ("any");
758 
759  if (p != dispatch_map.end ())
760  {
761  fname = p->second;
762 
763  octave_value fcn
764  = symbol_table::find_function (fname, args);
765 
766  if (fcn.is_defined ())
767  return fcn;
768  }
769  }
770 
771  // Command-line function.
772 
773  if (cmdline_function.is_defined ())
774  return cmdline_function;
775 
776  // Autoload?
777 
778  octave_value fcn = find_autoload ();
779 
780  if (fcn.is_defined ())
781  return fcn;
782 
783  // Function on the path.
784 
785  fcn = find_user_function ();
786 
787  if (fcn.is_defined ())
788  return fcn;
789 
790  // Built-in function (might be undefined).
791 
792  return built_in_function;
793 }
794 
795 // Find the definition of NAME according to the following precedence
796 // list:
797 //
798 // built-in function
799 // function on the path
800 // autoload function
801 // command-line function
802 // private function
803 // subfunction
804 
805 // This function is used to implement the "builtin" function, which
806 // searches for "built-in" functions. In Matlab, "builtin" only
807 // returns functions that are actually built-in to the interpreter.
808 // But since the list of built-in functions is different in Octave and
809 // Matlab, we also search up the precedence list until we find
810 // something that matches. Note that we are only searching by name,
811 // so class methods, constructors, and legacy dispatch functions are
812 // skipped.
813 
816 {
817  octave_value retval = x_builtin_find ();
818 
819  if (! retval.is_defined ())
820  {
821  // It is possible that the user created a file on the fly since
822  // the last prompt or chdir, so try updating the load path and
823  // searching again.
824 
826 
827  retval = x_builtin_find ();
828  }
829 
830  return retval;
831 }
832 
835 {
836  // Built-in function.
837  if (built_in_function.is_defined ())
838  return built_in_function;
839 
840  // Function on the path.
841 
843 
844  if (fcn.is_defined ())
845  return fcn;
846 
847  // Autoload?
848 
849  fcn = find_autoload ();
850 
851  if (fcn.is_defined ())
852  return fcn;
853 
854  // Command-line function.
855 
856  if (cmdline_function.is_defined ())
857  return cmdline_function;
858 
859  // Private function.
860 
862 
863  if (curr_fcn)
864  {
865  std::string dir_name = curr_fcn->dir_name ();
866 
867  if (! dir_name.empty ())
868  {
869  str_val_iterator q = private_functions.find (dir_name);
870 
871  if (q == private_functions.end ())
872  {
873  octave_value val = load_private_function (dir_name);
874 
875  if (val.is_defined ())
876  return val;
877  }
878  else
879  {
880  octave_value& fval = q->second;
881 
882  if (fval.is_defined ())
883  out_of_date_check (fval);
884 
885  if (fval.is_defined ())
886  return fval;
887  else
888  {
889  octave_value val = load_private_function (dir_name);
890 
891  if (val.is_defined ())
892  return val;
893  }
894  }
895  }
896  }
897 
898  // Subfunction. I think it only makes sense to check for
899  // subfunctions if we are currently executing a function defined
900  // from a .m file.
901 
902  for (scope_id scope = xcurrent_scope; scope >= 0;)
903  {
904  scope_val_iterator r = subfunctions.find (scope);
905  if (r != subfunctions.end ())
906  {
907  // FIXME: out-of-date check here.
908 
909  return r->second;
910  }
911 
912  octave_user_function *scope_curr_fcn = get_curr_fcn (scope);
913  if (scope_curr_fcn)
914  scope = scope_curr_fcn->parent_fcn_scope ();
915  else
916  scope = -1;
917  }
918 
919  return octave_value ();
920 }
921 
924  (const std::string& dispatch_type)
925 {
926  octave_value retval;
927 
928  str_val_iterator q = class_methods.find (dispatch_type);
929 
930  if (q == class_methods.end ())
931  {
932  octave_value val = load_class_method (dispatch_type);
933 
934  if (val.is_defined ())
935  return val;
936  }
937  else
938  {
939  octave_value& fval = q->second;
940 
941  if (fval.is_defined ())
942  out_of_date_check (fval, dispatch_type);
943 
944  if (fval.is_defined ())
945  return fval;
946  else
947  {
948  octave_value val = load_class_method (dispatch_type);
949 
950  if (val.is_defined ())
951  return val;
952  }
953  }
954 
955  return retval;
956 }
957 
960 {
961  octave_value retval;
962 
963  // Autoloaded function.
964 
965  if (autoload_function.is_defined ())
966  out_of_date_check (autoload_function);
967 
968  if (! autoload_function.is_defined ())
969  {
970  std::string file_name = lookup_autoload (name);
971 
972  if (! file_name.empty ())
973  {
974  size_t pos = file_name.find_last_of (file_ops::dir_sep_chars ());
975 
976  std::string dir_name = file_name.substr (0, pos);
977 
978  octave_function *fcn = load_fcn_from_file (file_name, dir_name,
979  "", name, true);
980 
981  if (fcn)
982  autoload_function = octave_value (fcn);
983  }
984  }
985 
986  return autoload_function;
987 }
988 
991 {
992  // Function on the path.
993 
994  if (function_on_path.is_defined ())
995  out_of_date_check (function_on_path);
996 
997  if (! (error_state || function_on_path.is_defined ()))
998  {
999  std::string dir_name;
1000 
1001  std::string file_name = load_path::find_fcn (name, dir_name);
1002 
1003  if (! file_name.empty ())
1004  {
1005  octave_function *fcn = load_fcn_from_file (file_name, dir_name);
1006 
1007  if (fcn)
1008  function_on_path = octave_value (fcn);
1009  }
1010  }
1011 
1012  return function_on_path;
1013 }
1014 
1015 // Insert INF_CLASS in the set of class names that are considered
1016 // inferior to SUP_CLASS. Return FALSE if INF_CLASS is currently
1017 // marked as superior to SUP_CLASS.
1018 
1019 bool
1020 symbol_table::set_class_relationship (const std::string& sup_class,
1021  const std::string& inf_class)
1022 {
1023  if (is_superiorto (inf_class, sup_class))
1024  return false;
1025 
1026  // If sup_class doesn't have an entry in the precedence table,
1027  // this will automatically create it, and associate to it a
1028  // singleton set {inf_class} of inferior classes.
1029  class_precedence_table[sup_class].insert (inf_class);
1030 
1031  return true;
1032 }
1033 
1034 // Has class A been marked as superior to class B? Also returns
1035 // TRUE if B has been marked as inferior to A, since we only keep
1036 // one table, and convert inferiorto information to a superiorto
1037 // relationship. Two calls are required to determine whether there
1038 // is no relationship between two classes:
1039 //
1040 // if (symbol_table::is_superiorto (a, b))
1041 // // A is superior to B, or B has been marked inferior to A.
1042 // else if (symbol_table::is_superiorto (b, a))
1043 // // B is superior to A, or A has been marked inferior to B.
1044 // else
1045 // // No relation.
1046 
1047 bool
1048 symbol_table::is_superiorto (const std::string& a, const std::string& b)
1049 {
1051  // If a has no entry in the precedence table, return false
1052  if (p == class_precedence_table.end ())
1053  return false;
1054 
1055  const std::set<std::string>& inferior_classes = p->second;
1056  std::set<std::string>::const_iterator q = inferior_classes.find (b);
1057  return (q != inferior_classes.end ());
1058 }
1059 
1060 static std::string
1062 {
1063  const octave_function *f = fcn.function_value ();
1064 
1065  return f ? f->fcn_file_name () : std::string ();
1066 }
1067 
1068 void
1070  const std::string& prefix) const
1071 {
1072  os << prefix << name
1073  << " ["
1074  << (cmdline_function.is_defined () ? "c" : "")
1075  << (built_in_function.is_defined () ? "b" : "")
1076  << "]\n";
1077 
1078  std::string tprefix = prefix + " ";
1079 
1080  if (autoload_function.is_defined ())
1081  os << tprefix << "autoload: "
1082  << fcn_file_name (autoload_function) << "\n";
1083 
1084  if (function_on_path.is_defined ())
1085  os << tprefix << "function from path: "
1086  << fcn_file_name (function_on_path) << "\n";
1087 
1088  if (! subfunctions.empty ())
1089  {
1090  for (scope_val_const_iterator p = subfunctions.begin ();
1091  p != subfunctions.end (); p++)
1092  os << tprefix << "subfunction: " << fcn_file_name (p->second)
1093  << " [" << p->first << "]\n";
1094  }
1095 
1096  if (! private_functions.empty ())
1097  {
1098  for (str_val_const_iterator p = private_functions.begin ();
1099  p != private_functions.end (); p++)
1100  os << tprefix << "private: " << fcn_file_name (p->second)
1101  << " [" << p->first << "]\n";
1102  }
1103 
1104  if (! class_constructors.empty ())
1105  {
1106  for (str_val_const_iterator p = class_constructors.begin ();
1107  p != class_constructors.end (); p++)
1108  os << tprefix << "constructor: " << fcn_file_name (p->second)
1109  << " [" << p->first << "]\n";
1110  }
1111 
1112  if (! class_methods.empty ())
1113  {
1114  for (str_val_const_iterator p = class_methods.begin ();
1115  p != class_methods.end (); p++)
1116  os << tprefix << "method: " << fcn_file_name (p->second)
1117  << " [" << p->first << "]\n";
1118  }
1119 
1120  if (! dispatch_map.empty ())
1121  {
1122  for (dispatch_map_const_iterator p = dispatch_map.begin ();
1123  p != dispatch_map.end (); p++)
1124  os << tprefix << "dispatch: " << fcn_file_name (p->second)
1125  << " [" << p->first << "]\n";
1126  }
1127 }
1128 
1129 void
1130 symbol_table::install_nestfunction (const std::string& name,
1131  const octave_value& fcn,
1132  scope_id parent_scope)
1133 {
1134  install_subfunction (name, fcn, parent_scope);
1135 
1136  // Stash the nest_parent for resolving variables after parsing is done.
1137  octave_function *fv = fcn.function_value ();
1138 
1139  symbol_table *fcn_table_loc = get_instance (fv->scope ());
1140 
1141  symbol_table *parent_table = get_instance (parent_scope);
1142 
1143  parent_table->add_nest_child (*fcn_table_loc);
1144 }
1145 
1147 symbol_table::find (const std::string& name,
1148  const octave_value_list& args,
1149  bool skip_variables,
1150  bool local_funcs)
1151 {
1153 
1154  return inst
1155  ? inst->do_find (name, args, skip_variables, local_funcs)
1156  : octave_value ();
1157 }
1158 
1160 symbol_table::builtin_find (const std::string& name)
1161 {
1163 
1164  return inst ? inst->do_builtin_find (name) : octave_value ();
1165 }
1166 
1168 symbol_table::find_function (const std::string& name,
1169  const octave_value_list& args,
1170  bool local_funcs)
1171 {
1172  octave_value retval;
1173 
1174  if (! name.empty () && name[0] == '@')
1175  {
1176  // Look for a class specific function.
1177  std::string dispatch_type =
1178  name.substr (1, name.find_first_of (file_ops::dir_sep_str ()) - 1);
1179 
1180  std::string method =
1181  name.substr (name.find_last_of (file_ops::dir_sep_str ()) + 1,
1182  std::string::npos);
1183 
1184  retval = find_method (method, dispatch_type);
1185  }
1186  else
1187  {
1188  size_t pos = name.find_first_of (Vfilemarker);
1189 
1190  if (pos == std::string::npos)
1191  retval = find (name, args, true, local_funcs);
1192  else
1193  {
1194  std::string fcn_scope = name.substr (0, pos);
1195  scope_id stored_scope = xcurrent_scope;
1197  octave_value parent = find_function (name.substr (0, pos),
1198  octave_value_list (), false);
1199 
1200  if (parent.is_defined ())
1201  {
1202  octave_function *parent_fcn = parent.function_value ();
1203 
1204  if (parent_fcn)
1205  {
1206  xcurrent_scope = parent_fcn->scope ();
1207 
1208  if (xcurrent_scope > 1)
1209  retval = find_function (name.substr (pos + 1), args);
1210  }
1211  }
1212 
1213  xcurrent_scope = stored_scope;
1214  }
1215  }
1216 
1217  return retval;
1218 }
1219 
1220 void
1221 symbol_table::dump (std::ostream& os, scope_id scope)
1222 {
1223  if (scope == xglobal_scope)
1224  dump_global (os);
1225  else
1226  {
1227  symbol_table *inst = get_instance (scope, false);
1228 
1229  if (inst)
1230  {
1231  os << "*** dumping symbol table scope " << scope
1232  << " (" << inst->table_name << ")\n\n";
1233 
1234  std::map<std::string, octave_value> sfuns
1236 
1237  if (! sfuns.empty ())
1238  {
1239  os << " subfunctions defined in this scope:\n";
1240 
1241  for (std::map<std::string,
1242  octave_value>::const_iterator p = sfuns.begin ();
1243  p != sfuns.end (); p++)
1244  os << " " << p->first << "\n";
1245 
1246  os << "\n";
1247  }
1248 
1249  inst->do_dump (os);
1250  }
1251  }
1252 }
1253 
1254 void
1255 symbol_table::dump_global (std::ostream& os)
1256 {
1257  if (! global_table.empty ())
1258  {
1259  os << "*** dumping global symbol table\n\n";
1260 
1261  for (global_table_const_iterator p = global_table.begin ();
1262  p != global_table.end (); p++)
1263  {
1264  std::string nm = p->first;
1265  octave_value val = p->second;
1266 
1267  os << " " << nm << " ";
1268  val.dump (os);
1269  os << "\n";
1270  }
1271  }
1272 }
1273 
1274 void
1276 {
1277  if (! fcn_table.empty ())
1278  {
1279  os << "*** dumping globally visible functions from symbol table\n"
1280  << " (c=commandline, b=built-in)\n\n";
1281 
1282  for (fcn_table_const_iterator p = fcn_table.begin ();
1283  p != fcn_table.end (); p++)
1284  p->second.dump (os, " ");
1285 
1286  os << "\n";
1287  }
1288 }
1289 
1290 void
1292  const std::string& dir_name)
1293 {
1294  // FIXME: is this the best way to do this? Maybe it would be
1295  // better if we had a map from scope to list of subfunctions
1296  // stored with the function. Do we?
1297 
1298  for (fcn_table_const_iterator p = fcn_table.begin ();
1299  p != fcn_table.end (); p++)
1300  {
1301  std::pair<std::string, octave_value> tmp
1302  = p->second.subfunction_defined_in_scope (scope);
1303 
1304  std::string nm = tmp.first;
1305 
1306  if (! nm.empty ())
1307  {
1308  octave_value& fcn = tmp.second;
1309 
1311 
1312  if (f)
1313  f->stash_dir_name (dir_name);
1314  }
1315  }
1316 }
1317 
1319 symbol_table::do_find (const std::string& name,
1320  const octave_value_list& args,
1321  bool skip_variables,
1322  bool local_funcs)
1323 {
1324  octave_value retval;
1325 
1326  // Variable.
1327 
1328  if (! skip_variables)
1329  {
1330  table_iterator p = table.find (name);
1331 
1332  if (p != table.end ())
1333  {
1334  symbol_record sr = p->second;
1335 
1336  if (sr.is_global ())
1337  return symbol_table::global_varval (name);
1338  else
1339  {
1340  octave_value val = sr.varval ();
1341 
1342  if (val.is_defined ())
1343  return val;
1344  }
1345  }
1346  }
1347 
1348  fcn_table_iterator p = fcn_table.find (name);
1349 
1350  if (p != fcn_table.end ())
1351  return p->second.find (args, local_funcs);
1352  else
1353  {
1354  fcn_info finfo (name);
1355 
1356  octave_value fcn = finfo.find (args, local_funcs);
1357 
1358  if (fcn.is_defined ())
1359  fcn_table[name] = finfo;
1360 
1361  return fcn;
1362  }
1363 
1364  return retval;
1365 }
1366 
1368 symbol_table::do_builtin_find (const std::string& name)
1369 {
1370  octave_value retval;
1371 
1372  fcn_table_iterator p = fcn_table.find (name);
1373 
1374  if (p != fcn_table.end ())
1375  return p->second.builtin_find ();
1376  else
1377  {
1378  fcn_info finfo (name);
1379 
1380  octave_value fcn = finfo.builtin_find ();
1381 
1382  if (fcn.is_defined ())
1383  fcn_table[name] = finfo;
1384 
1385  return fcn;
1386  }
1387 
1388  return retval;
1389 }
1390 
1391 std::list<workspace_element>
1393 {
1394  std::list<workspace_element> retval;
1395 
1396  for (table_const_iterator p = table.begin (); p != table.end (); p++)
1397  {
1398  std::string nm = p->first;
1399  symbol_record sr = p->second;
1400 
1401  if (! sr.is_hidden ())
1402  {
1403  octave_value val = sr.varval ();
1404 
1405  if (val.is_defined ())
1406  {
1407  dim_vector dv = val.dims ();
1408 
1409  char storage = ' ';
1410  if (sr.is_global ())
1411  storage = 'g';
1412  else if (sr.is_persistent ())
1413  storage = 'p';
1414  else if (sr.is_automatic ())
1415  storage = 'a';
1416  else if (sr.is_formal ())
1417  storage = 'f';
1418  else if (sr.is_hidden ())
1419  storage = 'h';
1420  else if (sr.is_inherited ())
1421  storage = 'i';
1422 
1423  std::ostringstream buf;
1424  val.short_disp (buf);
1425  std::string short_disp_str = buf.str ();
1426 
1427  workspace_element elt (storage, nm, val.class_name (),
1428  short_disp_str, dv.str (),
1429  val.is_complex_type ());
1430 
1431  retval.push_back (elt);
1432  }
1433  }
1434  }
1435 
1436  return retval;
1437 }
1438 
1439 void
1440 symbol_table::do_dump (std::ostream& os)
1441 {
1442  if (! persistent_table.empty ())
1443  {
1444  os << " persistent variables in this scope:\n\n";
1445 
1447  p != persistent_table.end (); p++)
1448  {
1449  std::string nm = p->first;
1450  octave_value val = p->second;
1451 
1452  os << " " << nm << " ";
1453  val.dump (os);
1454  os << "\n";
1455  }
1456 
1457  os << "\n";
1458  }
1459 
1460  if (! table.empty ())
1461  {
1462  os << " other symbols in this scope (l=local; a=auto; f=formal\n"
1463  << " h=hidden; i=inherited; g=global; p=persistent)\n\n";
1464 
1465  for (table_const_iterator p = table.begin (); p != table.end (); p++)
1466  p->second.dump (os, " ");
1467 
1468  os << "\n";
1469  }
1470 }
1471 
1473 {
1474  clear_all (true);
1475 
1476  // Delete all possibly remaining scopes.
1477  for (all_instances_iterator iter = all_instances.begin ();
1478  iter != all_instances.end (); iter++)
1479  {
1480  // First zero the table entry to avoid possible duplicate delete.
1481  symbol_table *inst = iter->second;
1482  iter->second = 0;
1483 
1484  // Now delete the scope. Note that there may be side effects, such as
1485  // deleting other scopes.
1486  delete inst;
1487  }
1488 
1489  global_table.clear ();
1490  fcn_table.clear ();
1491  class_precedence_table.clear ();
1492  parent_map.clear ();
1493  all_instances.clear ();
1494 }
1495 
1496 void
1498 {
1499  if (nest_parent || nest_children.size ())
1501 
1502  if (nest_parent)
1503  {
1504  // fix bad symbol_records
1505  for (table_iterator ti = table.begin (); ti != table.end (); ++ti)
1506  {
1507  symbol_record &ours = ti->second;
1508  symbol_record parents;
1509  if (! ours.is_formal ()
1510  && nest_parent->look_nonlocal (ti->first, parents))
1511  {
1512  if (ours.is_global () || ours.is_persistent ())
1513  ::error ("global and persistent may only be used in the topmost level in which a nested variable is used");
1514 
1515  if (! ours.is_formal ())
1516  {
1517  ours.invalidate ();
1518  ti->second = parents;
1519  }
1520  }
1521  else
1522  ours.set_curr_fcn (curr_fcn);
1523  }
1524  }
1525  else if (nest_children.size ())
1526  {
1527  static_workspace = true;
1528  for (table_iterator ti = table.begin (); ti != table.end (); ++ti)
1529  ti->second.set_curr_fcn (curr_fcn);
1530  }
1531 
1532  for (std::vector<symbol_table*>::iterator iter = nest_children.begin ();
1533  iter != nest_children.end (); ++iter)
1534  (*iter)->do_update_nest ();
1535 }
1536 
1537 DEFUN (ignore_function_time_stamp, args, nargout,
1538  "-*- texinfo -*-\n\
1539 @deftypefn {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\
1540 @deftypefnx {Built-in Function} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})\n\
1541 Query or set the internal variable that controls whether Octave checks\n\
1542 the time stamp on files each time it looks up functions defined in\n\
1543 function files. If the internal variable is set to @qcode{\"system\"},\n\
1544 Octave will not automatically recompile function files in subdirectories of\n\
1545 @file{@var{octave-home}/lib/@var{version}} if they have changed since\n\
1546 they were last compiled, but will recompile other function files in the\n\
1547 search path if they change. If set to @qcode{\"all\"}, Octave will not\n\
1548 recompile any function files unless their definitions are removed with\n\
1549 @code{clear}. If set to @qcode{\"none\"}, Octave will always check time\n\
1550 stamps on files to determine whether functions defined in function files\n\
1551 need to recompiled.\n\
1552 @end deftypefn")
1553 {
1554  octave_value retval;
1555 
1556  int nargin = args.length ();
1557 
1558  if (nargout > 0 || nargin == 0)
1559  {
1560  switch (Vignore_function_time_stamp)
1561  {
1562  case 1:
1563  retval = "system";
1564  break;
1565 
1566  case 2:
1567  retval = "all";
1568  break;
1569 
1570  default:
1571  retval = "none";
1572  break;
1573  }
1574  }
1575 
1576  if (nargin == 1)
1577  {
1578  std::string sval = args(0).string_value ();
1579 
1580  if (! error_state)
1581  {
1582  if (sval == "all")
1583  Vignore_function_time_stamp = 2;
1584  else if (sval == "system")
1585  Vignore_function_time_stamp = 1;
1586  else if (sval == "none")
1587  Vignore_function_time_stamp = 0;
1588  else
1589  error ("ignore_function_time_stamp: expecting argument to be \"all\", \"system\", or \"none\"");
1590  }
1591  else
1592  error ("ignore_function_time_stamp: expecting argument to be character string");
1593  }
1594  else if (nargin > 1)
1595  print_usage ();
1596 
1597  return retval;
1598 }
1599 
1600 /*
1601 %!shared old_state
1602 %! old_state = ignore_function_time_stamp ();
1603 %!test
1604 %! state = ignore_function_time_stamp ("all");
1605 %! assert (state, old_state);
1606 %! assert (ignore_function_time_stamp (), "all");
1607 %! state = ignore_function_time_stamp ("system");
1608 %! assert (state, "all");
1609 %! assert (ignore_function_time_stamp (), "system");
1610 %! ignore_function_time_stamp (old_state);
1611 
1612 ## Test input validation
1613 %!error (ignore_function_time_stamp ("all", "all"))
1614 %!error (ignore_function_time_stamp ("UNKNOWN_VALUE"))
1615 %!error (ignore_function_time_stamp (42))
1616 */
1617 
1618 DEFUN (__current_scope__, , ,
1619  "-*- texinfo -*-\n\
1620 @deftypefn {Built-in Function} {[@var{scope}, @var{context}]} __dump_symtab_info__ ()\n\
1621 Undocumented internal function.\n\
1622 @end deftypefn")
1623 {
1624  octave_value_list retval;
1625 
1626  retval(1) = symbol_table::current_context ();
1627  retval(0) = symbol_table::current_scope ();
1628 
1629  return retval;
1630 }
1631 
1632 DEFUN (__dump_symtab_info__, args, ,
1633  "-*- texinfo -*-\n\
1634 @deftypefn {Built-in Function} {} __dump_symtab_info__ ()\n\
1635 @deftypefnx {Built-in Function} {} __dump_symtab_info__ (@var{scope})\n\
1636 @deftypefnx {Built-in Function} {} __dump_symtab_info__ (\"scopes\")\n\
1637 @deftypefnx {Built-in Function} {} __dump_symtab_info__ (\"functions\")\n\
1638 Undocumented internal function.\n\
1639 @end deftypefn")
1640 {
1641  octave_value retval;
1642 
1643  int nargin = args.length ();
1644 
1645  if (nargin == 0)
1646  {
1648 
1650 
1651  std::list<symbol_table::scope_id> lst = symbol_table::scopes ();
1652 
1653  for (std::list<symbol_table::scope_id>::const_iterator p = lst.begin ();
1654  p != lst.end (); p++)
1656  }
1657  else if (nargin == 1)
1658  {
1659  octave_value arg = args(0);
1660 
1661  if (arg.is_string ())
1662  {
1663  std::string s_arg = arg.string_value ();
1664 
1665  if (s_arg == "scopes")
1666  {
1667  std::list<symbol_table::scope_id> lst = symbol_table::scopes ();
1668 
1669  RowVector v (lst.size ());
1670 
1671  octave_idx_type k = 0;
1672 
1673  for (std::list<symbol_table::scope_id>::const_iterator
1674  p = lst.begin (); p != lst.end (); p++)
1675  v.xelem (k++) = *p;
1676 
1677  retval = v;
1678  }
1679  else if (s_arg == "functions")
1680  {
1682  }
1683  else
1684  error ("__dump_symtab_info__: expecting \"functions\" or \"scopes\"");
1685  }
1686  else
1687  {
1688  int s = arg.int_value ();
1689 
1690  if (! error_state)
1692  else
1693  error ("__dump_symtab_info__: expecting string or scope id");
1694  }
1695  }
1696  else
1697  print_usage ();
1698 
1699  return retval;
1700 }
1701 
1702 #if 0
1703 
1704 // FIXME: should we have functions like this in Octave?
1705 
1706 DEFUN (set_variable, args, , "set_variable (NAME, VALUE)")
1707 {
1708  octave_value retval;
1709 
1710  if (args.length () == 2)
1711  {
1712  std::string name = args(0).string_value ();
1713 
1714  if (! error_state)
1715  symbol_table::assign (name, args(1));
1716  else
1717  error ("set_variable: expecting variable name as first argument");
1718  }
1719  else
1720  print_usage ();
1721 
1722  return retval;
1723 }
1724 
1725 DEFUN (variable_value, args, , "VALUE = variable_value (NAME)")
1726 {
1727  octave_value retval;
1728 
1729  if (args.length () == 1)
1730  {
1731  std::string name = args(0).string_value ();
1732 
1733  if (! error_state)
1734  {
1735  retval = symbol_table::varval (name);
1736 
1737  if (retval.is_undefined ())
1738  error ("variable_value: '%s' is not a variable in the current scope",
1739  name.c_str ());
1740  }
1741  else
1742  error ("variable_value: expecting variable name as first argument");
1743  }
1744  else
1745  print_usage ();
1746 
1747  return retval;
1748 }
1749 #endif
1750 
1751 
1752 /*
1753 bug #34497: 'clear -f' does not work for command line functions
1754 
1755 This test relies on bar being a core function that is implemented in an m-file.
1756 If the first assert fails, this is no longer the case and the tests need to be
1757 updated to use some other function.
1758 
1759 %!assert (! strcmp (which ("bar"), ""));
1760 
1761 %!function x = bar ()
1762 %! x = 5;
1763 %!endfunction
1764 %!test
1765 %! assert (bar == 5);
1766 %! assert (strcmp (which ("bar"), ""));
1767 %! clear -f bar;
1768 %! assert (! strcmp (which ("bar"), ""));
1769 
1770 %!function x = bar ()
1771 %! x = 5;
1772 %!endfunction
1773 %!test
1774 %! assert (bar == 5);
1775 %! assert (strcmp (which ("bar"), ""));
1776 %! clear bar;
1777 %! assert (! strcmp (which ("bar"), ""));
1778  */