1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 1996-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if defined (HAVE_CONFIG_H) 27 # include "config.h" 28 #endif 29 30 #include "error.h" 31 #include "interpreter.h" 32 #include "ov.h" 33 #include "profiler.h" 34 #include "pt-binop.h" 35 #include "pt-eval.h" 36 #include "variables.h" 37 38 namespace octave 39 { 40 // Binary expressions. 41 42 void matlab_style_short_circuit_warning(const char * op)43 tree_binary_expression::matlab_style_short_circuit_warning (const char *op) 44 { 45 warning_with_id ("Octave:possible-matlab-short-circuit-operator", 46 "Matlab-style short-circuit operation performed for operator %s", 47 op); 48 49 m_braindead_shortcircuit_warning_issued = true; 50 } 51 52 std::string oper(void) const53 tree_binary_expression::oper (void) const 54 { 55 return octave_value::binary_op_as_string (m_etype); 56 } 57 58 tree_expression * dup(symbol_scope & scope) const59 tree_binary_expression::dup (symbol_scope& scope) const 60 { 61 tree_binary_expression *new_be 62 = new tree_binary_expression (m_lhs ? m_lhs->dup (scope) : nullptr, 63 m_rhs ? m_rhs->dup (scope) : nullptr, 64 line (), column (), m_etype); 65 66 new_be->copy_base (*this); 67 68 return new_be; 69 } 70 71 octave_value evaluate(tree_evaluator & tw,int)72 tree_binary_expression::evaluate (tree_evaluator& tw, int) 73 { 74 octave_value val; 75 76 if (is_eligible_for_braindead_shortcircuit ()) 77 { 78 if (m_lhs) 79 { 80 octave_value a = m_lhs->evaluate (tw); 81 82 if (a.ndims () == 2 && a.rows () == 1 && a.columns () == 1) 83 { 84 bool result = false; 85 86 bool a_true = a.is_true (); 87 88 if (a_true) 89 { 90 if (m_etype == octave_value::op_el_or) 91 { 92 matlab_style_short_circuit_warning ("|"); 93 return octave_value (true); 94 } 95 } 96 else 97 { 98 if (m_etype == octave_value::op_el_and) 99 { 100 matlab_style_short_circuit_warning ("&"); 101 return octave_value (false); 102 } 103 } 104 105 if (m_rhs) 106 { 107 octave_value b = m_rhs->evaluate (tw); 108 109 result = b.is_true (); 110 } 111 112 return octave_value (result); 113 } 114 } 115 } 116 117 if (m_lhs) 118 { 119 octave_value a = m_lhs->evaluate (tw); 120 121 if (a.is_defined () && m_rhs) 122 { 123 octave_value b = m_rhs->evaluate (tw); 124 125 if (b.is_defined ()) 126 { 127 profiler::enter<tree_binary_expression> 128 block (tw.get_profiler (), *this); 129 130 // Note: The profiler does not catch the braindead 131 // short-circuit evaluation code above, but that should be 132 // ok. The evaluation of operands and the operator itself 133 // is entangled and it's not clear where to start/stop 134 // timing the operator to make it reasonable. 135 136 interpreter& interp = tw.get_interpreter (); 137 138 type_info& ti = interp.get_type_info (); 139 140 val = ::do_binary_op (ti, m_etype, a, b); 141 } 142 } 143 } 144 145 return val; 146 } 147 148 // Boolean expressions. 149 150 std::string oper(void) const151 tree_boolean_expression::oper (void) const 152 { 153 std::string retval = "<unknown>"; 154 155 switch (m_etype) 156 { 157 case bool_and: 158 retval = "&&"; 159 break; 160 161 case bool_or: 162 retval = "||"; 163 break; 164 165 default: 166 break; 167 } 168 169 return retval; 170 } 171 172 tree_expression * dup(symbol_scope & scope) const173 tree_boolean_expression::dup (symbol_scope& scope) const 174 { 175 tree_boolean_expression *new_be 176 = new tree_boolean_expression (m_lhs ? m_lhs->dup (scope) : nullptr, 177 m_rhs ? m_rhs->dup (scope) : nullptr, 178 line (), column (), m_etype); 179 180 new_be->copy_base (*this); 181 182 return new_be; 183 } 184 185 octave_value evaluate(tree_evaluator & tw,int)186 tree_boolean_expression::evaluate (tree_evaluator& tw, int) 187 { 188 octave_value val; 189 190 bool result = false; 191 192 // This evaluation is not caught by the profiler, since we can't find 193 // a reasonable place where to time. Note that we don't want to 194 // include evaluation of LHS or RHS into the timing, but this is 195 // entangled together with short-circuit evaluation here. 196 197 if (m_lhs) 198 { 199 octave_value a = m_lhs->evaluate (tw); 200 201 bool a_true = a.is_true (); 202 203 if (a_true) 204 { 205 if (m_etype == tree_boolean_expression::bool_or) 206 return octave_value (true); 207 } 208 else 209 { 210 if (m_etype == tree_boolean_expression::bool_and) 211 return octave_value (false); 212 } 213 214 if (m_rhs) 215 { 216 octave_value b = m_rhs->evaluate (tw); 217 218 result = b.is_true (); 219 } 220 221 val = octave_value (result); 222 } 223 224 return val; 225 } 226 } 227