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-binop.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 "error.h"
28 #include "defun.h"
29 #include "oct-obj.h"
30 #include "ov.h"
31 #include "profiler.h"
32 #include "pt-binop.h"
33 #include "pt-bp.h"
34 #include "pt-walk.h"
35 #include "variables.h"
36 
37 // TRUE means we mark | and & expressions for braindead short-circuit
38 // behavior.
40 
41 // Binary expressions.
42 
45 {
46  octave_value_list retval;
47 
48  if (nargout > 1)
49  error ("binary operator '%s': invalid number of output arguments",
50  oper () . c_str ());
51  else
52  retval = rvalue1 (nargout);
53 
54  return retval;
55 }
56 
59 {
60  octave_value retval;
61 
62  if (error_state)
63  return retval;
64 
65  if (Vdo_braindead_shortcircuit_evaluation
67  {
68  if (op_lhs)
69  {
70  octave_value a = op_lhs->rvalue1 ();
71 
72  if (! error_state)
73  {
74  if (a.ndims () == 2 && a.rows () == 1 && a.columns () == 1)
75  {
76  bool result = false;
77 
78  bool a_true = a.is_true ();
79 
80  if (! error_state)
81  {
82  if (a_true)
83  {
85  {
86  result = true;
87  goto done;
88  }
89  }
90  else
91  {
93  goto done;
94  }
95 
96  if (op_rhs)
97  {
98  octave_value b = op_rhs->rvalue1 ();
99 
100  if (! error_state)
101  result = b.is_true ();
102  }
103 
104  done:
105 
106  if (! error_state)
107  return octave_value (result);
108  }
109  }
110  }
111  }
112  }
113 
114  if (op_lhs)
115  {
116  octave_value a = op_lhs->rvalue1 ();
117 
118  if (! error_state && a.is_defined () && op_rhs)
119  {
120  octave_value b = op_rhs->rvalue1 ();
121 
122  if (! error_state && b.is_defined ())
123  {
124  BEGIN_PROFILER_BLOCK ("binary " + oper ())
125 
126  // Note: The profiler does not catch the braindead
127  // short-circuit evaluation code above, but that should be
128  // ok. The evaluation of operands and the operator itself
129  // is entangled and it's not clear where to start/stop
130  // timing the operator to make it reasonable.
131 
132  retval = ::do_binary_op (etype, a, b);
133 
134  if (error_state)
135  retval = octave_value ();
136 
138  }
139  }
140  }
141 
142  return retval;
143 }
144 
145 std::string
147 {
149 }
150 
154 {
155  tree_binary_expression *new_be
156  = new tree_binary_expression (op_lhs ? op_lhs->dup (scope, context) : 0,
157  op_rhs ? op_rhs->dup (scope, context) : 0,
158  line (), column (), etype);
159 
160  new_be->copy_base (*this);
161 
162  return new_be;
163 }
164 
165 void
167 {
168  tw.visit_binary_expression (*this);
169 }
170 
171 // Boolean expressions.
172 
175 {
176  octave_value_list retval;
177 
178  if (nargout > 1)
179  error ("binary operator '%s': invalid number of output arguments",
180  oper () . c_str ());
181  else
182  retval = rvalue1 (nargout);
183 
184  return retval;
185 }
186 
189 {
190  octave_value retval;
191 
192  if (error_state)
193  return retval;
194 
195  bool result = false;
196 
197  // This evaluation is not caught by the profiler, since we can't find
198  // a reasonable place where to time. Note that we don't want to
199  // include evaluation of LHS or RHS into the timing, but this is
200  // entangled together with short-circuit evaluation here.
201 
202  if (op_lhs)
203  {
204  octave_value a = op_lhs->rvalue1 ();
205 
206  if (! error_state)
207  {
208  bool a_true = a.is_true ();
209 
210  if (! error_state)
211  {
212  if (a_true)
213  {
214  if (etype == bool_or)
215  {
216  result = true;
217  goto done;
218  }
219  }
220  else
221  {
222  if (etype == bool_and)
223  goto done;
224  }
225 
226  if (op_rhs)
227  {
228  octave_value b = op_rhs->rvalue1 ();
229 
230  if (! error_state)
231  result = b.is_true ();
232  }
233 
234  done:
235 
236  if (! error_state)
237  retval = octave_value (result);
238  }
239  }
240  }
241 
242  return retval;
243 }
244 
245 std::string
247 {
248  std::string retval = "<unknown>";
249 
250  switch (etype)
251  {
252  case bool_and:
253  retval = "&&";
254  break;
255 
256  case bool_or:
257  retval = "||";
258  break;
259 
260  default:
261  break;
262  }
263 
264  return retval;
265 }
266 
270 {
272  = new tree_boolean_expression (op_lhs ? op_lhs->dup (scope, context) : 0,
273  op_rhs ? op_rhs->dup (scope, context) : 0,
274  line (), column (), etype);
275 
276  new_be->copy_base (*this);
277 
278  return new_be;
279 }
280 
281 DEFUN (do_braindead_shortcircuit_evaluation, args, nargout,
282  "-*- texinfo -*-\n\
283 @deftypefn {Built-in Function} {@var{val} =} do_braindead_shortcircuit_evaluation ()\n\
284 @deftypefnx {Built-in Function} {@var{old_val} =} do_braindead_shortcircuit_evaluation (@var{new_val})\n\
285 @deftypefnx {Built-in Function} {} do_braindead_shortcircuit_evaluation (@var{new_val}, \"local\")\n\
286 Query or set the internal variable that controls whether Octave will\n\
287 do short-circuit evaluation of @samp{|} and @samp{&} operators inside the\n\
288 conditions of if or while statements.\n\
289 \n\
290 This feature is only provided for compatibility with @sc{matlab} and should\n\
291 not be used unless you are porting old code that relies on this feature.\n\
292 \n\
293 To obtain short-circuit behavior for logical expressions in new programs,\n\
294 you should always use the @samp{&&} and @samp{||} operators.\n\
295 \n\
296 When called from inside a function with the @qcode{\"local\"} option, the\n\
297 variable is changed locally for the function and any subroutines it calls. \n\
298 The original variable value is restored when exiting the function.\n\
299 @end deftypefn")
300 {
301  return SET_INTERNAL_VARIABLE (do_braindead_shortcircuit_evaluation);
302 }
303 
304 /*
305 %!test
306 %! x = 0;
307 %! do_braindead_shortcircuit_evaluation (0);
308 %! if (1 | (x = 1))
309 %! endif
310 %! assert (x, 1);
311 %! do_braindead_shortcircuit_evaluation (1);
312 %! if (1 | (x = 0))
313 %! endif
314 %! assert (x, 1);
315 */