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