pt-idx.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include "Cell.h"
00028 #include "error.h"
00029 #include "oct-map.h"
00030 #include "oct-obj.h"
00031 #include "oct-lvalue.h"
00032 #include "ov.h"
00033 #include "pager.h"
00034 #include "pt-arg-list.h"
00035 #include "pt-bp.h"
00036 #include "pt-id.h"
00037 #include "pt-idx.h"
00038 #include "pt-walk.h"
00039 #include "utils.h"
00040 #include "variables.h"
00041 #include "gripes.h"
00042 
00043 // Index expressions.
00044 
00045 tree_index_expression::tree_index_expression (int l, int c)
00046   : tree_expression (l, c), expr (0), args (0), type (),
00047     arg_nm (), dyn_field () { }
00048 
00049 tree_index_expression::tree_index_expression (tree_expression *e,
00050                                               tree_argument_list *lst,
00051                                               int l, int c, char t)
00052   : tree_expression (l, c), expr (e), args (0), type (),
00053     arg_nm (), dyn_field ()
00054 {
00055   append (lst, t);
00056 }
00057 
00058 tree_index_expression::tree_index_expression (tree_expression *e,
00059                                               const std::string& n,
00060                                               int l, int c)
00061   : tree_expression (l, c), expr (e), args (0), type (),
00062     arg_nm (), dyn_field ()
00063 {
00064   append (n);
00065 }
00066 
00067 tree_index_expression::tree_index_expression (tree_expression *e,
00068                                               tree_expression *df,
00069                                               int l, int c)
00070   : tree_expression (l, c), expr (e), args (0), type (),
00071     arg_nm (), dyn_field ()
00072 {
00073   append (df);
00074 }
00075 
00076 void
00077 tree_index_expression::append (tree_argument_list *lst, char t)
00078 {
00079   args.push_back (lst);
00080   type.append (1, t);
00081   arg_nm.push_back (lst ? lst->get_arg_names () : string_vector ());
00082   dyn_field.push_back (static_cast<tree_expression *> (0));
00083 
00084   if (lst && lst->has_magic_tilde ())
00085     error ("invalid use of empty argument (~) in index expression");
00086 }
00087 
00088 void
00089 tree_index_expression::append (const std::string& n)
00090 {
00091   args.push_back (static_cast<tree_argument_list *> (0));
00092   type.append (".");
00093   arg_nm.push_back (n);
00094   dyn_field.push_back (static_cast<tree_expression *> (0));
00095 }
00096 
00097 void
00098 tree_index_expression::append (tree_expression *df)
00099 {
00100   args.push_back (static_cast<tree_argument_list *> (0));
00101   type.append (".");
00102   arg_nm.push_back ("");
00103   dyn_field.push_back (df);
00104 }
00105 
00106 tree_index_expression::~tree_index_expression (void)
00107 {
00108   delete expr;
00109 
00110   while (! args.empty ())
00111     {
00112       std::list<tree_argument_list *>::iterator p = args.begin ();
00113       delete *p;
00114       args.erase (p);
00115     }
00116 
00117   while (! dyn_field.empty ())
00118     {
00119       std::list<tree_expression *>::iterator p = dyn_field.begin ();
00120       delete *p;
00121       dyn_field.erase (p);
00122     }
00123 }
00124 
00125 bool
00126 tree_index_expression::has_magic_end (void) const
00127 {
00128   for (std::list<tree_argument_list *>::const_iterator p = args.begin ();
00129        p != args.end ();
00130        p++)
00131     {
00132       tree_argument_list *elt = *p;
00133 
00134       if (elt && elt->has_magic_end ())
00135         return true;
00136     }
00137 
00138   return false;
00139 }
00140 
00141 // This is useful for printing the name of the variable in an indexed
00142 // assignment.
00143 
00144 std::string
00145 tree_index_expression::name (void) const
00146 {
00147   return expr->name ();
00148 }
00149 
00150 static Cell
00151 make_subs_cell (tree_argument_list *args, const string_vector& arg_nm)
00152 {
00153   Cell retval;
00154 
00155   octave_value_list arg_values;
00156 
00157   if (args)
00158     arg_values = args->convert_to_const_vector ();
00159 
00160   if (! error_state)
00161     {
00162       int n = arg_values.length ();
00163 
00164       if (n > 0)
00165         {
00166           arg_values.stash_name_tags (arg_nm);
00167 
00168           retval.resize (dim_vector (1, n));
00169 
00170           for (int i = 0; i < n; i++)
00171             retval(0,i) = arg_values(i);
00172         }
00173     }
00174 
00175   return retval;
00176 }
00177 
00178 static inline octave_value_list
00179 make_value_list (tree_argument_list *args, const string_vector& arg_nm,
00180                  const octave_value *object, bool rvalue = true)
00181 {
00182   octave_value_list retval;
00183 
00184   if (args)
00185     {
00186       if (rvalue && object && args->has_magic_end () && object->is_undefined ())
00187         gripe_invalid_inquiry_subscript ();
00188       else
00189         retval = args->convert_to_const_vector (object);
00190     }
00191 
00192   if (! error_state)
00193     {
00194       octave_idx_type n = retval.length ();
00195 
00196       if (n > 0)
00197         retval.stash_name_tags (arg_nm);
00198     }
00199 
00200   return retval;
00201 }
00202 
00203 std::string
00204 tree_index_expression::get_struct_index
00205   (std::list<string_vector>::const_iterator p_arg_nm,
00206    std::list<tree_expression *>::const_iterator p_dyn_field) const
00207 {
00208   std::string fn = (*p_arg_nm)(0);
00209 
00210   if (fn.empty ())
00211     {
00212       tree_expression *df = *p_dyn_field;
00213 
00214       if (df)
00215         {
00216           octave_value t = df->rvalue1 ();
00217 
00218           if (! error_state)
00219             {
00220               fn = t.string_value ();
00221 
00222               if (! valid_identifier (fn))
00223                 ::error ("invalid structure field name '%s'", fn.c_str ());
00224             }
00225         }
00226       else
00227         panic_impossible ();
00228     }
00229 
00230   return fn;
00231 }
00232 
00233 octave_map
00234 tree_index_expression::make_arg_struct (void) const
00235 {
00236   int n = args.size ();
00237 
00238   Cell type_field (n, 1);
00239   Cell subs_field (n, 1);
00240 
00241   std::list<tree_argument_list *>::const_iterator p_args = args.begin ();
00242   std::list<string_vector>::const_iterator p_arg_nm = arg_nm.begin ();
00243   std::list<tree_expression *>::const_iterator p_dyn_field = dyn_field.begin ();
00244 
00245   octave_map m;
00246 
00247   for (int i = 0; i < n; i++)
00248     {
00249       switch (type[i])
00250         {
00251         case '(':
00252           subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
00253           break;
00254 
00255         case '{':
00256           subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
00257           break;
00258 
00259         case '.':
00260           subs_field(i) = get_struct_index (p_arg_nm, p_dyn_field);
00261           break;
00262 
00263         default:
00264           panic_impossible ();
00265         }
00266 
00267       if (error_state)
00268         return m;
00269 
00270       p_args++;
00271       p_arg_nm++;
00272       p_dyn_field++;
00273     }
00274 
00275   m.assign ("type", type_field);
00276   m.assign ("subs", subs_field);
00277 
00278   return m;
00279 }
00280 
00281 octave_value_list
00282 tree_index_expression::rvalue (int nargout)
00283 {
00284   return tree_index_expression::rvalue (nargout, 0);
00285 }
00286 
00287 octave_value_list
00288 tree_index_expression::rvalue (int nargout, const std::list<octave_lvalue> *lvalue_list)
00289 {
00290   octave_value_list retval;
00291 
00292   if (error_state)
00293     return retval;
00294 
00295   octave_value first_expr_val;
00296 
00297   octave_value_list first_args;
00298 
00299   bool have_args = false;
00300 
00301   if (expr->is_identifier () && type[0] == '(')
00302     {
00303       tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
00304 
00305       if (! (id->is_variable () || args.empty ()))
00306         {
00307           tree_argument_list *al = *(args.begin ());
00308 
00309           size_t n = al ? al->length () : 0;
00310 
00311           if (n > 0)
00312             {
00313               string_vector anm = *(arg_nm.begin ());
00314               have_args = true;
00315               first_args = al -> convert_to_const_vector ();
00316               first_args.stash_name_tags (anm);
00317 
00318               if (! error_state)
00319                 first_expr_val = id->do_lookup  (first_args);
00320             }
00321         }
00322     }
00323 
00324   if (! error_state)
00325     {
00326       if (first_expr_val.is_undefined ())
00327         first_expr_val = expr->rvalue1 ();
00328 
00329       octave_value tmp = first_expr_val;
00330       octave_idx_type tmpi = 0;
00331 
00332       std::list<octave_value_list> idx;
00333 
00334       int n = args.size ();
00335 
00336       std::list<tree_argument_list *>::iterator p_args = args.begin ();
00337       std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
00338       std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
00339 
00340       for (int i = 0; i < n; i++)
00341         {
00342           if (i > 0)
00343             {
00344               tree_argument_list *al = *p_args;
00345 
00346               // In Matlab, () can only be followed by . In Octave, we do not
00347               // enforce this for rvalue expressions, but we'll split the
00348               // evaluation at this point. This will, hopefully, allow Octave's
00349               // looser rules apply smoothly for Matlab overloaded subsref
00350               // codes.
00351               bool force_split = type[i-1] == '(' && type[i] != '.';
00352 
00353               if (force_split || (al && al->has_magic_end ()))
00354                 {
00355                   // We have an expression like
00356                   //
00357                   //   x{end}.a(end)
00358                   //
00359                   // and we are looking at the argument list that
00360                   // contains the second (or third, etc.) "end" token,
00361                   // so we must evaluate everything up to the point of
00362                   // that argument list so we can pass the appropriate
00363                   // value to the built-in __end__ function.
00364 
00365                   const octave_value_list tmp_list
00366                     = tmp.subsref (type.substr (tmpi, i - tmpi), idx, nargout);
00367 
00368                   tmp = tmp_list.length () ? tmp_list(0) : octave_value ();
00369                   tmpi = i;
00370                   idx.clear ();
00371 
00372                   if (tmp.is_cs_list ())
00373                     gripe_indexed_cs_list ();
00374 
00375                   if (error_state)
00376                     break;
00377                 }
00378             }
00379 
00380           switch (type[i])
00381             {
00382             case '(':
00383               if (have_args)
00384                 {
00385                   idx.push_back (first_args);
00386                   have_args = false;
00387                 }
00388               else
00389                 idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
00390               break;
00391 
00392             case '{':
00393               idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
00394               break;
00395 
00396             case '.':
00397               idx.push_back (octave_value (get_struct_index (p_arg_nm, p_dyn_field)));
00398               break;
00399 
00400             default:
00401               panic_impossible ();
00402             }
00403 
00404           if (error_state)
00405             break;
00406 
00407           p_args++;
00408           p_arg_nm++;
00409           p_dyn_field++;
00410         }
00411 
00412       if (! error_state)
00413         retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
00414                               lvalue_list);
00415     }
00416 
00417   return retval;
00418 }
00419 
00420 octave_value
00421 tree_index_expression::rvalue1 (int nargout)
00422 {
00423   octave_value retval;
00424 
00425   const octave_value_list tmp = rvalue (nargout);
00426 
00427   if (! tmp.empty ())
00428     retval = tmp(0);
00429 
00430   return retval;
00431 }
00432 
00433 octave_lvalue
00434 tree_index_expression::lvalue (void)
00435 {
00436   octave_lvalue retval;
00437 
00438   std::list<octave_value_list> idx;
00439   std::string tmp_type;
00440 
00441   int n = args.size ();
00442 
00443   std::list<tree_argument_list *>::iterator p_args = args.begin ();
00444   std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
00445   std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
00446 
00447   retval = expr->lvalue ();
00448 
00449   if (! error_state)
00450     {
00451       const octave_value *tro = retval.object ();
00452 
00453       octave_value tmp;
00454 
00455       if (tro)
00456         tmp = *tro;
00457 
00458       octave_idx_type tmpi = 0;
00459       std::list<octave_value_list> tmpidx;
00460 
00461       for (int i = 0; i < n; i++)
00462         {
00463           if (retval.numel () != 1)
00464             gripe_indexed_cs_list ();
00465           else if (tmpi < i)
00466             {
00467               tmp = tmp.subsref (type.substr (tmpi, i - tmpi), tmpidx, true);
00468               tmpidx.clear ();
00469             }
00470 
00471           if (error_state)
00472             break;
00473 
00474           switch (type[i])
00475             {
00476             case '(':
00477               {
00478                 octave_value_list tidx
00479                   = make_value_list (*p_args, *p_arg_nm, &tmp, false);
00480 
00481                 idx.push_back (tidx);
00482 
00483                 if (i < n - 1)
00484                   {
00485                     if (type[i+1] == '.')
00486                       {
00487                         tmpidx.push_back (tidx);
00488                         tmpi = i+1;
00489                       }
00490                     else
00491                       error ("() must be followed by . or close the index chain");
00492                   }
00493               }
00494               break;
00495 
00496             case '{':
00497               {
00498                 octave_value_list tidx
00499                   = make_value_list (*p_args, *p_arg_nm, &tmp, false);
00500 
00501                 if (tmp.is_undefined ())
00502                   {
00503                     if (tidx.has_magic_colon ())
00504                       gripe_invalid_inquiry_subscript ();
00505                     else
00506                       tmp = Cell ();
00507                   }
00508                 else if (tmp.is_zero_by_zero ()
00509                          && (tmp.is_matrix_type () || tmp.is_string ()))
00510                   {
00511                     tmp = Cell ();
00512                   }
00513 
00514                 retval.numel (tmp.numel (tidx));
00515 
00516                 if (error_state)
00517                   break;
00518 
00519                 idx.push_back (tidx);
00520                 tmpidx.push_back (tidx);
00521                 tmpi = i;
00522               }
00523               break;
00524 
00525             case '.':
00526               {
00527                 octave_value tidx = get_struct_index (p_arg_nm, p_dyn_field);
00528                 if (error_state)
00529                   break;
00530 
00531                 bool autoconv = (tmp.is_zero_by_zero ()
00532                                  && (tmp.is_matrix_type () || tmp.is_string ()
00533                                      || tmp.is_cell ()));
00534 
00535                 if (i > 0 && type [i-1] == '(')
00536                   {
00537                     octave_value_list pidx = idx.back ();
00538 
00539                     // Use octave_map, not octave_scalar_map so that the
00540                     // dimensions are 0x0, not 1x1.
00541                     if (tmp.is_undefined ())
00542                       {
00543                         if (pidx.has_magic_colon ())
00544                           gripe_invalid_inquiry_subscript ();
00545                         else
00546                           tmp = octave_map ();
00547                       }
00548                     else if (autoconv)
00549                       tmp = octave_map ();
00550 
00551                     retval.numel (tmp.numel (pidx));
00552 
00553                     tmpi = i-1;
00554                     tmpidx.push_back (tidx);
00555                   }
00556                 else
00557                   {
00558                     if (tmp.is_undefined () || autoconv)
00559                       {
00560                         tmpi = i+1;
00561                         tmp = octave_value ();
00562                       }
00563                     else
00564                       {
00565                         retval.numel (tmp.numel (octave_value_list ()));
00566 
00567                         tmpi = i;
00568                         tmpidx.push_back (tidx);
00569                       }
00570                   }
00571 
00572                 if (error_state)
00573                   break;
00574 
00575                 idx.push_back (tidx);
00576               }
00577               break;
00578 
00579             default:
00580               panic_impossible ();
00581             }
00582 
00583           if (idx.back ().empty ())
00584             error ("invalid empty index list");
00585 
00586           if (error_state)
00587             break;
00588 
00589           p_args++;
00590           p_arg_nm++;
00591           p_dyn_field++;
00592         }
00593 
00594       if (! error_state)
00595         retval.set_index (type, idx);
00596 
00597     }
00598 
00599   return retval;
00600 }
00601 
00602 /*
00603 %!test
00604 %! clear x
00605 %! clear y
00606 %! y = 3;
00607 %! x(y(end)) = 1;
00608 %! assert (x, [0, 0, 1]);
00609 %! clear x
00610 %! clear y
00611 %! y = {3};
00612 %! x(y{end}) = 1;
00613 %! assert (x, [0, 0, 1]);
00614 
00615 %!test
00616 %! x = {1, 2, 3};
00617 %! [x{:}] = deal (4, 5, 6);
00618 %! assert (x, {4, 5, 6});
00619 
00620 %!test
00621 %! [x.a, x.b.c] = deal (1, 2);
00622 %! assert (x.a == 1 && x.b.c == 2);
00623 
00624 %!test
00625 %! [x.a, x(2).b] = deal (1, 2);
00626 %! assert (x(1).a == 1 && isempty (x(2).a) && isempty (x(1).b) && x(2).b == 2);
00627 
00628 %!test
00629 %! x = struct (zeros (0, 1), {"a", "b"});
00630 %! x(2).b = 1;
00631 %! assert (x(2).b == 1);
00632 
00633 %!test
00634 %! x = struct (zeros (0, 1), {"a", "b"});
00635 %! x(2).b = 1;
00636 %! assert (x(2).b == 1);
00637 */
00638 
00639 tree_index_expression *
00640 tree_index_expression::dup (symbol_table::scope_id scope,
00641                             symbol_table::context_id context) const
00642 {
00643   tree_index_expression *new_idx_expr
00644     = new tree_index_expression (line (), column ());
00645 
00646   new_idx_expr->expr = expr ? expr->dup (scope, context) : 0;
00647 
00648   std::list<tree_argument_list *> new_args;
00649 
00650   for (std::list<tree_argument_list *>::const_iterator p = args.begin ();
00651        p != args.end ();
00652        p++)
00653     {
00654       const tree_argument_list *elt = *p;
00655 
00656       new_args.push_back (elt ? elt->dup (scope, context) : 0);
00657     }
00658 
00659   new_idx_expr->args = new_args;
00660 
00661   new_idx_expr->type = type;
00662 
00663   new_idx_expr->arg_nm = arg_nm;
00664 
00665   std::list<tree_expression *> new_dyn_field;
00666 
00667   for (std::list<tree_expression *>::const_iterator p = dyn_field.begin ();
00668        p != dyn_field.end ();
00669        p++)
00670     {
00671       const tree_expression *elt = *p;
00672 
00673       new_dyn_field.push_back (elt ? elt->dup (scope, context) : 0);
00674     }
00675 
00676   new_idx_expr->dyn_field = new_dyn_field;
00677 
00678   new_idx_expr->copy_base (*this);
00679 
00680   return new_idx_expr;
00681 }
00682 
00683 void
00684 tree_index_expression::accept (tree_walker& tw)
00685 {
00686   tw.visit_index_expression (*this);
00687 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines