Operation with null operand crashs Scilab
[scilab.git] / scilab / modules / ast / src / cpp / ast / run_OpExp.hpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2008-2008 - DIGITEO - Antoine ELIAS
4 *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13 *
14 */
15
16 //file included in runvisitor.cpp
17 namespace ast {
18
19 template<class T>
20 void RunVisitorT<T>::visitprivate(const OpExp &e)
21 {
22     CoverageInstance::invokeAndStartChrono((void*)&e);
23     types::InternalType * pITL = NULL, *pITR = NULL, *pResult = NULL;
24     try
25     {
26         /*getting what to assign*/
27         e.getLeft().accept(*this);
28         if (isSingleResult() == false)
29         {
30             clearResult();
31             std::wostringstream os;
32             os << _W("Incompatible output argument.\n");
33             //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
34             throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
35         }
36
37         pITL = getResult();
38         if (pITL == nullptr)
39         {
40             clearResult();
41             std::wostringstream os;
42             wchar_t szError[bsiz];
43             os_swprintf(szError, bsiz, _W("Operation '%ls': there is no left operand.\n").c_str(), e.getString().c_str());
44             os << szError;
45             throw ast::InternalError(os.str(), 999, e.getLeft().getLocation());
46         }
47
48         /*getting what to assign*/
49         e.getRight().accept(*this);
50         if (isSingleResult() == false)
51         {
52             clearResult();
53             std::wostringstream os;
54             os << _W("Incompatible output argument.\n");
55             //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
56             throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
57         }
58
59         pITR = getResult();
60         if (pITR == nullptr)
61         {
62             clearResult();
63             std::wostringstream os;
64             wchar_t szError[bsiz];
65             os_swprintf(szError, bsiz, _W("Operation '%ls': there is no right operand.\n").c_str(), e.getString().c_str());
66             os << szError;
67             throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
68         }
69
70         if (pITL->getType() == types::InternalType::ScilabImplicitList)
71         {
72             types::ImplicitList* pIL = pITL->getAs<types::ImplicitList>();
73             if (pIL->isComputable())
74             {
75                 pITL = pIL->extractFullMatrix();
76                 pIL->killMe();
77             }
78         }
79
80         if (pITR->getType() == types::InternalType::ScilabImplicitList)
81         {
82             types::ImplicitList* pIR = pITR->getAs<types::ImplicitList>();
83             if (pIR->isComputable())
84             {
85                 pITR = pIR->extractFullMatrix();
86                 pIR->killMe();
87             }
88         }
89
90         switch (e.getOper())
91         {
92             case OpExp::plus:
93             {
94                 pResult = GenericPlus(pITL, pITR);
95                 break;
96             }
97             case OpExp::unaryMinus:
98             {
99                 pResult = GenericUnaryMinus(pITR);
100                 break;
101             }
102             case OpExp::minus:
103             {
104                 pResult = GenericMinus(pITL, pITR);
105                 break;
106             }
107             case OpExp::times:
108             {
109                 pResult = GenericTimes(pITL, pITR);
110                 break;
111             }
112             case OpExp::ldivide:
113             {
114                 pResult = GenericLDivide(pITL, pITR);
115                 break;
116             }
117             case OpExp::dotldivide:
118             {
119                 pResult = GenericDotLDivide(pITL, pITR);
120                 break;
121             }
122             case OpExp::rdivide:
123             {
124                 pResult = GenericRDivide(pITL, pITR);
125                 break;
126             }
127             case OpExp::dotrdivide:
128             {
129                 pResult = GenericDotRDivide(pITL, pITR);
130                 break;
131             }
132             case OpExp::dottimes:
133             {
134                 pResult = GenericDotTimes(pITL, pITR);
135                 break;
136             }
137             case OpExp::dotpower:
138             {
139                 pResult = GenericDotPower(pITL, pITR);
140                 break;
141             }
142             case OpExp::eq:
143             {
144                 pResult = GenericComparisonEqual(pITL, pITR);
145                 break;
146             }
147             case OpExp::ne:
148             {
149                 pResult = GenericComparisonNonEqual(pITL, pITR);
150                 break;
151             }
152             case OpExp::lt:
153             {
154                 pResult = GenericLess(pITL, pITR);
155                 break;
156             }
157             case OpExp::le:
158             {
159                 pResult = GenericLessEqual(pITL, pITR);
160                 break;
161             }
162             case OpExp::gt:
163             {
164                 pResult = GenericGreater(pITL, pITR);
165                 break;
166             }
167             case OpExp::ge:
168             {
169                 pResult = GenericGreaterEqual(pITL, pITR);
170                 break;
171             }
172             case OpExp::power:
173             {
174                 pResult = GenericPower(pITL, pITR);
175                 break;
176             }
177             case OpExp::krontimes:
178             {
179                 pResult = GenericKrontimes(pITL, pITR);
180                 break;
181             }
182             case OpExp::kronrdivide:
183             {
184                 pResult = GenericKronrdivide(pITL, pITR);
185                 break;
186             }
187             case OpExp::kronldivide:
188             {
189                 pResult = GenericKronldivide(pITL, pITR);
190                 break;
191             }
192             default:
193                 break;
194         }
195
196         //overloading
197         if (pResult == NULL)
198         {
199             // We did not have any algorithm matching, so we try to call OverLoad
200             pResult = callOverloadOpExp(e.getOper(), pITL, pITR);
201         }
202
203         setResult(pResult);
204
205         //clear left and/or right operands
206         if (pResult != pITL)
207         {
208             pITL->killMe();
209         }
210
211         if (pResult != pITR)
212         {
213             pITR->killMe();
214         }
215     }
216     catch (ast::InternalError& error)
217     {
218         setResult(NULL);
219         if (pResult)
220         {
221             pResult->killMe();
222         }
223         if (pITL && (pITL != pResult))
224         {
225             pITL->killMe();
226         }
227         if (pITR && (pITR != pResult))
228         {
229             pITR->killMe();
230         }
231
232         error.SetErrorLocation(e.getLocation());
233         CoverageInstance::stopChrono((void*)&e);
234         throw error;
235     }
236
237     CoverageInstance::stopChrono((void*)&e);
238     /*if (e.getDecorator().res.isConstant())
239     {
240
241     }*/
242 }
243
244 template<class T>
245 void RunVisitorT<T>::visitprivate(const LogicalOpExp &e)
246 {
247     CoverageInstance::invokeAndStartChrono((void*)&e);
248     types::InternalType *pITR = NULL; //assign only in non shortcut operations.
249     types::InternalType *pITL = NULL;
250     types::InternalType *pResult = NULL;
251
252     try
253     {
254
255         /*getting what to assign*/
256         e.getLeft().accept(*this);
257         pITL = getResult();
258         if (isSingleResult() == false)
259         {
260             std::wostringstream os;
261             os << _W("Incompatible output argument.\n");
262             //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
263             throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
264         }
265
266         setResult(NULL);
267
268         if (pITL->getType() == types::InternalType::ScilabImplicitList)
269         {
270             types::ImplicitList* pIL = pITL->getAs<types::ImplicitList>();
271             if (pIL->isComputable())
272             {
273                 pITL = pIL->extractFullMatrix();
274                 pIL->killMe();
275             }
276         }
277
278         switch (e.getOper())
279         {
280             case LogicalOpExp::logicalShortCutAnd:
281             {
282                 pResult = GenericShortcutAnd(pITL);
283                 if (pResult)
284                 {
285                     break;
286                 }
287
288                 //Continue to logicalAnd
289             }
290             case LogicalOpExp::logicalAnd:
291             {
292                 /*getting what to assign*/
293                 e.getRight().accept(*this);
294                 pITR = getResult();
295                 if (isSingleResult() == false)
296                 {
297                     std::wostringstream os;
298                     os << _W("Incompatible output argument.\n");
299                     //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
300                     throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
301                 }
302
303                 if (pITR->getType() == types::InternalType::ScilabImplicitList)
304                 {
305                     types::ImplicitList* pIR = pITR->getAs<types::ImplicitList>();
306                     if (pIR->isComputable())
307                     {
308                         pITR = pIR->extractFullMatrix();
309                         pIR->killMe();
310                     }
311                 }
312                 pResult = GenericLogicalAnd(pITL, pITR);
313
314                 if (pResult && e.getOper() == LogicalOpExp::logicalShortCutAnd)
315                 {
316                     types::InternalType* pResult2 = GenericShortcutAnd(pResult);
317                     if(pResult != pITL && pResult != pITR)
318                     {
319                         pResult->killMe();
320                     }
321
322                     if (pResult2)
323                     {
324                         pResult = pResult2;
325                     }
326                     else
327                     {
328                         pResult = new types::Bool(1);
329                     }
330                 }
331                 break;
332             }
333             case LogicalOpExp::logicalShortCutOr:
334             {
335                 pResult = GenericShortcutOr(pITL);
336                 if (pResult)
337                 {
338                     break;
339                 }
340
341                 //Continue to logicalAnd
342             }
343             case LogicalOpExp::logicalOr:
344             {
345                 /*getting what to assign*/
346                 e.getRight().accept(*this);
347                 pITR = getResult();
348                 if (isSingleResult() == false)
349                 {
350                     std::wostringstream os;
351                     os << _W("Incompatible output argument.\n");
352                     //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
353                     throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
354                 }
355
356                 if (pITR->getType() == types::InternalType::ScilabImplicitList)
357                 {
358                     types::ImplicitList* pIR = pITR->getAs<types::ImplicitList>();
359                     if (pIR->isComputable())
360                     {
361                         pITR = pIR->extractFullMatrix();
362                     }
363                 }
364                 pResult = GenericLogicalOr(pITL, pITR);
365                 if (pResult && e.getOper() == LogicalOpExp::logicalShortCutOr)
366                 {
367                     types::InternalType* pResult2 = GenericShortcutOr(pResult);
368                     if(pResult != pITL && pResult != pITR)
369                     {
370                         pResult->killMe();
371                     }
372
373                     if (pResult2)
374                     {
375                         pResult = pResult2;
376                     }
377                     else
378                     {
379                         pResult = new types::Bool(0);
380                     }
381                 }
382                 break;
383             }
384
385             default:
386                 break;
387         }
388         //overloading
389         if (pResult == NULL)
390         {
391             // We did not have any algorithm matching, so we try to call OverLoad
392             e.getRight().accept(*this);
393             pITR = getResult();
394             if (isSingleResult() == false)
395             {
396                 clearResult();
397                 std::wostringstream os;
398                 os << _W("Incompatible output argument.\n");
399                 //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
400                 throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
401             }
402
403             if (pITR->getType() == types::InternalType::ScilabImplicitList)
404             {
405                 types::ImplicitList* pIR = pITR->getAs<types::ImplicitList>();
406                 if (pIR->isComputable())
407                 {
408                     pITR = pIR->extractFullMatrix();
409                 }
410             }
411             pResult = callOverloadOpExp(e.getOper(), pITL, pITR);
412         }
413
414         setResult(pResult);
415
416         // protect pResult in case where pITL or pITR equal pResult
417         pResult->IncreaseRef();
418
419         //clear left and/or right operands
420         pITL->killMe();
421         if (pITR)
422         {
423             pITR->killMe();
424         }
425
426         // unprotect pResult
427         pResult->DecreaseRef();
428     }
429     catch (ast::InternalError& error)
430     {
431         setResult(NULL);
432         if (pResult)
433         {
434             pResult->killMe();
435         }
436         if (pITL && (pITL != pResult))
437         {
438             pITL->killMe();
439         }
440         if (pITR && (pITR != pResult))
441         {
442             pITR->killMe();
443         }
444         error.SetErrorLocation(e.getLocation());
445         CoverageInstance::stopChrono((void*)&e);
446         throw error;
447     }
448
449     CoverageInstance::stopChrono((void*)&e);
450 }
451
452 template<class T>
453 types::InternalType* RunVisitorT<T>::callOverloadOpExp(OpExp::Oper _oper, types::InternalType* _paramL, types::InternalType* _paramR)
454 {
455     types::typed_list in;
456     types::typed_list out;
457
458     /*
459     ** Special case for unary minus => will call %{type_s}
460     */
461     if (_oper == OpExp::unaryMinus)
462     {
463         _paramR->IncreaseRef();
464         in.push_back(_paramR);
465         try
466         {
467             types::Callable::ReturnValue ret = Overload::generateNameAndCall(Overload::getNameFromOper(_oper), in, 1, out, true);
468             if(ret == types::Function::Error)
469             {
470                 throw ast::InternalError(ConfigVariable::getLastErrorMessage());
471             }
472         }
473         catch (const ast::InternalError& e)
474         {
475             _paramR->DecreaseRef();
476             throw e;
477         }
478
479         _paramR->DecreaseRef();
480         return out[0];
481     }
482
483     _paramL->IncreaseRef();
484     _paramR->IncreaseRef();
485     in.push_back(_paramL);
486     in.push_back(_paramR);
487
488     try
489     {
490         types::Callable::ReturnValue ret = Overload::generateNameAndCall(Overload::getNameFromOper(_oper), in, 1, out, true);
491         if(ret == types::Function::Error)
492         {
493             throw ast::InternalError(ConfigVariable::getLastErrorMessage());
494         }
495     }
496     catch (const ast::InternalError& e)
497     {
498         _paramL->DecreaseRef();
499         _paramR->DecreaseRef();
500         throw e;
501     }
502
503     _paramL->DecreaseRef();
504     _paramR->DecreaseRef();
505
506     return out[0];
507 }
508
509 } /* namespace ast */