comparison libinterp/parse-tree/pt-assign.cc @ 15195:2fc554ffbc28

split libinterp from src * libinterp: New directory. Move all files from src directory here except Makefile.am, main.cc, main-cli.cc, mkoctfile.in.cc, mkoctfilr.in.sh, octave-config.in.cc, octave-config.in.sh. * libinterp/Makefile.am: New file, extracted from src/Makefile.am. * src/Makefile.am: Delete everything except targets and definitions needed to build and link main and utility programs. * Makefile.am (SUBDIRS): Include libinterp in the list. * autogen.sh: Run config-module.sh in libinterp/dldfcn directory, not src/dldfcn directory. * configure.ac (AC_CONFIG_SRCDIR): Use libinterp/octave.cc, not src/octave.cc. (DL_LDFLAGS, LIBOCTINTERP): Use libinterp, not src. (AC_CONFIG_FILES): Include libinterp/Makefile in the list. * find-docstring-files.sh: Look in libinterp, not src. * gui/src/Makefile.am (liboctgui_la_CPPFLAGS): Find header files in libinterp, not src.
author John W. Eaton <jwe@octave.org>
date Sat, 18 Aug 2012 16:23:39 -0400
parents src/parse-tree/pt-assign.cc@46b19589b593
children fb9dffe5fbfb
comparison
equal deleted inserted replaced
15194:0f0b795044c3 15195:2fc554ffbc28
1 /*
2
3 Copyright (C) 1996-2012 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-walk.h"
42 #include "utils.h"
43 #include "variables.h"
44
45 // Simple assignment expressions.
46
47 // FIXME -- the following variable and the function that uses it
48 // should be removed from some future version of Octave.
49
50 static const char *former_built_in_variables[] =
51 {
52 "DEFAULT_EXEC_PATH",
53 "DEFAULT_LOADPATH",
54 "EDITOR",
55 "EXEC_PATH",
56 "FFTW_WISDOM_PROGRAM",
57 "IMAGEPATH",
58 "INFO_FILE",
59 "INFO_PROGRAM",
60 "LOADPATH",
61 "MAKEINFO_PROGRAM",
62 "PAGER",
63 "PS1",
64 "PS2",
65 "PS4",
66 "__kluge_procbuf_delay__",
67 "automatic_replot",
68 "beep_on_error",
69 "completion_append_char",
70 "crash_dumps_octave_core",
71 "current_script_file_name",
72 "debug_on_error",
73 "debug_on_interrupt",
74 "debug_on_warning",
75 "debug_symtab_lookups",
76 "default_save_options",
77 "echo_executing_commands",
78 "fixed_point_format",
79 "gnuplot_binary",
80 "gnuplot_command_axes",
81 "gnuplot_command_end",
82 "gnuplot_command_plot",
83 "gnuplot_command_replot",
84 "gnuplot_command_splot",
85 "gnuplot_command_title",
86 "gnuplot_command_using",
87 "gnuplot_command_with",
88 "gnuplot_has_frames",
89 "history_file",
90 "history_size",
91 "ignore_function_time_stamp",
92 "max_recursion_depth",
93 "octave_core_file_format",
94 "octave_core_file_limit",
95 "octave_core_file_name",
96 "output_max_field_width",
97 "output_precision",
98 "page_output_immediately",
99 "page_screen_output",
100 "print_answer_id_name",
101 "print_empty_dimensions",
102 "print_rhs_assign_val",
103 "save_header_format_string",
104 "save_precision",
105 "saving_history",
106 "sighup_dumps_octave_core",
107 "sigterm_dumps_octave_core",
108 "silent_functions",
109 "split_long_rows",
110 "string_fill_char",
111 "struct_levels_to_print",
112 "suppress_verbose_help_message",
113 "variables_can_hide_functions",
114 "warn_assign_as_truth_value",
115 "warn_associativity_change",
116 "warn_divide_by_zero",
117 "warn_empty_list_elements",
118 "warn_fortran_indexing",
119 "warn_function_name_clash",
120 "warn_future_time_stamp",
121 "warn_imag_to_real",
122 "warn_matlab_incompatible",
123 "warn_missing_semicolon",
124 "warn_neg_dim_as_zero",
125 "warn_num_to_str",
126 "warn_precedence_change",
127 "warn_reload_forces_clear",
128 "warn_resize_on_range_error",
129 "warn_separator_insert",
130 "warn_single_quote_string",
131 "warn_str_to_num",
132 "warn_undefined_return_values",
133 "warn_variable_switch_label",
134 "whos_line_format",
135 0,
136 };
137
138 static void
139 maybe_warn_former_built_in_variable (const std::string& nm)
140 {
141 static bool initialized = false;
142
143 static std::set<std::string> vars;
144
145 if (! initialized)
146 {
147 const char **p = former_built_in_variables;
148
149 while (*p)
150 vars.insert (*p++);
151
152 initialized = true;
153 }
154
155 if (vars.find (nm) != vars.end ())
156 {
157 const char *nm_c_str = nm.c_str ();
158
159 warning_with_id ("Octave:built-in-variable-assignment",
160 "\
161 In recent versions of Octave, %s is a function instead\n\
162 of a built-in variable.\n\n\
163 By assigning to %s, you have created a variable that hides\n\
164 the function %s. To remove the variable and restore the \n\
165 function, type \"clear %s\"\n",
166 nm_c_str, nm_c_str, nm_c_str, nm_c_str);
167 }
168 }
169
170 tree_simple_assignment::tree_simple_assignment
171 (tree_expression *le, tree_expression *re,
172 bool plhs, int l, int c, octave_value::assign_op t)
173 : tree_expression (l, c), lhs (le), rhs (re), preserve (plhs), etype (t),
174 first_execution (true) { }
175
176 tree_simple_assignment::~tree_simple_assignment (void)
177 {
178 if (! preserve)
179 delete lhs;
180
181 delete rhs;
182 }
183
184 octave_value_list
185 tree_simple_assignment::rvalue (int nargout)
186 {
187 octave_value_list retval;
188
189 if (nargout > 1)
190 error ("invalid number of output arguments for expression X = RHS");
191 else
192 retval = rvalue1 (nargout);
193
194 return retval;
195 }
196
197 octave_value
198 tree_simple_assignment::rvalue1 (int)
199 {
200 octave_value retval;
201
202 if (first_execution && lhs)
203 maybe_warn_former_built_in_variable (lhs->name ());
204
205 if (error_state)
206 return retval;
207
208 if (rhs)
209 {
210 octave_value rhs_val = rhs->rvalue1 ();
211
212 if (! error_state)
213 {
214 if (rhs_val.is_undefined ())
215 {
216 error ("value on right hand side of assignment is undefined");
217 return retval;
218 }
219 else
220 {
221 if (rhs_val.is_cs_list ())
222 {
223 const octave_value_list lst = rhs_val.list_value ();
224
225 if (! lst.empty ())
226 rhs_val = lst(0);
227 else
228 {
229 error ("invalid number of elements on RHS of assignment");
230 return retval;
231 }
232 }
233
234 octave_lvalue ult = lhs->lvalue ();
235
236 if (ult.numel () != 1)
237 gripe_nonbraced_cs_list_assignment ();
238
239 if (! error_state)
240 {
241 ult.assign (etype, rhs_val);
242
243 if (! error_state)
244 {
245 if (etype == octave_value::op_asn_eq)
246 retval = rhs_val;
247 else
248 retval = ult.value ();
249
250 if (print_result ())
251 {
252 // We clear any index here so that we can
253 // get the new value of the referenced
254 // object below, instead of the indexed
255 // value (which should be the same as the
256 // right hand side value).
257
258 ult.clear_index ();
259
260 octave_value lhs_val = ult.value ();
261
262 if (! error_state)
263 lhs_val.print_with_name (octave_stdout,
264 lhs->name ());
265 }
266 }
267 }
268 }
269 }
270 }
271
272 first_execution = false;
273
274 return retval;
275 }
276
277 std::string
278 tree_simple_assignment::oper (void) const
279 {
280 return octave_value::assign_op_as_string (etype);
281 }
282
283 tree_expression *
284 tree_simple_assignment::dup (symbol_table::scope_id scope,
285 symbol_table::context_id context) const
286 {
287 tree_simple_assignment *new_sa
288 = new tree_simple_assignment (lhs ? lhs->dup (scope, context) : 0,
289 rhs ? rhs->dup (scope, context) : 0,
290 preserve, etype);
291
292 new_sa->copy_base (*this);
293
294 return new_sa;
295 }
296
297 void
298 tree_simple_assignment::accept (tree_walker& tw)
299 {
300 tw.visit_simple_assignment (*this);
301 }
302
303 // Multi-valued assignment expressions.
304
305 tree_multi_assignment::tree_multi_assignment
306 (tree_argument_list *lst, tree_expression *r,
307 bool plhs, int l, int c)
308 : tree_expression (l, c), lhs (lst), rhs (r), preserve (plhs),
309 first_execution (true) { }
310
311 tree_multi_assignment::~tree_multi_assignment (void)
312 {
313 if (! preserve)
314 delete lhs;
315
316 delete rhs;
317 }
318
319 octave_value
320 tree_multi_assignment::rvalue1 (int nargout)
321 {
322 octave_value retval;
323
324 const octave_value_list tmp = rvalue (nargout);
325
326 if (! tmp.empty ())
327 retval = tmp(0);
328
329 return retval;
330 }
331
332 // FIXME -- this works, but it would look a little better if
333 // it were broken up into a couple of separate functions.
334
335 octave_value_list
336 tree_multi_assignment::rvalue (int)
337 {
338 octave_value_list retval;
339
340 if (error_state)
341 return retval;
342
343 if (first_execution)
344 {
345 for (tree_argument_list::iterator p = lhs->begin (); p != lhs->end (); p++)
346 {
347 tree_expression *lhs_expr = *p;
348
349 if (lhs_expr)
350 maybe_warn_former_built_in_variable (lhs_expr->name ());
351 }
352 }
353
354 if (rhs)
355 {
356 std::list<octave_lvalue> lvalue_list = lhs->lvalue_list ();
357
358 if (error_state)
359 return retval;
360
361 octave_idx_type n_out = 0;
362
363 for (std::list<octave_lvalue>::const_iterator p = lvalue_list.begin ();
364 p != lvalue_list.end ();
365 p++)
366 n_out += p->numel ();
367
368 // The following trick is used to keep rhs_val constant.
369 const octave_value_list rhs_val1 = rhs->rvalue (n_out, &lvalue_list);
370 const octave_value_list rhs_val = (rhs_val1.length () == 1 && rhs_val1(0).is_cs_list ()
371 ? rhs_val1(0).list_value () : rhs_val1);
372
373 if (error_state)
374 return retval;
375
376 octave_idx_type k = 0;
377
378 octave_idx_type n = rhs_val.length ();
379
380 // To avoid copying per elements and possible optimizations, we
381 // postpone joining the final values.
382 std::list<octave_value_list> retval_list;
383
384 tree_argument_list::iterator q = lhs->begin ();
385
386 for (std::list<octave_lvalue>::iterator p = lvalue_list.begin ();
387 p != lvalue_list.end ();
388 p++)
389 {
390 tree_expression *lhs_elt = *q++;
391
392 octave_lvalue ult = *p;
393
394 octave_idx_type nel = ult.numel ();
395
396 if (nel != 1)
397 {
398 if (k + nel <= n)
399 {
400 // This won't do a copy.
401 octave_value_list ovl = rhs_val.slice (k, nel);
402
403 ult.assign (octave_value::op_asn_eq, octave_value (ovl, true));
404
405 if (! error_state)
406 {
407 retval_list.push_back (ovl);
408
409 k += nel;
410 }
411 }
412 else
413 error ("some elements undefined in return list");
414 }
415 else
416 {
417 if (k < n)
418 {
419 ult.assign (octave_value::op_asn_eq, rhs_val(k));
420
421 if (ult.is_black_hole ())
422 {
423 k++;
424 continue;
425 }
426 else if (! error_state)
427 {
428 retval_list.push_back (rhs_val(k));
429
430 k++;
431 }
432 }
433 else
434 {
435 // This can happen for a function like
436 //
437 // function varargout = f ()
438 // varargout{1} = nargout;
439 // endfunction
440 //
441 // called with
442 //
443 // [a, ~] = f ();
444 //
445 // Then the list of of RHS values will contain one
446 // element but we are iterating over the list of all
447 // RHS values. We shouldn't complain that a value we
448 // don't need is missing from the list.
449
450 if (ult.is_black_hole ())
451 {
452 k++;
453 continue;
454 }
455 else
456 error ("element number %d undefined in return list", k+1);
457 }
458 }
459
460 if (error_state)
461 break;
462 else if (print_result ())
463 {
464 // We clear any index here so that we can get
465 // the new value of the referenced object below,
466 // instead of the indexed value (which should be
467 // the same as the right hand side value).
468
469 ult.clear_index ();
470
471 octave_value lhs_val = ult.value ();
472
473 if (! error_state)
474 lhs_val.print_with_name (octave_stdout,
475 lhs_elt->name ());
476 }
477
478 if (error_state)
479 break;
480
481 }
482
483 // Concatenate return values.
484 retval = retval_list;
485
486 }
487
488 first_execution = false;
489
490 return retval;
491 }
492
493 /*
494 %!function varargout = f ()
495 %! varargout{1} = nargout;
496 %!endfunction
497 %!
498 %!test
499 %! [a, ~] = f ();
500 %! assert (a, 2);
501 %!test
502 %! [a, ~, ~, ~, ~] = f ();
503 %! assert (a, 5);
504 */
505
506 std::string
507 tree_multi_assignment::oper (void) const
508 {
509 return octave_value::assign_op_as_string (op_type ());
510 }
511
512 tree_expression *
513 tree_multi_assignment::dup (symbol_table::scope_id scope,
514 symbol_table::context_id context) const
515 {
516 tree_multi_assignment *new_ma
517 = new tree_multi_assignment (lhs ? lhs->dup (scope, context) : 0,
518 rhs ? rhs->dup (scope, context) : 0,
519 preserve);
520
521 new_ma->copy_base (*this);
522
523 return new_ma;
524 }
525
526 void
527 tree_multi_assignment::accept (tree_walker& tw)
528 {
529 tw.visit_multi_assignment (*this);
530 }