Mercurial > octave
view libinterp/octave-value/ov-usr-fcn.cc @ 31607:aac27ad79be6 stable
maint: Re-indent code after switch to using namespace macros.
* build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc,
__ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc,
__pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h,
besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc,
call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc,
debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc,
dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h,
error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h,
event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc,
file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h,
gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h,
graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc,
gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h,
interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h,
inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc,
latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h,
lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc,
matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h,
oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc,
oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h,
oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h,
octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc,
pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc,
settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc,
sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc,
syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h,
symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h,
text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc,
url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h,
variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc,
gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc,
cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h,
cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h,
cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc,
ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc,
ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h,
ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc,
ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc,
ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc,
ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc,
ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h,
ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc,
ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h,
octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc,
op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h,
anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h,
comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h,
parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h,
pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h,
pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc,
pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc,
pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h,
pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h,
pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h,
pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h,
pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h,
pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h,
pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h,
pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h,
idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h,
aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h,
gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc,
lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h,
oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc,
oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h,
randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h,
sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc,
sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h,
file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h,
lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h,
oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc,
oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h,
action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h,
cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h,
lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h,
lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc,
oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc,
oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc,
oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc,
pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc,
url-transfer.h:
Re-indent code after switch to using namespace macros.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 18:02:15 -0800 |
parents | e88a07dec498 |
children | 597f3ee61a48 |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 1996-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // This file is part of Octave. // // Octave is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Octave is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Octave; see the file COPYING. If not, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include <sstream> #include "file-info.h" #include "file-ops.h" #include "file-stat.h" #include "str-vec.h" #include "builtin-defun-decls.h" #include "defaults.h" #include "Cell.h" #include "defun.h" #include "error.h" #include "errwarn.h" #include "input.h" #include "ovl.h" #include "ov-usr-fcn.h" #include "ov.h" #include "pager.h" #include "pt-eval.h" #include "pt-jump.h" #include "pt-misc.h" #include "pt-pr-code.h" #include "pt-stmt.h" #include "pt-walk.h" #include "symtab.h" #include "interpreter-private.h" #include "interpreter.h" #include "unwind-prot.h" #include "utils.h" #include "parse.h" #include "profiler.h" #include "variables.h" #include "ov-fcn-handle.h" // Whether to optimize subsasgn method calls. static bool Voptimize_subsasgn_calls = true; octave_user_code::~octave_user_code (void) { // This function is no longer valid, so remove the pointer to it from // the corresponding scope. // FIXME: would it be better to use shared/weak pointers for this job // instead of storing a bare pointer in the scope object? m_scope.set_user_code (nullptr); // FIXME: shouldn't this happen automatically when deleting cmd_list? if (m_cmd_list) { octave::event_manager& evmgr = octave::__get_event_manager__ (); m_cmd_list->remove_all_breakpoints (evmgr, m_file_name); } delete m_cmd_list; delete m_file_info; } void octave_user_code::get_file_info (void) { m_file_info = new octave::file_info (m_file_name); octave::sys::file_stat fs (m_file_name); if (fs && (fs.mtime () > time_parsed ())) warning ("function file '%s' changed since it was parsed", m_file_name.c_str ()); } std::string octave_user_code::get_code_line (std::size_t line) { if (! m_file_info) get_file_info (); return m_file_info->get_line (line); } std::deque<std::string> octave_user_code::get_code_lines (std::size_t line, std::size_t num_lines) { if (! m_file_info) get_file_info (); return m_file_info->get_lines (line, num_lines); } void octave_user_code::cache_function_text (const std::string& text, const octave::sys::time& timestamp) { if (m_file_info) delete m_file_info; if (timestamp > time_parsed ()) warning ("help text for function is newer than function"); m_file_info = new octave::file_info (text, timestamp); } std::map<std::string, octave_value> octave_user_code::subfunctions (void) const { return std::map<std::string, octave_value> (); } octave_value octave_user_code::dump (void) const { std::map<std::string, octave_value> m = {{ "scope_info", m_scope ? m_scope.dump () : "0x0" }, { "m_file_name", m_file_name }, { "time_parsed", m_t_parsed }, { "time_checked", m_t_checked } }; return octave_value (m); } // User defined scripts. DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_user_script, "user-defined script", "user-defined script"); octave_user_script::octave_user_script (void) : octave_user_code () { } octave_user_script::octave_user_script (const std::string& fnm, const std::string& nm, const octave::symbol_scope& scope, octave::tree_statement_list *cmds, const std::string& ds) : octave_user_code (fnm, nm, scope, cmds, ds) { if (m_cmd_list) m_cmd_list->mark_as_script_body (); } octave_user_script::octave_user_script (const std::string& fnm, const std::string& nm, const octave::symbol_scope& scope, const std::string& ds) : octave_user_code (fnm, nm, scope, nullptr, ds) { } // We must overload the call method so that we call the proper // push_stack_frame method, which is overloaded for pointers to // octave_function, octave_user_function, and octave_user_script // objects. octave_value_list octave_user_script::call (octave::tree_evaluator& tw, int nargout, const octave_value_list& args) { tw.push_stack_frame (this); octave::unwind_action act ([&tw] () { tw.pop_stack_frame (); }); return execute (tw, nargout, args); } octave_value_list octave_user_script::execute (octave::tree_evaluator& tw, int nargout, const octave_value_list& args) { return tw.execute_user_script (*this, nargout, args); } void octave_user_script::accept (octave::tree_walker& tw) { tw.visit_octave_user_script (*this); } // User defined functions. DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_user_function, "user-defined function", "user-defined function"); // Ugh. This really needs to be simplified (code/data? // extrinsic/intrinsic state?). octave_user_function::octave_user_function (const octave::symbol_scope& scope, octave::tree_parameter_list *pl, octave::tree_parameter_list *rl, octave::tree_statement_list *cl) : octave_user_code ("", "", scope, cl, ""), m_param_list (pl), m_ret_list (rl), m_lead_comm (), m_trail_comm (), m_location_line (0), m_location_column (0), m_system_fcn_file (false), m_num_named_args (m_param_list ? m_param_list->length () : 0), m_subfunction (false), m_inline_function (false), m_anonymous_function (false), m_nested_function (false), m_class_constructor (none), m_class_method (none) { if (m_cmd_list) m_cmd_list->mark_as_function_body (); } octave_user_function::~octave_user_function (void) { delete m_param_list; delete m_ret_list; delete m_lead_comm; delete m_trail_comm; } octave_user_function * octave_user_function::define_ret_list (octave::tree_parameter_list *t) { m_ret_list = t; return this; } // If there is no explicit end statement at the end of the function, // relocate the no_op that was generated for the end of file condition // to appear on the next line after the last statement in the file, or // the next line after the function keyword if there are no statements. // More precisely, the new location should probably be on the next line // after the end of the parameter list, but we aren't tracking that // information (yet). void octave_user_function::maybe_relocate_end_internal (void) { if (m_cmd_list && ! m_cmd_list->empty ()) { octave::tree_statement *last_stmt = m_cmd_list->back (); if (last_stmt && last_stmt->is_end_of_fcn_or_script () && last_stmt->is_end_of_file ()) { octave::tree_statement_list::reverse_iterator next_to_last_elt = m_cmd_list->rbegin (); next_to_last_elt++; int new_eof_line; int new_eof_col; if (next_to_last_elt == m_cmd_list->rend ()) { new_eof_line = beginning_line (); new_eof_col = beginning_column (); } else { octave::tree_statement *next_to_last_stmt = *next_to_last_elt; new_eof_line = next_to_last_stmt->line (); new_eof_col = next_to_last_stmt->column (); } last_stmt->set_location (new_eof_line + 1, new_eof_col); } } } void octave_user_function::maybe_relocate_end (void) { std::map<std::string, octave_value> fcns = subfunctions (); if (! fcns.empty ()) { for (auto& nm_fnval : fcns) { octave_user_function *f = nm_fnval.second.user_function_value (); if (f) f->maybe_relocate_end_internal (); } } maybe_relocate_end_internal (); } void octave_user_function::stash_parent_fcn_scope (const octave::symbol_scope& ps) { m_scope.set_parent (ps); } std::string octave_user_function::profiler_name (void) const { std::ostringstream result; if (is_anonymous_function ()) result << "anonymous@" << fcn_file_name () << ':' << m_location_line << ':' << m_location_column; else if (is_subfunction ()) result << parent_fcn_name () << '>' << name (); else if (is_class_method ()) result << '@' << dispatch_class () << '/' << name (); else if (is_class_constructor () || is_classdef_constructor ()) result << '@' << name (); else if (is_inline_function ()) result << "inline@" << fcn_file_name () << ':' << m_location_line << ':' << m_location_column; else result << name (); return result.str (); } void octave_user_function::mark_as_system_fcn_file (void) { if (! m_file_name.empty ()) { // We really should stash the whole path to the file we found, // when we looked it up, to avoid possible race conditions... // FIXME // // We probably also don't need to get the library directory // every time, but since this function is only called when the // function file is parsed, it probably doesn't matter that // much. std::string ff_name = octave::fcn_file_in_path (m_file_name); static const std::string canonical_fcn_file_dir = octave::sys::canonicalize_file_name (octave::config::fcn_file_dir ()); static const std::string fcn_file_dir = canonical_fcn_file_dir.empty () ? octave::config::fcn_file_dir () : canonical_fcn_file_dir; if (fcn_file_dir == ff_name.substr (0, fcn_file_dir.length ())) m_system_fcn_file = true; } else m_system_fcn_file = false; } void octave_user_function::erase_subfunctions (void) { m_scope.erase_subfunctions (); } bool octave_user_function::takes_varargs (void) const { return (m_param_list && m_param_list->takes_varargs ()); } bool octave_user_function::takes_var_return (void) const { return (m_ret_list && m_ret_list->takes_varargs ()); } void octave_user_function::mark_as_private_function (const std::string& cname) { m_scope.mark_subfunctions_in_scope_as_private (cname); octave_function::mark_as_private_function (cname); } void octave_user_function::lock_subfunctions (void) { m_scope.lock_subfunctions (); } void octave_user_function::unlock_subfunctions (void) { m_scope.unlock_subfunctions (); } std::map<std::string, octave_value> octave_user_function::subfunctions (void) const { return m_scope.subfunctions (); } // Find definition of final subfunction in list of subfcns: // // sub1>sub2>...>subN octave_value octave_user_function::find_subfunction (const std::string& subfcns_arg) const { std::string subfcns = subfcns_arg; std::string first_fcn = subfcns; std::size_t pos = subfcns.find ('>'); if (pos == std::string::npos) subfcns = ""; else { first_fcn = subfcns.substr (0, pos-1); subfcns = subfcns.substr (pos+1); } octave_value ov_fcn = m_scope.find_subfunction (first_fcn); if (subfcns.empty ()) return ov_fcn; octave_user_function *fcn = ov_fcn.user_function_value (); return fcn->find_subfunction (subfcns); } bool octave_user_function::has_subfunctions (void) const { return m_scope.has_subfunctions (); } void octave_user_function::stash_subfunction_names (const std::list<std::string>& names) { m_scope.stash_subfunction_names (names); } std::list<std::string> octave_user_function::subfunction_names (void) const { return m_scope.subfunction_names (); } octave_value_list octave_user_function::all_va_args (const octave_value_list& args) { octave_value_list retval; octave_idx_type n = args.length () - m_num_named_args; if (n > 0) retval = args.slice (m_num_named_args, n); return retval; } // We must overload the call method so that we call the proper // push_stack_frame method, which is overloaded for pointers to // octave_function, octave_user_function, and octave_user_script // objects. octave_value_list octave_user_function::call (octave::tree_evaluator& tw, int nargout, const octave_value_list& args) { tw.push_stack_frame (this); octave::unwind_action act ([&tw] () { tw.pop_stack_frame (); }); return execute (tw, nargout, args); } octave_value_list octave_user_function::execute (octave::tree_evaluator& tw, int nargout, const octave_value_list& args) { return tw.execute_user_function (*this, nargout, args); } void octave_user_function::accept (octave::tree_walker& tw) { tw.visit_octave_user_function (*this); } octave::tree_expression * octave_user_function::special_expr (void) { panic_unless (is_special_expr ()); panic_if (m_cmd_list->length () != 1); octave::tree_statement *stmt = m_cmd_list->front (); return stmt->expression (); } bool octave_user_function::subsasgn_optimization_ok (void) { bool retval = false; if (Voptimize_subsasgn_calls && m_param_list && m_ret_list && m_param_list->length () > 0 && ! m_param_list->varargs_only () && m_ret_list->length () == 1 && ! m_ret_list->takes_varargs ()) { octave::tree_identifier *par1 = m_param_list->front ()->ident (); octave::tree_identifier *ret1 = m_ret_list->front ()->ident (); retval = par1->name () == ret1->name (); } return retval; } std::string octave_user_function::ctor_type_str (void) const { std::string retval; switch (m_class_constructor) { case none: retval = "none"; break; case legacy: retval = "legacy"; break; case classdef: retval = "classdef"; break; default: retval = "unrecognized enum value"; break; } return retval; } std::string octave_user_function::method_type_str (void) const { std::string retval; switch (m_class_method) { case none: retval = "none"; break; case legacy: retval = "legacy"; break; case classdef: retval = "classdef"; break; default: retval = "unrecognized enum value"; break; } return retval; } octave_value octave_user_function::dump (void) const { std::map<std::string, octave_value> m = {{ "user_code", octave_user_code::dump () }, { "line", m_location_line }, { "col", m_location_column }, { "end_line", m_end_location_line }, { "end_col", m_end_location_column }, { "system_fcn_file", m_system_fcn_file }, { "num_named_args", m_num_named_args }, { "subfunction", m_subfunction }, { "inline_function", m_inline_function }, { "anonymous_function", m_anonymous_function }, { "nested_function", m_nested_function }, { "ctor_type", ctor_type_str () }, { "class_method", m_class_method } }; return octave_value (m); } void octave_user_function::print_code_function_header (const std::string& prefix) { octave::tree_print_code tpc (octave_stdout, prefix); tpc.visit_octave_user_function_header (*this); } void octave_user_function::print_code_function_trailer (const std::string& prefix) { octave::tree_print_code tpc (octave_stdout, prefix); tpc.visit_octave_user_function_trailer (*this); } void octave_user_function::restore_warning_states (void) { octave::interpreter& interp = octave::__get_interpreter__ (); octave::tree_evaluator& tw = interp.get_evaluator (); octave_value val = tw.get_auto_fcn_var (octave::stack_frame::SAVED_WARNING_STATES); if (val.is_defined ()) { // Fail spectacularly if SAVED_WARNING_STATES is not an // octave_map (or octave_scalar_map) object. if (! val.isstruct ()) panic_impossible (); octave_map m = val.map_value (); Cell ids = m.contents ("identifier"); Cell states = m.contents ("state"); for (octave_idx_type i = 0; i < m.numel (); i++) Fwarning (interp, ovl (states(i), ids(i))); } } OCTAVE_BEGIN_NAMESPACE(octave) DEFMETHOD (nargin, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{n} =} nargin () @deftypefnx {} {@var{n} =} nargin (@var{fcn}) Report the number of input arguments to a function. Called from within a function, return the number of arguments passed to the function. At the top level, return the number of command line arguments passed to Octave. If called with the optional argument @var{fcn}---a function name or handle---return the declared number of arguments that the function can accept. If the last argument to @var{fcn} is @var{varargin} the returned value is negative. For example, the function @code{union} for sets is declared as @example @group function [y, ia, ib] = union (a, b, varargin) and nargin ("union") @result{} -3 @end group @end example Programming Note: @code{nargin} does not work on compiled functions (@file{.oct} files) such as built-in or dynamically loaded functions. @seealso{nargout, narginchk, varargin, inputname} @end deftypefn */) { int nargin = args.length (); if (nargin > 1) print_usage (); octave_value retval; if (nargin == 1) { octave_value fcn = args(0); if (fcn.is_string ()) { symbol_table& symtab = interp.get_symbol_table (); std::string name = fcn.string_value (); fcn = symtab.find_function (name); if (fcn.is_undefined ()) error ("nargin: invalid function name: %s", name.c_str ()); } octave_function *fcn_val = fcn.function_value (true); if (! fcn_val) error ("nargin: FCN must be a string or function handle"); octave_user_function *ufcn = fcn_val->user_function_value (true); if (! ufcn) { // Matlab gives up for histc, so maybe it's ok that we // give up sometimes too? std::string type = fcn_val->type_name (); error ("nargin: number of input arguments unavailable for %s objects", type.c_str ()); } tree_parameter_list *m_param_list = ufcn->parameter_list (); retval = (m_param_list ? m_param_list->length () : 0); if (ufcn->takes_varargs ()) retval = -1 - retval; } else { tree_evaluator& tw = interp.get_evaluator (); retval = tw.get_auto_fcn_var (stack_frame::NARGIN); if (retval.is_undefined ()) retval = 0; } return retval; } DEFMETHOD (nargout, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{n} =} nargout () @deftypefnx {} {@var{n} =} nargout (@var{fcn}) Report the number of output arguments from a function. Called from within a function, return the number of values the caller expects to receive. At the top level, @code{nargout} with no argument is undefined and will produce an error. If called with the optional argument @var{fcn}---a function name or handle---return the number of declared output values that the function can produce. If the final output argument is @var{varargout} the returned value is negative. For example, @example f () @end example @noindent will cause @code{nargout} to return 0 inside the function @code{f} and @example [s, t] = f () @end example @noindent will cause @code{nargout} to return 2 inside the function @code{f}. In the second usage, @example nargout (@@histc) # or nargout ("histc") using a string input @end example @noindent will return 2, because @code{histc} has two outputs, whereas @example nargout (@@imread) @end example @noindent will return -2, because @code{imread} has two outputs and the second is @var{varargout}. Programming Note. @code{nargout} does not work for built-in functions and returns -1 for all anonymous functions. @seealso{nargin, varargout, isargout, nthargout} @end deftypefn */) { int nargin = args.length (); if (nargin > 1) print_usage (); octave_value retval; if (nargin == 1) { octave_value fcn = args(0); if (fcn.is_string ()) { symbol_table& symtab = interp.get_symbol_table (); std::string name = fcn.string_value (); fcn = symtab.find_function (name); if (fcn.is_undefined ()) error ("nargout: invalid function name: %s", name.c_str ()); } if (fcn.is_inline_function ()) return ovl (1); if (fcn.is_function_handle ()) { octave_fcn_handle *fh = fcn.fcn_handle_value (); if (fh->is_anonymous ()) return ovl (-1); } octave_function *fcn_val = fcn.function_value (true); if (! fcn_val) error ("nargout: FCN must be a string or function handle"); octave_user_function *ufcn = fcn_val->user_function_value (true); if (! ufcn) { // Matlab gives up for histc, so maybe it's ok that we // give up sometimes too? std::string type = fcn_val->type_name (); error ("nargout: number of output arguments unavailable for %s objects", type.c_str ()); } tree_parameter_list *m_ret_list = ufcn->return_list (); retval = (m_ret_list ? m_ret_list->length () : 0); if (ufcn->takes_var_return ()) retval = -1 - retval; } else { if (interp.at_top_level ()) error ("nargout: invalid call at top level"); tree_evaluator& tw = interp.get_evaluator (); retval = tw.get_auto_fcn_var (stack_frame::NARGOUT); if (retval.is_undefined ()) retval = 0; } return retval; } DEFUN (optimize_subsasgn_calls, args, nargout, doc: /* -*- texinfo -*- @deftypefn {} {@var{val} =} optimize_subsasgn_calls () @deftypefnx {} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val}) @deftypefnx {} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val}, "local") Query or set the internal flag for @code{subsasgn} method call optimizations. If true, Octave will attempt to eliminate the redundant copying when calling the @code{subsasgn} method of a user-defined class. When called from inside a function with the @qcode{"local"} option, the variable is changed locally for the function and any subroutines it calls. The original variable value is restored when exiting the function. @seealso{subsasgn} @end deftypefn */) { return set_internal_variable (Voptimize_subsasgn_calls, args, nargout, "optimize_subsasgn_calls"); } static bool val_in_table (const Matrix& table, double val) { if (table.isempty ()) return false; octave_idx_type i = table.lookup (val, ASCENDING); return (i > 0 && table(i-1) == val); } static bool isargout1 (int nargout, const Matrix& ignored, double k) { if (k != math::fix (k) || k <= 0) error ("isargout: K must be a positive integer"); return (k == 1 || k <= nargout) && ! val_in_table (ignored, k); } DEFMETHOD (isargout, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} isargout (@var{k}) Within a function, return a logical value indicating whether the argument @var{k} will be assigned to a variable on output. If the result is false, the argument has been ignored during the function call through the use of the tilde (~) special output argument. Functions can use @code{isargout} to avoid performing unnecessary calculations for outputs which are unwanted. If @var{k} is outside the range @code{1:max (nargout)}, the function returns false. @var{k} can also be an array, in which case the function works element-by-element and a logical array is returned. At the top level, @code{isargout} returns an error. @seealso{nargout, varargout, nthargout} @end deftypefn */) { if (args.length () != 1) print_usage (); if (interp.at_top_level ()) error ("isargout: invalid call at top level"); tree_evaluator& tw = interp.get_evaluator (); octave_value tmp; int nargout1 = 0; tmp = tw.get_auto_fcn_var (stack_frame::NARGOUT); if (tmp.is_defined ()) nargout1 = tmp.int_value (); Matrix ignored; tmp = tw.get_auto_fcn_var (stack_frame::IGNORED); if (tmp.is_defined ()) ignored = tmp.matrix_value (); if (args(0).is_scalar_type ()) { double k = args(0).double_value (); return ovl (isargout1 (nargout1, ignored, k)); } else if (args(0).isnumeric ()) { const NDArray ka = args(0).array_value (); boolNDArray r (ka.dims ()); for (octave_idx_type i = 0; i < ka.numel (); i++) r(i) = isargout1 (nargout1, ignored, ka(i)); return ovl (r); } else err_wrong_type_arg ("isargout", args(0)); return ovl (); } /* %!function [x, y] = try_isargout () %! if (isargout (1)) %! if (isargout (2)) %! x = 1; y = 2; %! else %! x = -1; %! endif %! else %! if (isargout (2)) %! y = -2; %! else %! error ("no outputs requested"); %! endif %! endif %!endfunction %! %!function [a, b] = try_isargout2 (x, y) %! a = y; %! b = {isargout(1), isargout(2), x}; %!endfunction %! %!test %! [x, y] = try_isargout (); %! assert ([x, y], [1, 2]); %! %!test %! [x, ~] = try_isargout (); %! assert (x, -1); %! %!test %! [~, y] = try_isargout (); %! assert (y, -2); %! %!error [~, ~] = try_isargout () %! ## Check to see that isargout isn't sticky: %!test %! [x, y] = try_isargout (); %! assert ([x, y], [1, 2]); %! ## It should work without (): %!test %! [~, y] = try_isargout; %! assert (y, -2); %! ## It should work in function handles, anonymous functions, and cell ## arrays of handles or anonymous functions. %!test %! fh = @try_isargout; %! af = @() try_isargout; %! c = {fh, af}; %! [~, y] = fh (); %! assert (y, -2); %! [~, y] = af (); %! assert (y, -2); %! [~, y] = c{1}(); %! assert (y, -2); %! [~, y] = c{2}(); %! assert (y, -2); %! ## Nesting, anyone? %!test %! [~, b] = try_isargout2 (try_isargout, rand); %! assert (b, {0, 1, -1}); %!test %! [~, b] = try_isargout2 ({try_isargout, try_isargout}, rand); %! assert (b, {0, 1, {-1, -1}}); */ OCTAVE_END_NAMESPACE(octave)