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