[bug_14379] bad expected size in recursive extraction.
[scilab.git] / scilab / modules / ast / src / cpp / ast / run_CallExp.hpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014 - Scilab Enterprises - 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 CallExp &e)
21 {
22     CoverageInstance::invokeAndStartChrono((void*)&e);
23     types::typed_list outTmp;
24     types::typed_list inTmp;
25     std::vector<std::wstring> vectOptName;
26     std::vector<int> vectNbResult;
27
28     int iRetCount = getExpectedSize();
29     int iSaveExpectedSize = iRetCount;
30
31     //get function arguments
32     exps_t args = e.getArgs();
33     try
34     {
35         for (auto& arg : args)
36         {
37             int iSize = getExpectedSize();
38             if (arg->isAssignExp())
39             {
40                 AssignExp* pAssign = static_cast<AssignExp*>(arg);
41                 //optional parameter
42                 Exp* pL = &pAssign->getLeftExp();
43                 if (!pL->isSimpleVar())
44                 {
45                     std::wostringstream os;
46                     os << _W("left side of optional parameter must be a variable") << std::endl;
47                     CoverageInstance::stopChrono((void*)&e);
48                     throw ast::InternalError(os.str(), 999, e.getLocation());
49                 }
50
51                 SimpleVar* pVar = pL->getAs<SimpleVar>();
52                 Exp* pR = &pAssign->getRightExp();
53                 // optional parameter have only one output argument
54                 setExpectedSize(1);
55                 try
56                 {
57                     pR->accept(*this);
58                 }
59                 catch (ScilabException &)
60                 {
61                     CoverageInstance::stopChrono((void*)&e);
62                     throw;
63                 }
64                 setExpectedSize(iSize);
65                 types::InternalType* pITR = getResult();
66                 // IncreaseRef to protect opt argument of scope_end delete
67                 // It will be deleted by clear_opt
68                 pITR->IncreaseRef();
69
70                 vectOptName.push_back(pVar->getSymbol().getName());
71                 inTmp.push_back(pITR);
72                 vectNbResult.push_back(1);
73
74                 clearResult();
75                 continue;
76             }
77
78             setExpectedSize(-1);
79             try
80             {
81                 arg->accept(*this);
82             }
83             catch (ScilabException &)
84             {
85                 CoverageInstance::stopChrono((void*)&e);
86                 throw;
87             }
88             setExpectedSize(iSize);
89
90             if (getResult() == NULL)
91             {
92                 //special case for empty extraction of list ( list()(:) )
93                 vectNbResult.push_back(0);
94                 continue;
95             }
96
97             if (isSingleResult())
98             {
99                 inTmp.push_back(getResult());
100                 getResult()->IncreaseRef();
101             }
102             else
103             {
104                 for (int i = 0; i < getResultSize(); i++)
105                 {
106                     types::InternalType * pITArg = getResult(i);
107                     pITArg->IncreaseRef();
108                     inTmp.push_back(pITArg);
109                 }
110             }
111
112             vectNbResult.push_back(getResultSize());
113             clearResult();
114         }
115     }
116     catch (const InternalError& ie)
117     {
118         clearResult();
119         cleanIn(inTmp, outTmp);
120         CoverageInstance::stopChrono((void*)&e);
121         throw ie;
122     }
123
124     // reset expected size for recursive call
125     // ie [a, b] = l(1)(1), where l is a list containing a function with two output argument
126     setExpectedSize(-1);
127     // get function/variable
128     try
129     {
130         e.getName().accept(*this);
131     }
132     catch (ScilabException &)
133     {
134         CoverageInstance::stopChrono((void*)&e);
135         throw;
136     }
137     setExpectedSize(iSaveExpectedSize);
138
139     types::InternalType* pIT = getResult();
140
141     // pIT can be NULL if one of call return nothing. foo()(1) with foo return nothing.
142     if(pIT == NULL)
143     {
144         clearResult();
145         std::wostringstream os;
146         os << _W("Cannot extract from nothing.") << std::endl;
147         CoverageInstance::stopChrono((void*)&e);
148         throw ast::InternalError(os.str(), 999, e.getLocation());
149     }
150
151     types::typed_list out;
152     types::typed_list in;
153     types::optional_list opt;
154
155     // manage case [a,b]=foo() where foo is defined as a=foo()
156     if (pIT->getInvokeNbOut() != -1 && pIT->getInvokeNbOut() < iRetCount)
157     {
158         clearResult();
159         std::wostringstream os;
160         os << _W("Wrong number of output arguments.\n") << std::endl;
161         CoverageInstance::stopChrono((void*)&e);
162         throw ast::InternalError(os.str(), 999, e.getLocation());
163     }
164
165     if (pIT->isCallable())
166     {
167         CoverageInstance::invoke(static_cast<types::Callable *>(pIT));
168     }
169
170     // manage input according the function/variable
171     int iLoop = -1;
172     int iterIn = 0;
173     int iterOptName = 0;
174     for (auto& arg : args)
175     {
176         iLoop++;
177
178         //special case for empty extraction of list ( list()(:) )
179         if (vectNbResult[iLoop] == 0)
180         {
181             continue;
182         }
183
184         //extract implicit list for call()
185         if (pIT->isCallable() || pIT->isUserType())
186         {
187             if (inTmp[iterIn]->isImplicitList())
188             {
189                 types::ImplicitList* pIL = inTmp[iterIn]->getAs<types::ImplicitList>();
190                 if (pIL->isComputable())
191                 {
192                     types::InternalType* pITExtract = pIL->extractFullMatrix();
193                     pITExtract->IncreaseRef();
194                     inTmp[iterIn] = pITExtract;
195                     pIL->DecreaseRef();
196                     pIL->killMe();
197                 }
198             }
199         }
200
201         // management of optional input
202         if (arg->isAssignExp())
203         {
204             if (pIT->hasInvokeOption())
205             {
206                 opt[vectOptName[iterOptName++]] = inTmp[iterIn++];
207
208                 //in case of macro/macrofile, we have to shift input param
209                 //so add NULL item in in list to keep initial order
210                 if (pIT->isMacro() || pIT->isMacroFile())
211                 {
212                     in.push_back(NULL);
213                 }
214             }
215             else
216             {
217                 in.push_back(inTmp[iterIn++]);
218             }
219
220             continue;
221         }
222
223         // default case
224         for (int i = 0; i < vectNbResult[iLoop]; i++, iterIn++)
225         {
226             in.push_back(inTmp[iterIn]);
227         }
228     }
229
230     try
231     {
232         // Extraction with a List in input argument.
233         // This extraction must be a recursive extract.
234         int iLoopSize = 1;
235         types::List* pListArg = NULL;
236         if (pIT->isCallable() == false && in.size() == 1 && in[0]->isList())
237         {
238             pListArg = in[0]->getAs<types::List>();
239             iLoopSize = pListArg->getSize();
240             cleanOpt(opt, out);
241         }
242
243         setExpectedSize(iSaveExpectedSize);
244         iRetCount = std::max(1, iRetCount);
245
246         for (int i = 0; i < iLoopSize; i++)
247         {
248             if (pListArg)
249             {
250                 in[0] = pListArg->get(i);
251
252                 if (in[0]->isList())
253                 {
254                     if (pIT->isCallable())
255                     {
256                         // list used like "varargin"
257                         types::List* pLFuncArgs = in[0]->getAs<types::List>();
258                         types::typed_list input;
259                         for (int j = 0; j < pLFuncArgs->getSize(); j++)
260                         {
261                             input.push_back(pLFuncArgs->get(j));
262                             input.back()->IncreaseRef();
263                         }
264
265                         in = input;
266                     }
267                     else
268                     {
269                         pListArg->DecreaseRef();
270                         pListArg->killMe();
271
272                         std::wostringstream os;
273                         os << _W("Invalid index.\n");
274                         throw ast::InternalError(os.str(), 999, e.getFirstLocation());
275                     }
276                 }
277                 else
278                 {
279                     in[0]->IncreaseRef();
280                 }
281             }
282
283             bool ret = false;
284             if (pIT->isInvokable() == false)
285             {
286                 // call overload
287                 ret = Overload::call(L"%" + pIT->getShortTypeStr() + L"_e", in, iRetCount, out, true);
288             }
289             else
290             {
291                 ret = pIT->invoke(in, opt, iRetCount, out, e);
292                 if (ret == false && pIT->isUserType())
293                 {
294                     // call overload
295                     ret = Overload::call(L"%" + pIT->getShortTypeStr() + L"_e", in, iRetCount, out, true);
296                 }
297             }
298
299             if (ret)
300             {
301                 if (iSaveExpectedSize != -1 && iSaveExpectedSize > out.size())
302                 {
303                     char szError[bsiz];
304                     if (pIT->isCallable())
305                     {
306                         char* strFName = wide_string_to_UTF8(pIT->getAs<types::Callable>()->getName().c_str());
307                         os_sprintf(szError, _("%s: Wrong number of output argument(s): %d expected.\n"), strFName, out.size());
308                         FREE(strFName);
309                     }
310                     else
311                     {
312                         os_sprintf(szError, _("%s: Wrong number of output argument(s): %d expected.\n"), "extract", out.size());
313                     }
314
315                     wchar_t* wError = to_wide_string(szError);
316                     std::wstring err(wError);
317                     FREE(wError);
318                     throw InternalError(err, 999, e.getLocation());
319                 }
320
321                 setExpectedSize(iSaveExpectedSize);
322                 setResult(out);
323                 cleanIn(in, out);
324                 cleanOpt(opt, out);
325
326                 // In case a.b(), getResult contain pIT ("b").
327                 // If out == pIT, do not delete it.
328                 if (getResult() != pIT)
329                 {
330                     // protect element of out in case where
331                     // out contain elements of pIT
332                     for (int i = 0; i < out.size(); i++)
333                     {
334                         out[i]->IncreaseRef();
335                     }
336
337                     pIT->killMe();
338
339                     // unprotect
340                     for (int i = 0; i < out.size(); i++)
341                     {
342                         out[i]->DecreaseRef();
343                     }
344                 }
345
346                 if (pListArg && i + 1 != iLoopSize)
347                 {
348                     pIT = out[0];
349                     out.clear();
350                     setResult(NULL);
351                 }
352             }
353             else
354             {
355                 std::wostringstream os;
356                 os << _W("Invalid index.\n");
357                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
358             }
359         }
360
361         if (pListArg)
362         {
363             pListArg->DecreaseRef();
364             pListArg->killMe();
365         }
366     }
367     catch (InternalAbort & ia)
368     {
369         setExpectedSize(iSaveExpectedSize);
370         if (pIT != getResult())
371         {
372             pIT->killMe();
373         }
374
375         clearResult();
376         cleanInOut(in, out);
377         cleanOpt(opt, out);
378         CoverageInstance::stopChrono((void*)&e);
379
380         throw ia;
381     }
382     catch (const InternalError& ie)
383     {
384         setExpectedSize(iSaveExpectedSize);
385         if (pIT != getResult())
386         {
387             pIT->killMe();
388         }
389
390         clearResult();
391         cleanInOut(in, out);
392         cleanOpt(opt, out);
393         CoverageInstance::stopChrono((void*)&e);
394
395         throw ie;
396     }
397
398     CoverageInstance::stopChrono((void*)&e);
399 }
400
401 template<class T>
402 void RunVisitorT<T>::visitprivate(const CellCallExp &e)
403 {
404     CoverageInstance::invokeAndStartChrono((void*)&e);
405
406     //get head
407     T execMeCell;
408     try
409     {
410         e.getName().accept(execMeCell);
411     }
412     catch (ScilabException &)
413     {
414         CoverageInstance::stopChrono((void*)&e);
415         throw;
416     }
417
418     if (execMeCell.getResult() != NULL)
419     {
420         //a{xxx} with a variable, extraction
421         types::InternalType *pIT = NULL;
422
423         pIT = execMeCell.getResult();
424
425         if (pIT)
426         {
427
428             if (pIT->isCell() == false)
429             {
430                 CoverageInstance::stopChrono((void*)&e);
431                 throw ast::InternalError(_W("[error] Cell contents reference from a non-cell array object.\n"), 999, e.getFirstLocation());
432             }
433             //Create list of indexes
434             ast::exps_t exps = e.getArgs();
435             types::typed_list *pArgs = GetArgumentList(exps);
436
437             if (pArgs->size() == 0)
438             {
439                 // Case a{}
440                 delete pArgs;
441                 std::wostringstream os;
442                 os << _W("Cell : Cannot extract without arguments.\n");
443                 CoverageInstance::stopChrono((void*)&e);
444                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
445             }
446
447             types::List* pList = pIT->getAs<types::Cell>()->extractCell(pArgs);
448
449             if (pList == NULL)
450             {
451                 delete pArgs;
452                 std::wostringstream os;
453                 os << _W("inconsistent row/column dimensions\n");
454                 //os << ((*e.args_get().begin())->getLocation()).getLocationString() << std::endl;
455                 CoverageInstance::stopChrono((void*)&e);
456                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
457             }
458
459             if (pList->getSize() == 1)
460             {
461                 types::InternalType* ret = pList->get(0);
462                 setResult(ret);
463
464                 ret->IncreaseRef();
465                 pList->killMe();
466                 ret->DecreaseRef();
467             }
468             else
469             {
470                 setResult(pList);
471             }
472
473
474             //clean pArgs return by GetArgumentList
475             for (int iArg = 0; iArg < (int)pArgs->size(); iArg++)
476             {
477                 (*pArgs)[iArg]->killMe();
478             }
479             delete pArgs;
480         }
481     }
482     else
483     {
484         //result == NULL ,variable doesn't exist :(
485         // Should never be in this case
486         // In worst case variable pointing to function does not exists
487         // visitprivate(SimpleVar) will throw the right exception.
488     }
489     CoverageInstance::stopChrono((void*)&e);
490 }
491
492 } /* namespace ast */