fix exception management in call overload failed
[scilab.git] / scilab / modules / ast / src / cpp / ast / run_MatrixExp.hpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2008-2008 - DIGITEO - Antoine ELIAS
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 //file included in runvisitor.cpp
14 namespace ast {
15
16 /*
17     [1,2;3,4] with/without special character $ and :
18 */
19 template<class T>
20 void RunVisitorT<T>::visitprivate(const MatrixExp &e)
21 {
22     try
23     {
24         exps_t::const_iterator row;
25         exps_t::const_iterator col;
26         InternalType *poResult = NULL;
27         list<InternalType*> rowList;
28
29         exps_t lines = e.getLines();
30         if (lines.size() == 0)
31         {
32             setResult(Double::Empty());
33             return;
34         }
35
36         //special case for 1x1 matrix
37         if (lines.size() == 1)
38         {
39             exps_t cols = lines[0]->getAs<MatrixLineExp>()->getColumns();
40             if (cols.size() == 1)
41             {
42                 setResult(NULL); // Reset value on loop re-start
43
44                 cols[0]->accept(*this);
45                 //manage evstr('//xxx') for example
46                 if (getResult() == NULL)
47                 {
48                     setResult(Double::Empty());
49                 }
50                 return;
51             }
52         }
53
54         //do all [x,x]
55         for (row = lines.begin() ; row != lines.end() ; row++)
56         {
57             InternalType* poRow = NULL;
58             exps_t cols = (*row)->getAs<MatrixLineExp>()->getColumns();
59             for (col = cols.begin() ; col != cols.end() ; col++)
60             {
61                 setResult(NULL); // Reset value on loop re-start
62
63                 try
64                 {
65                     (*col)->accept(*this);
66                 }
67                 catch (ScilabError& error)
68                 {
69                     if (poRow)
70                     {
71                         poRow->killMe();
72                     }
73                     if (poResult)
74                     {
75                         poResult->killMe();
76                     }
77
78                     throw error;
79                 }
80
81                 InternalType *pIT = getResult();
82                 if (pIT == NULL)
83                 {
84                     continue;
85                 }
86
87                 //reset result but without delete the value
88                 clearResultButFirst();
89
90                 if (pIT->isImplicitList())
91                 {
92                     ImplicitList *pIL = pIT->getAs<ImplicitList>();
93                     if (pIL->isComputable())
94                     {
95                         InternalType* pIT2 = pIL->extractFullMatrix();
96                         pIT->killMe();
97                         pIT = pIT2;
98                     }
99                     else
100                     {
101                         if (poRow == NULL)
102                         {
103                             //first loop
104                             poRow = pIT;
105                         }
106                         else
107                         {
108                             try
109                             {
110                                 poRow = callOverloadMatrixExp(L"c", poRow, pIT);
111                             }
112                             catch (ScilabError& error)
113                             {
114                                 if (poResult)
115                                 {
116                                     poResult->killMe();
117                                 }
118                                 throw error;
119                             }
120                         }
121
122                         continue;
123                     }
124                 }
125
126                 if (pIT->isGenericType() == false)
127                 {
128                     pIT->killMe();
129                     std::wostringstream os;
130                     os << _W("unable to concatenate\n");
131                     throw ast::ScilabError(os.str(), 999, (*col)->getLocation());
132                 }
133
134                 GenericType* pGT = pIT->getAs<GenericType>();
135                 if (pGT->isDouble() && pGT->getAs<Double>()->isEmpty())
136                 {
137                     pGT->killMe();
138                     continue;
139                 }
140
141                 if (poRow == NULL)
142                 {
143                     //first loop
144                     poRow = pGT;
145                     continue;
146                 }
147
148                 if (    pGT->isList() || poRow->isList() ||
149                         pGT->isStruct() || poRow->isStruct() ||
150                         poRow->isImplicitList() ||
151                         pGT->getDims() > 2)
152                 {
153                     try
154                     {
155                         poRow = callOverloadMatrixExp(L"c", poRow, pGT);
156                     }
157                     catch (ScilabError& error)
158                     {
159                         if (poResult)
160                         {
161                             poResult->killMe();
162                         }
163                         throw error;
164                     }
165
166                     continue;
167                 }
168
169                 GenericType* pGTResult = poRow->getAs<GenericType>();
170
171                 //check dimension
172                 if (pGT->getDims() != 2 || pGT->getRows() != pGTResult->getRows())
173                 {
174                     poRow->killMe();
175                     if (poRow != pGT)
176                     {
177                         pGT->killMe();
178                     }
179                     std::wostringstream os;
180                     os << _W("inconsistent row/column dimensions\n");
181                     throw ast::ScilabError(os.str(), 999, (*row)->getLocation());
182                 }
183
184                 // if we concatenate [Double Sparse], transform the Double to Sparse and perform [Sparse Sparse]
185                 // this avoids to allocate a Double result of size of Double+Sparse and initialize all elements.
186                 if (pGT->isSparse() && pGTResult->isDouble())
187                 {
188                     poRow = new types::Sparse(*pGTResult->getAs<types::Double>());
189                     pGTResult->killMe();
190                     pGTResult = poRow->getAs<types::GenericType>();
191                 }
192                 else if (pGT->isSparseBool() && pGTResult->isBool()) // [Bool SparseBool] => [SparseBool SparseBool]
193                 {
194                     poRow = new types::SparseBool(*pGTResult->getAs<types::Bool>());
195                     pGTResult->killMe();
196                     pGTResult = poRow->getAs<types::GenericType>();
197                 }
198                 else if (pGT->isDollar() && pGTResult->isDouble())
199                 {
200                     int _iRows = pGTResult->getRows();
201                     int _iCols = pGTResult->getCols();
202                     int* piRank = new int[_iRows * _iCols];
203                     memset(piRank, 0x00, _iRows * _iCols * sizeof(int));
204                     poRow = new types::Polynom(pGT->getAs<types::Polynom>()->getVariableName(), _iRows, _iCols, piRank);
205                     Polynom* pP = poRow->getAs<types::Polynom>();
206                     SinglePoly** pSS = pP->get();
207                     types::Double* pDb = pGTResult->getAs<types::Double>();
208                     double* pdblR = pDb->get();
209                     if (pDb->isComplex())
210                     {
211                         double* pdblI = pDb->getImg();
212                         pP->setComplex(true);
213                         for (int i = 0; i < pDb->getSize(); i++)
214                         {
215                             pSS[i]->setRank(0);
216                             pSS[i]->setCoef(pdblR + i, pdblI + i);
217                         }
218                     }
219                     else
220                     {
221                         for (int i = 0; i < pDb->getSize(); i++)
222                         {
223                             pSS[i]->setRank(0);
224                             pSS[i]->setCoef(pdblR + i, NULL);
225                         }
226                     }
227
228                     delete[] piRank;
229                 }
230
231                 InternalType *pNewSize = AddElementToVariable(NULL, poRow, pGTResult->getRows(), pGTResult->getCols() + pGT->getCols());
232                 InternalType* p = AddElementToVariable(pNewSize, pGT, 0, pGTResult->getCols());
233                 if (p != pNewSize)
234                 {
235                     pNewSize->killMe();
236                 }
237                 // call overload
238                 if (p == NULL)
239                 {
240                     try
241                     {
242                         poRow = callOverloadMatrixExp(L"c", pGTResult, pGT);
243                     }
244                     catch (ScilabError& error)
245                     {
246                         if (poResult)
247                         {
248                             poResult->killMe();
249                         }
250                         throw error;
251                     }
252                     continue;
253                 }
254
255                 if (poRow != pGT)
256                 {
257                     pGT->killMe();
258                 }
259
260                 if (p != poRow)
261                 {
262                     poRow->killMe();
263                     poRow = p;
264                 }
265             }
266
267             if (poRow == NULL)
268             {
269                 continue;
270             }
271
272             if (poResult == NULL)
273             {
274                 poResult = poRow;
275                 continue;
276             }
277
278             // management of concatenation with 1:$
279             if (poRow->isImplicitList() || poResult->isImplicitList())
280             {
281                 try
282                 {
283                     poResult = callOverloadMatrixExp(L"f", poResult, poRow);
284                 }
285                 catch (ScilabError& error)
286                 {
287                     throw error;
288                 }
289                 continue;
290             }
291
292             GenericType* pGT = poRow->getAs<GenericType>();
293
294             //check dimension
295             GenericType* pGTResult = poResult->getAs<GenericType>();
296
297             if (pGT->isList() || pGTResult->isList() ||
298                     pGT->isStruct() || pGTResult->isStruct())
299             {
300                 try
301                 {
302                     poResult = callOverloadMatrixExp(L"f", pGTResult, pGT);
303                 }
304                 catch (ScilabError& error)
305                 {
306                     throw error;
307                 }
308
309                 continue;
310             }
311
312             // hypermatrix case, will call %hm_f_hm
313             if (pGT->getDims() > 2)
314             {
315                 try
316                 {
317                     poResult = callOverloadMatrixExp(L"f", pGTResult, pGT);
318                 }
319                 catch (ScilabError& error)
320                 {
321                     throw error;
322                 }
323                 continue;
324             }
325
326             //check dimension
327             if (pGT->getCols() != pGTResult->getCols())
328             {
329                 poRow->killMe();
330                 if (poResult)
331                 {
332                     poResult->killMe();
333                 }
334                 std::wostringstream os;
335                 os << _W("inconsistent row/column dimensions\n");
336                 throw ast::ScilabError(os.str(), 999, (*e.getLines().begin())->getLocation());
337             }
338
339             // if we concatenate [Double Sparse], transform the Double to Sparse and perform [Sparse Sparse]
340             // this avoids to allocate a Double result of size of Double+Sparse and initialize all elements.
341             if (pGT->isSparse() && pGTResult->isDouble())
342             {
343                 poResult = new types::Sparse(*pGTResult->getAs<types::Double>());
344                 pGTResult->killMe();
345                 pGTResult = poResult->getAs<GenericType>();
346             }
347             else if (pGT->isSparseBool() && pGTResult->isBool()) // [Bool SparseBool] => [SparseBool SparseBool]
348             {
349                 poResult = new types::SparseBool(*pGTResult->getAs<types::Bool>());
350                 pGTResult->killMe();
351                 pGTResult = poResult->getAs<GenericType>();
352             }
353
354             InternalType* pNewSize = AddElementToVariable(NULL, poResult, pGTResult->getRows() + pGT->getRows(), pGT->getCols());
355             InternalType* p = AddElementToVariable(pNewSize, pGT, pGTResult->getRows(), 0);
356             if (p != pNewSize)
357             {
358                 pNewSize->killMe();
359             }
360
361             // call overload
362             if (p == NULL)
363             {
364                 try
365                 {
366                     poResult = callOverloadMatrixExp(L"f", pGTResult, pGT);
367                 }
368                 catch (ScilabError& error)
369                 {
370                     throw error;
371                 }
372                 continue;
373             }
374
375             if (poResult != poRow)
376             {
377                 poRow->killMe();
378             }
379
380             if (p != poResult)
381             {
382                 poResult->killMe();
383                 poResult = p;
384             }
385         }
386
387         if (poResult)
388         {
389             setResult(poResult);
390         }
391         else
392         {
393             setResult(Double::Empty());
394         }
395     }
396     catch (ast::ScilabError& error)
397     {
398         setResult(NULL);
399         throw error;
400     }
401 }
402
403 template<class T>
404 types::InternalType* RunVisitorT<T>::callOverloadMatrixExp(std::wstring strType, types::InternalType* _paramL, types::InternalType* _paramR)
405 {
406     types::typed_list in;
407     types::typed_list out;
408     Callable::ReturnValue Ret;
409
410     _paramL->IncreaseRef();
411     _paramR->IncreaseRef();
412
413     in.push_back(_paramL);
414     in.push_back(_paramR);
415
416     try
417     {
418         if (_paramR->isGenericType() && _paramR->getAs<types::GenericType>()->getDims() > 2)
419         {
420             Ret = Overload::call(L"%hm_" + strType + L"_hm", in, 1, out, this, true);
421         }
422         else
423         {
424             Ret = Overload::call(L"%" + _paramL->getAs<List>()->getShortTypeStr() + L"_" + strType + L"_" + _paramR->getAs<List>()->getShortTypeStr(), in, 1, out, this, true);
425         }
426     }
427     catch (ast::ScilabError error)
428     {
429         cleanInOut(in, out);
430         throw error;
431     }
432     catch (ast::ScilabMessage msg)
433     {
434         cleanInOut(in, out);
435         throw ScilabError(msg.GetErrorMessage(), msg.GetErrorNumber(), msg.GetErrorLocation());
436     }
437
438     if (Ret != Callable::OK)
439     {
440         cleanInOut(in, out);
441         throw ScilabError();
442     }
443
444     cleanIn(in, out);
445
446     if (out.empty())
447     {
448         // TODO: avoid crash if out is empty but must return an error...
449         return NULL;
450     }
451
452     return out[0];
453 }
454
455 } /* namespace ast */