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