diff --git a/libinterp/corefcn/Cell.cc b/libinterp/corefcn/Cell.cc --- a/libinterp/corefcn/Cell.cc +++ b/libinterp/corefcn/Cell.cc @@ -162,51 +162,64 @@ Cell::index (const octave_value_list& id octave_idx_type n = idx_arg.length (); - switch (n) + // If we catch an indexing error in index_vector(), we flag an error in + // index k. Ensure it is the right value befor each idx_vector() call. + // Same variable as used in for() loop in default: case. + octave_idx_type k = 0; + + try { - case 0: - retval = *this; - break; + switch (n) + { + case 0: + retval = *this; + break; - case 1: - { - idx_vector i = idx_arg(0).index_vector (); - - if (! error_state) - retval = Array::index (i, resize_ok, Matrix ()); - } - break; - - case 2: - { - idx_vector i = idx_arg(0).index_vector (); - - if (! error_state) + case 1: { - idx_vector j = idx_arg(1).index_vector (); + idx_vector i = idx_arg(0).index_vector (); if (! error_state) - retval = Array::index (i, j, resize_ok, Matrix ()); + retval = Array::index (i, resize_ok, Matrix ()); } - } - break; + break; - default: - { - Array iv (dim_vector (n, 1)); + case 2: + { + idx_vector i = idx_arg(0).index_vector (); - for (octave_idx_type i = 0; i < n; i++) + if (! error_state) + { + k = 1; + idx_vector j = idx_arg(1).index_vector (); + + if (! error_state) + retval = Array::index (i, j, resize_ok, Matrix ()); + } + } + break; + + default: { - iv(i) = idx_arg(i).index_vector (); + Array iv (dim_vector (n, 1)); - if (error_state) - break; + for (k = 0; k < n; k++) + { + iv(k) = idx_arg(k).index_vector (); + + if (error_state) + break; + } + if (!error_state) + retval = Array::index (iv, resize_ok, Matrix ()); } - - if (!error_state) - retval = Array::index (iv, resize_ok, Matrix ()); - } - break; + break; + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (n, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc, when var name known } return retval; @@ -228,7 +241,17 @@ Cell::assign (const octave_value_list& i Array ra_idx (dim_vector (len, 1)); for (octave_idx_type i = 0; i < len; i++) - ra_idx(i) = idx_arg(i).index_vector (); + { + try + { + ra_idx(i) = idx_arg(i).index_vector (); + } + catch (index_exception& e) + { + e.set_pos (len, i+1); + throw; // to be caught in pt-idx.cc or pt-assign.cc + } + } Array::assign (ra_idx, rhs, fill_val); } @@ -242,7 +265,15 @@ Cell::delete_elements (const octave_valu Array ra_idx (dim_vector (len, 1)); for (octave_idx_type i = 0; i < len; i++) - ra_idx.xelem (i) = idx_arg(i).index_vector (); + try + { + ra_idx.xelem (i) = idx_arg(i).index_vector (); + } + catch (index_exception& e) + { + e.set_pos (len, i+1); + throw; // to be caught in pt-idx.cc or pt-assign.cc + } Array::delete_elements (ra_idx); } diff --git a/libinterp/corefcn/data.cc b/libinterp/corefcn/data.cc --- a/libinterp/corefcn/data.cc +++ b/libinterp/corefcn/data.cc @@ -7244,200 +7244,30 @@ the ratio K/M is small; otherwise, it ma if (dim < 0) dim = argx.dims ().first_non_singleton (); - idx_vector n = args(1).index_vector (); - - if (error_state) - return retval; - - switch (argx.builtin_type ()) + try { - case btyp_double: - retval = argx.array_value ().nth_element (n, dim); - break; - case btyp_float: - retval = argx.float_array_value ().nth_element (n, dim); - break; - case btyp_complex: - retval = argx.complex_array_value ().nth_element (n, dim); - break; - case btyp_float_complex: - retval = argx.float_complex_array_value ().nth_element (n, dim); - break; -#define MAKE_INT_BRANCH(X) \ - case btyp_ ## X: \ - retval = argx.X ## _array_value ().nth_element (n, dim); \ - break; - - MAKE_INT_BRANCH (int8); - MAKE_INT_BRANCH (int16); - MAKE_INT_BRANCH (int32); - MAKE_INT_BRANCH (int64); - MAKE_INT_BRANCH (uint8); - MAKE_INT_BRANCH (uint16); - MAKE_INT_BRANCH (uint32); - MAKE_INT_BRANCH (uint64); -#undef MAKE_INT_BRANCH - default: - if (argx.is_cellstr ()) - retval = argx.cellstr_value ().nth_element (n, dim); - else - gripe_wrong_type_arg ("nth_element", argx); - } - } - else - print_usage (); - - return retval; -} - -template -static NDT -do_accumarray_sum (const idx_vector& idx, const NDT& vals, - octave_idx_type n = -1) -{ - typedef typename NDT::element_type T; - if (n < 0) - n = idx.extent (0); - else if (idx.extent (n) > n) - error ("accumarray: index out of range"); - - NDT retval (dim_vector (n, 1), T ()); - - if (vals.numel () == 1) - retval.idx_add (idx, vals (0)); - else if (vals.numel () == idx.length (n)) - retval.idx_add (idx, vals); - else - error ("accumarray: dimensions mismatch"); - - return retval; -} - -DEFUN (__accumarray_sum__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} __accumarray_sum__ (@var{idx}, @var{vals}, @var{n})\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - octave_value retval; - int nargin = args.length (); - if (nargin >= 2 && nargin <= 3 && args(0).is_numeric_type ()) - { - idx_vector idx = args(0).index_vector (); - octave_idx_type n = -1; - if (nargin == 3) - n = args(2).idx_type_value (true); - - if (! error_state) - { - octave_value vals = args(1); - if (vals.is_range ()) - { - Range r = vals.range_value (); - if (r.inc () == 0) - vals = r.base (); - } - - if (vals.is_single_type ()) - { - if (vals.is_complex_type ()) - retval = do_accumarray_sum (idx, - vals.float_complex_array_value (), - n); - else - retval = do_accumarray_sum (idx, vals.float_array_value (), n); - } - else if (vals.is_numeric_type () || vals.is_bool_type ()) - { - if (vals.is_complex_type ()) - retval = do_accumarray_sum (idx, - vals.complex_array_value (), - n); - else - retval = do_accumarray_sum (idx, vals.array_value (), n); - } - else - gripe_wrong_type_arg ("accumarray", vals); - } - } - else - print_usage (); - - return retval; -} - -template -static NDT -do_accumarray_minmax (const idx_vector& idx, const NDT& vals, - octave_idx_type n, bool ismin, - const typename NDT::element_type& zero_val) -{ - typedef typename NDT::element_type T; - if (n < 0) - n = idx.extent (0); - else if (idx.extent (n) > n) - error ("accumarray: index out of range"); - - NDT retval (dim_vector (n, 1), zero_val); - - // Pick minimizer or maximizer. - void (MArray::*op) (const idx_vector&, const MArray&) = - ismin ? (&MArray::idx_min) : (&MArray::idx_max); - - octave_idx_type l = idx.length (n); - if (vals.numel () == 1) - (retval.*op) (idx, NDT (dim_vector (l, 1), vals(0))); - else if (vals.numel () == l) - (retval.*op) (idx, vals); - else - error ("accumarray: dimensions mismatch"); - - return retval; -} - -static octave_value_list -do_accumarray_minmax_fun (const octave_value_list& args, - bool ismin) -{ - octave_value retval; - int nargin = args.length (); - if (nargin >= 3 && nargin <= 4 && args(0).is_numeric_type ()) - { - idx_vector idx = args(0).index_vector (); - octave_idx_type n = -1; - if (nargin == 4) - n = args(3).idx_type_value (true); - - if (! error_state) - { - octave_value vals = args(1); - octave_value zero = args(2); - - switch (vals.builtin_type ()) + idx_vector n = args(1).index_vector (); + + if (error_state) + return retval; + + switch (argx.builtin_type ()) { case btyp_double: - retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin, - zero.double_value ()); + retval = argx.array_value ().nth_element (n, dim); break; case btyp_float: - retval = do_accumarray_minmax (idx, vals.float_array_value (), n, - ismin, zero.float_value ()); + retval = argx.float_array_value ().nth_element (n, dim); break; case btyp_complex: - retval = do_accumarray_minmax (idx, vals.complex_array_value (), - n, ismin, zero.complex_value ()); + retval = argx.complex_array_value ().nth_element (n, dim); break; case btyp_float_complex: - retval = do_accumarray_minmax (idx, - vals.float_complex_array_value (), - n, ismin, - zero.float_complex_value ()); + retval = argx.float_complex_array_value ().nth_element (n, dim); break; #define MAKE_INT_BRANCH(X) \ case btyp_ ## X: \ - retval = do_accumarray_minmax (idx, vals.X ## _array_value (), \ - n, ismin, \ - zero.X ## _scalar_value ()); \ + retval = argx.X ## _array_value ().nth_element (n, dim); \ break; MAKE_INT_BRANCH (int8); @@ -7449,14 +7279,208 @@ do_accumarray_minmax_fun (const octave_v MAKE_INT_BRANCH (uint32); MAKE_INT_BRANCH (uint64); #undef MAKE_INT_BRANCH - case btyp_bool: - retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin, - zero.bool_value ()); - break; default: - gripe_wrong_type_arg ("accumarray", vals); + if (argx.is_cellstr ()) + retval = argx.cellstr_value ().nth_element (n, dim); + else + gripe_wrong_type_arg ("nth_element", argx); } } + catch (index_exception& e) + { + error ("nth_element: invalid N value %s. %s", e.idx (), e.explain ()); + } + } + else + print_usage (); + + return retval; +} + +template +static NDT +do_accumarray_sum (const idx_vector& idx, const NDT& vals, + octave_idx_type n = -1) +{ + typedef typename NDT::element_type T; + if (n < 0) + n = idx.extent (0); + else if (idx.extent (n) > n) + error ("accumarray: index out of range"); + + NDT retval (dim_vector (n, 1), T ()); + + if (vals.numel () == 1) + retval.idx_add (idx, vals (0)); + else if (vals.numel () == idx.length (n)) + retval.idx_add (idx, vals); + else + error ("accumarray: dimensions mismatch"); + + return retval; +} + +DEFUN (__accumarray_sum__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __accumarray_sum__ (@var{idx}, @var{vals}, @var{n})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + int nargin = args.length (); + if (nargin >= 2 && nargin <= 3 && args(0).is_numeric_type ()) + { + try + { + idx_vector idx = args(0).index_vector (); + octave_idx_type n = -1; + if (nargin == 3) + n = args(2).idx_type_value (true); + + if (! error_state) + { + octave_value vals = args(1); + if (vals.is_range ()) + { + Range r = vals.range_value (); + if (r.inc () == 0) + vals = r.base (); + } + + if (vals.is_single_type ()) + { + if (vals.is_complex_type ()) + retval = do_accumarray_sum (idx, + vals.float_complex_array_value (), + n); + else + retval = do_accumarray_sum (idx, vals.float_array_value (), n); + } + else if (vals.is_numeric_type () || vals.is_bool_type ()) + { + if (vals.is_complex_type ()) + retval = do_accumarray_sum (idx, + vals.complex_array_value (), + n); + else + retval = do_accumarray_sum (idx, vals.array_value (), n); + } + else + gripe_wrong_type_arg ("accumarray", vals); + } + } + catch (index_exception& e) + { + error ("__accumarray_sum__: invalid IDX %s. %s", + e.idx(), e.explain ()); + } + } + else + print_usage (); + + return retval; +} + +template +static NDT +do_accumarray_minmax (const idx_vector& idx, const NDT& vals, + octave_idx_type n, bool ismin, + const typename NDT::element_type& zero_val) +{ + typedef typename NDT::element_type T; + if (n < 0) + n = idx.extent (0); + else if (idx.extent (n) > n) + error ("accumarray: index out of range"); + + NDT retval (dim_vector (n, 1), zero_val); + + // Pick minimizer or maximizer. + void (MArray::*op) (const idx_vector&, const MArray&) = + ismin ? (&MArray::idx_min) : (&MArray::idx_max); + + octave_idx_type l = idx.length (n); + if (vals.numel () == 1) + (retval.*op) (idx, NDT (dim_vector (l, 1), vals(0))); + else if (vals.numel () == l) + (retval.*op) (idx, vals); + else + error ("accumarray: dimensions mismatch"); + + return retval; +} + +static octave_value_list +do_accumarray_minmax_fun (const octave_value_list& args, + bool ismin) +{ + octave_value retval; + int nargin = args.length (); + if (nargin >= 3 && nargin <= 4 && args(0).is_numeric_type ()) + { + try + { + idx_vector idx = args(0).index_vector (); + octave_idx_type n = -1; + if (nargin == 4) + n = args(3).idx_type_value (true); + + if (! error_state) + { + octave_value vals = args(1); + octave_value zero = args(2); + + switch (vals.builtin_type ()) + { + case btyp_double: + retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin, + zero.double_value ()); + break; + case btyp_float: + retval = do_accumarray_minmax (idx, vals.float_array_value (), n, + ismin, zero.float_value ()); + break; + case btyp_complex: + retval = do_accumarray_minmax (idx, vals.complex_array_value (), + n, ismin, zero.complex_value ()); + break; + case btyp_float_complex: + retval = do_accumarray_minmax (idx, + vals.float_complex_array_value (), + n, ismin, + zero.float_complex_value ()); + break; +#define MAKE_INT_BRANCH(X) \ + case btyp_ ## X: \ + retval = do_accumarray_minmax (idx, vals.X ## _array_value (), \ + n, ismin, \ + zero.X ## _scalar_value ()); \ + break; + + MAKE_INT_BRANCH (int8); + MAKE_INT_BRANCH (int16); + MAKE_INT_BRANCH (int32); + MAKE_INT_BRANCH (int64); + MAKE_INT_BRANCH (uint8); + MAKE_INT_BRANCH (uint16); + MAKE_INT_BRANCH (uint32); + MAKE_INT_BRANCH (uint64); +#undef MAKE_INT_BRANCH + case btyp_bool: + retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin, + zero.bool_value ()); + break; + default: + gripe_wrong_type_arg ("accumarray", vals); + } + } + } + catch (index_exception& e) + { + error ("do_accumarray_minmax_fun: invalid index %s. %s", + e.idx (), e.explain ()); + } + } else print_usage (); @@ -7523,39 +7547,46 @@ Undocumented internal function.\n\ int nargin = args.length (); if (nargin >= 2 && nargin <= 4 && args(0).is_numeric_type ()) { - idx_vector idx = args(0).index_vector (); - int dim = -1; - if (nargin >= 3) - dim = args(2).int_value () - 1; - - octave_idx_type n = -1; - if (nargin == 4) - n = args(3).idx_type_value (true); - - if (! error_state) + try { - octave_value vals = args(1); - - if (vals.is_single_type ()) + idx_vector idx = args(0).index_vector (); + int dim = -1; + if (nargin >= 3) + dim = args(2).int_value () - 1; + + octave_idx_type n = -1; + if (nargin == 4) + n = args(3).idx_type_value (true); + + if (! error_state) { - if (vals.is_complex_type ()) - retval = do_accumdim_sum (idx, - vals.float_complex_array_value (), - dim, n); + octave_value vals = args(1); + + if (vals.is_single_type ()) + { + if (vals.is_complex_type ()) + retval = do_accumdim_sum (idx, + vals.float_complex_array_value (), + dim, n); + else + retval = do_accumdim_sum (idx, vals.float_array_value (), + dim, n); + } + else if (vals.is_numeric_type () || vals.is_bool_type ()) + { + if (vals.is_complex_type ()) + retval = do_accumdim_sum (idx, vals.complex_array_value (), + dim, n); + else + retval = do_accumdim_sum (idx, vals.array_value (), dim, n); + } else - retval = do_accumdim_sum (idx, vals.float_array_value (), - dim, n); + gripe_wrong_type_arg ("accumdim", vals); } - else if (vals.is_numeric_type () || vals.is_bool_type ()) - { - if (vals.is_complex_type ()) - retval = do_accumdim_sum (idx, vals.complex_array_value (), - dim, n); - else - retval = do_accumdim_sum (idx, vals.array_value (), dim, n); - } - else - gripe_wrong_type_arg ("accumdim", vals); + } + catch (index_exception& e) + { + error ("__accumdim_sum__: invalid IDX %s. %s", e.idx(), e.explain ()); } } else diff --git a/libinterp/corefcn/find.cc b/libinterp/corefcn/find.cc --- a/libinterp/corefcn/find.cc +++ b/libinterp/corefcn/find.cc @@ -456,6 +456,8 @@ b = sparse (i, j, v, sz(1), sz(2));\n\ // This case is equivalent to extracting indices from a logical // matrix. Try to reuse the possibly cached index vector. retval(0) = arg.index_vector ().unmask (); + // No need to catch index_exception, since arg is bool. + // Out-of-range errors have already set pos, and will be caught later } else { diff --git a/libinterp/corefcn/oct-map.cc b/libinterp/corefcn/oct-map.cc --- a/libinterp/corefcn/oct-map.cc +++ b/libinterp/corefcn/oct-map.cc @@ -900,46 +900,60 @@ octave_map::index (const octave_value_li octave_idx_type n_idx = idx.length (); octave_map retval; - switch (n_idx) + // If we catch an indexing error in index_vector(), we flag an error in + // index k. Ensure it is the right value befor each idx_vector() call. + // Same variable as used in for() loop in default: case. + octave_idx_type k = 0; + + try { - case 1: - { - idx_vector i = idx(0).index_vector (); + switch (n_idx) + { + case 1: + { + idx_vector i = idx(0).index_vector (); - if (! error_state) - retval = index (i, resize_ok); - } - break; + if (! error_state) + retval = index (i, resize_ok); + } + break; - case 2: - { - idx_vector i = idx(0).index_vector (); + case 2: + { + idx_vector i = idx(0).index_vector (); - if (! error_state) + if (! error_state) + { + k = 1; + idx_vector j = idx(1).index_vector (); + + retval = index (i, j, resize_ok); + } + } + break; + + default: { - idx_vector j = idx(1).index_vector (); + Array ia (dim_vector (n_idx, 1)); - retval = index (i, j, resize_ok); + for (k = 0; k < n_idx; k++) + { + ia(k) = idx(k).index_vector (); + + if (error_state) + break; + } + + if (! error_state) + retval = index (ia, resize_ok); } - } - break; - - default: - { - Array ia (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) - { - ia(i) = idx(i).index_vector (); - - if (error_state) - break; - } - - if (! error_state) - retval = index (ia, resize_ok); - } - break; + break; + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (n_idx, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc, when var name known } return retval; @@ -1094,46 +1108,60 @@ octave_map::assign (const octave_value_l { octave_idx_type n_idx = idx.length (); - switch (n_idx) + // If we catch an indexing error in index_vector(), we flag an error in + // index k. Ensure it is the right value befor each idx_vector() call. + // Same variable as used in for() loop in default: case. + octave_idx_type k = 0; + + try { - case 1: - { - idx_vector i = idx(0).index_vector (); + switch (n_idx) + { + case 1: + { + idx_vector i = idx(0).index_vector (); - if (! error_state) - assign (i, rhs); - } - break; + if (! error_state) + assign (i, rhs); + } + break; - case 2: - { - idx_vector i = idx(0).index_vector (); + case 2: + { + idx_vector i = idx(0).index_vector (); - if (! error_state) + if (! error_state) + { + k = 1; + idx_vector j = idx(1).index_vector (); + + assign (i, j, rhs); + } + } + break; + + default: { - idx_vector j = idx(1).index_vector (); + Array ia (dim_vector (n_idx, 1)); - assign (i, j, rhs); + for (k = 0; k < n_idx; k++) + { + ia(k) = idx(k).index_vector (); + + if (error_state) + break; + } + + if (! error_state) + assign (ia, rhs); } - } - break; - - default: - { - Array ia (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) - { - ia(i) = idx(i).index_vector (); - - if (error_state) - break; - } - - if (! error_state) - assign (ia, rhs); - } - break; + break; + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (n_idx, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc, when var name known } } @@ -1244,7 +1272,15 @@ octave_map::delete_elements (const octav for (octave_idx_type i = 0; i < n_idx; i++) { - ia(i) = idx(i).index_vector (); + try + { + ia(i) = idx(i).index_vector (); + } + catch (index_exception& e) + { + e.set_pos_if_unset (n_idx, i+1); + throw; // caught in pt-idx.cc / pt-assign.cc, when var name known + } if (error_state) break; diff --git a/libinterp/corefcn/oct-tex-parser.in.yy b/libinterp/corefcn/oct-tex-parser.in.yy --- a/libinterp/corefcn/oct-tex-parser.in.yy +++ b/libinterp/corefcn/oct-tex-parser.in.yy @@ -95,105 +95,105 @@ static void yyerror (text_parser_tex& pa %% -simple_string : CH - { $$ = new std::string (1, $1); } - | simple_string CH - { $1->append (1, $2); $$ = $1; } - ; +simple_string : CH + { $$ = new std::string (1, $1); } + | simple_string CH + { $1->append (1, $2); $$ = $1; } + ; -symbol_element : SYM - { $$ = new text_element_symbol ($1); } - ; +symbol_element : SYM + { $$ = new text_element_symbol ($1); } + ; -font_modifier_element : BF - { $$ = new text_element_fontstyle (text_element_fontstyle::bold); } - | IT - { $$ = new text_element_fontstyle (text_element_fontstyle::italic); } - | SL - { $$ = new text_element_fontstyle (text_element_fontstyle::oblique); } - | RM - { $$ = new text_element_fontstyle (text_element_fontstyle::normal); } - ; +font_modifier_element : BF + { $$ = new text_element_fontstyle (text_element_fontstyle::bold); } + | IT + { $$ = new text_element_fontstyle (text_element_fontstyle::italic); } + | SL + { $$ = new text_element_fontstyle (text_element_fontstyle::oblique); } + | RM + { $$ = new text_element_fontstyle (text_element_fontstyle::normal); } + ; -fontsize_element : FONTSIZE START NUM END - { $$ = new text_element_fontsize ($3); } - ; +fontsize_element : FONTSIZE START NUM END + { $$ = new text_element_fontsize ($3); } + ; -fontname_element : FONTNAME START simple_string END - { - $$ = new text_element_fontname (*$3); - delete $3; - } - ; +fontname_element : FONTNAME START simple_string END + { + $$ = new text_element_fontname (*$3); + delete $3; + } + ; -color_element : COLOR START simple_string END - { - $$ = new text_element_color (*$3); - delete $3; - } - | COLOR_RGB START NUM NUM NUM END - { - $$ = new text_element_color ($3, $4, $5); - } - ; +color_element : COLOR START simple_string END + { + $$ = new text_element_color (*$3); + delete $3; + } + | COLOR_RGB START NUM NUM NUM END + { + $$ = new text_element_color ($3, $4, $5); + } + ; -string_element : simple_string %prec STR - { - $$ = new text_element_string (*$1); - delete $1; - } - | scoped_string_element_list - /* This is just to avoid a warning in bison. */ - { $$ = $1; } - | symbol_element - | font_modifier_element - | fontsize_element - | fontname_element - | color_element - | superscript_element %prec SCRIPT - | subscript_element %prec SCRIPT - | combined_script_element - ; +string_element : simple_string %prec STR + { + $$ = new text_element_string (*$1); + delete $1; + } + | scoped_string_element_list + /* This is just to avoid a warning in bison. */ + { $$ = $1; } + | symbol_element + | font_modifier_element + | fontsize_element + | fontname_element + | color_element + | superscript_element %prec SCRIPT + | subscript_element %prec SCRIPT + | combined_script_element + ; -superscript_element : SUPER CH - { $$ = new text_element_superscript ($2); } - | SUPER scoped_string_element_list - { $$ = new text_element_superscript ($2); } - | SUPER symbol_element - { $$ = new text_element_superscript ($2); } - ; +superscript_element : SUPER CH + { $$ = new text_element_superscript ($2); } + | SUPER scoped_string_element_list + { $$ = new text_element_superscript ($2); } + | SUPER symbol_element + { $$ = new text_element_superscript ($2); } + ; -subscript_element : SUB CH - { $$ = new text_element_subscript ($2); } - | SUB scoped_string_element_list - { $$ = new text_element_subscript ($2); } - | SUB symbol_element - { $$ = new text_element_subscript ($2); } - ; +subscript_element : SUB CH + { $$ = new text_element_subscript ($2); } + | SUB scoped_string_element_list + { $$ = new text_element_subscript ($2); } + | SUB symbol_element + { $$ = new text_element_subscript ($2); } + ; -combined_script_element : subscript_element superscript_element - { $$ = new text_element_combined ($1, $2); } - | superscript_element subscript_element - { $$ = new text_element_combined ($1, $2); } - ; +combined_script_element : subscript_element superscript_element + { $$ = new text_element_combined ($1, $2); } + | superscript_element subscript_element + { $$ = new text_element_combined ($1, $2); } + ; -string_element_list : string_element - { $$ = new text_element_list ($1); } - | string_element_list string_element - { $1->push_back ($2); $$ = $1; } - ; +string_element_list : string_element + { $$ = new text_element_list ($1); } + | string_element_list string_element + { $1->push_back ($2); $$ = $1; } + ; -scoped_string_element_list : START string_element_list END - { $$ = $2; } - | START END - { $$ = new text_element_list (); } - ; +scoped_string_element_list : START string_element_list END + { $$ = $2; } + | START END + { $$ = new text_element_list (); } + ; -string : /* empty */ - { parser.set_parse_result (new text_element_string ("")); } - | string_element_list - { parser.set_parse_result ($1); } - ; +string : /* empty */ + { parser.set_parse_result (new text_element_string ("")); } + | string_element_list + { parser.set_parse_result ($1); } + ; %% diff --git a/libinterp/corefcn/sparse.cc b/libinterp/corefcn/sparse.cc --- a/libinterp/corefcn/sparse.cc +++ b/libinterp/corefcn/sparse.cc @@ -198,20 +198,30 @@ Compressed Column Sparse (rows = 3, cols if (! error_state) { - idx_vector i = args(0).index_vector (); - idx_vector j = args(1).index_vector (); + int k = 0; // index we're checking when index_vector throws + try + { + idx_vector i = args(0).index_vector (); + k = 1; + idx_vector j = args(1).index_vector (); - if (args(2).is_bool_type ()) - retval = SparseBoolMatrix (args(2).bool_array_value (), i, j, + if (args(2).is_bool_type ()) + retval = SparseBoolMatrix (args(2).bool_array_value (), i,j, + m, n, summation, nzmax); + else if (args(2).is_complex_type ()) + retval = SparseComplexMatrix (args(2).complex_array_value(), + i, j, m, n, summation, nzmax); + else if (args(2).is_numeric_type ()) + retval = SparseMatrix (args(2).array_value (), i, j, m, n, summation, nzmax); - else if (args(2).is_complex_type ()) - retval = SparseComplexMatrix (args(2).complex_array_value (), - i, j, m, n, summation, nzmax); - else if (args(2).is_numeric_type ()) - retval = SparseMatrix (args(2).array_value (), i, j, - m, n, summation, nzmax); - else - gripe_wrong_type_arg ("sparse", args(2)); + else + gripe_wrong_type_arg ("sparse", args(2)); + } + catch (index_exception& e) + { + e.set_pos_if_unset (2, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc to get var name + } } } diff --git a/libinterp/corefcn/sub2ind.cc b/libinterp/corefcn/sub2ind.cc --- a/libinterp/corefcn/sub2ind.cc +++ b/libinterp/corefcn/sub2ind.cc @@ -99,11 +99,21 @@ linear_index = sub2ind ([3, 3], 2, 3)\n\ { if (args(j+1).is_numeric_type ()) { - idxa(j) = args(j+1).index_vector (); - if (error_state) - break; - else if (j > 0 && args(j+1).dims () != args(1).dims ()) - error ("sub2ind: all subscripts must be of the same size"); + try + { + idxa(j) = args(j+1).index_vector (); + if (error_state) + break; + else if (j > 0 && args(j+1).dims () != args(1).dims ()) + error ("sub2ind: all subscripts must be of the same size"); + } + catch (index_exception& e) + { + e.set_pos_if_unset (nargin-1, j+1); + e.set_var (""); // no particular variable + (*current_liboctave_error_with_id_handler) + (e.id(), e.err()); + } } else error ("sub2ind: subscripts must be numeric"); @@ -134,23 +144,23 @@ linear_index = sub2ind ([3, 3], 2, 3)\n\ # Test low index %!assert (sub2ind ([10 10 10], 1, 1, 1), 1) -%!error sub2ind ([10 10 10], 0, 1, 1) -%!error sub2ind ([10 10 10], 1, 0, 1) -%!error sub2ind ([10 10 10], 1, 1, 0) +%!error sub2ind ([10 10 10], 0, 1, 1) +%!error sub2ind ([10 10 10], 1, 0, 1) +%!error sub2ind ([10 10 10], 1, 1, 0) # Test high index %!assert (sub2ind ([10 10 10], 10, 10, 10), 1000) -%!error sub2ind ([10 10 10], 11, 10, 10) -%!error sub2ind ([10 10 10], 10, 11, 10) -%!error sub2ind ([10 10 10], 10, 10, 11) +%!error sub2ind ([10 10 10], 11, 10, 10) +%!error sub2ind ([10 10 10], 10, 11, 10) +%!error sub2ind ([10 10 10], 10, 10, 11) # Test high index in the trailing dimensions %!assert (sub2ind ([10, 1], 2, 1, 1), 2) -%!error sub2ind ([10, 1], 1, 2, 1) -%!error sub2ind ([10, 1], 1, 1, 2) +%!error sub2ind ([10, 1], 1, 2, 1) +%!error sub2ind ([10, 1], 1, 1, 2) %!assert (sub2ind ([10 10], 2, 2, 1), 12) -%!error sub2ind ([10 10], 2, 1, 2) -%!error sub2ind ([10 10], 1, 2, 2) +%!error sub2ind ([10 10], 2, 1, 2) +%!error sub2ind ([10 10], 1, 2, 2) # Test handling of empty arguments %!assert (sub2ind ([10 10], zeros (0,0), zeros (0,0)), zeros (0,0)) @@ -164,8 +174,8 @@ linear_index = sub2ind ([3, 3], 2, 3)\n\ ## Test input validation %!error sub2ind ([10 10.5], 1, 1) -%!error sub2ind ([10 10], 1.5, 1) -%!error sub2ind ([10 10], 1, 1.5) +%!error sub2ind ([10 10], 1.5, 1) +%!error sub2ind ([10 10], 1, 1.5) */ DEFUN (ind2sub, args, nargout, @@ -195,14 +205,21 @@ moving from one column to next, filling else { dim_vector dv = get_dim_vector (args(0), "ind2sub"); - idx_vector idx = args(1).index_vector (); - if (! error_state) + try { - if (nargout > dv.length ()) - dv = dv.redim (nargout); + idx_vector idx = args(1).index_vector (); + if (! error_state) + { + if (nargout > dv.length ()) + dv = dv.redim (nargout); - Array idxa = ind2sub (dv, idx); - retval = Array (idxa); + Array idxa = ind2sub (dv, idx); + retval = Array (idxa); + } + } + catch (index_exception& e) + { + error ("ind2sub: Invalid index %s. %s", e.idx (), e.explain ()); } } diff --git a/libinterp/corefcn/toplev.cc b/libinterp/corefcn/toplev.cc --- a/libinterp/corefcn/toplev.cc +++ b/libinterp/corefcn/toplev.cc @@ -658,6 +658,13 @@ main_loop (void) if (quitting_gracefully) return exit_status; } + catch (index_exception& e) + { + recover_from_exception (); + std::cerr << "error: unhandled index exception: " + << e.err () << " -- trying to return to prompt" + << std::endl; + } catch (const octave_execution_exception&) { recover_from_exception (); diff --git a/libinterp/corefcn/utils.cc b/libinterp/corefcn/utils.cc --- a/libinterp/corefcn/utils.cc +++ b/libinterp/corefcn/utils.cc @@ -1298,10 +1298,18 @@ dims_to_numel (const dim_vector& dims, c retval *= idxi.numel (); else { - idx_vector jdx = idxi.index_vector (); - if (error_state) - break; - retval *= jdx.length (dv(i)); + try + { + idx_vector jdx = idxi.index_vector (); + if (error_state) + break; + retval *= jdx.length (dv(i)); + } + catch (index_exception& e) + { + error ("dims_to_numel: Invalid IDX %s. %s", + e.idx (), e.explain ()); + } } } } diff --git a/libinterp/octave-value/ov-base-diag.cc b/libinterp/octave-value/ov-base-diag.cc --- a/libinterp/octave-value/ov-base-diag.cc +++ b/libinterp/octave-value/ov-base-diag.cc @@ -29,6 +29,7 @@ along with Octave; see the file COPYING. #include "mach-info.h" #include "lo-ieee.h" +#include "ov-base-diag.h" #include "mxarray.h" #include "ov-base.h" #include "ov-base-mat.h" @@ -103,26 +104,36 @@ octave_base_diag::do_index_op ( if (idx.length () == 2 && ! resize_ok) { - idx_vector idx0 = idx(0).index_vector (); - idx_vector idx1 = idx(1).index_vector (); + int k = 0; // index we're accesing when index_vector throws + try + { + idx_vector idx0 = idx(0).index_vector (); + k = 1; + idx_vector idx1 = idx(1).index_vector (); - if (idx0.is_scalar () && idx1.is_scalar ()) - { - retval = matrix.checkelem (idx0(0), idx1(0)); - } - else - { - octave_idx_type m = idx0.length (matrix.rows ()); - octave_idx_type n = idx1.length (matrix.columns ()); - if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n) - && m <= matrix.rows () && n <= matrix.rows ()) + if (idx0.is_scalar () && idx1.is_scalar ()) { - DMT rm (matrix); - rm.resize (m, n); - retval = rm; + retval = matrix.checkelem (idx0(0), idx1(0)); } else - retval = to_dense ().do_index_op (idx, resize_ok); + { + octave_idx_type m = idx0.length (matrix.rows ()); + octave_idx_type n = idx1.length (matrix.columns ()); + if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n) + && m <= matrix.rows () && n <= matrix.rows ()) + { + DMT rm (matrix); + rm.resize (m, n); + retval = rm; + } + else + retval = to_dense ().do_index_op (idx, resize_ok); + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (2, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc to get var name } } else @@ -153,17 +164,27 @@ octave_base_diag::subsasgn (con && jdx(0).is_scalar_type () && jdx(1).is_scalar_type ()) { typename DMT::element_type val; - idx_vector i0 = jdx(0).index_vector (); - idx_vector i1 = jdx(1).index_vector (); - if (! error_state && i0(0) == i1(0) - && i0(0) < matrix.rows () && i1(0) < matrix.cols () - && chk_valid_scalar (rhs, val)) + int k = 0; + try { - matrix.dgelem (i0(0)) = val; - retval = this; - this->count++; - // invalidate cache - dense_cache = octave_value (); + idx_vector i0 = jdx(0).index_vector (); + k = 1; + idx_vector i1 = jdx(1).index_vector (); + if (! error_state && i0(0) == i1(0) + && i0(0) < matrix.rows () && i1(0) < matrix.cols () + && chk_valid_scalar (rhs, val)) + { + matrix.dgelem (i0(0)) = val; + retval = this; + this->count++; + // invalidate cache + dense_cache = octave_value (); + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (2, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc to get var name } } diff --git a/libinterp/octave-value/ov-base-mat.cc b/libinterp/octave-value/ov-base-mat.cc --- a/libinterp/octave-value/ov-base-mat.cc +++ b/libinterp/octave-value/ov-base-mat.cc @@ -36,7 +36,7 @@ along with Octave; see the file COPYING. #include "ov-base-mat.h" #include "ov-base-scalar.h" #include "pr-output.h" - + template octave_value octave_base_matrix::subsref (const std::string& type, @@ -140,72 +140,87 @@ octave_base_matrix::do_index_op (con int nd = matrix.ndims (); const MT& cmatrix = matrix; - switch (n_idx) + // If we catch an indexing error in index_vector, we flag an error + // in index k. Ensure it is the right value befor each idx_vector + // call. Same variable as used in for loop in the default case. + + octave_idx_type k = 0; + + try { - case 0: - retval = matrix; - break; + switch (n_idx) + { + case 0: + retval = matrix; + break; - case 1: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + case 1: { - // optimize single scalar index. - if (! resize_ok && i.is_scalar ()) - retval = cmatrix.checkelem (i(0)); - else - retval = MT (matrix.index (i, resize_ok)); - } - } - break; - - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) - { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) { - // optimize two scalar indices. - if (! resize_ok && i.is_scalar () && j.is_scalar ()) - retval = cmatrix.checkelem (i(0), j(0)); + // optimize single scalar index. + if (! resize_ok && i.is_scalar ()) + retval = cmatrix.checkelem (i(0)); else - retval = MT (matrix.index (i, j, resize_ok)); + retval = MT (matrix.index (i, resize_ok)); } } - } - break; + break; - default: - { - Array idx_vec (dim_vector (n_idx, 1)); - bool scalar_opt = n_idx == nd && ! resize_ok; - const dim_vector dv = matrix.dims (); + case 2: + { + idx_vector i = idx (0).index_vector (); - for (octave_idx_type i = 0; i < n_idx; i++) + if (! error_state) + { + k=1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + { + // optimize two scalar indices. + if (! resize_ok && i.is_scalar () && j.is_scalar ()) + retval = cmatrix.checkelem (i(0), j(0)); + else + retval = MT (matrix.index (i, j, resize_ok)); + } + } + } + break; + + default: { - idx_vec(i) = idx(i).index_vector (); + Array idx_vec (dim_vector (n_idx, 1)); + bool scalar_opt = n_idx == nd && ! resize_ok; + const dim_vector dv = matrix.dims (); - if (error_state) - break; + for (k = 0; k < n_idx; k++) + { + idx_vec(k) = idx(k).index_vector (); - scalar_opt = (scalar_opt && idx_vec(i).is_scalar ()); + if (error_state) + break; + + scalar_opt = (scalar_opt && idx_vec(k).is_scalar ()); + } + + if (! error_state) + { + if (scalar_opt) + retval = cmatrix.checkelem (conv_to_int_array (idx_vec)); + else + retval = MT (matrix.index (idx_vec, resize_ok)); + } } - - if (! error_state) - { - if (scalar_opt) - retval = cmatrix.checkelem (conv_to_int_array (idx_vec)); - else - retval = MT (matrix.index (idx_vec, resize_ok)); - } - } - break; + break; + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (n_idx, k+1); + throw; // to be caught in pt-idx.cc / pt-assign.cc, when var name known } return retval; @@ -217,51 +232,65 @@ octave_base_matrix::assign (const oc { octave_idx_type n_idx = idx.length (); - switch (n_idx) + // If we catch an indexing error in index_vector, we flag an error + // in index k. Ensure it is the right value befor each idx_vector + // call. Same variable as used in for loop in the default case. + + octave_idx_type k = 0; + + try { - case 0: - panic_impossible (); - break; + switch (n_idx) + { + case 0: + panic_impossible (); + break; - case 1: - { - idx_vector i = idx (0).index_vector (); + case 1: + { + idx_vector i = idx (0).index_vector (); - if (! error_state) - matrix.assign (i, rhs); - } - break; + if (! error_state) + matrix.assign (i, rhs); + } + break; - case 2: - { - idx_vector i = idx (0).index_vector (); + case 2: + { + idx_vector i = idx (0).index_vector (); - if (! error_state) - { - idx_vector j = idx (1).index_vector (); + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); - if (! error_state) - matrix.assign (i, j, rhs); - } - } - break; + if (! error_state) + matrix.assign (i, j, rhs); + } + } + break; - default: - { - Array idx_vec (dim_vector (n_idx, 1)); + default: + { + Array idx_vec (dim_vector (n_idx, 1)); - for (octave_idx_type i = 0; i < n_idx; i++) - { - idx_vec(i) = idx(i).index_vector (); + for (k = 0; k < n_idx; k++) + { + idx_vec(k) = idx(k).index_vector (); - if (error_state) - break; - } + if (error_state) + break; + } - if (! error_state) - matrix.assign (idx_vec, rhs); - } - break; + if (! error_state) + matrix.assign (idx_vec, rhs); + } + break; + } + } + catch (index_exception& e) + { + gripe_invalid_index (e.idx(), n_idx, k+1); } // Clear cache. @@ -288,86 +317,100 @@ octave_base_matrix::assign (const oc MT mrhs (dim_vector (1, 1), rhs); - switch (n_idx) + // If we catch an indexing error in index_vector, we flag an error + // in index k. Ensure it is the right value befor each idx_vector + // call. Same variable as used in for loop in the default case. + + octave_idx_type k = 0; + + try { - case 0: - panic_impossible (); - break; + switch (n_idx) + { + case 0: + panic_impossible (); + break; - case 1: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + case 1: { - // optimize single scalar index. - if (i.is_scalar () && i(0) < matrix.numel ()) - matrix(i(0)) = rhs; - else - matrix.assign (i, mrhs); - } - } - break; - - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) - { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) { - // optimize two scalar indices. - if (i.is_scalar () && j.is_scalar () && nd == 2 - && i(0) < matrix.rows () && j(0) < matrix.columns ()) - matrix(i(0), j(0)) = rhs; + // optimize single scalar index. + if (i.is_scalar () && i(0) < matrix.numel ()) + matrix(i(0)) = rhs; else - matrix.assign (i, j, mrhs); + matrix.assign (i, mrhs); } } - } - break; + break; - default: - { - Array idx_vec (dim_vector (n_idx, 1)); - bool scalar_opt = n_idx == nd; - const dim_vector dv = matrix.dims ().redim (n_idx); + case 2: + { + idx_vector i = idx (0).index_vector (); - for (octave_idx_type i = 0; i < n_idx; i++) + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + { + // optimize two scalar indices. + if (i.is_scalar () && j.is_scalar () && nd == 2 + && i(0) < matrix.rows () && j(0) < matrix.columns ()) + matrix(i(0), j(0)) = rhs; + else + matrix.assign (i, j, mrhs); + } + } + } + break; + + default: { - idx_vec(i) = idx(i).index_vector (); + Array idx_vec (dim_vector (n_idx, 1)); + bool scalar_opt = n_idx == nd; + const dim_vector dv = matrix.dims ().redim (n_idx); - if (error_state) - break; + for (k = 0; k < n_idx; k++) + { + idx_vec(k) = idx(k).index_vector (); - scalar_opt = (scalar_opt && idx_vec(i).is_scalar () - && idx_vec(i)(0) < dv(i)); + if (error_state) + break; + + scalar_opt = (scalar_opt && idx_vec(k).is_scalar () + && idx_vec(k)(0) < dv(k)); + } + + if (! error_state) + { + if (scalar_opt) + { + // optimize all scalar indices. Don't construct + // an index array, but rather calc a scalar index directly. + octave_idx_type n = 1; + octave_idx_type j = 0; + for (octave_idx_type i = 0; i < n_idx; i++) + { + j += idx_vec(i)(0) * n; + n *= dv (i); + } + matrix(j) = rhs; + } + else + matrix.assign (idx_vec, mrhs); + } } - - if (! error_state) - { - if (scalar_opt) - { - // optimize all scalar indices. Don't construct an index array, - // but rather calc a scalar index directly. - octave_idx_type k = 1; - octave_idx_type j = 0; - for (octave_idx_type i = 0; i < n_idx; i++) - { - j += idx_vec(i)(0) * k; - k *= dv(i); - } - matrix(j) = rhs; - } - else - matrix.assign (idx_vec, mrhs); - } - } - break; + break; + } } + catch (const index_exception& e) + { + gripe_invalid_index (e.idx(), n_idx, k+1); + } // Clear cache. clear_cached_info (); diff --git a/libinterp/octave-value/ov-base-sparse.cc b/libinterp/octave-value/ov-base-sparse.cc --- a/libinterp/octave-value/ov-base-sparse.cc +++ b/libinterp/octave-value/ov-base-sparse.cc @@ -44,6 +44,8 @@ along with Octave; see the file COPYING. #include "pager.h" #include "utils.h" +#include "lo-array-gripes.h" + template octave_value octave_base_sparse::do_index_op (const octave_value_list& idx, @@ -53,36 +55,50 @@ octave_base_sparse::do_index_op (cons octave_idx_type n_idx = idx.length (); - switch (n_idx) + // If we catch an indexing error in index_vector(), we flag an error in + // index k. Ensure it is the right value befor each idx_vector() call. + // Same variable as used in for() loop in default: case. + octave_idx_type k = 0; + + try { - case 0: - retval = matrix; - break; + switch (n_idx) + { + case 0: + retval = matrix; + break; - case 1: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) - retval = octave_value (matrix.index (i, resize_ok)); - } - break; - - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + case 1: { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) - retval = octave_value (matrix.index (i, j, resize_ok)); + retval = octave_value (matrix.index (i, resize_ok)); } - } - break; - default: - error ("sparse indexing needs 1 or 2 indices"); + break; + + case 2: + { + idx_vector i = idx (0).index_vector (); + + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + retval = octave_value (matrix.index (i, j, resize_ok)); + } + } + break; + default: + error ("sparse indexing needs 1 or 2 indices"); + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (n_idx, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc, when var name known } return retval; @@ -170,35 +186,48 @@ octave_base_sparse::assign (const oct octave_idx_type len = idx.length (); - switch (len) + // If we catch an indexing error in index_vector(), we flag an error in + // index k. Ensure it is the right value befor each idx_vector() call. + // Same variable as used in for() loop in default: case. + octave_idx_type k = 0; + + try { - case 1: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) - matrix.assign (i, rhs); - - break; - } - - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + switch (len) + { + case 1: { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) - matrix.assign (i, j, rhs); + matrix.assign (i, rhs); + + break; } - break; - } + case 2: + { + idx_vector i = idx (0).index_vector (); - default: - error ("sparse indexing needs 1 or 2 indices"); + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + matrix.assign (i, j, rhs); + } + break; + } + + default: + error ("sparse indexing needs 1 or 2 indices"); + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (len, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc, when var name known } @@ -212,35 +241,49 @@ octave_base_sparse::delete_elements { octave_idx_type len = idx.length (); - switch (len) + // If we catch an indexing error in index_vector(), we flag an error in + // index k. Ensure it is the right value befor each idx_vector() call. + // Same variable as used in for() loop in default: case. + octave_idx_type k = 0; + + try { - case 1: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) - matrix.delete_elements (i); - - break; - } - - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + switch (len) + { + case 1: { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) - matrix.delete_elements (i, j); + matrix.delete_elements (i); + + break; } - break; - } + case 2: + { + idx_vector i = idx (0).index_vector (); - default: - error ("sparse indexing needs 1 or 2 indices"); + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + matrix.delete_elements (i, j); + } + + break; + } + + default: + error ("sparse indexing needs 1 or 2 indices"); + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (len, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc, when var name known } // Invalidate the matrix type diff --git a/libinterp/octave-value/ov-base.cc b/libinterp/octave-value/ov-base.cc --- a/libinterp/octave-value/ov-base.cc +++ b/libinterp/octave-value/ov-base.cc @@ -218,8 +218,8 @@ octave_base_value::do_multi_index_op (in idx_vector octave_base_value::index_vector (bool /* require_integers */) const { - std::string nm = type_name (); - error ("%s type invalid as index value", nm.c_str ()); + std::string nm = "<" + type_name () + ">"; + gripe_invalid_index (nm.c_str ()); return idx_vector (); } diff --git a/libinterp/octave-value/ov-classdef.cc b/libinterp/octave-value/ov-classdef.cc --- a/libinterp/octave-value/ov-classdef.cc +++ b/libinterp/octave-value/ov-classdef.cc @@ -1647,7 +1647,15 @@ cdef_object_array::subsref (const std::s for (int i = 0; ! error_state && i < ival.length (); i++) { - iv(i) = ival(i).index_vector (); + try + { + iv(i) = ival(i).index_vector (); + } + catch (index_exception& e) + { + e.set_pos_if_unset (ival.length (), i+1); + throw; // caught in pt-idx.cc / pt-assign.cc to get var name + } if (! error_state) is_scalar = is_scalar && iv(i).is_scalar (); } @@ -1745,7 +1753,15 @@ cdef_object_array::subsasgn (const std:: for (int i = 0; ! error_state && i < ival.length (); i++) { - iv(i) = ival(i).index_vector (); + try + { + iv(i) = ival(i).index_vector (); + } + catch (index_exception& e) + { + e.set_pos_if_unset (ival.length (), i+1); + throw; // var name set in pt-idx.cc / pt-assign.cc + } if (! error_state) is_scalar = is_scalar && iv(i).is_scalar (); } @@ -1798,7 +1814,15 @@ cdef_object_array::subsasgn (const std:: for (int i = 0; ! error_state && i < ival.length (); i++) { - iv(i) = ival(i).index_vector (); + try + { + iv(i) = ival(i).index_vector (); + } + catch (index_exception& e) + { + e.set_pos_if_unset (ival.length (), i+1); + throw; // caught in pt-idx.cc / pt-assign.cc to get var name + } if (! error_state) { diff --git a/libinterp/octave-value/ov-complex.cc b/libinterp/octave-value/ov-complex.cc --- a/libinterp/octave-value/ov-complex.cc +++ b/libinterp/octave-value/ov-complex.cc @@ -480,3 +480,39 @@ octave_complex::map (unary_mapper_t umap return octave_base_value::map (umap); } } + +class complex_index : public index_exception +{ +public: + + complex_index (const char *value) : index_exception (value) { } + + ~complex_index (void) { } + + const char* explain (void) const + { + return "subscripts must be real (forgot to initialize i or j?)"; + } + + // ID of error to throw. + const char* id (void) const + { + return error_id_invalid_index; + } +}; + +// Complain if a complex value is used as a subscript + +void +gripe_complex_index (Complex idx) +{ + // FIXME: don't use a fixed size buffer! + + char buf [100]; + + sprintf (buf, "%g%+gi", std::real(idx), std::imag(idx)); + + complex_index e (buf); + + throw e; +} diff --git a/libinterp/octave-value/ov-complex.h b/libinterp/octave-value/ov-complex.h --- a/libinterp/octave-value/ov-complex.h +++ b/libinterp/octave-value/ov-complex.h @@ -43,6 +43,9 @@ class octave_value_list; class tree_walker; +extern void OCTAVE_API +gripe_complex_index (Complex idx); + // Complex scalar values. class @@ -81,8 +84,7 @@ public: // Use this to give a more specific error message idx_vector index_vector (bool /* require_integers */ = false) const { - error ("attempted to use a complex scalar as an index\n" - " (forgot to initialize i or j?)"); + gripe_complex_index (scalar); return idx_vector (); } diff --git a/libinterp/octave-value/ov-java.cc b/libinterp/octave-value/ov-java.cc --- a/libinterp/octave-value/ov-java.cc +++ b/libinterp/octave-value/ov-java.cc @@ -827,28 +827,34 @@ make_java_index (JNIEnv* jni_env, const jobjectArray retval = jni_env->NewObjectArray (idx.length (), ocls, 0); for (int i = 0; i < idx.length (); i++) - { - idx_vector v = idx(i).index_vector (); - - if (! error_state) - { - jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ())); - jint *buf = jni_env->GetIntArrayElements (i_array, 0); - - for (int k = 0; k < v.length (); k++) - buf[k] = v(k); - - jni_env->ReleaseIntArrayElements (i_array, buf, 0); - jni_env->SetObjectArrayElement (retval, i, i_array); - - check_exception (jni_env); - - if (error_state) - break; - } - else - break; - } + try + { + idx_vector v = idx(i).index_vector (); + + if (! error_state) + { + jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ())); + jint *buf = jni_env->GetIntArrayElements (i_array, 0); + + for (int k = 0; k < v.length (); k++) + buf[k] = v(k); + + jni_env->ReleaseIntArrayElements (i_array, buf, 0); + jni_env->SetObjectArrayElement (retval, i, i_array); + + check_exception (jni_env); + + if (error_state) + break; + } + else + break; + } + catch (index_exception& e) + { + e.set_pos_if_unset (idx.length (), i+1); + throw; // caught in pt-idx.cc / pt-assign.cc to get var name + } return retval; } diff --git a/libinterp/octave-value/ov-perm.cc b/libinterp/octave-value/ov-perm.cc --- a/libinterp/octave-value/ov-perm.cc +++ b/libinterp/octave-value/ov-perm.cc @@ -74,8 +74,18 @@ octave_perm_matrix::do_index_op (const o idx_vector idx0, idx1; if (nidx == 2) { - idx0 = idx(0).index_vector (); - idx1 = idx(1).index_vector (); + int k = 0; // index we're processing when index_vector throws + try + { + idx0 = idx(0).index_vector (); + k = 1; + idx1 = idx(1).index_vector (); + } + catch (index_exception& e) + { + e.set_pos_if_unset (2, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc to get var name + } } // This hack is to allow constructing permutation matrices using diff --git a/libinterp/octave-value/ov-range.cc b/libinterp/octave-value/ov-range.cc --- a/libinterp/octave-value/ov-range.cc +++ b/libinterp/octave-value/ov-range.cc @@ -128,13 +128,25 @@ octave_range::do_index_op (const octave_ octave_value retval; // The range can handle a single subscript. - idx_vector i = idx(0).index_vector (); - if (! error_state) + + try { - if (i.is_scalar () && i(0) < range.numel ()) - retval = range.elem (i(0)); - else - retval = range.index (i); + idx_vector i = idx(0).index_vector (); + + if (! error_state) + { + if (i.is_scalar () && i(0) < range.numel ()) + retval = range.elem (i(0)); + else + retval = range.index (i); + } + } + catch (index_exception& e) + { + // More info may be added later before displaying error. + + e.set_pos_if_unset (1, 1); + throw; } return retval; diff --git a/libinterp/octave-value/ov-re-diag.cc b/libinterp/octave-value/ov-re-diag.cc --- a/libinterp/octave-value/ov-re-diag.cc +++ b/libinterp/octave-value/ov-re-diag.cc @@ -92,31 +92,41 @@ octave_diag_matrix::do_index_op (const o // vectors. if (! resize_ok && idx.length () == 2 && matrix.is_multiple_of_identity (1)) { - idx_vector idx0 = idx(0).index_vector (); - idx_vector idx1 = idx(1).index_vector (); + int k = 0; // index we're accesing when index_vector throws + try + { + idx_vector idx0 = idx(0).index_vector (); + k = 1; + idx_vector idx1 = idx(1).index_vector (); - if (! error_state) - { - bool left = idx0.is_permutation (matrix.rows ()); - bool right = idx1.is_permutation (matrix.cols ()); + if (! error_state) + { + bool left = idx0.is_permutation (matrix.rows ()); + bool right = idx1.is_permutation (matrix.cols ()); - if (left && right) - { - if (idx0.is_colon ()) left = false; - if (idx1.is_colon ()) right = false; if (left && right) - retval = PermMatrix (idx0, false) * PermMatrix (idx1, true); - else if (left) - retval = PermMatrix (idx0, false); - else if (right) - retval = PermMatrix (idx1, true); - else { - retval = this; - this->count++; + if (idx0.is_colon ()) left = false; + if (idx1.is_colon ()) right = false; + if (left && right) + retval = PermMatrix (idx0, false) * PermMatrix (idx1, true); + else if (left) + retval = PermMatrix (idx0, false); + else if (right) + retval = PermMatrix (idx1, true); + else + { + retval = this; + this->count++; + } } } } + catch (index_exception& e) + { + e.set_pos_if_unset (2, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc to get var name + } } // if error_state is set, we've already griped. diff --git a/libinterp/octave-value/ov-re-sparse.cc b/libinterp/octave-value/ov-re-sparse.cc --- a/libinterp/octave-value/ov-re-sparse.cc +++ b/libinterp/octave-value/ov-re-sparse.cc @@ -61,8 +61,8 @@ octave_sparse_matrix::index_vector (bool return idx_vector (array_value ()); else { - std::string nm = type_name (); - error ("%s type invalid as index value", nm.c_str ()); + std::string nm = "<" + type_name () + ">"; + gripe_invalid_index (nm.c_str ()); return idx_vector (); } } diff --git a/libinterp/octave-value/ov-str-mat.cc b/libinterp/octave-value/ov-str-mat.cc --- a/libinterp/octave-value/ov-str-mat.cc +++ b/libinterp/octave-value/ov-str-mat.cc @@ -94,46 +94,60 @@ octave_char_matrix_str::do_index_op_inte octave_idx_type len = idx.length (); - switch (len) + // If we catch an indexing error in index_vector(), we flag an error in + // index k. Ensure it is the right value befor each idx_vector() call. + // Same variable as used in for() loop in default: case. + octave_idx_type k = 0; + + try { - case 0: - retval = octave_value (matrix, type); - break; + switch (len) + { + case 0: + retval = octave_value (matrix, type); + break; - case 1: - { - idx_vector i = idx (0).index_vector (); + case 1: + { + idx_vector i = idx (0).index_vector (); - if (! error_state) - retval = octave_value (charNDArray (matrix.index (i, resize_ok)), - type); - } - break; + if (! error_state) + retval = octave_value (charNDArray (matrix.index (i, resize_ok)), + type); + } + break; - case 2: - { - idx_vector i = idx (0).index_vector (); - idx_vector j = idx (1).index_vector (); + case 2: + { + idx_vector i = idx (0).index_vector (); + k = 1; + idx_vector j = idx (1).index_vector (); - if (! error_state) - retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)), - type); - } - break; + if (! error_state) + retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)), + type); + } + break; - default: - { - Array idx_vec (dim_vector (len, 1)); + default: + { + Array idx_vec (dim_vector (len, 1)); - for (octave_idx_type i = 0; i < len; i++) - idx_vec(i) = idx(i).index_vector (); + for (k = 0; k < len; k++) + idx_vec(k) = idx(k).index_vector (); - if (! error_state) - retval = - octave_value (charNDArray (matrix.index (idx_vec, resize_ok)), - type); - } - break; + if (! error_state) + retval = + octave_value (charNDArray (matrix.index (idx_vec, resize_ok)), + type); + } + break; + } + } + catch (index_exception& e) + { + e.set_pos_if_unset (len, k+1); + throw; // caught in pt-idx.cc / pt-assign.cc, when var name known } return retval; diff --git a/libinterp/parse-tree/pt-assign.cc b/libinterp/parse-tree/pt-assign.cc --- a/libinterp/parse-tree/pt-assign.cc +++ b/libinterp/parse-tree/pt-assign.cc @@ -106,41 +106,49 @@ tree_simple_assignment::rvalue1 (int) } } - octave_lvalue ult = lhs->lvalue (); + try + { + octave_lvalue ult = lhs->lvalue (); - if (ult.numel () != 1) - gripe_nonbraced_cs_list_assignment (); - - if (! error_state) - { - ult.assign (etype, rhs_val); + if (ult.numel () != 1) + gripe_nonbraced_cs_list_assignment (); if (! error_state) { - if (etype == octave_value::op_asn_eq) - retval = rhs_val; - else - retval = ult.value (); + ult.assign (etype, rhs_val); - if (print_result () - && tree_evaluator::statement_printing_enabled ()) + if (! error_state) { - // We clear any index here so that we can - // get the new value of the referenced - // object below, instead of the indexed - // value (which should be the same as the - // right hand side value). + if (etype == octave_value::op_asn_eq) + retval = rhs_val; + else + retval = ult.value (); - ult.clear_index (); + if (print_result () + && tree_evaluator::statement_printing_enabled ()) + { + // We clear any index here so that we can + // get the new value of the referenced + // object below, instead of the indexed + // value (which should be the same as the + // right hand side value). - octave_value lhs_val = ult.value (); + ult.clear_index (); - if (! error_state) - lhs_val.print_with_name (octave_stdout, - lhs->name ()); + octave_value lhs_val = ult.value (); + + if (! error_state) + lhs_val.print_with_name (octave_stdout, + lhs->name ()); + } } } } + catch (index_exception& e) + { // problems with range, invalid index type etc. + e.set_var (lhs->name ()); + (*current_liboctave_error_with_id_handler) (e.id(), e.err()); + } } } } diff --git a/libinterp/parse-tree/pt-id.h b/libinterp/parse-tree/pt-id.h --- a/libinterp/parse-tree/pt-id.h +++ b/libinterp/parse-tree/pt-id.h @@ -66,7 +66,7 @@ public: bool is_defined (void) { return sym->is_defined (); } - virtual bool is_variable (void) { return sym->is_variable (); } + virtual bool is_variable (void) const { return sym->is_variable (); } virtual bool is_black_hole (void) { return false; } @@ -152,7 +152,7 @@ public: std::string name (void) const { return "~"; } - bool is_variable (void) { return false; } + bool is_variable (void) const { return false; } bool is_black_hole (void) { return true; } diff --git a/libinterp/parse-tree/pt-idx.cc b/libinterp/parse-tree/pt-idx.cc --- a/libinterp/parse-tree/pt-idx.cc +++ b/libinterp/parse-tree/pt-idx.cc @@ -284,6 +284,18 @@ tree_index_expression::rvalue (int nargo return tree_index_expression::rvalue (nargout, 0); } +// Final step of processing an indexing error. Add the name of the +// variable being indexed, if any, then issue an error. +// (Will this also be needed by pt-lvalue, which calls subsref?) +void +final_index_error (index_exception& e, const tree_expression *expr) +{ + if (expr->is_identifier () && + dynamic_cast (expr)->is_variable ()) + e.set_var (expr->name ()); + (*current_liboctave_error_with_id_handler) (e.id (), e.err ()); +} + octave_value_list tree_index_expression::rvalue (int nargout, const std::list *lvalue_list) @@ -353,7 +365,7 @@ tree_index_expression::rvalue (int nargo if (force_split || (al && al->has_magic_end ())) { - // We have an expression like + // (we have force_split, or) we have an expression like // // x{end}.a(end) // @@ -363,37 +375,44 @@ tree_index_expression::rvalue (int nargo // that argument list so we can pass the appropriate // value to the built-in end function. - octave_value_list tmp_list - = tmp.subsref (type.substr (tmpi, i - tmpi), idx, nargout); + try + { + octave_value_list tmp_list + =tmp.subsref (type.substr (tmpi, i-tmpi), idx, nargout); - tmp = tmp_list.length () ? tmp_list(0) : octave_value (); - tmpi = i; - idx.clear (); + tmp = tmp_list.length () ? tmp_list(0) : octave_value (); + tmpi = i; + idx.clear (); - if (tmp.is_cs_list ()) - gripe_indexed_cs_list (); + if (tmp.is_cs_list ()) + gripe_indexed_cs_list (); - if (error_state) - break; + if (error_state) + break; - if (tmp.is_function ()) + if (tmp.is_function ()) + { + octave_function *fcn = tmp.function_value (true); + + if (fcn && ! fcn->is_postfix_index_handled (type[i])) + { + octave_value_list empty_args; + + tmp_list = tmp.do_multi_index_op (1, empty_args); + tmp = (tmp_list.length () + ? tmp_list(0) : octave_value ()); + + if (tmp.is_cs_list ()) + gripe_indexed_cs_list (); + + if (error_state) + break; + } + } + } + catch (index_exception& e) // problems with index range, type etc. { - octave_function *fcn = tmp.function_value (true); - - if (fcn && ! fcn->is_postfix_index_handled (type[i])) - { - octave_value_list empty_args; - - tmp_list = tmp.do_multi_index_op (1, empty_args); - tmp = (tmp_list.length () - ? tmp_list(0) : octave_value ()); - - if (tmp.is_cs_list ()) - gripe_indexed_cs_list (); - - if (error_state) - break; - } + final_index_error (e, expr); } } } @@ -433,8 +452,15 @@ tree_index_expression::rvalue (int nargo if (! error_state) { - retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout, - lvalue_list); + try + { + retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout, + lvalue_list); + } + catch (index_exception& e) // problems with range, invalid index type etc. + { + final_index_error (e, expr); + } octave_value val = retval.length () ? retval(0) : octave_value (); @@ -500,7 +526,14 @@ tree_index_expression::lvalue (void) gripe_indexed_cs_list (); else if (tmpi < i) { - tmp = tmp.subsref (type.substr (tmpi, i - tmpi), tmpidx, true); + try + { + tmp = tmp.subsref (type.substr (tmpi, i-tmpi), tmpidx, true); + } + catch (index_exception& e) // problems with range, invalid type etc. + { + final_index_error (e, expr); + } tmpidx.clear (); } diff --git a/liboctave/array/Array-util.cc b/liboctave/array/Array-util.cc --- a/liboctave/array/Array-util.cc +++ b/liboctave/array/Array-util.cc @@ -178,9 +178,9 @@ octave_idx_type compute_index (octave_idx_type n, const dim_vector& dims) { if (n < 0) - gripe_invalid_index (); + gripe_invalid_index (n, 1, 1); if (n >= dims.numel ()) - gripe_index_out_of_range (1, 1, n+1, dims.numel ()); + gripe_index_out_of_range (1, 1, n+1, dims.numel (), dims); return n; } @@ -188,12 +188,14 @@ compute_index (octave_idx_type n, const octave_idx_type compute_index (octave_idx_type i, octave_idx_type j, const dim_vector& dims) { - if (i < 0 || j < 0) - gripe_invalid_index (); + if (i < 0) + gripe_invalid_index (i, 2, 1); + else if (j < 0) + gripe_invalid_index (j, 2, 2); if (i >= dims(0)) - gripe_index_out_of_range (2, 1, i+1, dims(0)); + gripe_index_out_of_range (2, 1, i+1, dims(0), dims); if (j >= dims.numel (1)) - gripe_index_out_of_range (2, 2, j+1, dims.numel (1)); + gripe_index_out_of_range (2, 2, j+1, dims.numel (1), dims); return j*dims(0) + i; } @@ -202,14 +204,18 @@ octave_idx_type compute_index (octave_idx_type i, octave_idx_type j, octave_idx_type k, const dim_vector& dims) { - if (i < 0 || j < 0 || k < 0) - gripe_invalid_index (); + if (i < 0) + gripe_invalid_index (i, 3, 1); + else if (j < 0) + gripe_invalid_index (j, 3, 2); + else if (k < 0) + gripe_invalid_index (k, 3, 3); if (i >= dims(0)) - gripe_index_out_of_range (3, 1, i+1, dims(0)); + gripe_index_out_of_range (3, 1, i+1, dims(0), dims); if (j >= dims(1)) - gripe_index_out_of_range (3, 2, j+1, dims(1)); + gripe_index_out_of_range (3, 2, j+1, dims(1), dims); if (k >= dims.numel (2)) - gripe_index_out_of_range (3, 3, k+1, dims.numel (2)); + gripe_index_out_of_range (3, 3, k+1, dims.numel (2), dims); return (k*dims(1) + j)*dims(0) + i; } @@ -222,9 +228,9 @@ compute_index (const Array= dv(d)) - gripe_index_out_of_range (nd, d+1, ra_idx(d)+1, dv(d)); + gripe_index_out_of_range (nd, d+1, ra_idx(d)+1, dv(d), dims); } return dv.compute_index (ra_idx.data ()); @@ -540,18 +546,29 @@ sub2ind (const dim_vector& dv, const Arr for (octave_idx_type i = 0; i < len; i++) { - idx_vector idx = idxa(i); - octave_idx_type n = dvx(i); + try + { + idx_vector idx = idxa(i); + octave_idx_type n = dvx(i); - all_ranges = all_ranges && idx.is_range (); - if (clen < 0) - clen = idx.length (n); - else if (clen != idx.length (n)) - current_liboctave_error_handler ("sub2ind: lengths of indices must match"); + all_ranges = all_ranges && idx.is_range (); + if (clen < 0) + clen = idx.length (n); + else if (clen != idx.length (n)) + current_liboctave_error_handler ("sub2ind: lengths of indices must match"); - if (idx.extent (n) > n) - current_liboctave_error_handler ("sub2ind: index out of range"); + if (idx.extent (n) > n) + gripe_index_out_of_range (len, i+1, idx.extent (n), n); + } + catch (index_exception& e) + { + e.set_pos_if_unset (len, i+1); + e.set_var (""); // no particular variable + (*current_liboctave_error_with_id_handler) (e.id(), e.err()); + } } + // idxa known to be valid. Shouldn't need to catch index_exception below here. + if (len == 1) retval = idxa(0); diff --git a/liboctave/array/Array.cc b/liboctave/array/Array.cc --- a/liboctave/array/Array.cc +++ b/liboctave/array/Array.cc @@ -190,9 +190,9 @@ Array::checkelem (octave_idx_type n) { // Do checks directly to avoid recomputing slice_len. if (n < 0) - gripe_invalid_index (); + gripe_invalid_index (n); if (n >= slice_len) - gripe_index_out_of_range (1, 1, n+1, slice_len); + gripe_index_out_of_range (1, 1, n+1, slice_len, dimensions); return elem (n); } @@ -224,9 +224,9 @@ Array::checkelem (octave_idx_type n) { // Do checks directly to avoid recomputing slice_len. if (n < 0) - gripe_invalid_index (); + gripe_invalid_index (n); if (n >= slice_len) - gripe_index_out_of_range (1, 1, n+1, slice_len); + gripe_index_out_of_range (1, 1, n+1, slice_len, dimensions); return elem (n); } @@ -260,7 +260,7 @@ Array::column (octave_idx_type k) con octave_idx_type r = dimensions(0); #ifdef BOUNDS_CHECKING if (k < 0 || k > dimensions.numel (1)) - gripe_index_out_of_range (2, 2, k+1, dimensions.numel (1)); + gripe_index_out_of_range (2, 2, k+1, dimensions.numel (1), dimensions); #endif return Array (*this, dim_vector (r, 1), k*r, k*r + r); @@ -275,7 +275,7 @@ Array::page (octave_idx_type k) const octave_idx_type p = r*c; #ifdef BOUNDS_CHECKING if (k < 0 || k > dimensions.numel (2)) - gripe_index_out_of_range (3, 3, k+1, dimensions.numel (2)); + gripe_index_out_of_range (3, 3, k+1, dimensions.numel (2), dimensions); #endif return Array (*this, dim_vector (r, c), k*p, k*p + p); @@ -287,9 +287,9 @@ Array::linear_slice (octave_idx_type { #ifdef BOUNDS_CHECKING if (lo < 0) - gripe_index_out_of_range (1, 1, lo+1, numel ()); + gripe_index_out_of_range (1, 1, lo+1, numel (), dimensions); if (up > numel ()) - gripe_index_out_of_range (1, 1, up, numel ()); + gripe_index_out_of_range (1, 1, up, numel (), dimensions); #endif if (up < lo) up = lo; return Array (*this, dim_vector (up - lo, 1), lo, up); @@ -726,7 +726,7 @@ Array::index (const idx_vector& i) co else { if (i.extent (n) != n) - gripe_index_out_of_range (1, 1, i.extent (n), n); // throws + gripe_index_out_of_range (1, 1, i.extent (n), n, dimensions); // throws // FIXME: this is the only place where orig_dimensions are used. dim_vector rd = i.orig_dimensions (); @@ -793,9 +793,9 @@ Array::index (const idx_vector& i, co else { if (i.extent (r) != r) - gripe_index_out_of_range (2, 1, i.extent (r), r); // throws + gripe_index_out_of_range (2, 1, i.extent (r), r, dimensions); // throws if (j.extent (c) != c) - gripe_index_out_of_range (2, 2, j.extent (c), c); // throws + gripe_index_out_of_range (2, 2, j.extent (c), c, dimensions); // throws octave_idx_type n = numel (); octave_idx_type il = i.length (r); @@ -855,7 +855,7 @@ Array::index (const Array for (int i = 0; i < ial; i++) { if (ia(i).extent (dv(i)) != dv(i)) - gripe_index_out_of_range (ial, i+1, ia(i).extent (dv(i)), dv(i)); // throws + gripe_index_out_of_range (ial, i+1, ia(i).extent (dv(i)), dv(i), dimensions); // throws all_colons = all_colons && ia(i).is_colon (); } @@ -1180,7 +1180,7 @@ Array::assign (const idx_vector& i, c } } else - gripe_invalid_assignment_size (); + gripe_nonconformant ("=", dim_vector(i.length(n),1), rhs.dims()); } // Assignment to a 2-dimensional array @@ -1284,7 +1284,7 @@ Array::assign (const idx_vector& i, c } // any empty RHS can be assigned to an empty LHS else if ((il != 0 && jl != 0) || (rhdv(0) != 0 && rhdv(1) != 0)) - gripe_assignment_dimension_mismatch (); + gripe_nonconformant ("=", il, jl, rhs.dim1 (), rhs.dim2 ()); } // Assignment to a multi-dimensional array @@ -1398,11 +1398,19 @@ Array::assign (const Array @@ -2214,7 +2214,7 @@ Sparse::assign (const idx_vector& idx assign (idx_i, idx_j, Sparse (n, m)); } else - gripe_assignment_dimension_mismatch (); + gripe_nonconformant ("=", idx_i.length (nr), idx_j.length (nc), n, m); } // Can't use versions of these in Array.cc due to duplication of the diff --git a/liboctave/array/idx-vector.cc b/liboctave/array/idx-vector.cc --- a/liboctave/array/idx-vector.cc +++ b/liboctave/array/idx-vector.cc @@ -113,9 +113,14 @@ idx_vector::idx_range_rep::idx_range_rep gripe_invalid_range (); err = true; } - else if (start < 0 || (step < 0 && start + (len-1)*step < 0)) + else if (start < 0) { - gripe_invalid_index (); + gripe_invalid_index (start); + err = true; + } + else if (step < 0 && start + (len-1)*step < 0) + { + gripe_invalid_index (start + (len-1)*step); err = true; } } @@ -134,15 +139,23 @@ idx_vector::idx_range_rep::idx_range_rep { start = static_cast (r.base ()) - 1; step = static_cast (r.inc ()); - if (start < 0 || (step < 0 && start + (len-1)*step < 0)) + if (start < 0) { - gripe_invalid_index (); + gripe_invalid_index (start); + err = true; + } + else if (step < 0 && start + (len-1)*step < 0) + { + gripe_invalid_index (start + (len-1)*step); err = true; } } else { - gripe_invalid_index (); + // find first non-integer, then gripe about it + double b = r.base(); + double inc = r.inc(); + gripe_invalid_index (b != floor(b) ? b : b+inc); err = true; } } @@ -221,7 +234,11 @@ convert_index (octave_idx_type i, bool& octave_idx_type& ext) { if (i <= 0) - conv_error = true; + { + if (!conv_error) // only gripe once, for things like A(-10000:0) + gripe_invalid_index (i-1); + conv_error = true; + } if (ext < i) ext = i; @@ -235,7 +252,10 @@ convert_index (double x, bool& conv_erro octave_idx_type i = static_cast (x); if (static_cast (i) != x) - conv_error = true; + { + gripe_invalid_index (x-1); + conv_error = true; + } return convert_index (i, conv_error, ext); } @@ -264,9 +284,6 @@ idx_vector::idx_scalar_rep::idx_scalar_r octave_idx_type dummy = 0; data = convert_index (x, err, dummy); - - if (err) - gripe_invalid_index (); } idx_vector::idx_scalar_rep::idx_scalar_rep (octave_idx_type i) @@ -274,7 +291,7 @@ idx_vector::idx_scalar_rep::idx_scalar_r { if (data < 0) { - gripe_invalid_index (); + gripe_invalid_index (data); err = true; } } @@ -327,10 +344,7 @@ idx_vector::idx_vector_rep::idx_vector_r data = d; if (err) - { - delete [] data; - gripe_invalid_index (); - } + delete [] data; } } @@ -347,15 +361,16 @@ idx_vector::idx_vector_rep::idx_vector_r { octave_idx_type k = inda.xelem (i); if (k < 0) - err = true; + { + if (!err) // only report first error, in case 1000s. + gripe_invalid_index (k); + err = true; + } else if (k > max) max = k; } ext = max + 1; - - if (err) - gripe_invalid_index (); } } @@ -459,7 +474,7 @@ idx_vector::idx_vector_rep::checkelem (o { if (n < 0 || n >= len) { - gripe_invalid_index (); + gripe_invalid_index (n); return 0; } @@ -709,7 +724,7 @@ idx_vector::idx_mask_rep::checkelem (oct { if (n < 0 || n >= len) { - gripe_invalid_index (); + gripe_invalid_index (n); return 0; } diff --git a/liboctave/util/lo-array-gripes.cc b/liboctave/util/lo-array-gripes.cc --- a/liboctave/util/lo-array-gripes.cc +++ b/liboctave/util/lo-array-gripes.cc @@ -25,6 +25,7 @@ along with Octave; see the file COPYING. #include #endif +#include #include "lo-array-gripes.h" #include "lo-error.h" @@ -90,34 +91,6 @@ gripe_nonconformant (const char *op, con } void -gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, - octave_idx_type ext) -{ - const char *err_id = error_id_index_out_of_bounds; - - switch (nd) - { - case 1: - (*current_liboctave_error_with_id_handler) - (err_id, "A(I): index out of bounds; value %d out of bound %d", - idx, ext); - break; - - case 2: - (*current_liboctave_error_with_id_handler) - (err_id, "A(I,J): %s index out of bounds; value %d out of bound %d", - (dim == 1) ? "row" : "column", idx, ext); - break; - - default: - (*current_liboctave_error_with_id_handler) - (err_id, "A(I,J,...): index to dimension %d out of bounds; value %d out of bound %d", - dim, idx, ext); - break; - } -} - -void gripe_del_index_out_of_range (bool is1d, octave_idx_type idx, octave_idx_type ext) { @@ -128,19 +101,238 @@ gripe_del_index_out_of_range (bool is1d, is1d ? "I" : "..,I,..", idx, ext); } + + +// Common procedures of base class index_exception, thrown whenever an +// object is indexed incorrectly, such as by an index that is out of +// range, negative, fractional, complex, or of a non-numeric type. + +const char * +index_exception::err (void) throw () +{ + msg = access () + "; " + explain (); + return msg.c_str (); +} + +// Show what was illegally accessed, e.g., "A(-1,_)", "A(0+1i)", "A(_,3)" +// Show how many indices come before/after the offending one, +// e.g., (), (,_), or (_,,...[x5]...) + +std::string +index_exception:: access (void) const +{ + // FIXME: don't use a fixed size buffer! + + int buf_len = 300; + + char output [buf_len]; + char pre [buf_len]; + char post [buf_len]; + + // dim == 0 if position not yet given, or + // (-1) if explicitly shown to be unknown + // both are caught by this condition + + if (static_cast (dim-1) > 100000) + { + // No parentheses are given if the dimension is not known. + pre[0] = post[0] = '\0'; + } + else + { + if (dim < 5) + { + pre[0] = '('; + octave_idx_type i; + + for (i = 1; i < dim; i++) + { + pre[2*i-1] = '_'; + pre[2*i] = ','; + } + + pre[2*i-1] = '\0'; // i == min (1, dim) + } + else + { + sprintf (pre, "(...[x%d]...", dim-1); + } + + if (static_cast (nd-dim) < 5) + { + for (octave_idx_type i = 0; i < nd-dim; i++) + { + post[2*i] = ','; + post[2*i+1] = '_'; + } + + if (nd >= dim) + { + post[2*(nd-dim)] = ')'; + post[2*(nd-dim)+1] = '\0'; + } + } + else + sprintf (post, "...[x%d]...)", nd-dim); + } + + const char *v; + + if (var[0] == '\0' || var == "") + v = "index "; + else + v = var.c_str (); + + snprintf (output, buf_len, "%s%s%s%s", v, pre, idx(), post); + + return output; +} + +class invalid_index : public index_exception +{ +public: + + invalid_index (const char *value, octave_idx_type ndim, + octave_idx_type dimen) + : index_exception (value, ndim, dimen) + { } + + const char* explain (void) const + { +#ifdef USE_64_BIT_IDX_T + return "subscripts must be either integers 1 to (2^63)-1 or logicals"; +#else + return "subscripts must be either integers 1 to (2^31)-1 or logicals"; +#endif + } + + // ID of error to throw + const char* id (void) const + { + return error_id_invalid_index; + } +}; + +// Complain of an index that is: negative, fractional, or too big. + void -gripe_invalid_index (void) +gripe_invalid_index (const char *idx, octave_idx_type nd, + octave_idx_type dim, const char * /* var */) { - const char *err_id = error_id_invalid_index; + invalid_index e (idx, nd, dim); - (*current_liboctave_error_with_id_handler) -#ifdef USE_64_BIT_IDX_T - (err_id, "subscript indices must be either positive integers less than 2^63 or logicals"); -#else - (err_id, "subscript indices must be either positive integers less than 2^31 or logicals"); -#endif + throw e; } +void +gripe_invalid_index (octave_idx_type n, octave_idx_type nd, + octave_idx_type dim, const char *var) +{ + // FIXME: don't use a fixed size buffer! + char buf [100]; + + sprintf (buf, "%d", n+1); + + gripe_invalid_index (buf, nd, dim, var); +} + +void +gripe_invalid_index (double n, octave_idx_type nd, octave_idx_type dim, + const char *var) +{ + // FIXME: don't use a fixed size buffer! + char buf [100]; + + sprintf (buf, "%g", n+1); + + gripe_invalid_index (buf, nd, dim, var); +} + + +// Gripe and exception for read access beyond the bounds of an array. + +class out_of_range : public index_exception +{ +public: + + out_of_range (const char *value, octave_idx_type nd_in,octave_idx_type dim_in) + : index_exception (value, nd_in, dim_in), extent(0) + { } + + const char* explain (void) const + { + static std::string expl; // should probably be member variable, but + // then explain() can't be const. + + if (nd >= size.length ()) // if not an index slice + { + if (var != "") + expl = "but " + var + " has size "; + else + expl = "but object has size "; + + expl = expl + size.str ('x'); + } + else + { + // FIXME: don't use a fixed size buffer! + char buf [100]; + sprintf (buf, "%d", extent); + expl = "out of bound " + std::string (buf); + } + + return expl.c_str (); + } + + // ID of error to throw. + const char* id (void) const + { + return (error_id_index_out_of_bounds); + } + + void set_size (const dim_vector& size_in) { size = size_in; } + + void set_extent (octave_idx_type ext) { extent = ext; } + +private: + + dim_vector size; // dimension of object being accessed + + octave_idx_type extent; // length of dimension being accessed +}; + +// Complain of an index that is out of range, but we don't know matrix size +void +gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, + octave_idx_type ext) +{ + char buf [100]; + sprintf (buf, "%d", idx); + out_of_range e (buf, nd, dim); + + e.set_extent (ext); + dim_vector d (1,1,1,1,1,1,1); // make explain() give extent not size + e.set_size (d); + throw e; +} + +// Complain of an index that is out of range +void +gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, + octave_idx_type ext, const dim_vector& d) +{ + char buf [100]; + sprintf (buf, "%d", idx); + out_of_range e (buf, nd, dim); + + e.set_extent (ext); + e.set_size (d); + throw e; +} + + +/******************************************************************************/ + // FIXME: the following is a common error message to resize, // regardless of whether it's called from assign or elsewhere. It // seems OK to me, but eventually the gripe can be specialized. @@ -157,20 +349,6 @@ gripe_invalid_resize (void) } void -gripe_invalid_assignment_size (void) -{ - (*current_liboctave_error_handler) - ("A(I) = X: X must have the same size as I"); -} - -void -gripe_assignment_dimension_mismatch (void) -{ - (*current_liboctave_error_handler) - ("A(I,J,...) = X: dimensions mismatch"); -} - -void gripe_singular_matrix (double rcond) { if (rcond == 0.0) @@ -186,3 +364,5 @@ gripe_singular_matrix (double rcond) "matrix singular to machine precision, rcond = %g", rcond); } } + +/* Tests in test/index.tst */ diff --git a/liboctave/util/lo-array-gripes.h b/liboctave/util/lo-array-gripes.h --- a/liboctave/util/lo-array-gripes.h +++ b/liboctave/util/lo-array-gripes.h @@ -24,6 +24,80 @@ along with Octave; see the file COPYING. #define octave_lo_array_gripes_h 1 #include "dim-vector.h" +#include "quit.h" + +// Exception thrown by gripe_invalid_index +// This is thrown when the invalid index is detected, at which point nd and dim +// are usually not known. It is caught at the place they are known, where a +// new gripe_invalid_index is called. +// +// Typically, this should be caught after any call to +// octave_value_list::index_vector() +class index_exception : public octave_execution_exception +{ +public: + + index_exception (const char *index_in, octave_idx_type nd_in = 0, + octave_idx_type dim_in = 0, const char *var_in = "") + : index (index_in), nd (nd_in), dim (dim_in), var (var_in) + { } + + ~index_exception (void) throw () { } + + // Erroneous index value. Called in what, and by external code + // (e.g., nth_element) to make a custom error message. + const char *idx (void) const { return index.c_str (); } + + // details set by subclass. + virtual const char* explain (void) const = 0; + + // ID of error to throw. + virtual const char* id (void) const = 0; + + virtual const char* err (void) throw (); + + // Position of error: dimension in error, and number of dimensions. + void set_pos (octave_idx_type nd_in, octave_idx_type dim_in) + { + nd = nd_in; + dim = dim_in; + } + + void set_pos_if_unset (octave_idx_type nd_in, octave_idx_type dim_in) + { + if (nd == 0) + { + nd = nd_in; + dim = dim_in; + } + } + + // Name of variable being indexed. eye(2)(1,1) gives "". + void set_var (std::string var_in) { var = var_in; } + +private: + + // Value of invalid index. + std::string index; + + // Formatted message returned by what(), (not on stack). + std::string msg; + +protected: + + // Show what's wrong, e.g., A(-1,_), A(0+1i). + std::string access (void) const; + + // Number of dimensions of indexed object. + octave_idx_type nd; + + // Dimension number in which invalid index occurred. + octave_idx_type dim; + + // Name of variable being indexed. + std::string var; + +}; extern OCTAVE_API const char *error_id_nonconformant_args; @@ -57,6 +131,11 @@ gripe_nonconformant (const char *op, con extern void OCTAVE_API gripe_index_out_of_range (int nd, int dim, + octave_idx_type iext, octave_idx_type ext, + const dim_vector& d); + +extern void OCTAVE_API +gripe_index_out_of_range (int nd, int dim, octave_idx_type iext, octave_idx_type ext); extern void OCTAVE_API @@ -64,18 +143,21 @@ gripe_del_index_out_of_range (bool is1d, octave_idx_type ext); extern void OCTAVE_API -gripe_invalid_index (void); +gripe_invalid_index (double, octave_idx_type nd=0, + octave_idx_type dim=0, const char *var = NULL); + +extern void OCTAVE_API +gripe_invalid_index (octave_idx_type n, octave_idx_type nd=0, + octave_idx_type dim=0, const char *var = NULL); + +extern void OCTAVE_API +gripe_invalid_index (const char *idx, octave_idx_type nd=0, + octave_idx_type dim=0, const char *var = NULL); extern void OCTAVE_API gripe_invalid_resize (void); extern void OCTAVE_API -gripe_invalid_assignment_size (void); - -extern void OCTAVE_API -gripe_assignment_dimension_mismatch (void); - -extern void OCTAVE_API gripe_singular_matrix (double rcond = 0.0); #endif diff --git a/test/index.tst b/test/index.tst --- a/test/index.tst +++ b/test/index.tst @@ -205,12 +205,6 @@ %!error (a(1:2,1:2) = 1:4) -%!shared x -%! x = 1:5; -%!error x(i) -%!error x(j) -%!error x(1+i) - ## bug #38357 %!shared d, dd %! d = diag ([1, 2, 3]); @@ -501,3 +495,84 @@ %! x = ones (2, 2); %! x([], false, :) = []; %! assert (x, y); + + + ## Test indexing of unnamed constants +%!error 1(0) +%!error 1(-1) +%!error {}(1,0.5) +%!error 1(NaN,1) +%!error [](1,1,{},1,1,1,1,1,1,1,1) +%!error 1(1,1,1,1,1,1,1,1,1,-1,1) +%!error 1(2) +%!error [](1) +%!error zeros(5,0)(3,1) +%!error zeros(0,5)(3,1) +%!error 1(1)(-1)(1) +%! +%!shared abc +%! abc = [1, 2]; +%! ## Test full matrices in variables +%!error abc([false, true, true]) +%!error abc(-1)(1)(1) +%! ## xerror abc(1)(-1)(1) ## why no 'xerror' test? + +%!shared abc +%! abc = [1 2; 3 4]; +%!error abc(5) +%!error abc(2,3) +%!error exp (abc(2,3,0.5)) + +%!shared abc +%! abc = [1 2; 3 4]; abc(1,1,2) = 1; +%!error abc(2,5) +%!error abc(2,3,2) +%!error abc(3,:) = [] +%!error abc(3:50) = [] +%!error abc(3,5) = [] +%!error <=: nonconformant arguments \(op1 is 1x1, op2 is 1x5\)> abc(3,5) = 1:5 + +%! ## Test diagonal matrices, and access of function results +%!error eye(3)(2,3,5) +%!error eye(4)(-2,3) + +%! ## Test cells +%!shared abc +%! abc = {1, 2; 3, 4}; +%!error abc(2,0.3,5) +%!error abc{2,0.3,5} +%!error abc{-2,1,1,1} +%!error abc(0,1,1,1) = 1 + +%! ## Test permutation matrices +%!shared abc +%! abc = eye(3)([3 1 2],:); +%!error abc(NA) +%!error abc(1,1,1,Inf,1) + +%! ## Test sparse matrices +%!shared abc +%! abc = sparse(3,3); +%!error abc(-1) +%!error abc(-1) = 1 +%!error abc(-1,1) +%!error abc(-1,1) = 1 +%!error abc(0,0,0,0) +%!error abc(4,1) + +%! ## Test ranges +%!shared abc +%! abc = 1:10; +%!error abc(-1) +%!error abc(-1,1) +%!error abc(4,1) + +%! ## Test complex +%!shared abc, z +%! abc = [1 2]; +%!error abc(i) +%! abc = [1 2; 3 4]; +%!error abc(complex(1)) +%!error abc(1+0.5*i,3) +%!error abc(2,0-2*i) +