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