Coverity #1350628 fixed
[scilab.git] / scilab / modules / ast / src / cpp / ast / run_AssignExp.hpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2008-2008 - DIGITEO - 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 AssignExp  &e)
21 {
22     CoverageInstance::invokeAndStartChrono((void*)&e);
23     symbol::Context* ctx = symbol::Context::getInstance();
24     /*Create local exec visitor*/
25     try
26     {
27         SimpleVar * pVar = NULL;
28         if (e.getLeftExp().isSimpleVar())
29         {
30             pVar = static_cast<SimpleVar*>(&e.getLeftExp());
31         }
32
33         /*get king of left hand*/
34         if (pVar)
35         {
36             // x = ?
37             /*getting what to assign*/
38             types::InternalType *pIT = e.getRightVal();
39             if (pIT == NULL)
40             {
41                 setExpectedSize(1);
42                 e.getRightExp().accept(*this);
43
44                 if (getResultSize() != 1)
45                 {
46                     std::wostringstream os;
47                     os << _W("Can not assign multiple value in a single variable") << std::endl;
48                     //os << ((Location)e.getRightExp().getLocation()).getLocationString() << std::endl;
49                     throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
50                 }
51
52                 pIT = getResult();
53                 //reset result
54                 setResult(NULL);
55             }
56
57             if (pIT->isImplicitList())
58             {
59                 if (pIT->getAs<types::ImplicitList>()->isComputable())
60                 {
61                     types::InternalType *pTemp = pIT->getAs<types::ImplicitList>()->extractFullMatrix();
62                     pIT->killMe();
63                     pIT = pTemp;
64                 }
65             }
66
67             if (pIT->isAssignable() == false)
68             {
69                 if (pIT->isListDelete())
70                 {
71                     //used to delete a variable in current scope
72                     symbol::Symbol sym = pVar->getSymbol();
73                     if (ctx->isprotected(sym) == false)
74                     {
75                         ctx->remove(sym);
76                     }
77                     else
78                     {
79                         std::wostringstream os;
80                         os << _W("Redefining permanent variable.\n");
81                         throw ast::InternalError(os.str(), 999, e.getLeftExp().getLocation());
82                     }
83                 }
84
85                 setResult(NULL);
86                 CoverageInstance::stopChrono((void*)&e);
87                 return;
88             }
89
90             if (pIT->isList() && pIT->getRef() > 0)
91             {
92                 // Prevent modification of all scilab variable
93                 // which point to this container when it is used
94                 // in setfield scilab function.
95                 // A clone on a container will not clone what it contain.
96                 pIT = pIT->clone();
97             }
98
99             if (e.getRightExp().isReturnExp())
100             {
101                 //ReturnExp so, put the value in the previous scope
102                 if (ctx->putInPreviousScope(pVar->getStack(), pIT) == false)
103                 {
104                     char pstError[1024];
105                     char* pstFuncName = wide_string_to_UTF8(pVar->getSymbol().getName().data());
106                     os_sprintf(pstError, _("It is not possible to redefine the %s primitive this way (see clearfun).\n"), pstFuncName);
107                     wchar_t* pwstError = to_wide_string(pstError);
108                     std::wstring wstError(pwstError);
109                     FREE(pstFuncName);
110                     FREE(pwstError);
111                     pIT->killMe();
112                     CoverageInstance::stopChrono((void*)&e);
113                     throw InternalError(wstError, 999, e.getLocation());
114                 }
115
116                 ((AssignExp*)&e)->setReturn();
117             }
118             else
119             {
120                 if (ctx->isprotected(pVar->getStack()) == false)
121                 {
122                     ctx->put(pVar->getStack(), pIT);
123                 }
124                 else
125                 {
126                     std::wostringstream os;
127                     os << _W("Redefining permanent variable.\n");
128                     throw ast::InternalError(os.str(), 999, e.getLeftExp().getLocation());
129                 }
130             }
131
132             if (e.isVerbose() && ConfigVariable::isPrintOutput())
133             {
134                 std::wstring wstrName = pVar->getSymbol().getName();
135                 std::wostringstream ostr;
136                 ostr << L" " << wstrName << L"  = " << std::endl << std::endl;
137                 scilabWriteW(ostr.str().c_str());
138                 std::wostringstream ostrName;
139                 ostrName << wstrName;
140                 VariableToString(pIT, ostrName.str().c_str());
141             }
142             CoverageInstance::stopChrono((void*)&e);
143             return;
144         }
145
146         if (e.getLeftExp().isCellCallExp())
147         {
148             CellCallExp *pCell = static_cast<CellCallExp*>(&e.getLeftExp());
149             types::InternalType *pOut = NULL;
150
151             /*getting what to assign*/
152             types::InternalType* pITR = e.getRightVal();
153             if (pITR == NULL)
154             {
155                 e.getRightExp().accept(*this);
156                 pITR = getResult();
157                 //reset result
158                 setResult(NULL);
159             }
160
161             if (pITR == NULL)
162             {
163                 // if the right hand is NULL.
164                 std::wostringstream os;
165                 os << _W("Unable to extract right part expression.\n");
166                 throw ast::InternalError(os.str(), 999, e.getLeftExp().getLocation());
167             }
168
169             std::list<ExpHistory*> fields;
170             if (getFieldsFromExp(pCell, fields) == false)
171             {
172                 for (std::list<ExpHistory*>::const_iterator i = fields.begin(), end = fields.end(); i != end; i++)
173                 {
174                     delete *i;
175                 }
176                 std::wostringstream os;
177                 os << _W("Get fields from expression failed.");
178                 throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
179             }
180
181             try
182             {
183                 pOut = evaluateFields(pCell, fields, pITR);
184             }
185             catch (const InternalError& error)
186             {
187                 // catch error when call overload
188                 for (std::list<ExpHistory*>::const_iterator i = fields.begin(), end = fields.end(); i != end; i++)
189                 {
190                     (*i)->setDeleteCurrent(true);
191                     delete *i;
192                 }
193
194                 pITR->killMe();
195                 throw error;
196             }
197
198             for (std::list<ExpHistory*>::const_iterator i = fields.begin(), end = fields.end(); i != end; i++)
199             {
200                 delete *i;
201             }
202
203             pITR->killMe();
204
205             if (pOut == NULL)
206             {
207                 std::wostringstream os;
208                 os << _W("Fields evaluation failed.");
209                 throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
210             }
211
212             if (pOut != NULL)
213             {
214                 if (e.isVerbose() && ConfigVariable::isPrintOutput())
215                 {
216                     std::wostringstream ostr;
217                     ostr << L" " << *getStructNameFromExp(pCell) << L"  = " << std::endl;
218                     ostr << std::endl;
219                     scilabWriteW(ostr.str().c_str());
220
221                     VariableToString(pOut, ostr.str().c_str());
222                 }
223             }
224             else
225             {
226                 //manage error
227                 std::wostringstream os;
228                 os << _W("Invalid Index.\n");
229                 throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
230             }
231
232             CoverageInstance::stopChrono((void*)&e);
233             return;
234         }
235
236         if (e.getLeftExp().isCallExp())
237         {
238             CallExp *pCall = static_cast<CallExp*>(&e.getLeftExp());
239             //x(?) = ?
240             types::InternalType *pOut = NULL;
241
242             if (e.getRightExp().isReturnExp())
243             {
244                 // We can't put in the previous scope a variable create like that : a(2)=resume(1)
245                 std::wostringstream os;
246                 os << _W("Indexing not allowed for output arguments of resume.\n");
247                 throw ast::InternalError(os.str(), 79, e.getLeftExp().getLocation());
248             }
249
250             /*getting what to assign*/
251             types::InternalType* pITR = e.getRightVal();
252             if (pITR == NULL)
253             {
254                 e.getRightExp().accept(*this);
255                 pITR = getResult();
256                 //reset result
257                 setResult(NULL);
258             }
259
260             if (pITR == NULL)
261             {
262                 // if the right hand is NULL.
263                 std::wostringstream os;
264                 os << _W("Unable to extract right part expression.\n");
265                 throw ast::InternalError(os.str(), 999, e.getLeftExp().getLocation());
266             }
267
268             bool alreadyProcessed = false;
269             //a(...) without fields or whatever on arrayof derived types
270             if (pCall->getName().isSimpleVar())
271             {
272                 ast::SimpleVar* var = pCall->getName().getAs<ast::SimpleVar>();
273                 types::InternalType* pIT = ctx->getCurrentLevel(var->getStack());
274                 if (pIT && pIT->isArrayOf())
275                 {
276                     if (ctx->isprotected(var->getStack()))
277                     {
278                         std::wostringstream os;
279                         os << _W("Redefining permanent variable.\n");
280                         throw ast::InternalError(os.str(), 999, pCall->getLocation());
281                     }
282
283                     // prevent delete after extractFullMatrix
284                     // called in insertionCall when pITR is an ImplicitList
285                     pITR->IncreaseRef();
286
287                     types::typed_list* currentArgs = GetArgumentList(pCall->getArgs());
288
289                     try
290                     {
291                         pOut = insertionCall(e, currentArgs, pIT, pITR);
292                     }
293                     catch (const InternalError& error)
294                     {
295                         pITR->DecreaseRef();
296                         // call killMe on all arguments
297                         cleanOut(*currentArgs);
298                         delete currentArgs;
299                         // insertion have done, call killMe on pITR
300                         pITR->killMe();
301                         throw error;
302                     }
303
304                     pITR->DecreaseRef();
305
306                     // call killMe on all arguments
307                     cleanOut(*currentArgs);
308                     delete currentArgs;
309
310                     // insertion have done, call killMe on pITR
311                     pITR->killMe();
312
313                     if (pOut == NULL)
314                     {
315                         std::wostringstream os;
316                         os << _W("Submatrix incorrectly defined.\n");
317                         throw ast::InternalError(os.str(), 999, e.getLocation());
318                     }
319
320
321                     //update variable with new value
322                     if (pOut != pIT)
323                     {
324                         ctx->put(var->getStack(), pOut);
325                     }
326
327                     alreadyProcessed = true;
328                 }
329             }
330
331             if (alreadyProcessed == false)
332             {
333                 std::list<ExpHistory*> fields;
334                 if (getFieldsFromExp(pCall, fields) == false)
335                 {
336                     for (std::list<ExpHistory*>::const_iterator i = fields.begin(), end = fields.end(); i != end; i++)
337                     {
338                         delete *i;
339                     }
340
341                     std::wostringstream os;
342                     os << _W("Instruction left hand side: waiting for a name.");
343                     throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
344                 }
345
346                 // prevent delete after extractFullMatrix
347                 // called in evaluateFields when pITR is an ImplicitList
348                 pITR->IncreaseRef();
349
350                 try
351                 {
352                     pOut = evaluateFields(pCall, fields, pITR);
353                 }
354                 catch (const InternalError& error)
355                 {
356                     // catch error when call overload
357                     for (std::list<ExpHistory*>::const_iterator i = fields.begin(), end = fields.end(); i != end; i++)
358                     {
359                         delete *i;
360                     }
361
362                     pITR->DecreaseRef();
363                     pITR->killMe();
364
365                     throw error;
366                 }
367
368                 for (std::list<ExpHistory*>::const_iterator i = fields.begin(), end = fields.end(); i != end; i++)
369                 {
370                     delete *i;
371                 }
372
373                 pITR->DecreaseRef();
374                 pITR->killMe();
375
376                 if (pOut == NULL)
377                 {
378                     std::wostringstream os;
379                     os << _W("Fields evaluation failed.");
380                     throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
381                 }
382             }
383
384             if (e.isVerbose() && ConfigVariable::isPrintOutput())
385             {
386                 std::wostringstream ostr;
387                 ostr << L" " << *getStructNameFromExp(&pCall->getName()) << L"  = " << std::endl;
388                 ostr << std::endl;
389                 scilabWriteW(ostr.str().c_str());
390
391                 std::wostringstream ostrName;
392                 ostrName << *getStructNameFromExp(&pCall->getName());
393                 VariableToString(pOut, ostrName.str().c_str());
394             }
395
396             clearResult();
397             CoverageInstance::stopChrono((void*)&e);
398
399             return;
400         }
401
402         if (e.getLeftExp().isAssignListExp())
403         {
404             AssignListExp *pList = e.getLeftExp().getAs<AssignListExp>();
405             //[x,y] = ?
406             int iLhsCount = (int)pList->getExps().size();
407
408             /*getting what to assign*/
409             T exec;
410             exec.setExpectedSize(iLhsCount);
411             e.getRightExp().accept(exec);
412
413             if (exec.getResultSize() < iLhsCount)
414             {
415                 std::wostringstream os;
416                 os << _W("Incompatible assignation: trying to assign ") << exec.getResultSize();
417                 os << _W(" values in ") << iLhsCount << _W(" variables.") << std::endl;
418                 throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
419             }
420
421             exps_t::const_reverse_iterator it;
422             exps_t exps = pList->getExps();
423             types::InternalType** pIT = new types::InternalType*[iLhsCount];
424             int i = 0;
425             for (i = iLhsCount - 1; i >= 0; i--)
426             {
427                 //create a new AssignExp and run it
428                 pIT[i] = exec.getResult(i);
429                 //protet rhs against removal [a,b] = (b,a);
430                 pIT[i]->IncreaseRef();
431             }
432
433             for (i = iLhsCount - 1, it = exps.rbegin(); it != exps.rend(); it++, i--)
434             {
435                 Exp* pExp = e.getRightExp().clone();
436                 AssignExp pAssign((*it)->getLocation(), *(*it), *pExp, pIT[i]);
437                 pAssign.setLrOwner(false);
438                 pAssign.setVerbose(e.isVerbose());
439                 pAssign.accept(*this);
440                 //clear result to take care of [n,n]
441                 exec.setResult(i, NULL);
442                 delete pExp;
443             }
444
445             for (i = iLhsCount - 1; i >= 0; i--)
446             {
447                 //unprotect rhs
448                 pIT[i]->DecreaseRef();
449                 pIT[i]->killMe();
450             }
451
452             delete[] pIT;
453             exec.clearResult();
454             CoverageInstance::stopChrono((void*)&e);
455             return;
456         }
457
458         if (e.getLeftExp().isFieldExp())
459         {
460             FieldExp *pField = static_cast<FieldExp*>(&e.getLeftExp());
461             types::InternalType *pIT = e.getRightVal();
462             if (pIT == NULL)
463             {
464                 //a.b = x
465                 //a.b can be a struct or a tlist/mlist or a handle
466                 /*getting what to assign*/
467                 setExpectedSize(1);
468                 e.getRightExp().accept(*this);
469                 pIT = getResult();
470                 setResult(NULL);
471             }
472
473             if (pIT->isImplicitList())
474             {
475                 if (pIT->getAs<types::ImplicitList>()->isComputable())
476                 {
477                     types::InternalType *pTemp = pIT->getAs<types::ImplicitList>()->extractFullMatrix();
478                     delete pIT;
479                     setResult(NULL);
480                     pIT = pTemp;
481                 }
482             }
483
484             std::list<ExpHistory*> fields;
485             if (getFieldsFromExp(pField, fields) == false)
486             {
487                 for (std::list<ExpHistory*>::const_iterator i = fields.begin(), end = fields.end(); i != end; i++)
488                 {
489                     delete *i;
490                 }
491                 std::wostringstream os;
492                 os << _W("Get fields from expression failed.");
493                 throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
494             }
495
496             try
497             {
498                 if (evaluateFields(pField, fields, pIT) == NULL)
499                 {
500                     for (std::list<ExpHistory*>::const_iterator i = fields.begin(), end = fields.end(); i != end; i++)
501                     {
502                         delete *i;
503                     }
504                     std::wostringstream os;
505                     os << _W("Fields evaluation failed.");
506                     throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
507                 }
508             }
509             catch (const InternalError& error)
510             {
511                 for (auto i : fields)
512                 {
513                     delete i;
514                 }
515
516                 throw error;
517             }
518
519             for (auto i : fields)
520             {
521                 delete i;
522             }
523
524             if (e.isVerbose() && ConfigVariable::isPrintOutput())
525             {
526                 const std::wstring *pstName = getStructNameFromExp(pField);
527
528                 types::InternalType* pPrint = ctx->get(symbol::Symbol(*pstName));
529                 std::wostringstream ostr;
530                 ostr << L" " << *pstName << L"  = " << std::endl << std::endl;
531                 scilabWriteW(ostr.str().c_str());
532
533                 std::wostringstream ostrName;
534                 ostrName << *pstName;
535                 VariableToString(pPrint, ostrName.str().c_str());
536             }
537
538             clearResult();
539             CoverageInstance::stopChrono((void*)&e);
540             return;
541         }
542
543         std::wostringstream os;
544         os << _W("unknown script form");
545         //os << ((Location)e.getRightExp().getLocation()).getLocationString() << std::endl;
546         throw ast::InternalError(os.str(), 999, e.getRightExp().getLocation());
547     }
548     catch (const InternalError& error)
549     {
550         CoverageInstance::stopChrono((void*)&e);
551         throw error;
552     }
553 }
554
555 } /* namespace ast */