GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
pt-assign.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <iostream>
28 #include <set>
29 
30 #include "defun.h"
31 #include "error.h"
32 #include "gripes.h"
33 #include "input.h"
34 #include "oct-obj.h"
35 #include "oct-lvalue.h"
36 #include "pager.h"
37 #include "ov.h"
38 #include "pt-arg-list.h"
39 #include "pt-bp.h"
40 #include "pt-assign.h"
41 #include "pt-eval.h"
42 #include "pt-walk.h"
43 #include "utils.h"
44 #include "variables.h"
45 
46 // Simple assignment expressions.
47 
50  bool plhs, int l, int c, octave_value::assign_op t)
51  : tree_expression (l, c), lhs (le), rhs (re), preserve (plhs), etype (t)
52 { }
53 
55 {
56  if (! preserve)
57  delete lhs;
58 
59  delete rhs;
60 }
61 
64 {
65  octave_value_list retval;
66 
67  if (nargout > 1)
68  error ("invalid number of output arguments for expression X = RHS");
69  else
70  retval = rvalue1 (nargout);
71 
72  return retval;
73 }
74 
77 {
78  octave_value retval;
79 
80  if (error_state)
81  return retval;
82 
83  if (rhs)
84  {
85  octave_value rhs_val = rhs->rvalue1 ();
86 
87  if (! error_state)
88  {
89  if (rhs_val.is_undefined ())
90  {
91  error ("value on right hand side of assignment is undefined");
92  return retval;
93  }
94  else
95  {
96  if (rhs_val.is_cs_list ())
97  {
98  const octave_value_list lst = rhs_val.list_value ();
99 
100  if (! lst.empty ())
101  rhs_val = lst(0);
102  else
103  {
104  error ("invalid number of elements on RHS of assignment");
105  return retval;
106  }
107  }
108 
109  octave_lvalue ult = lhs->lvalue ();
110 
111  if (ult.numel () != 1)
113 
114  if (! error_state)
115  {
116  ult.assign (etype, rhs_val);
117 
118  if (! error_state)
119  {
121  retval = rhs_val;
122  else
123  retval = ult.value ();
124 
125  if (print_result ()
127  {
128  // We clear any index here so that we can
129  // get the new value of the referenced
130  // object below, instead of the indexed
131  // value (which should be the same as the
132  // right hand side value).
133 
134  ult.clear_index ();
135 
136  octave_value lhs_val = ult.value ();
137 
138  if (! error_state)
140  lhs->name ());
141  }
142  }
143  }
144  }
145  }
146  }
147 
148  return retval;
149 }
150 
151 std::string
153 {
155 }
156 
160 {
161  tree_simple_assignment *new_sa
162  = new tree_simple_assignment (lhs ? lhs->dup (scope, context) : 0,
163  rhs ? rhs->dup (scope, context) : 0,
164  preserve, etype);
165 
166  new_sa->copy_base (*this);
167 
168  return new_sa;
169 }
170 
171 void
173 {
174  tw.visit_simple_assignment (*this);
175 }
176 
177 // Multi-valued assignment expressions.
178 
181  bool plhs, int l, int c)
182  : tree_expression (l, c), lhs (lst), rhs (r), preserve (plhs)
183 { }
184 
186 {
187  if (! preserve)
188  delete lhs;
189 
190  delete rhs;
191 }
192 
195 {
196  octave_value retval;
197 
198  const octave_value_list tmp = rvalue (nargout);
199 
200  if (! tmp.empty ())
201  retval = tmp(0);
202 
203  return retval;
204 }
205 
206 // FIXME: this works, but it would look a little better if
207 // it were broken up into a couple of separate functions.
208 
211 {
212  octave_value_list retval;
213 
214  if (error_state)
215  return retval;
216 
217  if (rhs)
218  {
219  std::list<octave_lvalue> lvalue_list = lhs->lvalue_list ();
220 
221  if (error_state)
222  return retval;
223 
224  octave_idx_type n_out = 0;
225 
226  for (std::list<octave_lvalue>::const_iterator p = lvalue_list.begin ();
227  p != lvalue_list.end ();
228  p++)
229  n_out += p->numel ();
230 
231  // The following trick is used to keep rhs_val constant.
232  const octave_value_list rhs_val1 = rhs->rvalue (n_out, &lvalue_list);
233  const octave_value_list rhs_val = (rhs_val1.length () == 1
234  && rhs_val1(0).is_cs_list ()
235  ? rhs_val1(0).list_value ()
236  : rhs_val1);
237 
238  if (error_state)
239  return retval;
240 
241  octave_idx_type k = 0;
242 
243  octave_idx_type n = rhs_val.length ();
244 
245  // To avoid copying per elements and possible optimizations, we
246  // postpone joining the final values.
247  std::list<octave_value_list> retval_list;
248 
250 
251  for (std::list<octave_lvalue>::iterator p = lvalue_list.begin ();
252  p != lvalue_list.end ();
253  p++)
254  {
255  tree_expression *lhs_elt = *q++;
256 
257  octave_lvalue ult = *p;
258 
259  octave_idx_type nel = ult.numel ();
260 
261  if (nel != 1)
262  {
263  if (k + nel <= n)
264  {
265  // This won't do a copy.
266  octave_value_list ovl = rhs_val.slice (k, nel);
267 
269  octave_value (ovl, true));
270 
271  if (! error_state)
272  {
273  retval_list.push_back (ovl);
274 
275  k += nel;
276  }
277  }
278  else
279  error ("some elements undefined in return list");
280  }
281  else
282  {
283  if (k < n)
284  {
285  ult.assign (octave_value::op_asn_eq, rhs_val(k));
286 
287  if (ult.is_black_hole ())
288  {
289  k++;
290  continue;
291  }
292  else if (! error_state)
293  {
294  retval_list.push_back (rhs_val(k));
295 
296  k++;
297  }
298  }
299  else
300  {
301  // This can happen for a function like
302  //
303  // function varargout = f ()
304  // varargout{1} = nargout;
305  // endfunction
306  //
307  // called with
308  //
309  // [a, ~] = f ();
310  //
311  // Then the list of of RHS values will contain one
312  // element but we are iterating over the list of all
313  // RHS values. We shouldn't complain that a value we
314  // don't need is missing from the list.
315 
316  if (ult.is_black_hole ())
317  {
318  k++;
319  continue;
320  }
321  else
322  error ("element number %d undefined in return list", k+1);
323  }
324  }
325 
326  if (error_state)
327  break;
328  else if (print_result ()
330  {
331  // We clear any index here so that we can get
332  // the new value of the referenced object below,
333  // instead of the indexed value (which should be
334  // the same as the right hand side value).
335 
336  ult.clear_index ();
337 
338  octave_value lhs_val = ult.value ();
339 
340  if (! error_state)
342  lhs_elt->name ());
343  }
344 
345  if (error_state)
346  break;
347 
348  }
349 
350  // Concatenate return values.
351  retval = retval_list;
352 
353  }
354 
355  return retval;
356 }
357 
358 /*
359 %!function varargout = f ()
360 %! varargout{1} = nargout;
361 %!endfunction
362 %!
363 %!test
364 %! [a, ~] = f ();
365 %! assert (a, 2);
366 %!test
367 %! [a, ~, ~, ~, ~] = f ();
368 %! assert (a, 5);
369 */
370 
371 std::string
373 {
375 }
376 
380 {
381  tree_multi_assignment *new_ma
382  = new tree_multi_assignment (lhs ? lhs->dup (scope, context) : 0,
383  rhs ? rhs->dup (scope, context) : 0,
384  preserve);
385 
386  new_ma->copy_base (*this);
387 
388  return new_ma;
389 }
390 
391 void
393 {
394  tw.visit_multi_assignment (*this);
395 }