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