# HG changeset patch # User Jaroslav Hajek # Date 1284109837 -7200 # Node ID 9e95b90ab7cdba17984f258210762ddb6e3a00b2 # Parent cab8365e476df0bee65f5e98d7b606ca3df3bcec [mq]: binders.diff diff --git a/src/ov-fcn-handle.cc b/src/ov-fcn-handle.cc --- a/src/ov-fcn-handle.cc +++ b/src/ov-fcn-handle.cc @@ -47,6 +47,7 @@ #include "pt-cmd.h" #include "pt-exp.h" #include "pt-assign.h" +#include "pt-arg-list.h" #include "variables.h" #include "parse.h" #include "unwind-prot.h" @@ -1756,3 +1757,188 @@ %!test %! assert (testrecursionfunc (@(x) x, 1), 8); */ + +octave_fcn_binder::octave_fcn_binder (const octave_value& f, + const octave_value& root, + const octave_value_list& templ, + const std::vector& mask, + int exp_nargin) +: octave_fcn_handle (f), root_handle (root), arg_template (templ), + arg_mask (mask), expected_nargin (exp_nargin) +{ +} + +octave_fcn_handle * +octave_fcn_binder::maybe_binder (const octave_value& f) +{ + octave_fcn_handle *retval = 0; + + octave_user_function *usr_fcn = f.user_function_value (false); + tree_parameter_list *param_list = usr_fcn ? usr_fcn->parameter_list () : 0; + + // Verify that the body is a single expression (always true in theory). + + tree_statement_list *cmd_list = usr_fcn ? usr_fcn->body () : 0; + tree_expression *body_expr = (cmd_list->length () == 1 + ? cmd_list->front ()->expression () : 0); + + + if (body_expr && body_expr->is_index_expression () + && ! (param_list && param_list->takes_varargs ())) + { + // It's an index expression. + tree_index_expression *idx_expr = dynamic_cast (body_expr); + tree_expression *head_expr = idx_expr->expression (); + std::list arg_lists = idx_expr->arg_lists (); + std::string type_tags = idx_expr->type_tags (); + + if (type_tags.length () == 1 && type_tags[0] == '(' + && head_expr->is_identifier ()) + { + assert (arg_lists.size () == 1); + + // It's a single index expression: a(x,y,....) + tree_identifier *head_id = dynamic_cast (head_expr); + tree_argument_list *arg_list = arg_lists.front (); + + // Build a map of input params to their position. + std::map arginmap; + int npar = 0; + + if (param_list) + { + for (tree_parameter_list::iterator it = param_list->begin (); + it != param_list->end (); ++it, ++npar) + { + tree_decl_elt *elt = *it; + tree_identifier *id = elt ? elt->ident () : 0; + if (id && ! id->is_black_hole ()) + arginmap[id->name ()] = npar; + } + } + + if (arg_list && arg_list->length () > 0) + { + bool bad = false; + int nargs = arg_list->length (); + octave_value_list arg_template (nargs); + std::vector arg_mask (nargs); + + // Verify that each argument is either a named param, a constant, or a defined identifier. + int iarg = 0; + for (tree_argument_list::iterator it = arg_list->begin (); + it != arg_list->end (); ++it, ++iarg) + { + tree_expression *elt = *it; + if (elt && elt->is_constant ()) + { + arg_template(iarg) = elt->rvalue1 (); + arg_mask[iarg] = -1; + } + else if (elt && elt->is_identifier ()) + { + tree_identifier *elt_id = dynamic_cast (elt); + if (arginmap.find (elt_id->name ()) != arginmap.end ()) + { + arg_mask[iarg] = arginmap[elt_id->name ()]; + } + else if (elt_id->is_defined ()) + { + arg_template(iarg) = elt_id->rvalue1 (); + arg_mask[iarg] = -1; + } + else + { + bad = true; + break; + } + } + else + { + bad = true; + break; + } + } + + octave_value root_val; + + if (! bad) + { + // If the head is a value, use it as root. + if (head_id->is_defined ()) + root_val = head_id->rvalue1 (); + else + { + // It's a name. + std::string head_name = head_id->name (); + // Function handles can't handle legacy dispatch, so + // we make sure it's not defined. + if (symbol_table::get_dispatch (head_name).size () > 0) + bad = true; + else + { + // Simulate try/catch. + // FIXME: there should be a method for that. + unwind_protect frame; + + frame.protect_var (error_state); + frame.protect_var (buffer_error_messages); + frame.protect_var (Vdebug_on_error); + frame.protect_var (Vdebug_on_warning); + + buffer_error_messages++; + Vdebug_on_error = false; + Vdebug_on_warning = false; + + root_val = make_fcn_handle (head_name); + if (error_state) + bad = true; + } + } + } + + if (! bad) + { + retval = new octave_fcn_binder (f, root_val, arg_template, + arg_mask, npar); + } + } + } + } + + if (! retval) + retval = new octave_fcn_handle (f, octave_fcn_handle::anonymous); + + return retval; +} + +octave_value_list +octave_fcn_binder::do_multi_index_op (int nargout, + const octave_value_list& args) +{ + return do_multi_index_op (nargout, args, 0); +} + +octave_value_list +octave_fcn_binder::do_multi_index_op (int nargout, + const octave_value_list& args, + const std::list* lvalue_list) +{ + octave_value_list retval; + + if (args.length () == expected_nargin) + { + for (int i = 0; i < arg_template.length (); i++) + { + int j = arg_mask[i]; + if (j >= 0) + arg_template.xelem(i) = args(j); + } + + retval = root_handle.do_multi_index_op (nargout, arg_template, lvalue_list); + } + else + retval = octave_fcn_handle::do_multi_index_op (nargout, args, lvalue_list); + + return retval; +} diff --git a/src/ov-fcn-handle.h b/src/ov-fcn-handle.h --- a/src/ov-fcn-handle.h +++ b/src/ov-fcn-handle.h @@ -187,4 +187,33 @@ extern octave_value make_fcn_handle (const std::string& nm, bool local_funcs = true); +class +OCTINTERP_API +octave_fcn_binder : public octave_fcn_handle +{ +private: + // Private ctor. + octave_fcn_binder (const octave_value& f, const octave_value& root, + const octave_value_list& templ, + const std::vector& mask, int exp_nargin); + +public: + + // Factory method. + static octave_fcn_handle *maybe_binder (const octave_value& f); + + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& args); + + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& args, + const std::list* lvalue_list); + +protected: + + octave_value root_handle; + octave_value_list arg_template; + std::vector arg_mask; + int expected_nargin; +}; #endif diff --git a/src/pt-fcn-handle.cc b/src/pt-fcn-handle.cc --- a/src/pt-fcn-handle.cc +++ b/src/pt-fcn-handle.cc @@ -126,7 +126,7 @@ octave_value ov_fcn (uf); - octave_value fh (new octave_fcn_handle (ov_fcn, octave_fcn_handle::anonymous)); + octave_value fh (octave_fcn_binder::maybe_binder (ov_fcn)); return fh; } # HG changeset patch # User Jaroslav Hajek # Date 1284112121 -7200 # Node ID bf4e506cff0ed1156b80cd1eca6619570c353efe # Parent cab8365e476df0bee65f5e98d7b606ca3df3bcec [mq]: binders.diff diff --git a/src/ov-fcn-handle.cc b/src/ov-fcn-handle.cc --- a/src/ov-fcn-handle.cc +++ b/src/ov-fcn-handle.cc @@ -2,6 +2,7 @@ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 John W. Eaton Copyright (C) 2009 VZLU Prague, a.s. +Copyright (C) 2010 Jaroslav Hajek This file is part of Octave. @@ -47,6 +48,7 @@ #include "pt-cmd.h" #include "pt-exp.h" #include "pt-assign.h" +#include "pt-arg-list.h" #include "variables.h" #include "parse.h" #include "unwind-prot.h" @@ -1756,3 +1758,188 @@ %!test %! assert (testrecursionfunc (@(x) x, 1), 8); */ + +octave_fcn_binder::octave_fcn_binder (const octave_value& f, + const octave_value& root, + const octave_value_list& templ, + const std::vector& mask, + int exp_nargin) +: octave_fcn_handle (f), root_handle (root), arg_template (templ), + arg_mask (mask), expected_nargin (exp_nargin) +{ +} + +octave_fcn_handle * +octave_fcn_binder::maybe_binder (const octave_value& f) +{ + octave_fcn_handle *retval = 0; + + octave_user_function *usr_fcn = f.user_function_value (false); + tree_parameter_list *param_list = usr_fcn ? usr_fcn->parameter_list () : 0; + + // Verify that the body is a single expression (always true in theory). + + tree_statement_list *cmd_list = usr_fcn ? usr_fcn->body () : 0; + tree_expression *body_expr = (cmd_list->length () == 1 + ? cmd_list->front ()->expression () : 0); + + + if (body_expr && body_expr->is_index_expression () + && ! (param_list && param_list->takes_varargs ())) + { + // It's an index expression. + tree_index_expression *idx_expr = dynamic_cast (body_expr); + tree_expression *head_expr = idx_expr->expression (); + std::list arg_lists = idx_expr->arg_lists (); + std::string type_tags = idx_expr->type_tags (); + + if (type_tags.length () == 1 && type_tags[0] == '(' + && head_expr->is_identifier ()) + { + assert (arg_lists.size () == 1); + + // It's a single index expression: a(x,y,....) + tree_identifier *head_id = dynamic_cast (head_expr); + tree_argument_list *arg_list = arg_lists.front (); + + // Build a map of input params to their position. + std::map arginmap; + int npar = 0; + + if (param_list) + { + for (tree_parameter_list::iterator it = param_list->begin (); + it != param_list->end (); ++it, ++npar) + { + tree_decl_elt *elt = *it; + tree_identifier *id = elt ? elt->ident () : 0; + if (id && ! id->is_black_hole ()) + arginmap[id->name ()] = npar; + } + } + + if (arg_list && arg_list->length () > 0) + { + bool bad = false; + int nargs = arg_list->length (); + octave_value_list arg_template (nargs); + std::vector arg_mask (nargs); + + // Verify that each argument is either a named param, a constant, or a defined identifier. + int iarg = 0; + for (tree_argument_list::iterator it = arg_list->begin (); + it != arg_list->end (); ++it, ++iarg) + { + tree_expression *elt = *it; + if (elt && elt->is_constant ()) + { + arg_template(iarg) = elt->rvalue1 (); + arg_mask[iarg] = -1; + } + else if (elt && elt->is_identifier ()) + { + tree_identifier *elt_id = dynamic_cast (elt); + if (arginmap.find (elt_id->name ()) != arginmap.end ()) + { + arg_mask[iarg] = arginmap[elt_id->name ()]; + } + else if (elt_id->is_defined ()) + { + arg_template(iarg) = elt_id->rvalue1 (); + arg_mask[iarg] = -1; + } + else + { + bad = true; + break; + } + } + else + { + bad = true; + break; + } + } + + octave_value root_val; + + if (! bad) + { + // If the head is a value, use it as root. + if (head_id->is_defined ()) + root_val = head_id->rvalue1 (); + else + { + // It's a name. + std::string head_name = head_id->name (); + // Function handles can't handle legacy dispatch, so + // we make sure it's not defined. + if (symbol_table::get_dispatch (head_name).size () > 0) + bad = true; + else + { + // Simulate try/catch. + // FIXME: there should be a method for that. + unwind_protect frame; + + frame.protect_var (error_state); + frame.protect_var (buffer_error_messages); + frame.protect_var (Vdebug_on_error); + frame.protect_var (Vdebug_on_warning); + + buffer_error_messages++; + Vdebug_on_error = false; + Vdebug_on_warning = false; + + root_val = make_fcn_handle (head_name); + if (error_state) + bad = true; + } + } + } + + if (! bad) + { + retval = new octave_fcn_binder (f, root_val, arg_template, + arg_mask, npar); + } + } + } + } + + if (! retval) + retval = new octave_fcn_handle (f, octave_fcn_handle::anonymous); + + return retval; +} + +octave_value_list +octave_fcn_binder::do_multi_index_op (int nargout, + const octave_value_list& args) +{ + return do_multi_index_op (nargout, args, 0); +} + +octave_value_list +octave_fcn_binder::do_multi_index_op (int nargout, + const octave_value_list& args, + const std::list* lvalue_list) +{ + octave_value_list retval; + + if (args.length () == expected_nargin) + { + for (int i = 0; i < arg_template.length (); i++) + { + int j = arg_mask[i]; + if (j >= 0) + arg_template.xelem(i) = args(j); + } + + retval = root_handle.do_multi_index_op (nargout, arg_template, lvalue_list); + } + else + retval = octave_fcn_handle::do_multi_index_op (nargout, args, lvalue_list); + + return retval; +} diff --git a/src/ov-fcn-handle.h b/src/ov-fcn-handle.h --- a/src/ov-fcn-handle.h +++ b/src/ov-fcn-handle.h @@ -187,4 +187,33 @@ extern octave_value make_fcn_handle (const std::string& nm, bool local_funcs = true); +class +OCTINTERP_API +octave_fcn_binder : public octave_fcn_handle +{ +private: + // Private ctor. + octave_fcn_binder (const octave_value& f, const octave_value& root, + const octave_value_list& templ, + const std::vector& mask, int exp_nargin); + +public: + + // Factory method. + static octave_fcn_handle *maybe_binder (const octave_value& f); + + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& args); + + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& args, + const std::list* lvalue_list); + +protected: + + octave_value root_handle; + octave_value_list arg_template; + std::vector arg_mask; + int expected_nargin; +}; #endif diff --git a/src/pt-fcn-handle.cc b/src/pt-fcn-handle.cc --- a/src/pt-fcn-handle.cc +++ b/src/pt-fcn-handle.cc @@ -126,7 +126,7 @@ octave_value ov_fcn (uf); - octave_value fh (new octave_fcn_handle (ov_fcn, octave_fcn_handle::anonymous)); + octave_value fh (octave_fcn_binder::maybe_binder (ov_fcn)); return fh; }