comparison libinterp/octave-value/ov-usr-fcn.cc @ 15195:2fc554ffbc28

split libinterp from src * libinterp: New directory. Move all files from src directory here except Makefile.am, main.cc, main-cli.cc, mkoctfile.in.cc, mkoctfilr.in.sh, octave-config.in.cc, octave-config.in.sh. * libinterp/Makefile.am: New file, extracted from src/Makefile.am. * src/Makefile.am: Delete everything except targets and definitions needed to build and link main and utility programs. * Makefile.am (SUBDIRS): Include libinterp in the list. * autogen.sh: Run config-module.sh in libinterp/dldfcn directory, not src/dldfcn directory. * configure.ac (AC_CONFIG_SRCDIR): Use libinterp/octave.cc, not src/octave.cc. (DL_LDFLAGS, LIBOCTINTERP): Use libinterp, not src. (AC_CONFIG_FILES): Include libinterp/Makefile in the list. * find-docstring-files.sh: Look in libinterp, not src. * gui/src/Makefile.am (liboctgui_la_CPPFLAGS): Find header files in libinterp, not src.
author John W. Eaton <jwe@octave.org>
date Sat, 18 Aug 2012 16:23:39 -0400
parents src/octave-value/ov-usr-fcn.cc@46b19589b593
children 44d6ffdf9479
comparison
equal deleted inserted replaced
15194:0f0b795044c3 15195:2fc554ffbc28
1 /*
2
3 Copyright (C) 1996-2012 John W. Eaton
4
5 This file is part of Octave.
6
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <sstream>
28
29 #include "str-vec.h"
30
31 #include <defaults.h>
32 #include "Cell.h"
33 #include "defun.h"
34 #include "error.h"
35 #include "gripes.h"
36 #include "input.h"
37 #include "oct-obj.h"
38 #include "ov-usr-fcn.h"
39 #include "ov.h"
40 #include "pager.h"
41 #include "pt-eval.h"
42 #include "pt-jump.h"
43 #include "pt-misc.h"
44 #include "pt-pr-code.h"
45 #include "pt-stmt.h"
46 #include "pt-walk.h"
47 #include "symtab.h"
48 #include "toplev.h"
49 #include "unwind-prot.h"
50 #include "utils.h"
51 #include "parse.h"
52 #include "profiler.h"
53 #include "variables.h"
54 #include "ov-fcn-handle.h"
55
56 // Whether to optimize subsasgn method calls.
57 static bool Voptimize_subsasgn_calls = true;
58
59 // User defined scripts.
60
61 DEFINE_OCTAVE_ALLOCATOR (octave_user_script);
62
63 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_user_script,
64 "user-defined script",
65 "user-defined script");
66
67 octave_user_script::octave_user_script (void)
68 : octave_user_code (), cmd_list (0), file_name (),
69 t_parsed (static_cast<time_t> (0)),
70 t_checked (static_cast<time_t> (0)),
71 call_depth (-1)
72 { }
73
74 octave_user_script::octave_user_script (const std::string& fnm,
75 const std::string& nm,
76 tree_statement_list *cmds,
77 const std::string& ds)
78 : octave_user_code (nm, ds), cmd_list (cmds), file_name (fnm),
79 t_parsed (static_cast<time_t> (0)),
80 t_checked (static_cast<time_t> (0)),
81 call_depth (-1)
82 {
83 if (cmd_list)
84 cmd_list->mark_as_script_body ();
85 }
86
87 octave_user_script::octave_user_script (const std::string& fnm,
88 const std::string& nm,
89 const std::string& ds)
90 : octave_user_code (nm, ds), cmd_list (0), file_name (fnm),
91 t_parsed (static_cast<time_t> (0)),
92 t_checked (static_cast<time_t> (0)),
93 call_depth (-1)
94 { }
95
96 octave_user_script::~octave_user_script (void)
97 {
98 delete cmd_list;
99 }
100
101 octave_value_list
102 octave_user_script::subsref (const std::string&,
103 const std::list<octave_value_list>&, int)
104 {
105 octave_value_list retval;
106
107 ::error ("invalid use of script %s in index expression", file_name.c_str ());
108
109 return retval;
110 }
111
112 octave_value_list
113 octave_user_script::do_multi_index_op (int nargout,
114 const octave_value_list& args)
115 {
116 octave_value_list retval;
117
118 unwind_protect frame;
119
120 if (! error_state)
121 {
122 if (args.length () == 0 && nargout == 0)
123 {
124 if (cmd_list)
125 {
126 frame.protect_var (call_depth);
127 call_depth++;
128
129 if (call_depth < Vmax_recursion_depth)
130 {
131 octave_call_stack::push (this);
132
133 frame.add_fcn (octave_call_stack::pop);
134
135 frame.protect_var (tree_evaluator::statement_context);
136 tree_evaluator::statement_context = tree_evaluator::script;
137
138 BEGIN_PROFILER_BLOCK (profiler_name ())
139 cmd_list->accept (*current_evaluator);
140 END_PROFILER_BLOCK
141
142 if (tree_return_command::returning)
143 tree_return_command::returning = 0;
144
145 if (tree_break_command::breaking)
146 tree_break_command::breaking--;
147
148 if (error_state)
149 octave_call_stack::backtrace_error_message ();
150 }
151 else
152 ::error ("max_recursion_depth exceeded");
153 }
154 }
155 else
156 error ("invalid call to script %s", file_name.c_str ());
157 }
158
159 return retval;
160 }
161
162 void
163 octave_user_script::accept (tree_walker& tw)
164 {
165 tw.visit_octave_user_script (*this);
166 }
167
168 // User defined functions.
169
170 DEFINE_OCTAVE_ALLOCATOR (octave_user_function);
171
172 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_user_function,
173 "user-defined function",
174 "user-defined function");
175
176 // Ugh. This really needs to be simplified (code/data?
177 // extrinsic/intrinsic state?).
178
179 octave_user_function::octave_user_function
180 (symbol_table::scope_id sid, tree_parameter_list *pl,
181 tree_parameter_list *rl, tree_statement_list *cl)
182 : octave_user_code (std::string (), std::string ()),
183 param_list (pl), ret_list (rl), cmd_list (cl),
184 lead_comm (), trail_comm (), file_name (),
185 location_line (0), location_column (0),
186 parent_name (), t_parsed (static_cast<time_t> (0)),
187 t_checked (static_cast<time_t> (0)),
188 system_fcn_file (false), call_depth (-1),
189 num_named_args (param_list ? param_list->length () : 0),
190 subfunction (false), inline_function (false),
191 anonymous_function (false), nested_function (false),
192 class_constructor (false), class_method (false),
193 parent_scope (-1), local_scope (sid),
194 curr_unwind_protect_frame (0)
195 {
196 if (cmd_list)
197 cmd_list->mark_as_function_body ();
198
199 if (local_scope >= 0)
200 symbol_table::set_curr_fcn (this, local_scope);
201 }
202
203 octave_user_function::~octave_user_function (void)
204 {
205 delete param_list;
206 delete ret_list;
207 delete cmd_list;
208 delete lead_comm;
209 delete trail_comm;
210
211 symbol_table::erase_scope (local_scope);
212 }
213
214 octave_user_function *
215 octave_user_function::define_ret_list (tree_parameter_list *t)
216 {
217 ret_list = t;
218
219 return this;
220 }
221
222 void
223 octave_user_function::stash_fcn_file_name (const std::string& nm)
224 {
225 file_name = nm;
226 }
227
228 std::string
229 octave_user_function::profiler_name (void) const
230 {
231 std::ostringstream result;
232
233 if (is_inline_function ())
234 result << "inline@" << fcn_file_name ()
235 << ":" << location_line << ":" << location_column;
236 else if (is_anonymous_function ())
237 result << "anonymous@" << fcn_file_name ()
238 << ":" << location_line << ":" << location_column;
239 else if (is_subfunction ())
240 result << parent_fcn_name () << ">" << name ();
241 else
242 result << name ();
243
244 return result.str ();
245 }
246
247 void
248 octave_user_function::mark_as_system_fcn_file (void)
249 {
250 if (! file_name.empty ())
251 {
252 // We really should stash the whole path to the file we found,
253 // when we looked it up, to avoid possible race conditions...
254 // FIXME
255 //
256 // We probably also don't need to get the library directory
257 // every time, but since this function is only called when the
258 // function file is parsed, it probably doesn't matter that
259 // much.
260
261 std::string ff_name = fcn_file_in_path (file_name);
262
263 if (Vfcn_file_dir == ff_name.substr (0, Vfcn_file_dir.length ()))
264 system_fcn_file = true;
265 }
266 else
267 system_fcn_file = false;
268 }
269
270 bool
271 octave_user_function::takes_varargs (void) const
272 {
273 return (param_list && param_list->takes_varargs ());
274 }
275
276 bool
277 octave_user_function::takes_var_return (void) const
278 {
279 return (ret_list && ret_list->takes_varargs ());
280 }
281
282 void
283 octave_user_function::lock_subfunctions (void)
284 {
285 symbol_table::lock_subfunctions (local_scope);
286 }
287
288 void
289 octave_user_function::unlock_subfunctions (void)
290 {
291 symbol_table::unlock_subfunctions (local_scope);
292 }
293
294 octave_value_list
295 octave_user_function::all_va_args (const octave_value_list& args)
296 {
297 octave_value_list retval;
298
299 octave_idx_type n = args.length () - num_named_args;
300
301 if (n > 0)
302 retval = args.slice (num_named_args, n);
303
304 return retval;
305 }
306
307 octave_value_list
308 octave_user_function::subsref (const std::string& type,
309 const std::list<octave_value_list>& idx,
310 int nargout)
311 {
312 return octave_user_function::subsref (type, idx, nargout, 0);
313 }
314
315 octave_value_list
316 octave_user_function::subsref (const std::string& type,
317 const std::list<octave_value_list>& idx,
318 int nargout, const std::list<octave_lvalue>* lvalue_list)
319 {
320 octave_value_list retval;
321
322 switch (type[0])
323 {
324 case '(':
325 {
326 int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
327
328 retval = do_multi_index_op (tmp_nargout, idx.front (),
329 idx.size () == 1 ? lvalue_list : 0);
330 }
331 break;
332
333 case '{':
334 case '.':
335 {
336 std::string nm = type_name ();
337 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
338 }
339 break;
340
341 default:
342 panic_impossible ();
343 }
344
345 // FIXME -- perhaps there should be an
346 // octave_value_list::next_subsref member function? See also
347 // octave_builtin::subsref.
348
349 if (idx.size () > 1)
350 retval = retval(0).next_subsref (nargout, type, idx);
351
352 return retval;
353 }
354
355 octave_value_list
356 octave_user_function::do_multi_index_op (int nargout,
357 const octave_value_list& args)
358 {
359 return do_multi_index_op (nargout, args, 0);
360 }
361
362 octave_value_list
363 octave_user_function::do_multi_index_op (int nargout,
364 const octave_value_list& args,
365 const std::list<octave_lvalue>* lvalue_list)
366 {
367 octave_value_list retval;
368
369 if (error_state)
370 return retval;
371
372 if (! cmd_list)
373 return retval;
374
375 int nargin = args.length ();
376
377 unwind_protect frame;
378
379 frame.protect_var (call_depth);
380 call_depth++;
381
382 if (call_depth >= Vmax_recursion_depth)
383 {
384 ::error ("max_recursion_depth exceeded");
385 return retval;
386 }
387
388 // Save old and set current symbol table context, for
389 // eval_undefined_error().
390
391 int context = active_context ();
392
393 octave_call_stack::push (this, local_scope, context);
394 frame.add_fcn (octave_call_stack::pop);
395
396 if (call_depth > 0 && ! is_anonymous_function ())
397 {
398 symbol_table::push_context ();
399
400 frame.add_fcn (symbol_table::pop_context);
401 }
402
403 string_vector arg_names = args.name_tags ();
404
405 if (param_list && ! param_list->varargs_only ())
406 {
407 param_list->define_from_arg_vector (args);
408 if (error_state)
409 return retval;
410 }
411
412 // Force parameter list to be undefined when this function exits.
413 // Doing so decrements the reference counts on the values of local
414 // variables that are also named function parameters.
415
416 if (param_list)
417 frame.add_method (param_list, &tree_parameter_list::undefine);
418
419 // Force return list to be undefined when this function exits.
420 // Doing so decrements the reference counts on the values of local
421 // variables that are also named values returned by this function.
422
423 if (ret_list)
424 frame.add_method (ret_list, &tree_parameter_list::undefine);
425
426 if (call_depth == 0)
427 {
428 // Force symbols to be undefined again when this function
429 // exits.
430 //
431 // This cleanup function is added to the unwind_protect stack
432 // after the calls to clear the parameter lists so that local
433 // variables will be cleared before the parameter lists are
434 // cleared. That way, any function parameters that have been
435 // declared global will be unmarked as global before they are
436 // undefined by the clear_param_list cleanup function.
437
438 frame.add_fcn (symbol_table::clear_variables);
439 }
440
441 bind_automatic_vars (arg_names, nargin, nargout, all_va_args (args),
442 lvalue_list);
443
444 bool echo_commands = (Vecho_executing_commands & ECHO_FUNCTIONS);
445
446 if (echo_commands)
447 print_code_function_header ();
448
449 // Set pointer to the current unwind_protect frame to allow
450 // certain builtins register simple cleanup in a very optimized manner.
451 // This is *not* intended as a general-purpose on-cleanup mechanism,
452 frame.protect_var (curr_unwind_protect_frame);
453 curr_unwind_protect_frame = &frame;
454
455 // Evaluate the commands that make up the function.
456
457 frame.protect_var (tree_evaluator::statement_context);
458 tree_evaluator::statement_context = tree_evaluator::function;
459
460 bool special_expr = (is_inline_function () || is_anonymous_function ());
461
462 BEGIN_PROFILER_BLOCK (profiler_name ())
463
464 if (special_expr)
465 {
466 assert (cmd_list->length () == 1);
467
468 tree_statement *stmt = 0;
469
470 if ((stmt = cmd_list->front ())
471 && stmt->is_expression ())
472 {
473 tree_expression *expr = stmt->expression ();
474
475 retval = expr->rvalue (nargout);
476 }
477 }
478 else
479 cmd_list->accept (*current_evaluator);
480
481 END_PROFILER_BLOCK
482
483 if (echo_commands)
484 print_code_function_trailer ();
485
486 if (tree_return_command::returning)
487 tree_return_command::returning = 0;
488
489 if (tree_break_command::breaking)
490 tree_break_command::breaking--;
491
492 if (error_state)
493 {
494 octave_call_stack::backtrace_error_message ();
495 return retval;
496 }
497
498 // Copy return values out.
499
500 if (ret_list && ! special_expr)
501 {
502 ret_list->initialize_undefined_elements (my_name, nargout, Matrix ());
503
504 Cell varargout;
505
506 if (ret_list->takes_varargs ())
507 {
508 octave_value varargout_varval = symbol_table::varval ("varargout");
509
510 if (varargout_varval.is_defined ())
511 {
512 varargout = varargout_varval.cell_value ();
513
514 if (error_state)
515 error ("expecting varargout to be a cell array object");
516 }
517 }
518
519 if (! error_state)
520 retval = ret_list->convert_to_const_vector (nargout, varargout);
521 }
522
523 return retval;
524 }
525
526 void
527 octave_user_function::accept (tree_walker& tw)
528 {
529 tw.visit_octave_user_function (*this);
530 }
531
532 bool
533 octave_user_function::subsasgn_optimization_ok (void)
534 {
535 bool retval = false;
536 if (Voptimize_subsasgn_calls
537 && param_list->length () > 0 && ! param_list->varargs_only ()
538 && ret_list->length () == 1 && ! ret_list->takes_varargs ())
539 {
540 tree_identifier *par1 = param_list->front ()->ident ();
541 tree_identifier *ret1 = ret_list->front ()->ident ();
542 retval = par1->name () == ret1->name ();
543 }
544
545 return retval;
546 }
547
548 #if 0
549 void
550 octave_user_function::print_symtab_info (std::ostream& os) const
551 {
552 symbol_table::print_info (os, local_scope);
553 }
554 #endif
555
556 void
557 octave_user_function::print_code_function_header (void)
558 {
559 tree_print_code tpc (octave_stdout, VPS4);
560
561 tpc.visit_octave_user_function_header (*this);
562 }
563
564 void
565 octave_user_function::print_code_function_trailer (void)
566 {
567 tree_print_code tpc (octave_stdout, VPS4);
568
569 tpc.visit_octave_user_function_trailer (*this);
570 }
571
572 void
573 octave_user_function::bind_automatic_vars
574 (const string_vector& arg_names, int nargin, int nargout,
575 const octave_value_list& va_args, const std::list<octave_lvalue> *lvalue_list)
576 {
577 if (! arg_names.empty ())
578 {
579 // It is better to save this in the hidden variable .argn. and
580 // then use that in the inputname function instead of using argn,
581 // which might be redefined in a function. Keep the old argn name
582 // for backward compatibility of functions that use it directly.
583
584 symbol_table::varref ("argn") = arg_names;
585 symbol_table::varref (".argn.") = Cell (arg_names);
586
587 symbol_table::mark_hidden (".argn.");
588
589 symbol_table::mark_automatic ("argn");
590 symbol_table::mark_automatic (".argn.");
591 }
592
593 symbol_table::varref (".nargin.") = nargin;
594 symbol_table::varref (".nargout.") = nargout;
595
596 symbol_table::mark_hidden (".nargin.");
597 symbol_table::mark_hidden (".nargout.");
598
599 symbol_table::mark_automatic (".nargin.");
600 symbol_table::mark_automatic (".nargout.");
601
602 if (takes_varargs ())
603 symbol_table::varref ("varargin") = va_args.cell_value ();
604
605 // Force .ignored. variable to be undefined by default.
606 symbol_table::varref (".ignored.") = octave_value ();
607
608 if (lvalue_list)
609 {
610 octave_idx_type nbh = 0;
611 for (std::list<octave_lvalue>::const_iterator p = lvalue_list->begin ();
612 p != lvalue_list->end (); p++)
613 nbh += p->is_black_hole ();
614
615 if (nbh > 0)
616 {
617 // Only assign the hidden variable if black holes actually present.
618 Matrix bh (1, nbh);
619 octave_idx_type k = 0, l = 0;
620 for (std::list<octave_lvalue>::const_iterator p = lvalue_list->begin ();
621 p != lvalue_list->end (); p++)
622 {
623 if (p->is_black_hole ())
624 bh(l++) = k+1;
625 k += p->numel ();
626 }
627
628 symbol_table::varref (".ignored.") = bh;
629 }
630 }
631
632 symbol_table::mark_hidden (".ignored.");
633 symbol_table::mark_automatic (".ignored.");
634 }
635
636 DEFUN (nargin, args, ,
637 "-*- texinfo -*-\n\
638 @deftypefn {Built-in Function} {} nargin ()\n\
639 @deftypefnx {Built-in Function} {} nargin (@var{fcn})\n\
640 Within a function, return the number of arguments passed to the function.\n\
641 At the top level, return the number of command line arguments passed to\n\
642 Octave.\n\
643 \n\
644 If called with the optional argument @var{fcn}, a function name or handle,\n\
645 return the declared number of arguments that the function can accept.\n\
646 If the last argument is @var{varargin} the returned value is negative.\n\
647 This feature does not work on builtin functions.\n\
648 @seealso{nargout, varargin, isargout, varargout, nthargout}\n\
649 @end deftypefn")
650 {
651 octave_value retval;
652
653 int nargin = args.length ();
654
655 if (nargin == 1)
656 {
657 octave_value func = args(0);
658
659 if (func.is_string ())
660 {
661 std::string name = func.string_value ();
662 func = symbol_table::find_function (name);
663 if (func.is_undefined ())
664 error ("nargout: invalid function name: %s", name.c_str ());
665 }
666
667 octave_function *fcn_val = func.function_value ();
668 if (fcn_val)
669 {
670 octave_user_function *fcn = fcn_val->user_function_value (true);
671
672 if (fcn)
673 {
674 tree_parameter_list *param_list = fcn->parameter_list ();
675
676 retval = param_list ? param_list->length () : 0;
677 if (fcn->takes_varargs ())
678 retval = -1 - retval;
679 }
680 else
681 {
682 // Matlab gives up for histc, so maybe it's ok we give up somtimes too.
683 error ("nargin: nargin information not available for builtin functions");
684 }
685 }
686 else
687 error ("nargin: FCN must be a string or function handle");
688 }
689 else if (nargin == 0)
690 {
691 retval = symbol_table::varval (".nargin.");
692
693 if (retval.is_undefined ())
694 retval = 0;
695 }
696 else
697 print_usage ();
698
699 return retval;
700 }
701
702 DEFUN (nargout, args, ,
703 "-*- texinfo -*-\n\
704 @deftypefn {Built-in Function} {} nargout ()\n\
705 @deftypefnx {Built-in Function} {} nargout (@var{fcn})\n\
706 Within a function, return the number of values the caller expects to\n\
707 receive. If called with the optional argument @var{fcn}, a function\n\
708 name or handle, return the number of declared output values that the\n\
709 function can produce. If the final output argument is @var{varargout}\n\
710 the returned value is negative.\n\
711 \n\
712 For example,\n\
713 \n\
714 @example\n\
715 f ()\n\
716 @end example\n\
717 \n\
718 @noindent\n\
719 will cause @code{nargout} to return 0 inside the function @code{f} and\n\
720 \n\
721 @example\n\
722 [s, t] = f ()\n\
723 @end example\n\
724 \n\
725 @noindent\n\
726 will cause @code{nargout} to return 2 inside the function\n\
727 @code{f}.\n\
728 \n\
729 In the second usage,\n\
730 \n\
731 @example\n\
732 nargout (@@histc) \% or nargout ('histc')\n\
733 @end example\n\
734 \n\
735 @noindent\n\
736 will return 2, because @code{histc} has two outputs, whereas\n\
737 \n\
738 @example\n\
739 nargout (@@deal)\n\
740 @end example\n\
741 \n\
742 @noindent\n\
743 will return -1, because @code{deal} has a variable number of outputs.\n\
744 \n\
745 At the top level, @code{nargout} with no argument is undefined.\n\
746 @code{nargout} does not work on builtin functions.\n\
747 @code{nargout} returns -1 for all anonymous functions.\n\
748 @seealso{nargin, varargin, isargout, varargout, nthargout}\n\
749 @end deftypefn")
750 {
751 octave_value retval;
752
753 int nargin = args.length ();
754
755 if (nargin == 1)
756 {
757 octave_value func = args(0);
758
759 if (func.is_string ())
760 {
761 std::string name = func.string_value ();
762 func = symbol_table::find_function (name);
763 if (func.is_undefined ())
764 error ("nargout: invalid function name: %s", name.c_str ());
765 }
766
767 if (func.is_inline_function ())
768 {
769 retval = 1;
770 return retval;
771 }
772
773 if (func.is_function_handle ())
774 {
775 octave_fcn_handle *fh = func.fcn_handle_value ();
776 std::string fh_nm = fh->fcn_name ();
777
778 if (fh_nm == octave_fcn_handle::anonymous)
779 {
780 retval = -1;
781 return retval;
782 }
783 }
784
785 octave_function *fcn_val = func.function_value ();
786 if (fcn_val)
787 {
788 octave_user_function *fcn = fcn_val->user_function_value (true);
789
790 if (fcn)
791 {
792 tree_parameter_list *ret_list = fcn->return_list ();
793
794 retval = ret_list ? ret_list->length () : 0;
795
796 if (fcn->takes_var_return ())
797 retval = -1 - retval;
798 }
799 else
800 {
801 // JWE said this information is not available (currently, 2011-03-10)
802 // without making intrusive changes to Octave.
803 // Matlab gives up for histc, so maybe it's ok we give up somtimes too.
804 error ("nargout: nargout information not available for builtin functions.");
805 }
806 }
807 else
808 error ("nargout: FCN must be a string or function handle");
809 }
810 else if (nargin == 0)
811 {
812 if (! symbol_table::at_top_level ())
813 {
814 retval = symbol_table::varval (".nargout.");
815
816 if (retval.is_undefined ())
817 retval = 0;
818 }
819 else
820 error ("nargout: invalid call at top level");
821 }
822 else
823 print_usage ();
824
825 return retval;
826 }
827
828 DEFUN (optimize_subsasgn_calls, args, nargout,
829 "-*- texinfo -*-\n\
830 @deftypefn {Built-in Function} {@var{val} =} optimize_subsasgn_calls ()\n\
831 @deftypefnx {Built-in Function} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val})\n\
832 @deftypefnx {Built-in Function} {} optimize_subsasgn_calls (@var{new_val}, \"local\")\n\
833 Query or set the internal flag for subsasgn method call optimizations.\n\
834 If true, Octave will attempt to eliminate the redundant copying when calling\n\
835 subsasgn method of a user-defined class.\n\
836 \n\
837 When called from inside a function with the \"local\" option, the variable is\n\
838 changed locally for the function and any subroutines it calls. The original\n\
839 variable value is restored when exiting the function.\n\
840 @end deftypefn")
841 {
842 return SET_INTERNAL_VARIABLE (optimize_subsasgn_calls);
843 }
844
845 static bool val_in_table (const Matrix& table, double val)
846 {
847 if (table.is_empty ())
848 return false;
849
850 octave_idx_type i = table.lookup (val, ASCENDING);
851 return (i > 0 && table(i-1) == val);
852 }
853
854 static bool isargout1 (int nargout, const Matrix& ignored, double k)
855 {
856 if (k != xround (k) || k <= 0)
857 {
858 error ("isargout: K must be a positive integer");
859 return false;
860 }
861 else
862 return (k == 1 || k <= nargout) && ! val_in_table (ignored, k);
863 }
864
865 DEFUN (isargout, args, ,
866 "-*- texinfo -*-\n\
867 @deftypefn {Built-in Function} {} isargout (@var{k})\n\
868 Within a function, return a logical value indicating whether the argument\n\
869 @var{k} will be assigned on output to a variable. If the result is false,\n\
870 the argument has been ignored during the function call through the use of\n\
871 the tilde (~) special output argument. Functions can use @code{isargout} to\n\
872 avoid performing unnecessary calculations for outputs which are unwanted.\n\
873 \n\
874 If @var{k} is outside the range @code{1:max (nargout)}, the function returns\n\
875 false. @var{k} can also be an array, in which case the function works\n\
876 element-by-element and a logical array is returned. At the top level,\n\
877 @code{isargout} returns an error.\n\
878 @seealso{nargout, nargin, varargin, varargout, nthargout}\n\
879 @end deftypefn")
880 {
881 octave_value retval;
882
883 int nargin = args.length ();
884
885 if (nargin == 1)
886 {
887 if (! symbol_table::at_top_level ())
888 {
889 int nargout1 = symbol_table::varval (".nargout.").int_value ();
890 if (error_state)
891 {
892 error ("isargout: internal error");
893 return retval;
894 }
895
896 Matrix ignored;
897 octave_value tmp = symbol_table::varval (".ignored.");
898 if (tmp.is_defined ())
899 ignored = tmp.matrix_value ();
900
901 if (args(0).is_scalar_type ())
902 {
903 double k = args(0).double_value ();
904 if (! error_state)
905 retval = isargout1 (nargout1, ignored, k);
906 }
907 else if (args(0).is_numeric_type ())
908 {
909 const NDArray ka = args(0).array_value ();
910 if (! error_state)
911 {
912 boolNDArray r (ka.dims ());
913 for (octave_idx_type i = 0; i < ka.numel () && ! error_state; i++)
914 r(i) = isargout1 (nargout1, ignored, ka(i));
915
916 retval = r;
917 }
918 }
919 else
920 gripe_wrong_type_arg ("isargout", args(0));
921 }
922 else
923 error ("isargout: invalid call at top level");
924 }
925 else
926 print_usage ();
927
928 return retval;
929 }
930
931 /*
932 %!function [x, y] = try_isargout ()
933 %! if (isargout (1))
934 %! if (isargout (2))
935 %! x = 1; y = 2;
936 %! else
937 %! x = -1;
938 %! endif
939 %! else
940 %! if (isargout (2))
941 %! y = -2;
942 %! else
943 %! error ("no outputs requested");
944 %! endif
945 %! endif
946 %!endfunction
947 %!
948 %!test
949 %! [x, y] = try_isargout ();
950 %! assert ([x, y], [1, 2]);
951 %!
952 %!test
953 %! [x, ~] = try_isargout ();
954 %! assert (x, -1);
955 %!
956 %!test
957 %! [~, y] = try_isargout ();
958 %! assert (y, -2);
959 %!
960 %!error [~, ~] = try_isargout ();
961 %!
962 %% Check to see that isargout isn't sticky:
963 %!test
964 %! [x, y] = try_isargout ();
965 %! assert ([x, y], [1, 2]);
966 */