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