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