GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-usr-fcn.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-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 <sstream>
31 
32 #include "file-info.h"
33 #include "file-ops.h"
34 #include "file-stat.h"
35 #include "str-vec.h"
36 
37 #include "builtin-defun-decls.h"
38 #include "defaults.h"
39 #include "Cell.h"
40 #include "defun.h"
41 #include "error.h"
42 #include "errwarn.h"
43 #include "input.h"
44 #include "ovl.h"
45 #include "ov-usr-fcn.h"
46 #include "ov.h"
47 #include "pager.h"
48 #include "pt-eval.h"
49 #include "pt-jump.h"
50 #include "pt-misc.h"
51 #include "pt-pr-code.h"
52 #include "pt-stmt.h"
53 #include "pt-walk.h"
54 #include "symtab.h"
55 #include "interpreter-private.h"
56 #include "interpreter.h"
57 #include "unwind-prot.h"
58 #include "utils.h"
59 #include "parse.h"
60 #include "profiler.h"
61 #include "variables.h"
62 #include "ov-fcn-handle.h"
63 
64 // Whether to optimize subsasgn method calls.
65 static bool Voptimize_subsasgn_calls = true;
66 
68 {
69  // This function is no longer valid, so remove the pointer to it from
70  // the corresponding scope.
71  // FIXME: would it be better to use shared/weak pointers for this job
72  // instead of storing a bare pointer in the scope object?
73  m_scope.set_user_code (nullptr);
74 
75  // FIXME: shouldn't this happen automatically when deleting cmd_list?
76  if (m_cmd_list)
77  {
78  octave::event_manager& evmgr = octave::__get_event_manager__ ();
79 
80  m_cmd_list->remove_all_breakpoints (evmgr, m_file_name);
81  }
82 
83  delete m_cmd_list;
84  delete m_file_info;
85 }
86 
87 void
89 {
90  m_file_info = new octave::file_info (m_file_name);
91 
92  octave::sys::file_stat fs (m_file_name);
93 
94  if (fs && (fs.mtime () > time_parsed ()))
95  warning ("function file '%s' changed since it was parsed",
96  m_file_name.c_str ());
97 }
98 
99 std::string
101 {
102  if (! m_file_info)
103  get_file_info ();
104 
105  return m_file_info->get_line (line);
106 }
107 
108 std::deque<std::string>
109 octave_user_code::get_code_lines (std::size_t line, std::size_t num_lines)
110 {
111  if (! m_file_info)
112  get_file_info ();
113 
114  return m_file_info->get_lines (line, num_lines);
115 }
116 
117 void
118 octave_user_code::cache_function_text (const std::string& text,
119  const octave::sys::time& timestamp)
120 {
121  if (m_file_info)
122  delete m_file_info;
123 
124  if (timestamp > time_parsed ())
125  warning ("help text for function is newer than function");
126 
127  m_file_info = new octave::file_info (text, timestamp);
128 }
129 
130 std::map<std::string, octave_value>
132 {
133  return std::map<std::string, octave_value> ();
134 }
135 
138 {
139  std::map<std::string, octave_value> m
140  = {{ "scope_info", m_scope ? m_scope.dump () : "0x0" },
141  { "m_file_name", m_file_name },
142  { "time_parsed", m_t_parsed },
143  { "time_checked", m_t_checked }
144  };
145 
146  return octave_value (m);
147 }
148 
149 
150 // User defined scripts.
151 
153  "user-defined script",
154  "user-defined script");
155 
157  : octave_user_code ()
158 { }
159 
161 (const std::string& fnm, const std::string& nm,
162  const octave::symbol_scope& scope, octave::tree_statement_list *cmds,
163  const std::string& ds)
164  : octave_user_code (fnm, nm, scope, cmds, ds)
165 {
166  if (m_cmd_list)
167  m_cmd_list->mark_as_script_body ();
168 }
169 
171 (const std::string& fnm, const std::string& nm,
172  const octave::symbol_scope& scope, const std::string& ds)
173  : octave_user_code (fnm, nm, scope, nullptr, ds)
174 { }
175 
176 // We must overload the call method so that we call the proper
177 // push_stack_frame method, which is overloaded for pointers to
178 // octave_function, octave_user_function, and octave_user_script
179 // objects.
180 
182 octave_user_script::call (octave::tree_evaluator& tw, int nargout,
183  const octave_value_list& args)
184 {
185  tw.push_stack_frame (this);
186 
187  octave::unwind_action act ([&tw] () { tw.pop_stack_frame (); });
188 
189  return execute (tw, nargout, args);
190 }
191 
193 octave_user_script::execute (octave::tree_evaluator& tw, int nargout,
194  const octave_value_list& args)
195 {
196  return tw.execute_user_script (*this, nargout, args);
197 }
198 
199 void
200 octave_user_script::accept (octave::tree_walker& tw)
201 {
202  tw.visit_octave_user_script (*this);
203 }
204 
205 // User defined functions.
206 
208  "user-defined function",
209  "user-defined function");
210 
211 // Ugh. This really needs to be simplified (code/data?
212 // extrinsic/intrinsic state?).
213 
215 (const octave::symbol_scope& scope, octave::tree_parameter_list *pl,
216  octave::tree_parameter_list *rl, octave::tree_statement_list *cl)
217  : octave_user_code ("", "", scope, cl, ""),
218  m_param_list (pl), m_ret_list (rl),
219  m_lead_comm (), m_trail_comm (),
220  m_location_line (0), m_location_column (0),
221  m_system_fcn_file (false),
222  m_num_named_args (m_param_list ? m_param_list->length () : 0),
223  m_subfunction (false), m_inline_function (false),
224  m_anonymous_function (false), m_nested_function (false),
225  m_class_constructor (none), m_class_method (none)
226 {
227  if (m_cmd_list)
228  m_cmd_list->mark_as_function_body ();
229 }
230 
232 {
233  delete m_param_list;
234  delete m_ret_list;
235  delete m_lead_comm;
236  delete m_trail_comm;
237 }
238 
240 octave_user_function::define_ret_list (octave::tree_parameter_list *t)
241 {
242  m_ret_list = t;
243 
244  return this;
245 }
246 
247 // If there is no explicit end statement at the end of the function,
248 // relocate the no_op that was generated for the end of file condition
249 // to appear on the next line after the last statement in the file, or
250 // the next line after the function keyword if there are no statements.
251 // More precisely, the new location should probably be on the next line
252 // after the end of the parameter list, but we aren't tracking that
253 // information (yet).
254 
255 void
257 {
258  if (m_cmd_list && ! m_cmd_list->empty ())
259  {
260  octave::tree_statement *last_stmt = m_cmd_list->back ();
261 
262  if (last_stmt && last_stmt->is_end_of_fcn_or_script ()
263  && last_stmt->is_end_of_file ())
264  {
265  octave::tree_statement_list::reverse_iterator
266  next_to_last_elt = m_cmd_list->rbegin ();
267 
268  next_to_last_elt++;
269 
270  int new_eof_line;
271  int new_eof_col;
272 
273  if (next_to_last_elt == m_cmd_list->rend ())
274  {
275  new_eof_line = beginning_line ();
276  new_eof_col = beginning_column ();
277  }
278  else
279  {
280  octave::tree_statement *next_to_last_stmt = *next_to_last_elt;
281 
282  new_eof_line = next_to_last_stmt->line ();
283  new_eof_col = next_to_last_stmt->column ();
284  }
285 
286  last_stmt->set_location (new_eof_line + 1, new_eof_col);
287  }
288  }
289 }
290 
291 void
293 {
294  std::map<std::string, octave_value> fcns = subfunctions ();
295 
296  if (! fcns.empty ())
297  {
298  for (auto& nm_fnval : fcns)
299  {
300  octave_user_function *f = nm_fnval.second.user_function_value ();
301 
302  if (f)
303  f->maybe_relocate_end_internal ();
304  }
305  }
306 
308 }
309 
310 void
311 octave_user_function::stash_parent_fcn_scope (const octave::symbol_scope& ps)
312 {
313  m_scope.set_parent (ps);
314 }
315 
316 std::string
318 {
319  std::ostringstream result;
320 
321  if (is_anonymous_function ())
322  result << "anonymous@" << fcn_file_name ()
323  << ':' << m_location_line << ':' << m_location_column;
324  else if (is_subfunction ())
325  result << parent_fcn_name () << '>' << name ();
326  else if (is_class_method ())
327  result << '@' << dispatch_class () << '/' << name ();
329  result << '@' << name ();
330  else if (is_inline_function ())
331  result << "inline@" << fcn_file_name ()
332  << ':' << m_location_line << ':' << m_location_column;
333  else
334  result << name ();
335 
336  return result.str ();
337 }
338 
339 void
341 {
342  if (! m_file_name.empty ())
343  {
344  // We really should stash the whole path to the file we found,
345  // when we looked it up, to avoid possible race conditions...
346  // FIXME
347  //
348  // We probably also don't need to get the library directory
349  // every time, but since this function is only called when the
350  // function file is parsed, it probably doesn't matter that
351  // much.
352 
353  std::string ff_name = octave::fcn_file_in_path (m_file_name);
354 
355  static const std::string canonical_fcn_file_dir
358  static const std::string fcn_file_dir
359  = canonical_fcn_file_dir.empty () ? octave::config::fcn_file_dir ()
360  : canonical_fcn_file_dir;
361 
362  if (fcn_file_dir == ff_name.substr (0, fcn_file_dir.length ()))
363  m_system_fcn_file = true;
364  }
365  else
366  m_system_fcn_file = false;
367 }
368 
369 void
371 {
372  m_scope.erase_subfunctions ();
373 }
374 
375 bool
377 {
378  return (m_param_list && m_param_list->takes_varargs ());
379 }
380 
381 bool
383 {
384  return (m_ret_list && m_ret_list->takes_varargs ());
385 }
386 
387 void
389 {
390  m_scope.mark_subfunctions_in_scope_as_private (cname);
391 
393 }
394 
395 void
397 {
398  m_scope.lock_subfunctions ();
399 }
400 
401 void
403 {
404  m_scope.unlock_subfunctions ();
405 }
406 
407 std::map<std::string, octave_value>
409 {
410  return m_scope.subfunctions ();
411 }
412 
413 // Find definition of final subfunction in list of subfcns:
414 //
415 // sub1>sub2>...>subN
416 
418 octave_user_function::find_subfunction (const std::string& subfcns_arg) const
419 {
420  std::string subfcns = subfcns_arg;
421 
422  std::string first_fcn = subfcns;
423 
424  std::size_t pos = subfcns.find ('>');
425 
426  if (pos == std::string::npos)
427  subfcns = "";
428  else
429  {
430  first_fcn = subfcns.substr (0, pos-1);
431  subfcns = subfcns.substr (pos+1);
432  }
433 
434  octave_value ov_fcn = m_scope.find_subfunction (first_fcn);
435 
436  if (subfcns.empty ())
437  return ov_fcn;
438 
439  octave_user_function *fcn = ov_fcn.user_function_value ();
440 
441  return fcn->find_subfunction (subfcns);
442 }
443 
444 bool
446 {
447  return m_scope.has_subfunctions ();
448 }
449 
450 void
451 octave_user_function::stash_subfunction_names (const std::list<std::string>& names)
452 {
453  m_scope.stash_subfunction_names (names);
454 }
455 
456 std::list<std::string>
458 {
459  return m_scope.subfunction_names ();
460 }
461 
464 {
465  octave_value_list retval;
466 
468 
469  if (n > 0)
470  retval = args.slice (m_num_named_args, n);
471 
472  return retval;
473 }
474 
475 // We must overload the call method so that we call the proper
476 // push_stack_frame method, which is overloaded for pointers to
477 // octave_function, octave_user_function, and octave_user_script
478 // objects.
479 
481 octave_user_function::call (octave::tree_evaluator& tw, int nargout,
482  const octave_value_list& args)
483 {
484  tw.push_stack_frame (this);
485 
486  octave::unwind_action act ([&tw] () { tw.pop_stack_frame (); });
487 
488  return execute (tw, nargout, args);
489 }
490 
492 octave_user_function::execute (octave::tree_evaluator& tw, int nargout,
493  const octave_value_list& args)
494 {
495  return tw.execute_user_function (*this, nargout, args);
496 }
497 
498 void
499 octave_user_function::accept (octave::tree_walker& tw)
500 {
501  tw.visit_octave_user_function (*this);
502 }
503 
504 octave::tree_expression *
506 {
508  panic_if (m_cmd_list->length () != 1);
509 
510  octave::tree_statement *stmt = m_cmd_list->front ();
511  return stmt->expression ();
512 }
513 
514 bool
516 {
517  bool retval = false;
520  && m_param_list->length () > 0 && ! m_param_list->varargs_only ()
521  && m_ret_list->length () == 1 && ! m_ret_list->takes_varargs ())
522  {
523  octave::tree_identifier *par1 = m_param_list->front ()->ident ();
524  octave::tree_identifier *ret1 = m_ret_list->front ()->ident ();
525  retval = par1->name () == ret1->name ();
526  }
527 
528  return retval;
529 }
530 
531 std::string
533 {
534  std::string retval;
535 
536  switch (m_class_constructor)
537  {
538  case none:
539  retval = "none";
540  break;
541 
542  case legacy:
543  retval = "legacy";
544  break;
545 
546  case classdef:
547  retval = "classdef";
548  break;
549 
550  default:
551  retval = "unrecognized enum value";
552  break;
553  }
554 
555  return retval;
556 }
557 
558 std::string
560 {
561  std::string retval;
562 
563  switch (m_class_method)
564  {
565  case none:
566  retval = "none";
567  break;
568 
569  case legacy:
570  retval = "legacy";
571  break;
572 
573  case classdef:
574  retval = "classdef";
575  break;
576 
577  default:
578  retval = "unrecognized enum value";
579  break;
580  }
581 
582  return retval;
583 }
584 
587 {
588  std::map<std::string, octave_value> m
589  = {{ "user_code", octave_user_code::dump () },
590  { "line", m_location_line },
591  { "col", m_location_column },
592  { "end_line", m_end_location_line },
593  { "end_col", m_end_location_column },
594  { "system_fcn_file", m_system_fcn_file },
595  { "num_named_args", m_num_named_args },
596  { "subfunction", m_subfunction },
597  { "inline_function", m_inline_function },
598  { "anonymous_function", m_anonymous_function },
599  { "nested_function", m_nested_function },
600  { "ctor_type", ctor_type_str () },
601  { "class_method", m_class_method }
602  };
603 
604  return octave_value (m);
605 }
606 
607 void
609 {
610  octave::tree_print_code tpc (octave_stdout, prefix);
611 
612  tpc.visit_octave_user_function_header (*this);
613 }
614 
615 void
617 {
618  octave::tree_print_code tpc (octave_stdout, prefix);
619 
620  tpc.visit_octave_user_function_trailer (*this);
621 }
622 
623 void
625 {
626  octave::interpreter& interp = octave::__get_interpreter__ ();
627 
628  octave::tree_evaluator& tw = interp.get_evaluator ();
629 
630  octave_value val
631  = tw.get_auto_fcn_var (octave::stack_frame::SAVED_WARNING_STATES);
632 
633  if (val.is_defined ())
634  {
635  // Fail spectacularly if SAVED_WARNING_STATES is not an
636  // octave_map (or octave_scalar_map) object.
637 
638  if (! val.isstruct ())
639  panic_impossible ();
640 
641  octave_map m = val.map_value ();
642 
643  Cell ids = m.contents ("identifier");
644  Cell states = m.contents ("state");
645 
646  for (octave_idx_type i = 0; i < m.numel (); i++)
647  Fwarning (interp, ovl (states(i), ids(i)));
648  }
649 }
650 
652 
653 DEFMETHOD (nargin, interp, args, ,
654  doc: /* -*- texinfo -*-
655 @deftypefn {} {@var{n} =} nargin ()
656 @deftypefnx {} {@var{n} =} nargin (@var{fcn})
657 Report the number of input arguments to a function.
658 
659 Called from within a function, return the number of arguments passed to the
660 function. At the top level, return the number of command line arguments
661 passed to Octave.
662 
663 If called with the optional argument @var{fcn}---a function name or
664 handle---return the declared number of arguments that the function can
665 accept.
666 
667 If the last argument to @var{fcn} is @var{varargin} the returned value is
668 negative. For example, the function @code{union} for sets is declared as
669 
670 @example
671 @group
672 function [y, ia, ib] = union (a, b, varargin)
673 
674 and
675 
676 nargin ("union")
677 @result{} -3
678 @end group
679 @end example
680 
681 Programming Note: @code{nargin} does not work on compiled functions
682 (@file{.oct} files) such as built-in or dynamically loaded functions.
683 @seealso{nargout, narginchk, varargin, inputname}
684 @end deftypefn */)
685 {
686  int nargin = args.length ();
687 
688  if (nargin > 1)
689  print_usage ();
690 
691  octave_value retval;
692 
693  if (nargin == 1)
694  {
695  octave_value fcn = args(0);
696 
697  if (fcn.is_string ())
698  {
699  symbol_table& symtab = interp.get_symbol_table ();
700 
701  std::string name = fcn.string_value ();
702  fcn = symtab.find_function (name);
703  if (fcn.is_undefined ())
704  error ("nargin: invalid function name: %s", name.c_str ());
705  }
706 
707  octave_function *fcn_val = fcn.function_value (true);
708  if (! fcn_val)
709  error ("nargin: FCN must be a string or function handle");
710 
711  octave_user_function *ufcn = fcn_val->user_function_value (true);
712 
713  if (! ufcn)
714  {
715  // Matlab gives up for histc, so maybe it's ok that we
716  // give up sometimes too?
717 
718  std::string type = fcn_val->type_name ();
719  error ("nargin: number of input arguments unavailable for %s objects",
720  type.c_str ());
721  }
722 
723  tree_parameter_list *m_param_list = ufcn->parameter_list ();
724 
725  retval = (m_param_list ? m_param_list->length () : 0);
726  if (ufcn->takes_varargs ())
727  retval = -1 - retval;
728  }
729  else
730  {
731  tree_evaluator& tw = interp.get_evaluator ();
732 
734 
735  if (retval.is_undefined ())
736  retval = 0;
737  }
738 
739  return retval;
740 }
741 
742 DEFMETHOD (nargout, interp, args, ,
743  doc: /* -*- texinfo -*-
744 @deftypefn {} {@var{n} =} nargout ()
745 @deftypefnx {} {@var{n} =} nargout (@var{fcn})
746 Report the number of output arguments from a function.
747 
748 Called from within a function, return the number of values the caller
749 expects to receive. At the top level, @code{nargout} with no argument is
750 undefined and will produce an error.
751 
752 If called with the optional argument @var{fcn}---a function name or
753 handle---return the number of declared output values that the function can
754 produce.
755 
756 If the final output argument is @var{varargout} the returned value is
757 negative.
758 
759 For example,
760 
761 @example
762 f ()
763 @end example
764 
765 @noindent
766 will cause @code{nargout} to return 0 inside the function @code{f} and
767 
768 @example
769 [s, t] = f ()
770 @end example
771 
772 @noindent
773 will cause @code{nargout} to return 2 inside the function @code{f}.
774 
775 In the second usage,
776 
777 @example
778 nargout (@@histc) # or nargout ("histc") using a string input
779 @end example
780 
781 @noindent
782 will return 2, because @code{histc} has two outputs, whereas
783 
784 @example
785 nargout (@@imread)
786 @end example
787 
788 @noindent
789 will return -2, because @code{imread} has two outputs and the second is
790 @var{varargout}.
791 
792 Programming Note. @code{nargout} does not work for built-in functions and
793 returns -1 for all anonymous functions.
794 @seealso{nargin, varargout, isargout, nthargout}
795 @end deftypefn */)
796 {
797  int nargin = args.length ();
798 
799  if (nargin > 1)
800  print_usage ();
801 
802  octave_value retval;
803 
804  if (nargin == 1)
805  {
806  octave_value fcn = args(0);
807 
808  if (fcn.is_string ())
809  {
810  symbol_table& symtab = interp.get_symbol_table ();
811 
812  std::string name = fcn.string_value ();
813  fcn = symtab.find_function (name);
814  if (fcn.is_undefined ())
815  error ("nargout: invalid function name: %s", name.c_str ());
816  }
817 
818  if (fcn.is_inline_function ())
819  return ovl (1);
820 
821  if (fcn.is_function_handle ())
822  {
823  octave_fcn_handle *fh = fcn.fcn_handle_value ();
824 
825  if (fh->is_anonymous ())
826  return ovl (-1);
827  }
828 
829  octave_function *fcn_val = fcn.function_value (true);
830  if (! fcn_val)
831  error ("nargout: FCN must be a string or function handle");
832 
833  octave_user_function *ufcn = fcn_val->user_function_value (true);
834 
835  if (! ufcn)
836  {
837  // Matlab gives up for histc, so maybe it's ok that we
838  // give up sometimes too?
839 
840  std::string type = fcn_val->type_name ();
841  error ("nargout: number of output arguments unavailable for %s objects",
842  type.c_str ());
843  }
844 
845  tree_parameter_list *m_ret_list = ufcn->return_list ();
846 
847  retval = (m_ret_list ? m_ret_list->length () : 0);
848 
849  if (ufcn->takes_var_return ())
850  retval = -1 - retval;
851  }
852  else
853  {
854  if (interp.at_top_level ())
855  error ("nargout: invalid call at top level");
856 
857  tree_evaluator& tw = interp.get_evaluator ();
858 
860 
861  if (retval.is_undefined ())
862  retval = 0;
863  }
864 
865  return retval;
866 }
867 
868 DEFUN (optimize_subsasgn_calls, args, nargout,
869  doc: /* -*- texinfo -*-
870 @deftypefn {} {@var{val} =} optimize_subsasgn_calls ()
871 @deftypefnx {} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val})
872 @deftypefnx {} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val}, "local")
873 Query or set the internal flag for @code{subsasgn} method call
874 optimizations.
875 
876 If true, Octave will attempt to eliminate the redundant copying when calling
877 the @code{subsasgn} method of a user-defined class.
878 
879 When called from inside a function with the @qcode{"local"} option, the
880 variable is changed locally for the function and any subroutines it calls.
881 The original variable value is restored when exiting the function.
882 @seealso{subsasgn}
883 @end deftypefn */)
884 {
885  return set_internal_variable (Voptimize_subsasgn_calls, args, nargout,
886  "optimize_subsasgn_calls");
887 }
888 
889 static bool val_in_table (const Matrix& table, double val)
890 {
891  if (table.isempty ())
892  return false;
893 
894  octave_idx_type i = table.lookup (val, ASCENDING);
895  return (i > 0 && table(i-1) == val);
896 }
897 
898 static bool isargout1 (int nargout, const Matrix& ignored, double k)
899 {
900  if (k != math::fix (k) || k <= 0)
901  error ("isargout: K must be a positive integer");
902 
903  return (k == 1 || k <= nargout) && ! val_in_table (ignored, k);
904 }
905 
906 DEFMETHOD (isargout, interp, args, ,
907  doc: /* -*- texinfo -*-
908 @deftypefn {} {@var{tf} =} isargout (@var{k})
909 Within a function, return a logical value indicating whether the argument
910 @var{k} will be assigned to a variable on output.
911 
912 If the result is false, the argument has been ignored during the function
913 call through the use of the tilde (~) special output argument. Functions
914 can use @code{isargout} to avoid performing unnecessary calculations for
915 outputs which are unwanted.
916 
917 If @var{k} is outside the range @code{1:max (nargout)}, the function returns
918 false. @var{k} can also be an array, in which case the function works
919 element-by-element and a logical array is returned. At the top level,
920 @code{isargout} returns an error.
921 @seealso{nargout, varargout, nthargout}
922 @end deftypefn */)
923 {
924  if (args.length () != 1)
925  print_usage ();
926 
927  if (interp.at_top_level ())
928  error ("isargout: invalid call at top level");
929 
930  tree_evaluator& tw = interp.get_evaluator ();
931 
932  octave_value tmp;
933 
934  int nargout1 = 0;
936  if (tmp.is_defined ())
937  nargout1 = tmp.int_value ();
938 
939  Matrix ignored;
941  if (tmp.is_defined ())
942  ignored = tmp.matrix_value ();
943 
944  if (args(0).is_scalar_type ())
945  {
946  double k = args(0).double_value ();
947 
948  return ovl (isargout1 (nargout1, ignored, k));
949  }
950  else if (args(0).isnumeric ())
951  {
952  const NDArray ka = args(0).array_value ();
953 
954  boolNDArray r (ka.dims ());
955  for (octave_idx_type i = 0; i < ka.numel (); i++)
956  r(i) = isargout1 (nargout1, ignored, ka(i));
957 
958  return ovl (r);
959  }
960  else
961  err_wrong_type_arg ("isargout", args(0));
962 
963  return ovl ();
964 }
965 
966 /*
967 %!function [x, y] = try_isargout ()
968 %! if (isargout (1))
969 %! if (isargout (2))
970 %! x = 1; y = 2;
971 %! else
972 %! x = -1;
973 %! endif
974 %! else
975 %! if (isargout (2))
976 %! y = -2;
977 %! else
978 %! error ("no outputs requested");
979 %! endif
980 %! endif
981 %!endfunction
982 %!
983 %!function [a, b] = try_isargout2 (x, y)
984 %! a = y;
985 %! b = {isargout(1), isargout(2), x};
986 %!endfunction
987 %!
988 %!test
989 %! [x, y] = try_isargout ();
990 %! assert ([x, y], [1, 2]);
991 %!
992 %!test
993 %! [x, ~] = try_isargout ();
994 %! assert (x, -1);
995 %!
996 %!test
997 %! [~, y] = try_isargout ();
998 %! assert (y, -2);
999 %!
1000 %!error [~, ~] = try_isargout ()
1001 %!
1002 ## Check to see that isargout isn't sticky:
1003 %!test
1004 %! [x, y] = try_isargout ();
1005 %! assert ([x, y], [1, 2]);
1006 %!
1007 ## It should work without ():
1008 %!test
1009 %! [~, y] = try_isargout;
1010 %! assert (y, -2);
1011 %!
1012 ## It should work in function handles, anonymous functions, and cell
1013 ## arrays of handles or anonymous functions.
1014 %!test
1015 %! fh = @try_isargout;
1016 %! af = @() try_isargout;
1017 %! c = {fh, af};
1018 %! [~, y] = fh ();
1019 %! assert (y, -2);
1020 %! [~, y] = af ();
1021 %! assert (y, -2);
1022 %! [~, y] = c{1}();
1023 %! assert (y, -2);
1024 %! [~, y] = c{2}();
1025 %! assert (y, -2);
1026 %!
1027 ## Nesting, anyone?
1028 %!test
1029 %! [~, b] = try_isargout2 (try_isargout, rand);
1030 %! assert (b, {0, 1, -1});
1031 %!test
1032 %! [~, b] = try_isargout2 ({try_isargout, try_isargout}, rand);
1033 %! assert (b, {0, 1, {-1, -1}});
1034 */
1035 
OCTAVE_END_NAMESPACE(octave)
OCTARRAY_OVERRIDABLE_FUNC_API bool isempty(void) const
Size of the specified dimension.
Definition: Array.h:651
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
OCTARRAY_OVERRIDABLE_FUNC_API const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
OCTARRAY_API octave_idx_type lookup(const T &value, sortmode mode=UNSORTED) const
Do a binary lookup in a sorted array.
Definition: Array-base.cc:2160
Definition: Cell.h:43
Definition: dMatrix.h:42
std::size_t length(void) const
Definition: base-list.h:53
virtual octave_user_function * user_function_value(bool silent=false)
Definition: ov-base.cc:949
virtual std::string type_name(void) const
Definition: ov-base.h:932
friend class octave_value
Definition: ov-base.h:263
bool is_anonymous(void) const
std::string dispatch_class(void) const
Definition: ov-fcn.h:150
bool is_class_method(const std::string &cname="") const
Definition: ov-fcn.h:117
bool is_class_constructor(const std::string &cname="") const
Definition: ov-fcn.h:112
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
octave_value dump(void) const
Definition: ov-usr-fcn.cc:137
std::string fcn_file_name(void) const
Definition: ov-usr-fcn.h:107
std::string get_code_line(std::size_t line)
Definition: ov-usr-fcn.cc:100
std::string m_file_name
Definition: ov-usr-fcn.h:132
octave::sys::time m_t_checked
Definition: ov-usr-fcn.h:139
~octave_user_code(void)
Definition: ov-usr-fcn.cc:67
std::deque< std::string > get_code_lines(std::size_t line, std::size_t num_lines)
Definition: ov-usr-fcn.cc:109
octave::tree_statement_list * m_cmd_list
Definition: ov-usr-fcn.h:146
octave::sys::time m_t_parsed
Definition: ov-usr-fcn.h:135
octave::file_info * m_file_info
Definition: ov-usr-fcn.h:143
void get_file_info(void)
Definition: ov-usr-fcn.cc:88
octave::sys::time time_parsed(void) const
Definition: ov-usr-fcn.h:109
void cache_function_text(const std::string &text, const octave::sys::time &timestamp)
Definition: ov-usr-fcn.cc:118
virtual std::map< std::string, octave_value > subfunctions(void) const
Definition: ov-usr-fcn.cc:131
octave::symbol_scope m_scope
Definition: ov-usr-fcn.h:129
std::string parent_fcn_name(void) const
Definition: ov-usr-fcn.h:264
void restore_warning_states(void)
Definition: ov-usr-fcn.cc:624
octave::tree_expression * special_expr(void)
Definition: ov-usr-fcn.cc:505
void unlock_subfunctions(void)
Definition: ov-usr-fcn.cc:402
void erase_subfunctions(void)
Definition: ov-usr-fcn.cc:370
void mark_as_system_fcn_file(void)
Definition: ov-usr-fcn.cc:340
octave_value_list call(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:481
bool is_special_expr(void) const
Definition: ov-usr-fcn.h:338
octave::tree_parameter_list * return_list(void)
Definition: ov-usr-fcn.h:396
octave::comment_list * m_trail_comm
Definition: ov-usr-fcn.h:435
octave::tree_parameter_list * m_param_list
Definition: ov-usr-fcn.h:425
void stash_parent_fcn_scope(const octave::symbol_scope &ps)
Definition: ov-usr-fcn.cc:311
void maybe_relocate_end(void)
Definition: ov-usr-fcn.cc:292
octave_user_function * define_ret_list(octave::tree_parameter_list *t)
Definition: ov-usr-fcn.cc:240
octave_value_list all_va_args(const octave_value_list &args)
Definition: ov-usr-fcn.cc:463
void stash_subfunction_names(const std::list< std::string > &names)
Definition: ov-usr-fcn.cc:451
std::string profiler_name(void) const
Definition: ov-usr-fcn.cc:317
bool is_classdef_constructor(const std::string &cname="") const
Definition: ov-usr-fcn.h:359
bool takes_varargs(void) const
Definition: ov-usr-fcn.cc:376
octave_value_list execute(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:492
octave::tree_parameter_list * parameter_list(void)
Definition: ov-usr-fcn.h:394
bool takes_var_return(void) const
Definition: ov-usr-fcn.cc:382
void mark_as_private_function(const std::string &cname="")
Definition: ov-usr-fcn.cc:388
std::list< std::string > subfunction_names(void) const
Definition: ov-usr-fcn.cc:457
int beginning_column(void) const
Definition: ov-usr-fcn.h:243
class_method_type m_class_method
Definition: ov-usr-fcn.h:467
void print_code_function_header(const std::string &prefix)
Definition: ov-usr-fcn.cc:608
octave::tree_parameter_list * m_ret_list
Definition: ov-usr-fcn.h:429
void accept(octave::tree_walker &tw)
Definition: ov-usr-fcn.cc:499
bool is_inline_function(void) const
Definition: ov-usr-fcn.h:319
void print_code_function_trailer(const std::string &prefix)
Definition: ov-usr-fcn.cc:616
std::map< std::string, octave_value > subfunctions(void) const
Definition: ov-usr-fcn.cc:408
bool has_subfunctions(void) const
Definition: ov-usr-fcn.cc:445
octave_value find_subfunction(const std::string &subfuns) const
Definition: ov-usr-fcn.cc:418
octave_user_function(const octave::symbol_scope &scope=octave::symbol_scope(), octave::tree_parameter_list *pl=nullptr, octave::tree_parameter_list *rl=nullptr, octave::tree_statement_list *cl=nullptr)
Definition: ov-usr-fcn.cc:215
class_method_type m_class_constructor
Definition: ov-usr-fcn.h:464
bool is_subfunction(void) const
Definition: ov-usr-fcn.h:315
bool subsasgn_optimization_ok(void)
Definition: ov-usr-fcn.cc:515
int beginning_line(void) const
Definition: ov-usr-fcn.h:242
void lock_subfunctions(void)
Definition: ov-usr-fcn.cc:396
std::string method_type_str(void) const
Definition: ov-usr-fcn.cc:559
octave::comment_list * m_lead_comm
Definition: ov-usr-fcn.h:432
std::string ctor_type_str(void) const
Definition: ov-usr-fcn.cc:532
octave_value dump(void) const
Definition: ov-usr-fcn.cc:586
bool is_anonymous_function(void) const
Definition: ov-usr-fcn.h:323
void maybe_relocate_end_internal(void)
Definition: ov-usr-fcn.cc:256
void accept(octave::tree_walker &tw)
Definition: ov-usr-fcn.cc:200
octave_value_list call(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:182
octave_value_list execute(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-usr-fcn.cc:193
octave_idx_type length(void) const
Definition: ovl.h:113
octave_value_list slice(octave_idx_type offset, octave_idx_type len, bool tags=false) const
Definition: ovl.h:131
OCTINTERP_API octave_function * function_value(bool silent=false) const
int int_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:857
bool is_string(void) const
Definition: ov.h:682
bool is_defined(void) const
Definition: ov.h:637
bool is_function_handle(void) const
Definition: ov.h:813
OCTINTERP_API octave_user_function * user_function_value(bool silent=false) const
bool isstruct(void) const
Definition: ov.h:694
OCTINTERP_API octave_fcn_handle * fcn_handle_value(bool silent=false) const
std::string string_value(bool force=false) const
Definition: ov.h:1019
OCTINTERP_API octave_map map_value(void) const
bool is_undefined(void) const
Definition: ov.h:640
bool is_inline_function(void) const
Definition: ov.h:819
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:898
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope())
Definition: symtab.cc:249
octave_value get_auto_fcn_var(stack_frame::auto_var_type avt) const
Definition: pt-eval.cc:2205
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
std::string fcn_file_dir(void)
Definition: defaults.cc:315
OCTINTERP_API void print_usage(void)
Definition: defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:111
#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
OCTAVE_EXPORT octave_value_list Fwarning(octave::interpreter &interp, const octave_value_list &args, int nargout)
Definition: error.cc:1471
void error(const char *fmt,...)
Definition: error.cc:979
void panic_unless(bool cond)
Definition: error.h:526
void panic_if(bool cond)
Definition: error.h:512
#define panic_impossible()
Definition: error.h:508
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:744
interpreter & __get_interpreter__(void)
event_manager & __get_event_manager__(void)
double fix(double x)
Definition: lo-mappers.h:118
F77_RET_T const F77_DBLE const F77_DBLE * f
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
@ ASCENDING
Definition: oct-sort.h:97
#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)
Definition: ov-base.h:229
static bool Voptimize_subsasgn_calls
Definition: ov-usr-fcn.cc:65
static bool val_in_table(const Matrix &table, double val)
Definition: ov-usr-fcn.cc:889
static bool isargout1(int nargout, const Matrix &ignored, double k)
Definition: ov-usr-fcn.cc:898
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
#define octave_stdout
Definition: pager.h:314
std::string fcn_file_in_path(const std::string &name)
Definition: utils.cc:742
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition: variables.cc:584