[mem leak] run_CallExp fixed about ImplicitList
[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                     pIL->DecreaseRef();
164                     pIL->killMe();
165                     iterIn++;
166                     continue;
167                 }
168             }
169         }
170
171         // default case
172         for(int i = 0; i < vectNbResult[iLoop]; i++, iterIn++)
173         {
174             in.push_back(inTmp[iterIn]);
175         }
176     }
177
178     try
179     {
180         // Extraction with a List in input argument.
181         // This extraction must be a recursive extract.
182         int iLoopSize = 1;
183         types::List* pListArg = NULL;
184         if (pIT->isCallable() == false && in.size() == 1 && in[0]->isList())
185         {
186             pListArg = in[0]->getAs<types::List>();
187             iLoopSize = pListArg->getSize();
188             cleanOpt(opt);
189         }
190
191         setExpectedSize(iSaveExpectedSize);
192         iRetCount = std::max(1, iRetCount);
193
194         for (int i = 0; i < iLoopSize; i++)
195         {
196             if (pListArg)
197             {
198                 in[0] = pListArg->get(i);
199
200                 if (in[0]->isList())
201                 {
202                     if (pIT->isCallable())
203                     {
204                         // list used like "varargin"
205                         types::List* pLFuncArgs = in[0]->getAs<types::List>();
206                         types::typed_list input;
207                         for (int j = 0; j < pLFuncArgs->getSize(); j++)
208                         {
209                             input.push_back(pLFuncArgs->get(j));
210                             input.back()->IncreaseRef();
211                         }
212
213                         in = input;
214                     }
215                     else
216                     {
217                         pListArg->DecreaseRef();
218                         pListArg->killMe();
219
220                         std::wostringstream os;
221                         os << _W("Invalid index.\n");
222                         throw ast::InternalError(os.str(), 999, e.getFirstLocation());
223                     }
224                 }
225                 else
226                 {
227                     in[0]->IncreaseRef();
228                 }
229             }
230
231             bool ret = false;
232             if (pIT->isInvokable() == false)
233             {
234                 // call overload
235                 ret = Overload::call(L"%" + pIT->getShortTypeStr() + L"_e", in, iRetCount, out, this);
236             }
237             else
238             {
239                 ret = pIT->invoke(in, opt, iRetCount, out, e);
240                 if (ret == false && pIT->isUserType())
241                 {
242                     // call overload
243                     ret = Overload::call(L"%" + pIT->getShortTypeStr() + L"_e", in, iRetCount, out, this);
244                 }
245             }
246
247             if (ret)
248             {
249                 if (iSaveExpectedSize != -1 && iSaveExpectedSize > out.size())
250                 {
251                     char szError[bsiz];
252                     if (pIT->isCallable())
253                     {
254                         char* strFName = wide_string_to_UTF8(pIT->getAs<types::Callable>()->getName().c_str());
255                         os_sprintf(szError, _("%s: Wrong number of output argument(s): %d expected.\n"), strFName, out.size());
256                         FREE(strFName);
257                     }
258                     else
259                     {
260                         os_sprintf(szError, _("%s: Wrong number of output argument(s): %d expected.\n"), "extract", out.size());
261                     }
262
263                     wchar_t* wError = to_wide_string(szError);
264                     std::wstring err(wError);
265                     FREE(wError);
266                     throw InternalError(err, 999, e.getLocation());
267                 }
268
269                 setExpectedSize(iSaveExpectedSize);
270                 setResult(out);
271                 cleanIn(in, out);
272                 cleanOpt(opt);
273
274                 // In case a.b(), getResult contain pIT ("b").
275                 // If out == pIT, do not delete it.
276                 if (getResult() != pIT)
277                 {
278                     // protect element of out in case where
279                     // out contain elements of pIT
280                     for (int i = 0; i < out.size(); i++)
281                     {
282                         out[i]->IncreaseRef();
283                     }
284
285                     pIT->killMe();
286
287                     // unprotect
288                     for (int i = 0; i < out.size(); i++)
289                     {
290                         out[i]->DecreaseRef();
291                     }
292                 }
293
294                 if (pListArg && i + 1 != iLoopSize)
295                 {
296                     pIT = out[0];
297                     out.clear();
298                     setResult(NULL);
299                 }
300             }
301             else
302             {
303                 std::wostringstream os;
304                 os << _W("Invalid index.\n");
305                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
306             }
307         }
308
309         if (pListArg)
310         {
311             pListArg->DecreaseRef();
312             pListArg->killMe();
313         }
314     }
315     catch (InternalAbort & ia)
316     {
317         setExpectedSize(iSaveExpectedSize);
318         if (pIT != getResult())
319         {
320             pIT->killMe();
321         }
322
323         clearResult();
324         cleanInOut(in, out);
325         cleanOpt(opt);
326
327         throw ia;
328     }
329     catch (const InternalError& ie)
330     {
331         setExpectedSize(iSaveExpectedSize);
332         if (pIT != getResult())
333         {
334             pIT->killMe();
335         }
336
337         clearResult();
338         cleanInOut(in, out);
339         cleanOpt(opt);
340
341         throw ie;
342     }
343 }
344
345 template<class T>
346 void RunVisitorT<T>::visitprivate(const CellCallExp &e)
347 {
348     //get head
349     T execMeCell;
350     e.getName().accept(execMeCell);
351
352     if (execMeCell.getResult() != NULL)
353     {
354         //a{xxx} with a variable, extraction
355         types::InternalType *pIT = NULL;
356
357         pIT = execMeCell.getResult();
358
359         if (pIT)
360         {
361
362             if (pIT->isCell() == false)
363             {
364                 throw ast::InternalError(_W("[error] Cell contents reference from a non-cell array object.\n"), 999, e.getFirstLocation());
365             }
366             //Create list of indexes
367             ast::exps_t exps = e.getArgs();
368             types::typed_list *pArgs = GetArgumentList(exps);
369
370             if (pArgs->size() == 0)
371             {
372                 // Case a{}
373                 delete pArgs;
374                 std::wostringstream os;
375                 os << _W("Cell : Cannot extract without arguments.\n");
376                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
377             }
378
379             types::List* pList = pIT->getAs<types::Cell>()->extractCell(pArgs);
380
381             if (pList == NULL)
382             {
383                 delete pArgs;
384                 std::wostringstream os;
385                 os << _W("inconsistent row/column dimensions\n");
386                 //os << ((*e.args_get().begin())->getLocation()).getLocationString() << std::endl;
387                 throw ast::InternalError(os.str(), 999, e.getFirstLocation());
388             }
389
390             if (pList->getSize() == 1)
391             {
392                 types::InternalType* ret = pList->get(0);
393                 setResult(ret);
394
395                 ret->IncreaseRef();
396                 pList->killMe();
397                 ret->DecreaseRef();
398             }
399             else
400             {
401                 setResult(pList);
402             }
403
404
405             //clean pArgs return by GetArgumentList
406             for (int iArg = 0 ; iArg < (int)pArgs->size() ; iArg++)
407             {
408                 (*pArgs)[iArg]->killMe();
409             }
410             delete pArgs;
411         }
412     }
413     else
414     {
415         //result == NULL ,variable doesn't exist :(
416         // Sould never be in this case
417         // In worst case variable pointing to function does not exists
418         // visitprivate(SimpleVar) will throw the right exception.
419     }
420 }
421
422 } /* namespace ast */