ast: fix memleaks detected by ASAN during testing
[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::unaryPlus:
93             {
94                 pResult = GenericUnaryPlus(pITR);
95                 break;
96             }
97             case OpExp::plus:
98             {
99                 pResult = GenericPlus(pITL, pITR);
100                 break;
101             }
102             case OpExp::unaryMinus:
103             {
104                 pResult = GenericUnaryMinus(pITR);
105                 break;
106             }
107             case OpExp::minus:
108             {
109                 pResult = GenericMinus(pITL, pITR);
110                 break;
111             }
112             case OpExp::times:
113             {
114                 pResult = GenericTimes(pITL, pITR);
115                 break;
116             }
117             case OpExp::ldivide:
118             {
119                 pResult = GenericLDivide(pITL, pITR);
120                 break;
121             }
122             case OpExp::dotldivide:
123             {
124                 pResult = GenericDotLDivide(pITL, pITR);
125                 break;
126             }
127             case OpExp::rdivide:
128             {
129                 pResult = GenericRDivide(pITL, pITR);
130                 break;
131             }
132             case OpExp::dotrdivide:
133             {
134                 pResult = GenericDotRDivide(pITL, pITR);
135                 break;
136             }
137             case OpExp::dottimes:
138             {
139                 pResult = GenericDotTimes(pITL, pITR);
140                 break;
141             }
142             case OpExp::dotpower:
143             {
144                 pResult = GenericDotPower(pITL, pITR);
145                 break;
146             }
147             case OpExp::eq:
148             {
149                 pResult = GenericComparisonEqual(pITL, pITR);
150                 break;
151             }
152             case OpExp::ne:
153             {
154                 pResult = GenericComparisonNonEqual(pITL, pITR);
155                 break;
156             }
157             case OpExp::lt:
158             {
159                 pResult = GenericLess(pITL, pITR);
160                 break;
161             }
162             case OpExp::le:
163             {
164                 pResult = GenericLessEqual(pITL, pITR);
165                 break;
166             }
167             case OpExp::gt:
168             {
169                 pResult = GenericGreater(pITL, pITR);
170                 break;
171             }
172             case OpExp::ge:
173             {
174                 pResult = GenericGreaterEqual(pITL, pITR);
175                 break;
176             }
177             case OpExp::power:
178             {
179                 pResult = GenericPower(pITL, pITR);
180                 break;
181             }
182             case OpExp::krontimes:
183             {
184                 pResult = GenericKrontimes(pITL, pITR);
185                 break;
186             }
187             case OpExp::kronrdivide:
188             {
189                 pResult = GenericKronrdivide(pITL, pITR);
190                 break;
191             }
192             case OpExp::kronldivide:
193             {
194                 pResult = GenericKronldivide(pITL, pITR);
195                 break;
196             }
197             default:
198                 break;
199         }
200
201         //overloading
202         if (pResult == NULL)
203         {
204             // We did not have any algorithm matching, so we try to call OverLoad
205             pResult = callOverloadOpExp(e.getOper(), pITL, pITR);
206         }
207
208         setResult(pResult);
209
210         //clear left and/or right operands
211         if (pResult != pITL)
212         {
213             pITL->killMe();
214         }
215
216         if (pResult != pITR)
217         {
218             pITR->killMe();
219         }
220     }
221     catch (ast::InternalError& error)
222     {
223         setResult(NULL);
224         if (pResult)
225         {
226             pResult->killMe();
227         }
228         if (pITL && (pITL != pResult))
229         {
230             pITL->killMe();
231         }
232         if (pITR && (pITR != pResult))
233         {
234             pITR->killMe();
235         }
236
237         error.SetErrorLocation(e.getLocation());
238         CoverageInstance::stopChrono((void*)&e);
239         throw error;
240     }
241
242     CoverageInstance::stopChrono((void*)&e);
243     /*if (e.getDecorator().res.isConstant())
244     {
245
246     }*/
247 }
248
249 template<class T>
250 void RunVisitorT<T>::visitprivate(const LogicalOpExp &e)
251 {
252     CoverageInstance::invokeAndStartChrono((void*)&e);
253     types::InternalType *pITR = NULL; //assign only in non shortcut operations.
254     types::InternalType *pITL = NULL;
255     types::InternalType *pResult = NULL;
256
257     try
258     {
259
260         /*getting what to assign*/
261         e.getLeft().accept(*this);
262         pITL = getResult();
263         if (isSingleResult() == false)
264         {
265             std::wostringstream os;
266             os << _W("Incompatible output argument.\n");
267             //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
268             throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
269         }
270
271         setResult(NULL);
272
273         if (pITL->getType() == types::InternalType::ScilabImplicitList)
274         {
275             types::ImplicitList* pIL = pITL->getAs<types::ImplicitList>();
276             if (pIL->isComputable())
277             {
278                 pITL = pIL->extractFullMatrix();
279                 pIL->killMe();
280             }
281         }
282
283         switch (e.getOper())
284         {
285             case LogicalOpExp::logicalShortCutAnd:
286             {
287                 pResult = GenericShortcutAnd(pITL);
288                 if (pResult)
289                 {
290                     break;
291                 }
292
293                 //Continue to logicalAnd
294             }
295             case LogicalOpExp::logicalAnd:
296             {
297                 /*getting what to assign*/
298                 e.getRight().accept(*this);
299                 pITR = getResult();
300                 if (isSingleResult() == false)
301                 {
302                     std::wostringstream os;
303                     os << _W("Incompatible output argument.\n");
304                     //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
305                     throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
306                 }
307
308                 if (pITR->getType() == types::InternalType::ScilabImplicitList)
309                 {
310                     types::ImplicitList* pIR = pITR->getAs<types::ImplicitList>();
311                     if (pIR->isComputable())
312                     {
313                         pITR = pIR->extractFullMatrix();
314                         pIR->killMe();
315                     }
316                 }
317                 pResult = GenericLogicalAnd(pITL, pITR);
318
319                 if (pResult && e.getOper() == LogicalOpExp::logicalShortCutAnd)
320                 {
321                     types::InternalType* pResult2 = GenericShortcutAnd(pResult);
322                     if(pResult != pITL && pResult != pITR)
323                     {
324                         pResult->killMe();
325                     }
326
327                     if (pResult2)
328                     {
329                         pResult = pResult2;
330                     }
331                     else
332                     {
333                         pResult = new types::Bool(1);
334                     }
335                 }
336                 break;
337             }
338             case LogicalOpExp::logicalShortCutOr:
339             {
340                 pResult = GenericShortcutOr(pITL);
341                 if (pResult)
342                 {
343                     break;
344                 }
345
346                 //Continue to logicalAnd
347             }
348             case LogicalOpExp::logicalOr:
349             {
350                 /*getting what to assign*/
351                 e.getRight().accept(*this);
352                 pITR = getResult();
353                 if (isSingleResult() == false)
354                 {
355                     std::wostringstream os;
356                     os << _W("Incompatible output argument.\n");
357                     //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
358                     throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
359                 }
360
361                 if (pITR->getType() == types::InternalType::ScilabImplicitList)
362                 {
363                     types::ImplicitList* pIR = pITR->getAs<types::ImplicitList>();
364                     if (pIR->isComputable())
365                     {
366                         pITR = pIR->extractFullMatrix();
367                     }
368                 }
369                 pResult = GenericLogicalOr(pITL, pITR);
370                 if (pResult && e.getOper() == LogicalOpExp::logicalShortCutOr)
371                 {
372                     types::InternalType* pResult2 = GenericShortcutOr(pResult);
373                     if(pResult != pITL && pResult != pITR)
374                     {
375                         pResult->killMe();
376                     }
377
378                     if (pResult2)
379                     {
380                         pResult = pResult2;
381                     }
382                     else
383                     {
384                         pResult = new types::Bool(0);
385                     }
386                 }
387                 break;
388             }
389
390             default:
391                 break;
392         }
393         //overloading
394         if (pResult == NULL)
395         {
396             // We did not have any algorithm matching, so we try to call OverLoad
397             e.getRight().accept(*this);
398             if (pITR)
399             {
400                 pITR->killMe();
401             }
402             pITR = getResult();
403             if (isSingleResult() == false)
404             {
405                 clearResult();
406                 std::wostringstream os;
407                 os << _W("Incompatible output argument.\n");
408                 //os << ((Location)e.right_get().getLocation()).getLocationString() << std::endl;
409                 throw ast::InternalError(os.str(), 999, e.getRight().getLocation());
410             }
411
412             if (pITR->getType() == types::InternalType::ScilabImplicitList)
413             {
414                 types::ImplicitList* pIR = pITR->getAs<types::ImplicitList>();
415                 if (pIR->isComputable())
416                 {
417                     pITR = pIR->extractFullMatrix();
418                 }
419             }
420             pResult = callOverloadOpExp(e.getOper(), pITL, pITR);
421         }
422
423         setResult(pResult);
424
425         // protect pResult in case where pITL or pITR equal pResult
426         pResult->IncreaseRef();
427
428         //clear left and/or right operands
429         pITL->killMe();
430         if (pITR)
431         {
432             pITR->killMe();
433         }
434
435         // unprotect pResult
436         pResult->DecreaseRef();
437     }
438     catch (ast::InternalError& error)
439     {
440         setResult(NULL);
441         if (pResult)
442         {
443             pResult->killMe();
444         }
445         if (pITL && (pITL != pResult))
446         {
447             pITL->killMe();
448         }
449         if (pITR && (pITR != pResult))
450         {
451             pITR->killMe();
452         }
453         error.SetErrorLocation(e.getLocation());
454         CoverageInstance::stopChrono((void*)&e);
455         throw error;
456     }
457
458     CoverageInstance::stopChrono((void*)&e);
459 }
460
461 template<class T>
462 types::InternalType* RunVisitorT<T>::callOverloadOpExp(OpExp::Oper _oper, types::InternalType* _paramL, types::InternalType* _paramR)
463 {
464     types::typed_list in;
465     types::typed_list out;
466
467     /*
468     ** Special case for unary minus => will call %{type_s}
469     */
470     if (_oper == OpExp::unaryMinus || _oper == OpExp::unaryPlus)
471     {
472         _paramR->IncreaseRef();
473         in.push_back(_paramR);
474         try
475         {
476             types::Callable::ReturnValue ret = Overload::generateNameAndCall(Overload::getNameFromOper(_oper), in, 1, out, true);
477             if(ret == types::Function::Error)
478             {
479                 throw ast::InternalError(ConfigVariable::getLastErrorMessage());
480             }
481         }
482         catch (const ast::InternalError& e)
483         {
484             _paramR->DecreaseRef();
485             throw e;
486         }
487
488         _paramR->DecreaseRef();
489         return out[0];
490     } 
491
492     _paramL->IncreaseRef();
493     _paramR->IncreaseRef();
494     in.push_back(_paramL);
495     in.push_back(_paramR);
496
497     try
498     {
499         types::Callable::ReturnValue ret = Overload::generateNameAndCall(Overload::getNameFromOper(_oper), in, 1, out, true);
500         if(ret == types::Function::Error)
501         {
502             throw ast::InternalError(ConfigVariable::getLastErrorMessage());
503         }
504     }
505     catch (const ast::InternalError& e)
506     {
507         _paramL->DecreaseRef();
508         _paramR->DecreaseRef();
509         throw e;
510     }
511
512     _paramL->DecreaseRef();
513     _paramR->DecreaseRef();
514
515     return out.size() ? out[0] : nullptr;
516 }
517
518 } /* namespace ast */