ede60201158d30ac96860e58463271a589fa3230
[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     // get function/variable
125     try
126     {
127         e.getName().accept(*this);
128     }
129     catch (ScilabException &)
130     {
131         CoverageInstance::stopChrono((void*)&e);
132         throw;
133     }
134     types::InternalType* pIT = getResult();
135
136     // pIT can be NULL if one of call return nothing. foo()(1) with foo return nothing.
137     if(pIT == NULL)
138     {
139         clearResult();
140         std::wostringstream os;
141         os << _W("Cannot extract from nothing.") << std::endl;
142         CoverageInstance::stopChrono((void*)&e);
143         throw ast::InternalError(os.str(), 999, e.getLocation());
144     }
145
146     types::typed_list out;
147     types::typed_list in;
148     types::optional_list opt;
149
150     // manage case [a,b]=foo() where foo is defined as a=foo()
151     if (pIT->getInvokeNbOut() != -1 && pIT->getInvokeNbOut() < iRetCount)
152     {
153         clearResult();
154         std::wostringstream os;
155         os << _W("Wrong number of output arguments.\n") << std::endl;
156         CoverageInstance::stopChrono((void*)&e);
157         throw ast::InternalError(os.str(), 999, e.getLocation());
158     }
159
160     if (pIT->isCallable())
161     {
162         CoverageInstance::invoke(static_cast<types::Callable *>(pIT));
163     }
164
165     // manage input according the function/variable
166     int iLoop = -1;
167     int iterIn = 0;
168     int iterOptName = 0;
169     for (auto& arg : args)
170     {
171         iLoop++;
172
173         //special case for empty extraction of list ( list()(:) )
174         if (vectNbResult[iLoop] == 0)
175         {
176             continue;
177         }
178
179         //extract implicit list for call()
180         if (pIT->isCallable() || pIT->isUserType())
181         {
182             if (inTmp[iterIn]->isImplicitList())
183             {
184                 types::ImplicitList* pIL = inTmp[iterIn]->getAs<types::ImplicitList>();
185                 if (pIL->isComputable())
186                 {
187                     types::InternalType* pITExtract = pIL->extractFullMatrix();
188                     pITExtract->IncreaseRef();
189                     inTmp[iterIn] = pITExtract;
190                     pIL->DecreaseRef();
191                     pIL->killMe();
192                 }
193             }
194         }
195
196         // management of optional input
197         if (arg->isAssignExp())
198         {
199             if (pIT->hasInvokeOption())
200             {
201                 opt[vectOptName[iterOptName++]] = inTmp[iterIn++];
202
203                 //in case of macro/macrofile, we have to shift input param
204                 //so add NULL item in in list to keep initial order
205                 if (pIT->isMacro() || pIT->isMacroFile())
206                 {
207                     in.push_back(NULL);
208                 }
209             }
210             else
211             {
212                 in.push_back(inTmp[iterIn++]);
213             }
214
215             continue;
216         }
217
218         // default case
219         for (int i = 0; i < vectNbResult[iLoop]; i++, iterIn++)
220         {
221             in.push_back(inTmp[iterIn]);
222         }
223     }
224
225     try
226     {
227         // Extraction with a List in input argument.
228         // This extraction must be a recursive extract.
229         int iLoopSize = 1;
230         types::List* pListArg = NULL;
231         if (pIT->isCallable() == false && in.size() == 1 && in[0]->isList())
232         {
233             pListArg = in[0]->getAs<types::List>();
234             iLoopSize = pListArg->getSize();
235             cleanOpt(opt, out);
236         }
237
238         setExpectedSize(iSaveExpectedSize);
239         iRetCount = std::max(1, iRetCount);
240
241         for (int i = 0; i < iLoopSize; i++)
242         {
243             if (pListArg)
244             {
245                 in[0] = pListArg->get(i);
246
247                 if (in[0]->isList())
248                 {
249                     if (pIT->isCallable())
250                     {
251                         // list used like "varargin"
252                         types::List* pLFuncArgs = in[0]->getAs<types::List>();
253                         types::typed_list input;
254                         for (int j = 0; j < pLFuncArgs->getSize(); j++)
255                         {
256                             input.push_back(pLFuncArgs->get(j));
257                             input.back()->IncreaseRef();
258                         }
259
260                         in = input;
261                     }
262                     else
263                     {
264                         pListArg->DecreaseRef();
265                         pListArg->killMe();
266
267                         std::wostringstream os;
268                         os << _W("Invalid index.\n");
269                         throw ast::InternalError(os.str(), 999, e.getFirstLocation());
270                     }
271                 }
272                 else
273                 {
274                     in[0]->IncreaseRef();
275                 }
276             }
277
278             bool ret = false;
279             if (pIT->isInvokable() == false)
280             {
281                 // call overload
282                 ret = Overload::call(L"%" + pIT->getShortTypeStr() + L"_e", in, iRetCount, out, true);
283             }
284             else
285             {
286                 ret = pIT->invoke(in, opt, iRetCount, out, e);
287                 if (ret == false && pIT->isUserType())
288                 {
289                     // call overload
290                     ret = Overload::call(L"%" + pIT->getShortTypeStr() + L"_e", in, iRetCount, out, true);
291                 }
292             }
293
294             if (ret)
295             {
296                 if (iSaveExpectedSize != -1 && iSaveExpectedSize > out.size())
297                 {
298                     char szError[bsiz];
299                     if (pIT->isCallable())
300                     {
301                         char* strFName = wide_string_to_UTF8(pIT->getAs<types::Callable>()->getName().c_str());
302                         os_sprintf(szError, _("%s: Wrong number of output argument(s): %d expected.\n"), strFName, out.size());
303                         FREE(strFName);
304                     }
305                     else
306                     {
307                         os_sprintf(szError, _("%s: Wrong number of output argument(s): %d expected.\n"), "extract", out.size());
308                     }
309
310                     wchar_t* wError = to_wide_string(szError);
311                     std::wstring err(wError);
312                     FREE(wError);
313                     throw InternalError(err, 999, e.getLocation());
314                 }
315
316                 setExpectedSize(iSaveExpectedSize);
317                 setResult(out);
318                 cleanIn(in, out);
319                 cleanOpt(opt, out);
320
321                 // In case a.b(), getResult contain pIT ("b").
322                 // If out == pIT, do not delete it.
323                 if (getResult() != pIT)
324                 {
325                     // protect element of out in case where
326                     // out contain elements of pIT
327                     for (int i = 0; i < out.size(); i++)
328                     {
329                         out[i]->IncreaseRef();
330                     }
331
332                     pIT->killMe();
333
334                     // unprotect
335                     for (int i = 0; i < out.size(); i++)
336                     {
337                         out[i]->DecreaseRef();
338                     }
339                 }
340
341                 if (pListArg && i + 1 != iLoopSize)
342                 {
343                     pIT = out[0];
344                     out.clear();
345                     setResult(NULL);
346                 }
347             }
348             else
349             {
350                 std::wostringstream os;
351                 os << _W("Invalid index.\n");
352                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
353             }
354         }
355
356         if (pListArg)
357         {
358             pListArg->DecreaseRef();
359             pListArg->killMe();
360         }
361     }
362     catch (InternalAbort & ia)
363     {
364         setExpectedSize(iSaveExpectedSize);
365         if (pIT != getResult())
366         {
367             pIT->killMe();
368         }
369
370         clearResult();
371         cleanInOut(in, out);
372         cleanOpt(opt, out);
373         CoverageInstance::stopChrono((void*)&e);
374
375         throw ia;
376     }
377     catch (const InternalError& ie)
378     {
379         setExpectedSize(iSaveExpectedSize);
380         if (pIT != getResult())
381         {
382             pIT->killMe();
383         }
384
385         clearResult();
386         cleanInOut(in, out);
387         cleanOpt(opt, out);
388         CoverageInstance::stopChrono((void*)&e);
389
390         throw ie;
391     }
392
393     CoverageInstance::stopChrono((void*)&e);
394 }
395
396 template<class T>
397 void RunVisitorT<T>::visitprivate(const CellCallExp &e)
398 {
399     CoverageInstance::invokeAndStartChrono((void*)&e);
400
401     //get head
402     T execMeCell;
403     try
404     {
405         e.getName().accept(execMeCell);
406     }
407     catch (ScilabException &)
408     {
409         CoverageInstance::stopChrono((void*)&e);
410         throw;
411     }
412
413     if (execMeCell.getResult() != NULL)
414     {
415         //a{xxx} with a variable, extraction
416         types::InternalType *pIT = NULL;
417
418         pIT = execMeCell.getResult();
419
420         if (pIT)
421         {
422
423             if (pIT->isCell() == false)
424             {
425                 CoverageInstance::stopChrono((void*)&e);
426                 throw ast::InternalError(_W("[error] Cell contents reference from a non-cell array object.\n"), 999, e.getFirstLocation());
427             }
428             //Create list of indexes
429             ast::exps_t exps = e.getArgs();
430             types::typed_list *pArgs = GetArgumentList(exps);
431
432             if (pArgs->size() == 0)
433             {
434                 // Case a{}
435                 delete pArgs;
436                 std::wostringstream os;
437                 os << _W("Cell : Cannot extract without arguments.\n");
438                 CoverageInstance::stopChrono((void*)&e);
439                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
440             }
441
442             types::List* pList = pIT->getAs<types::Cell>()->extractCell(pArgs);
443
444             if (pList == NULL)
445             {
446                 delete pArgs;
447                 std::wostringstream os;
448                 os << _W("inconsistent row/column dimensions\n");
449                 //os << ((*e.args_get().begin())->getLocation()).getLocationString() << std::endl;
450                 CoverageInstance::stopChrono((void*)&e);
451                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
452             }
453
454             if (pList->getSize() == 1)
455             {
456                 types::InternalType* ret = pList->get(0);
457                 setResult(ret);
458
459                 ret->IncreaseRef();
460                 pList->killMe();
461                 ret->DecreaseRef();
462             }
463             else
464             {
465                 setResult(pList);
466             }
467
468
469             //clean pArgs return by GetArgumentList
470             for (int iArg = 0; iArg < (int)pArgs->size(); iArg++)
471             {
472                 (*pArgs)[iArg]->killMe();
473             }
474             delete pArgs;
475         }
476     }
477     else
478     {
479         //result == NULL ,variable doesn't exist :(
480         // Should never be in this case
481         // In worst case variable pointing to function does not exists
482         // visitprivate(SimpleVar) will throw the right exception.
483     }
484     CoverageInstance::stopChrono((void*)&e);
485 }
486
487 } /* namespace ast */