pt-assign.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 <iostream>
00028 #include <set>
00029 
00030 #include "defun.h"
00031 #include "error.h"
00032 #include "gripes.h"
00033 #include "input.h"
00034 #include "oct-obj.h"
00035 #include "oct-lvalue.h"
00036 #include "pager.h"
00037 #include "ov.h"
00038 #include "pt-arg-list.h"
00039 #include "pt-bp.h"
00040 #include "pt-assign.h"
00041 #include "pt-walk.h"
00042 #include "utils.h"
00043 #include "variables.h"
00044 
00045 // Simple assignment expressions.
00046 
00047 // FIXME -- the following variable and the function that uses it
00048 // should be removed from some future version of Octave.
00049 
00050 static const char *former_built_in_variables[] =
00051 {
00052   "DEFAULT_EXEC_PATH",
00053   "DEFAULT_LOADPATH",
00054   "EDITOR",
00055   "EXEC_PATH",
00056   "FFTW_WISDOM_PROGRAM",
00057   "IMAGEPATH",
00058   "INFO_FILE",
00059   "INFO_PROGRAM",
00060   "LOADPATH",
00061   "MAKEINFO_PROGRAM",
00062   "PAGER",
00063   "PS1",
00064   "PS2",
00065   "PS4",
00066   "__kluge_procbuf_delay__",
00067   "automatic_replot",
00068   "beep_on_error",
00069   "completion_append_char",
00070   "crash_dumps_octave_core",
00071   "current_script_file_name",
00072   "debug_on_error",
00073   "debug_on_interrupt",
00074   "debug_on_warning",
00075   "debug_symtab_lookups",
00076   "default_save_options",
00077   "echo_executing_commands",
00078   "fixed_point_format",
00079   "gnuplot_binary",
00080   "gnuplot_command_axes",
00081   "gnuplot_command_end",
00082   "gnuplot_command_plot",
00083   "gnuplot_command_replot",
00084   "gnuplot_command_splot",
00085   "gnuplot_command_title",
00086   "gnuplot_command_using",
00087   "gnuplot_command_with",
00088   "gnuplot_has_frames",
00089   "history_file",
00090   "history_size",
00091   "ignore_function_time_stamp",
00092   "max_recursion_depth",
00093   "octave_core_file_format",
00094   "octave_core_file_limit",
00095   "octave_core_file_name",
00096   "output_max_field_width",
00097   "output_precision",
00098   "page_output_immediately",
00099   "page_screen_output",
00100   "print_answer_id_name",
00101   "print_empty_dimensions",
00102   "print_rhs_assign_val",
00103   "save_header_format_string",
00104   "save_precision",
00105   "saving_history",
00106   "sighup_dumps_octave_core",
00107   "sigterm_dumps_octave_core",
00108   "silent_functions",
00109   "split_long_rows",
00110   "string_fill_char",
00111   "struct_levels_to_print",
00112   "suppress_verbose_help_message",
00113   "variables_can_hide_functions",
00114   "warn_assign_as_truth_value",
00115   "warn_associativity_change",
00116   "warn_divide_by_zero",
00117   "warn_empty_list_elements",
00118   "warn_fortran_indexing",
00119   "warn_function_name_clash",
00120   "warn_future_time_stamp",
00121   "warn_imag_to_real",
00122   "warn_matlab_incompatible",
00123   "warn_missing_semicolon",
00124   "warn_neg_dim_as_zero",
00125   "warn_num_to_str",
00126   "warn_precedence_change",
00127   "warn_reload_forces_clear",
00128   "warn_resize_on_range_error",
00129   "warn_separator_insert",
00130   "warn_single_quote_string",
00131   "warn_str_to_num",
00132   "warn_undefined_return_values",
00133   "warn_variable_switch_label",
00134   "whos_line_format",
00135   0,
00136 };
00137 
00138 static void
00139 maybe_warn_former_built_in_variable (const std::string& nm)
00140 {
00141   static bool initialized = false;
00142 
00143   static std::set<std::string> vars;
00144 
00145   if (! initialized)
00146     {
00147       const char **p = former_built_in_variables;
00148 
00149       while (*p)
00150         vars.insert (*p++);
00151 
00152       initialized = true;
00153     }
00154 
00155   if (vars.find (nm) != vars.end ())
00156     {
00157       const char *nm_c_str = nm.c_str ();
00158 
00159       warning_with_id ("Octave:built-in-variable-assignment",
00160                        "\
00161 In recent versions of Octave, %s is a function instead\n\
00162 of a built-in variable.\n\n\
00163 By assigning to %s, you have created a variable that hides\n\
00164 the function %s. To remove the variable and restore the \n\
00165 function, type \"clear %s\"\n",
00166                        nm_c_str, nm_c_str, nm_c_str, nm_c_str);
00167     }
00168 }
00169 
00170 tree_simple_assignment::tree_simple_assignment
00171   (tree_expression *le, tree_expression *re,
00172    bool plhs, int l, int c, octave_value::assign_op t)
00173     : tree_expression (l, c), lhs (le), rhs (re), preserve (plhs), etype (t),
00174       first_execution (true) { }
00175 
00176 tree_simple_assignment::~tree_simple_assignment (void)
00177 {
00178   if (! preserve)
00179     delete lhs;
00180 
00181   delete rhs;
00182 }
00183 
00184 octave_value_list
00185 tree_simple_assignment::rvalue (int nargout)
00186 {
00187   octave_value_list retval;
00188 
00189   if (nargout > 1)
00190     error ("invalid number of output arguments for expression X = RHS");
00191   else
00192     retval = rvalue1 (nargout);
00193 
00194   return retval;
00195 }
00196 
00197 octave_value
00198 tree_simple_assignment::rvalue1 (int)
00199 {
00200   octave_value retval;
00201 
00202   if (first_execution && lhs)
00203     maybe_warn_former_built_in_variable (lhs->name ());
00204 
00205   if (error_state)
00206     return retval;
00207 
00208   if (rhs)
00209     {
00210       octave_value rhs_val = rhs->rvalue1 ();
00211 
00212       if (! error_state)
00213         {
00214           if (rhs_val.is_undefined ())
00215             {
00216               error ("value on right hand side of assignment is undefined");
00217               return retval;
00218             }
00219           else
00220             {
00221               if (rhs_val.is_cs_list ())
00222                 {
00223                   const octave_value_list lst = rhs_val.list_value ();
00224 
00225                   if (! lst.empty ())
00226                     rhs_val = lst(0);
00227                   else
00228                     {
00229                       error ("invalid number of elements on RHS of assignment");
00230                       return retval;
00231                     }
00232                 }
00233 
00234               octave_lvalue ult = lhs->lvalue ();
00235 
00236               if (ult.numel () != 1)
00237                 gripe_nonbraced_cs_list_assignment ();
00238 
00239               if (! error_state)
00240                 {
00241                   ult.assign (etype, rhs_val);
00242 
00243                   if (! error_state)
00244                     {
00245                       if (etype == octave_value::op_asn_eq)
00246                         retval = rhs_val;
00247                       else
00248                         retval = ult.value ();
00249 
00250                       if (print_result ())
00251                         {
00252                           // We clear any index here so that we can
00253                           // get the new value of the referenced
00254                           // object below, instead of the indexed
00255                           // value (which should be the same as the
00256                           // right hand side value).
00257 
00258                           ult.clear_index ();
00259 
00260                           octave_value lhs_val = ult.value ();
00261 
00262                           if (! error_state)
00263                             lhs_val.print_with_name (octave_stdout,
00264                                                      lhs->name ());
00265                         }
00266                     }
00267                 }
00268             }
00269         }
00270     }
00271 
00272   first_execution = false;
00273 
00274   return retval;
00275 }
00276 
00277 std::string
00278 tree_simple_assignment::oper (void) const
00279 {
00280   return octave_value::assign_op_as_string (etype);
00281 }
00282 
00283 tree_expression *
00284 tree_simple_assignment::dup (symbol_table::scope_id scope,
00285                              symbol_table::context_id context) const
00286 {
00287   tree_simple_assignment *new_sa
00288     = new tree_simple_assignment (lhs ? lhs->dup (scope, context) : 0,
00289                                   rhs ? rhs->dup (scope, context) : 0,
00290                                   preserve, etype);
00291 
00292   new_sa->copy_base (*this);
00293 
00294   return new_sa;
00295 }
00296 
00297 void
00298 tree_simple_assignment::accept (tree_walker& tw)
00299 {
00300   tw.visit_simple_assignment (*this);
00301 }
00302 
00303 // Multi-valued assignment expressions.
00304 
00305 tree_multi_assignment::tree_multi_assignment
00306   (tree_argument_list *lst, tree_expression *r,
00307    bool plhs, int l, int c)
00308     : tree_expression (l, c), lhs (lst), rhs (r), preserve (plhs),
00309       first_execution (true) { }
00310 
00311 tree_multi_assignment::~tree_multi_assignment (void)
00312 {
00313   if (! preserve)
00314     delete lhs;
00315 
00316   delete rhs;
00317 }
00318 
00319 octave_value
00320 tree_multi_assignment::rvalue1 (int nargout)
00321 {
00322   octave_value retval;
00323 
00324   const octave_value_list tmp = rvalue (nargout);
00325 
00326   if (! tmp.empty ())
00327     retval = tmp(0);
00328 
00329   return retval;
00330 }
00331 
00332 // FIXME -- this works, but it would look a little better if
00333 // it were broken up into a couple of separate functions.
00334 
00335 octave_value_list
00336 tree_multi_assignment::rvalue (int)
00337 {
00338   octave_value_list retval;
00339 
00340   if (error_state)
00341     return retval;
00342 
00343   if (first_execution)
00344     {
00345       for (tree_argument_list::iterator p = lhs->begin (); p != lhs->end (); p++)
00346         {
00347           tree_expression *lhs_expr = *p;
00348 
00349           if (lhs_expr)
00350             maybe_warn_former_built_in_variable (lhs_expr->name ());
00351         }
00352     }
00353 
00354   if (rhs)
00355     {
00356       std::list<octave_lvalue> lvalue_list = lhs->lvalue_list ();
00357 
00358       if (error_state)
00359         return retval;
00360 
00361       octave_idx_type n_out = 0;
00362 
00363       for (std::list<octave_lvalue>::const_iterator p = lvalue_list.begin ();
00364            p != lvalue_list.end ();
00365            p++)
00366         n_out += p->numel ();
00367 
00368       // The following trick is used to keep rhs_val constant.
00369       const octave_value_list rhs_val1 = rhs->rvalue (n_out, &lvalue_list);
00370       const octave_value_list rhs_val = (rhs_val1.length () == 1 && rhs_val1(0).is_cs_list ()
00371                                          ? rhs_val1(0).list_value () : rhs_val1);
00372 
00373       if (error_state)
00374         return retval;
00375 
00376       octave_idx_type k = 0;
00377 
00378       octave_idx_type n = rhs_val.length ();
00379 
00380       // To avoid copying per elements and possible optimizations, we
00381       // postpone joining the final values.
00382       std::list<octave_value_list> retval_list;
00383 
00384       tree_argument_list::iterator q = lhs->begin ();
00385 
00386       for (std::list<octave_lvalue>::iterator p = lvalue_list.begin ();
00387            p != lvalue_list.end ();
00388            p++)
00389         {
00390           tree_expression *lhs_elt = *q++;
00391 
00392           octave_lvalue ult = *p;
00393 
00394           octave_idx_type nel = ult.numel ();
00395 
00396           if (nel != 1)
00397             {
00398               if (k + nel <= n)
00399                 {
00400                   // This won't do a copy.
00401                   octave_value_list ovl  = rhs_val.slice (k, nel);
00402 
00403                   ult.assign (octave_value::op_asn_eq, octave_value (ovl, true));
00404 
00405                   if (! error_state)
00406                     {
00407                       retval_list.push_back (ovl);
00408 
00409                       k += nel;
00410                     }
00411                 }
00412               else
00413                 error ("some elements undefined in return list");
00414             }
00415           else
00416             {
00417               if (k < n)
00418                 {
00419                   ult.assign (octave_value::op_asn_eq, rhs_val(k));
00420 
00421                   if (ult.is_black_hole ())
00422                     {
00423                       k++;
00424                       continue;
00425                     }
00426                   else if (! error_state)
00427                     {
00428                       retval_list.push_back (rhs_val(k));
00429 
00430                       k++;
00431                     }
00432                 }
00433               else
00434                 {
00435                   // This can happen for a function like
00436                   //
00437                   //   function varargout = f ()
00438                   //     varargout{1} = nargout;
00439                   //   endfunction
00440                   //
00441                   // called with
00442                   //
00443                   //    [a, ~] = f ();
00444                   //
00445                   // Then the list of of RHS values will contain one
00446                   // element but we are iterating over the list of all
00447                   // RHS values.  We shouldn't complain that a value we
00448                   // don't need is missing from the list.
00449 
00450                   if (ult.is_black_hole ())
00451                     {
00452                       k++;
00453                       continue;
00454                     }
00455                   else
00456                     error ("element number %d undefined in return list", k+1);
00457                 }
00458             }
00459 
00460           if (error_state)
00461             break;
00462           else if (print_result ())
00463             {
00464               // We clear any index here so that we can get
00465               // the new value of the referenced object below,
00466               // instead of the indexed value (which should be
00467               // the same as the right hand side value).
00468 
00469               ult.clear_index ();
00470 
00471               octave_value lhs_val = ult.value ();
00472 
00473               if (! error_state)
00474                 lhs_val.print_with_name (octave_stdout,
00475                                          lhs_elt->name ());
00476             }
00477 
00478           if (error_state)
00479             break;
00480 
00481         }
00482 
00483       // Concatenate return values.
00484       retval = retval_list;
00485 
00486     }
00487 
00488   first_execution = false;
00489 
00490   return retval;
00491 }
00492 
00493 /*
00494 %!function varargout = f ()
00495 %!  varargout{1} = nargout;
00496 %!endfunction
00497 %!
00498 %!test
00499 %! [a, ~] = f ();
00500 %! assert (a, 2);
00501 %!test
00502 %! [a, ~, ~, ~, ~] = f ();
00503 %! assert (a, 5);
00504 */
00505 
00506 std::string
00507 tree_multi_assignment::oper (void) const
00508 {
00509   return octave_value::assign_op_as_string (op_type ());
00510 }
00511 
00512 tree_expression *
00513 tree_multi_assignment::dup (symbol_table::scope_id scope,
00514                             symbol_table::context_id context) const
00515 {
00516   tree_multi_assignment *new_ma
00517     = new tree_multi_assignment (lhs ? lhs->dup (scope, context) : 0,
00518                                  rhs ? rhs->dup (scope, context) : 0,
00519                                  preserve);
00520 
00521   new_ma->copy_base (*this);
00522 
00523   return new_ma;
00524 }
00525 
00526 void
00527 tree_multi_assignment::accept (tree_walker& tw)
00528 {
00529   tw.visit_multi_assignment (*this);
00530 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines