Mercurial > octave
changeset 26958:51414d51a973
make function handles work for classdef static methods (bug #51709)
* ov-fcn-handle.cc (err_invalid_fcn_handle): New function.
(octave_fcn_handle::call): Recognize names containing '.' as calls to
functions in +package directories or static classdef methods calls,
possibly defined in +package directories.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 21 Mar 2019 13:33:16 +0000 |
parents | 0ffbc690b493 |
children | 3ed8955dcdf9 |
files | libinterp/octave-value/ov-fcn-handle.cc |
diffstat | 1 files changed, 111 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/octave-value/ov-fcn-handle.cc Wed Mar 20 18:00:27 2019 -0700 +++ b/libinterp/octave-value/ov-fcn-handle.cc Thu Mar 21 13:33:16 2019 +0000 @@ -177,21 +177,130 @@ return retval; } +static void +err_invalid_fcn_handle (const std::string& name) +{ + error ("%s: invalid function handle", name.c_str ()); +} + octave_value_list octave_fcn_handle::call (int nargout, const octave_value_list& args) { + // FIXME: if m_name has a '.' in the name, lookup first component. If + // it is a classdef meta object, then build TYPE and IDX arguments and + // make a subsref call using them. + octave_value fcn_to_call = m_fcn; if (! fcn_to_call.is_defined ()) { + // The following code is similar to part of + // tree_evaluator::visit_index_expression but simpler because it + // handles a more restricted case. + octave::symbol_table& symtab = octave::__get_symbol_table__ ("octave_fcn_handle::call"); - fcn_to_call = symtab.find_function (m_name, args, m_scope); + size_t pos = m_name.find ('.'); + + if (pos != std::string::npos) + { + // We can have one of + // + // pkg-list . fcn (args) + // pkg-list . cls . meth (args) + // cls . meth (args) + + // Evaluate package elements until we find a function or a + // classdef_meta object that is not a package. + // subsref call. + + size_t beg = 0; + size_t end = pos; + + std::vector<std::string> idx_elts; + + while (true) + { + end = m_name.find ('.', beg); + + idx_elts.push_back (m_name.substr (beg, end-beg)); + + if (end == std::string::npos) + break; + + beg = end+1; + } + + octave_value partial_expr_val + = symtab.find_function (idx_elts[0], ovl (), m_scope); + + std::string type; + std::list<octave_value_list> arg_list; + + size_t n_elts = idx_elts.size (); + + for (size_t i = 1; i < n_elts; i++) + { + if (partial_expr_val.is_package ()) + { + type = "."; + arg_list.push_back (ovl (idx_elts[i])); + + try + { + // Silently ignore extra output values. + + octave_value_list tmp_list + = partial_expr_val.subsref (type, arg_list, 0); + + partial_expr_val + = tmp_list.length () ? tmp_list(0) : octave_value (); + + if (partial_expr_val.is_cs_list ()) + err_invalid_fcn_handle (m_name); + + arg_list.clear (); + } + catch (octave::index_exception&) + { + err_invalid_fcn_handle (m_name); + } + } + else if (partial_expr_val.is_classdef_meta ()) + { + // Class name must be the next to the last element (it + // was the previous one, so if this is the final + // element, it should be as static classdef method, + // but we'll let the classdef_meta subsref function + // sort that out. + + if (i != n_elts-1) + err_invalid_fcn_handle (m_name); + + type = ".("; + arg_list.push_back (ovl (idx_elts[i])); + arg_list.push_back (args); + + return partial_expr_val.subsref (type, arg_list, nargout); + } + else + err_invalid_fcn_handle (m_name); + } + + // If we get here, we must have a function to call. + + if (! partial_expr_val.is_function ()) + err_invalid_fcn_handle (m_name); + + fcn_to_call = partial_expr_val; + } + else + fcn_to_call = symtab.find_function (m_name, args, m_scope); } if (! fcn_to_call.is_defined ()) - error ("%s: invalid function handle", m_name.c_str ()); + err_invalid_fcn_handle (m_name); octave::stack_frame *closure_context = nullptr;