Merge 6.0 into master
[scilab.git] / scilab / modules / ast / src / cpp / symbol / variables.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2015 - Scilab Enterprises - 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 #include <algorithm>
17 #include "variables.hxx"
18 #include "configvariable.hxx"
19 #include "macro.hxx"
20 #include "macrofile.hxx"
21 #include "types_tools.hxx"
22
23 extern "C"
24 {
25 #include "sciprint.h"
26 }
27
28 namespace symbol
29 {
30 Variable::~Variable()
31 {
32     while (!empty())
33     {
34         ScopedVariable * pSV = top();
35         types::InternalType * pIT = pSV->m_pIT;
36         pIT->DecreaseRef();
37         pIT->killMe();
38         pop();
39         delete pSV;
40     }
41
42     if (m_GlobalValue)
43     {
44         m_GlobalValue->DecreaseRef();
45         m_GlobalValue->killMe();
46     }
47 }
48
49 void Variable::setGlobalValue(types::InternalType* _pIT)
50 {
51     if (m_GlobalValue != _pIT)
52     {
53         if (m_GlobalValue)
54         {
55             m_GlobalValue->DecreaseRef();
56             m_GlobalValue->killMe();
57         }
58
59         m_GlobalValue = _pIT;
60         if (_pIT != NULL)
61         {
62             _pIT->IncreaseRef();
63         }
64     }
65 }
66
67 void Variable::setGlobalVisible(int _iLevel, bool _bVisible)
68 {
69     if (empty() || top()->m_iLevel != _iLevel)
70     {
71         last = new ScopedVariable(_iLevel, types::Double::Empty());
72         stack.push(last);
73     }
74
75     top()->m_globalVisible = _bVisible;
76 }
77
78
79 bool Variable::put(types::InternalType* _pIT, int _iLevel)
80 {
81     if (isGlobal() && isGlobalVisible(_iLevel))
82     {
83         setGlobalValue(_pIT);
84         return true;
85     }
86
87     if (empty() || top()->m_iLevel < _iLevel)
88     {
89         //create a new level
90         last = new ScopedVariable(_iLevel, _pIT);
91         stack.push(last);
92         _pIT->IncreaseRef();
93     }
94     else
95     {
96         //update current level
97         types::InternalType* pIT = top()->m_pIT;
98         if (pIT != _pIT)
99         {
100             //check macro redefinition
101             if (_pIT->isMacro())
102             {
103                 int iFuncProt = ConfigVariable::getFuncprot();
104                 if (iFuncProt != 0)
105                 {
106                     bool bEquals = true;
107                     if (pIT && pIT->isCallable())
108                     {
109                         if (pIT->isMacroFile())
110                         {
111                             types::MacroFile* pMF = pIT->getAs<types::MacroFile>();
112                             bEquals = *pMF->getMacro() == *_pIT;
113                         }
114                         else if (pIT->isMacro())
115                         {
116                             types::Macro* pM = pIT->getAs<types::Macro>();
117                             bEquals = *pM == *_pIT;
118                         }
119                     }
120
121                     if (bEquals == false)
122                     {
123                         if (iFuncProt == 2)
124                         {
125                             return false;
126                         }
127
128                         if (ConfigVariable::getWarningMode())
129                         {
130                             wchar_t pwstFuncName[1024];
131                             os_swprintf(pwstFuncName, 1024, L"%-24ls", name.getName().c_str());
132                             char* pstFuncName = wide_string_to_UTF8(pwstFuncName);
133
134                             sciprint(_("Warning : redefining function: %s. Use funcprot(0) to avoid this message"), pstFuncName);
135                             sciprint("\n");
136                             FREE(pstFuncName);
137                         }
138                     }
139                 }
140             }
141
142             // _pIT may contained in pIT
143             // so increases ref of _pIT before kill pIT
144             top()->m_pIT = _pIT;
145             if (pIT)
146             {
147                 _pIT->IncreaseRef();
148                 pIT->DecreaseRef();
149                 pIT->killMe();
150             }
151         }
152     }
153
154     return true;
155 }
156
157 Variable* Variables::getOrCreate(const Symbol& _key)
158 {
159     MapVars::const_iterator it = vars.find(_key);
160     if (it == vars.end())
161     {
162         //create an empty StackedValues
163         Variable* var = new Variable(_key);
164         vars[_key] = var;
165         return var;
166     }
167
168     return it->second;
169 }
170
171 int Variables::getLevel(const Symbol& _key) const
172 {
173     MapVars::const_iterator it = vars.find(_key);
174     if (it != vars.end() && !it->second->empty())
175     {
176         return it->second->top()->m_iLevel;
177     }
178
179     return SCOPE_ALL;
180 }
181
182 void Variables::put(const Symbol& _key, types::InternalType* _pIT, int _iLevel)
183 {
184     Variable* var = getOrCreate(_key);
185     var->put(_pIT, _iLevel);
186 }
187
188 types::InternalType* Variables::get(const Symbol& _key, int _iLevel)
189 {
190     MapVars::const_iterator it = vars.find(_key);
191     if (it != vars.end() && it->second->empty() == false)
192     {
193         if (_iLevel == SCOPE_ALL || it->second->top()->m_iLevel == _iLevel)
194         {
195             return it->second->get();
196         }
197     }
198
199     return NULL;
200 }
201
202 types::InternalType* Variables::get(Variable* _var, int _iLevel)
203 {
204     if (_var != NULL && _var->empty() == false)
205     {
206         if (_iLevel == SCOPE_ALL || _var->top()->m_iLevel == _iLevel)
207         {
208             return _var->get();
209         }
210     }
211
212     return NULL;
213 }
214
215 types::InternalType* Variables::getAllButCurrentLevel(const Symbol& _key, int _iLevel)
216 {
217     MapVars::const_iterator it = vars.find(_key);
218     if (it != vars.end() && it->second->empty() == false)
219     {
220         if (it->second->top()->m_iLevel < _iLevel)
221         {
222             return it->second->get();
223         }
224         else
225         {
226             ScopedVariable* pSave = it->second->top();
227             it->second->pop();
228             types::InternalType* pIT = getAllButCurrentLevel(_key, _iLevel);
229             it->second->put(pSave);
230             return pIT;
231         }
232     }
233
234     return NULL;
235 }
236
237 bool Variables::remove(Variable* _var, int _iLevel)
238 {
239     if (_var->empty() == false)
240     {
241         if (_var->top()->m_iLevel == _iLevel)
242         {
243             ScopedVariable* pSave = _var->top();
244             types::InternalType* pIT = pSave->m_pIT;
245             pIT->DecreaseRef();
246             pIT->killMe();
247             _var->pop();
248             delete pSave;
249             return true;
250         }
251     }
252
253     return false;
254 }
255
256 bool Variables::remove(const Symbol& _key, int _iLevel)
257 {
258     MapVars::iterator it = vars.find(_key);
259     if (it != vars.end())
260     {
261         Variable* pVar = it->second;
262         return remove(pVar, _iLevel);
263     }
264
265     return false;
266 }
267
268 int Variables::getMacrosName(std::list<std::wstring>& lst)
269 {
270     for (auto it : vars)
271     {
272         if (it.second->empty() == false)
273         {
274             types::InternalType* pIT = it.second->top()->m_pIT;
275             if (pIT && (pIT->isMacro() || pIT->isMacroFile()))
276             {
277                 lst.push_back(it.first.getName().c_str());
278             }
279         }
280     }
281
282     return static_cast<int>(lst.size());
283 }
284
285 int Variables::getVarsName(std::list<std::wstring>& lst)
286 {
287     for (auto it : vars)
288     {
289         if (it.second->empty() == false)
290         {
291             types::InternalType* pIT = it.second->top()->m_pIT;
292             if (pIT &&
293                     pIT->isMacro() == false &&
294                     pIT->isMacroFile() == false &&
295                     pIT->isFunction() == false)
296             {
297                 lst.push_back(it.first.getName().c_str());
298             }
299         }
300     }
301
302     return static_cast<int>(lst.size());
303 }
304
305 bool Variables::getVarsInfoForWho(std::list<std::pair<std::wstring, int>>& lstVar, int* iVarLenMax, bool bSorted) const
306 {
307     for (auto it : vars)
308     {
309         if (it.second->empty() == false)
310         {
311             types::InternalType* pIT = it.second->top()->m_pIT;
312             if (pIT && pIT->isFunction() == false)
313             {
314                 std::wstring wstrVarName(it.first.getName().c_str());
315                 *iVarLenMax = std::max(*iVarLenMax, (int)wstrVarName.size());
316                 int iSize, iSizePlusType;
317                 if (pIT->getMemory(&iSize, &iSizePlusType))
318                 {
319                     lstVar.emplace_back(wstrVarName, iSizePlusType);
320                 }
321             }
322         }
323     }
324
325     if (bSorted)
326     {
327         lstVar.sort();
328     }
329
330     return true;
331 }
332
333 bool Variables::getGlobalInfoForWho(std::list<std::pair<std::wstring, int>>& lstVar, int* iVarLenMax, bool bSorted) const
334 {
335     for (auto it : vars)
336     {
337         if (it.second->isGlobal())
338         {
339             std::wstring wstrVarName(it.first.getName().c_str());
340             *iVarLenMax = std::max(*iVarLenMax, (int)wstrVarName.size());
341             int iSize, iSizePlusType;
342             types::InternalType* pIT = it.second->empty() ? it.second->getGlobalValue() : it.second->top()->m_pIT;
343             if(pIT->getMemory(&iSize, &iSizePlusType))
344             {
345                 lstVar.emplace_back(wstrVarName, iSizePlusType);
346             }
347         }
348     }
349
350     if (bSorted)
351     {
352         lstVar.sort();
353     }
354
355     return true;
356 }
357
358 int Variables::getProtectedVarsName(std::list<std::wstring>& lstVarName) const
359 {
360     for (auto it : vars)
361     {
362         if (it.second->empty() == false)
363         {
364             ScopedVariable* pSV = it.second->top();
365             if (pSV->protect && it.first.getName() != L"ans")
366             {
367                 lstVarName.push_back(it.first.getName());
368             }
369         }
370     }
371
372     return static_cast<int>(lstVarName.size());
373 }
374
375 int Variables::getFunctionsName(std::list<std::wstring>& lst)
376 {
377     for (auto it : vars)
378     {
379         if (it.second->empty() == false)
380         {
381             types::InternalType* pIT = it.second->top()->m_pIT;
382             if (pIT && pIT->isFunction())
383             {
384                 lst.push_back(it.first.getName().c_str());
385             }
386         }
387     }
388
389     return static_cast<int>(lst.size());
390 }
391
392 int Variables::getFunctionList(std::list<Symbol>& lst, std::wstring _stModuleName, int _iLevel)
393 {
394     for (auto var : vars)
395     {
396         if (var.second->empty())
397         {
398             continue;
399         }
400
401         if ((var.second->top()->m_iLevel == _iLevel || _iLevel == 1) && var.second->top()->m_pIT->isCallable())
402         {
403             types::Callable* pCall = var.second->top()->m_pIT->getAs<types::Callable>();
404             if (_stModuleName == L"" || _stModuleName == pCall->getModule())
405             {
406                 lst.push_back(var.first);
407             }
408         }
409     }
410
411     return static_cast<int>(lst.size());
412 }
413
414 int Variables::getFunctionList(std::list<types::Callable *>& lst, std::wstring _stModuleName, int _iLevel)
415 {
416     for (auto var : vars)
417     {
418         if (var.second->empty())
419         {
420             continue;
421         }
422
423         if ((var.second->top()->m_iLevel == _iLevel || _iLevel == 1) && var.second->top()->m_pIT->isCallable())
424         {
425             types::Callable * pCall = var.second->top()->m_pIT->getAs<types::Callable>();
426             if (_stModuleName == L"" || _stModuleName == pCall->getModule())
427             {
428                 lst.push_back(pCall);
429             }
430         }
431     }
432
433     return static_cast<int>(lst.size());
434 }
435
436 int Variables::getVarsToVariableBrowser(std::list<Variable*>& lst)
437 {
438     for (auto var : vars)
439     {
440         if (var.second->empty() == false)
441         {
442             types::InternalType* pIT = var.second->top()->m_pIT;
443             if (pIT &&
444                     pIT->isMacro() == false &&
445                     pIT->isMacroFile() == false &&
446                     pIT->isFunction() == false)
447             {
448                 lst.push_back(var.second);
449             }
450         }
451     }
452
453     return static_cast<int>(lst.size());
454 }
455
456 int Variables::getCurrentScope(std::list<std::wstring>& lst, int level, bool sorted)
457 {
458     for (auto var : vars)
459     {
460         if (var.second->empty() == false)
461         {
462             if (var.second->top()->m_iLevel == level)
463             {
464                 types::InternalType* pIT = var.second->top()->m_pIT;
465                 lst.push_back(var.first.getName());
466             }
467         }
468     }
469
470     if (sorted)
471     {
472         lst.sort();
473     }
474
475     return static_cast<int>(lst.size());
476 }
477
478 bool Variables::putInPreviousScope(Variable* _var, types::InternalType* _pIT, int _iLevel)
479 {
480     if (_var->empty())
481     {
482         return _var->put(_pIT, _iLevel);
483     }
484     else if (_var->top()->m_iLevel > _iLevel)
485     {
486         ScopedVariable* pVar = _var->top();
487         _var->pop();
488         if (putInPreviousScope(_var, _pIT, _iLevel) == false)
489         {
490             return false;
491         }
492         //decresef ref before, increase it in put
493         //pVar->m_pIT->DecreaseRef();
494         return _var->put(pVar);
495     }
496     else
497     {
498         if (_var->top()->protect == false)
499         {
500             return _var->put(_pIT, _iLevel);
501         }
502     }
503
504     return false;
505 }
506
507 //globals
508
509 void Variables::setGlobal(const Symbol& _key)
510 {
511     getOrCreate(_key)->setGlobal(true);
512 }
513
514 void Variables::setGlobalVisible(const Symbol& _key, bool _bVisible, int _iLevel)
515 {
516     Variable* pVar = getOrCreate(_key);
517     pVar->setGlobalVisible(_iLevel, _bVisible);
518     if (_bVisible)
519     {
520         pVar->setGlobal(true);
521     }
522 }
523
524 bool Variables::isGlobalVisible(const Symbol& _key, int _iLevel)
525 {
526     return getOrCreate(_key)->isGlobalVisible(_iLevel);
527 }
528
529 bool Variables::isGlobal(const Symbol& _key, int /*_iLevel*/)
530 {
531     return getOrCreate(_key)->isGlobal();
532 }
533
534 types::InternalType* Variables::getGlobalValue(const Symbol& _key)
535 {
536     return getOrCreate(_key)->getGlobalValue();
537 }
538
539 void Variables::removeGlobal(const Symbol& _key, int _iLevel)
540 {
541     Variable* pVar = getOrCreate(_key);
542     if (pVar->isGlobal())
543     {
544         pVar->setGlobal(false);
545         pVar->setGlobalValue(NULL);
546     }
547
548     remove(pVar, _iLevel);
549 }
550
551 void Variables::clearAll()
552 {
553     for (auto var : vars)
554     {
555         delete var.second;
556     }
557
558     vars.clear();
559 }
560
561
562 }