pt-binop.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 "error.h"
00028 #include "defun.h"
00029 #include "oct-obj.h"
00030 #include "ov.h"
00031 #include "profiler.h"
00032 #include "pt-binop.h"
00033 #include "pt-bp.h"
00034 #include "pt-walk.h"
00035 #include "variables.h"
00036 
00037 // TRUE means we mark | and & expressions for braindead short-circuit
00038 // behavior.
00039 static bool Vdo_braindead_shortcircuit_evaluation;
00040 
00041 // Binary expressions.
00042 
00043 octave_value_list
00044 tree_binary_expression::rvalue (int nargout)
00045 {
00046   octave_value_list retval;
00047 
00048   if (nargout > 1)
00049     error ("binary operator '%s': invalid number of output arguments",
00050            oper () . c_str ());
00051   else
00052     retval = rvalue1 (nargout);
00053 
00054   return retval;
00055 }
00056 
00057 octave_value
00058 tree_binary_expression::rvalue1 (int)
00059 {
00060   octave_value retval;
00061 
00062   if (error_state)
00063     return retval;
00064 
00065   if (Vdo_braindead_shortcircuit_evaluation
00066       && eligible_for_braindead_shortcircuit)
00067     {
00068       if (op_lhs)
00069         {
00070           octave_value a = op_lhs->rvalue1 ();
00071 
00072           if (! error_state)
00073             {
00074               if (a.ndims () == 2 && a.rows () == 1 && a.columns () == 1)
00075                 {
00076                   bool result = false;
00077 
00078                   bool a_true = a.is_true ();
00079 
00080                   if (! error_state)
00081                     {
00082                       if (a_true)
00083                         {
00084                           if (etype == octave_value::op_el_or)
00085                             {
00086                               result = true;
00087                               goto done;
00088                             }
00089                         }
00090                       else
00091                         {
00092                           if (etype == octave_value::op_el_and)
00093                             goto done;
00094                         }
00095 
00096                       if (op_rhs)
00097                         {
00098                           octave_value b = op_rhs->rvalue1 ();
00099 
00100                           if (! error_state)
00101                             result = b.is_true ();
00102                         }
00103 
00104                     done:
00105 
00106                       if (! error_state)
00107                         return octave_value (result);
00108                     }
00109                 }
00110             }
00111         }
00112     }
00113 
00114   if (op_lhs)
00115     {
00116       octave_value a = op_lhs->rvalue1 ();
00117 
00118       if (! error_state && a.is_defined () && op_rhs)
00119         {
00120           octave_value b = op_rhs->rvalue1 ();
00121 
00122           if (! error_state && b.is_defined ())
00123             {
00124               BEGIN_PROFILER_BLOCK ("binary " + oper ())
00125 
00126               // Note: The profiler does not catch the braindead
00127               // short-circuit evaluation code above, but that should be
00128               // ok. The evaluation of operands and the operator itself
00129               // is entangled and it's not clear where to start/stop
00130               // timing the operator to make it reasonable.
00131 
00132               retval = ::do_binary_op (etype, a, b);
00133 
00134               if (error_state)
00135                 retval = octave_value ();
00136 
00137               END_PROFILER_BLOCK
00138             }
00139         }
00140     }
00141 
00142   return retval;
00143 }
00144 
00145 std::string
00146 tree_binary_expression::oper (void) const
00147 {
00148   return octave_value::binary_op_as_string (etype);
00149 }
00150 
00151 tree_expression *
00152 tree_binary_expression::dup (symbol_table::scope_id scope,
00153                              symbol_table::context_id context) const
00154 {
00155   tree_binary_expression *new_be
00156     = new tree_binary_expression (op_lhs ? op_lhs->dup (scope, context) : 0,
00157                                   op_rhs ? op_rhs->dup (scope, context) : 0,
00158                                   line (), column (), etype);
00159 
00160   new_be->copy_base (*this);
00161 
00162   return new_be;
00163 }
00164 
00165 void
00166 tree_binary_expression::accept (tree_walker& tw)
00167 {
00168   tw.visit_binary_expression (*this);
00169 }
00170 
00171 // Boolean expressions.
00172 
00173 octave_value_list
00174 tree_boolean_expression::rvalue (int nargout)
00175 {
00176   octave_value_list retval;
00177 
00178   if (nargout > 1)
00179     error ("binary operator '%s': invalid number of output arguments",
00180            oper () . c_str ());
00181   else
00182     retval = rvalue1 (nargout);
00183 
00184   return retval;
00185 }
00186 
00187 octave_value
00188 tree_boolean_expression::rvalue1 (int)
00189 {
00190   octave_value retval;
00191 
00192   if (error_state)
00193     return retval;
00194 
00195   bool result = false;
00196 
00197   // This evaluation is not caught by the profiler, since we can't find
00198   // a reasonable place where to time. Note that we don't want to
00199   // include evaluation of LHS or RHS into the timing, but this is
00200   // entangled together with short-circuit evaluation here.
00201 
00202   if (op_lhs)
00203     {
00204       octave_value a = op_lhs->rvalue1 ();
00205 
00206       if (! error_state)
00207         {
00208           bool a_true = a.is_true ();
00209 
00210           if (! error_state)
00211             {
00212               if (a_true)
00213                 {
00214                   if (etype == bool_or)
00215                     {
00216                       result = true;
00217                       goto done;
00218                     }
00219                 }
00220               else
00221                 {
00222                   if (etype == bool_and)
00223                     goto done;
00224                 }
00225 
00226               if (op_rhs)
00227                 {
00228                   octave_value b = op_rhs->rvalue1 ();
00229 
00230                   if (! error_state)
00231                     result = b.is_true ();
00232                 }
00233 
00234             done:
00235 
00236               if (! error_state)
00237                 retval = octave_value (result);
00238             }
00239         }
00240     }
00241 
00242   return retval;
00243 }
00244 
00245 std::string
00246 tree_boolean_expression::oper (void) const
00247 {
00248   std::string retval = "<unknown>";
00249 
00250   switch (etype)
00251     {
00252     case bool_and:
00253       retval = "&&";
00254       break;
00255 
00256     case bool_or:
00257       retval = "||";
00258       break;
00259 
00260     default:
00261       break;
00262     }
00263 
00264   return retval;
00265 }
00266 
00267 tree_expression *
00268 tree_boolean_expression::dup (symbol_table::scope_id scope,
00269                               symbol_table::context_id context) const
00270 {
00271   tree_boolean_expression *new_be
00272     = new tree_boolean_expression (op_lhs ? op_lhs->dup (scope, context) : 0,
00273                                    op_rhs ? op_rhs->dup (scope, context) : 0,
00274                                    line (), column (), etype);
00275 
00276   new_be->copy_base (*this);
00277 
00278   return new_be;
00279 }
00280 
00281 DEFUN (do_braindead_shortcircuit_evaluation, args, nargout,
00282   "-*- texinfo -*-\n\
00283 @deftypefn  {Built-in Function} {@var{val} =} do_braindead_shortcircuit_evaluation ()\n\
00284 @deftypefnx {Built-in Function} {@var{old_val} =} do_braindead_shortcircuit_evaluation (@var{new_val})\n\
00285 @deftypefnx {Built-in Function} {} do_braindead_shortcircuit_evaluation (@var{new_val}, \"local\")\n\
00286 Query or set the internal variable that controls whether Octave will\n\
00287 do short-circuit evaluation of @samp{|} and @samp{&} operators inside the\n\
00288 conditions of if or while statements.\n\
00289 \n\
00290 This feature is only provided for compatibility with @sc{matlab} and should\n\
00291 not be used unless you are porting old code that relies on this feature.\n\
00292 \n\
00293 To obtain short-circuit behavior for logical expressions in new programs,\n\
00294 you should always use the @samp{&&} and @samp{||} operators.\n\
00295 \n\
00296 When called from inside a function with the \"local\" option, the variable is\n\
00297 changed locally for the function and any subroutines it calls.  The original\n\
00298 variable value is restored when exiting the function.\n\
00299 @end deftypefn")
00300 {
00301   return SET_INTERNAL_VARIABLE (do_braindead_shortcircuit_evaluation);
00302 }
00303 
00304 /*
00305 
00306 %!test
00307 %! x = 0;
00308 %! do_braindead_shortcircuit_evaluation (0);
00309 %! if (1 | (x = 1))
00310 %! endif
00311 %! assert (x, 1);
00312 %! do_braindead_shortcircuit_evaluation (1);
00313 %! if (1 | (x = 0))
00314 %! endif
00315 %! assert (x, 1);
00316 
00317 */
00318 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines