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