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