Improve performance for loop and insertion
[scilab.git] / scilab / modules / ast / src / cpp / symbol / context.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2008-2008 - DIGITEO - Antoine ELIAS
4 *
5 *  This file must be used under the terms of the CeCILL.
6 *  This source file is licensed as described in the file COPYING, which
7 *  you should have received as part of this distribution.  The terms
8 *  are also available at
9 *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12 #include <iomanip>
13 #include <cctype>
14
15 #include "context.hxx"
16 #include "internal.hxx"
17 #include "function.hxx"
18 #include "macro.hxx"
19 #include "macrofile.hxx"
20 #include "variables.hxx"
21 #include "configvariable.hxx"
22
23 extern "C"
24 {
25 #include "getmemory.h"
26 #include "os_string.h"
27 }
28
29 namespace symbol
30 {
31 Context* Context::me;
32
33 Context::Context()
34 {
35     m_iLevel = 0;
36     varStack.push(new VarList());
37     globals = new std::list<Symbol>();
38 }
39
40 Context::~Context()
41 {
42     while (!varStack.empty())
43     {
44         VarList * pVL = varStack.top();
45         pVL->clear();
46         delete pVL;
47         varStack.pop();
48     }
49     if (globals)
50     {
51         delete globals;
52     }
53 }
54
55 Context* Context::getInstance(void)
56 {
57     if (me == 0)
58     {
59         me = new Context();
60     }
61     return me;
62 }
63
64 void Context::destroyInstance(void)
65 {
66     if (me)
67     {
68         delete me;
69     }
70 }
71
72 void Context::scope_begin()
73 {
74     m_iLevel++;
75     varStack.push(new VarList());
76 }
77
78 void Context::clearAll()
79 {
80     libraries.clearAll();
81     variables.clearAll();
82 }
83
84 void Context::scope_end()
85 {
86     //clear varList of current scope
87     if (varStack.empty() == false)
88     {
89         clearCurrentScope(true);
90     }
91
92     m_iLevel--;
93 }
94
95 bool Context::clearCurrentScope(bool _bClose)
96 {
97     if (varStack.empty())
98     {
99         return true;
100     }
101
102     VarList* varList = varStack.top();
103     std::list<Symbol> toremove;
104     for (auto var : *varList)
105     {
106         if (var.second->empty() == false)
107         {
108             ScopedVariable* pSV = var.second->top();
109             if (pSV->m_iLevel == m_iLevel && (_bClose || pSV->protect == false))
110             {
111                 ScopedVariable * pSV = var.second->top();
112                 types::InternalType * pIT = pSV->m_pIT;
113                 pIT->DecreaseRef();
114                 pIT->killMe();
115                 var.second->pop();
116                 delete pSV;
117                 toremove.push_back(var.first);
118             }
119         }
120     }
121
122     if (_bClose)
123     {
124         delete varList;
125         varStack.pop();
126     }
127     else
128     {
129         for (auto var : toremove)
130         {
131             varList->erase(var);
132         }
133     }
134     return true;
135 }
136
137 Variable* Context::getOrCreate(const Symbol& _key)
138 {
139     return variables.getOrCreate(_key);
140 }
141
142 types::InternalType* Context::get(const Symbol& _key)
143 {
144     return get(_key, -1);
145 }
146
147 types::InternalType* Context::get(const Variable* _var)
148 {
149     types::InternalType* pIT = _var->get();
150     if (pIT == NULL)
151     {
152         //look in libraries
153         pIT = libraries.get(_var->getSymbol(), -1);
154         if (pIT && pIT->isLibrary() == false)
155         {
156             put((Variable*)_var, pIT);
157         }
158     }
159
160     return pIT;
161 }
162
163 types::InternalType* Context::get(const Symbol& _key, int _iLevel)
164 {
165     types::InternalType* pIT = NULL;
166     if (_iLevel == m_iLevel || _iLevel == -1)
167     {
168         //look for in current VarList
169         VarList::iterator it = varStack.top()->find(_key);
170         if (it != varStack.top()->end())
171         {
172             if (it->second->empty() == false)
173             {
174                 pIT = it->second->get();
175             }
176         }
177     }
178
179     if (pIT == NULL)
180     {
181         pIT = variables.get(_key, _iLevel);
182         if (pIT == NULL)
183         {
184             //find in libraries
185             pIT = libraries.get(_key, _iLevel);
186         }
187     }
188     return pIT;
189 }
190
191 types::InternalType* Context::getCurrentLevel(const Symbol& _key)
192 {
193     return variables.get(_key, m_iLevel);
194 }
195
196 types::InternalType* Context::getCurrentLevel(Variable* _var)
197 {
198     return variables.get(_var, m_iLevel);
199 }
200
201 types::InternalType* Context::getAllButCurrentLevel(const Symbol& _key)
202 {
203     return variables.getAllButCurrentLevel(_key, m_iLevel);
204 }
205
206 types::InternalType* Context::getFunction(const Symbol& _key)
207 {
208     return get(_key);
209 }
210
211 int Context::getFunctionList(std::list<Symbol>& lst, std::wstring _stModuleName)
212 {
213     return variables.getFunctionList(lst, _stModuleName, m_iLevel);
214 }
215
216 int Context::getVarsName(std::list<std::wstring>& lst)
217 {
218     variables.getVarsName(lst);
219     libraries.getVarsName(lst);
220
221     return static_cast<int>(lst.size());
222 }
223
224 int Context::getMacrosName(std::list<std::wstring>& lst)
225 {
226     variables.getMacrosName(lst);
227     libraries.getMacrosName(lst);
228     return static_cast<int>(lst.size());
229 }
230
231 int Context::getFunctionsName(std::list<std::wstring>& lst)
232 {
233     return variables.getFunctionsName(lst);
234 }
235
236 int Context::getVarsNameForWho(std::list<std::wstring>& lst, bool bSorted)
237 {
238     int iZero = 0;
239     variables.getVarsNameForWho(lst, &iZero, bSorted);
240     return static_cast<int>(lst.size());
241 }
242
243 int Context::getGlobalNameForWho(std::list<std::wstring>& lst, bool bSorted)
244 {
245     int iZero = 0;
246     variables.getGlobalNameForWho(lst, &iZero, bSorted);
247     return static_cast<int>(lst.size());
248 }
249
250 int Context::getWhereIs(std::list<std::wstring>& lst, const std::wstring& _str)
251 {
252     return libraries.whereis(lst, Symbol(_str));
253 }
254
255 int Context::getLibrariesList(std::list<std::wstring>& lst)
256 {
257     return libraries.librarieslist(lst);
258 }
259
260 void Context::put(Variable* _var, types::InternalType* _pIT)
261 {
262     if (_pIT->isLibrary())
263     {
264         Library* lib = libraries.getOrCreate(_var->getSymbol());
265         lib->put((types::Library*)_pIT, m_iLevel);
266     }
267     else
268     {
269         _var->put(_pIT, m_iLevel);
270         if (varStack.empty() == false)
271         {
272             (*varStack.top())[_var->getSymbol()] = _var;
273         }
274     }
275 }
276
277 void Context::put(const Symbol& _key, types::InternalType* _pIT)
278 {
279     Variable* var = variables.getOrCreate(_key);
280     put(var, _pIT);
281 }
282
283 bool Context::remove(const Symbol& _key)
284 {
285     bool ret = variables.remove(_key, m_iLevel);
286
287     if (ret)
288     {
289         varStack.top()->erase(_key);
290     }
291
292     ret = ret | libraries.remove(_key, m_iLevel);
293     return ret;
294 }
295
296 bool Context::removeAll()
297 {
298     return clearCurrentScope(false);
299 }
300
301 bool Context::putInPreviousScope(Variable* _var, types::InternalType* _pIT)
302 {
303     //add variable in previous scope
304     variables.putInPreviousScope(_var, _pIT, m_iLevel - 1);
305
306     //add variable in stack of using variables
307     if (varStack.empty() == false)
308     {
309         VarList * list = varStack.top();
310         varStack.pop();
311         if (varStack.empty() == false)
312         {
313             (*varStack.top())[_var->getSymbol()] = _var;
314         }
315         varStack.push(list);
316     }
317     return true;
318 }
319
320 bool Context::addFunction(types::Function *_info)
321 {
322     Variable* var = variables.getOrCreate(Symbol(_info->getName()));
323     variables.putInPreviousScope(var, _info, 0);
324     return true;
325 }
326
327 bool Context::addMacro(types::Macro *_info)
328 {
329     put(Symbol(_info->getName()), _info);
330     return true;
331 }
332
333 bool Context::addMacroFile(types::MacroFile *_info)
334 {
335     put(Symbol(_info->getName()), _info);
336     return true;
337 }
338
339 bool Context::isGlobalVisible(const Symbol& _key)
340 {
341     return variables.isGlobalVisible(_key, m_iLevel);
342 }
343
344 /*return global variable existance status*/
345 bool Context::isGlobal(const Symbol& _key)
346 {
347     return variables.isGlobal(_key, m_iLevel);
348 }
349
350 types::InternalType* Context::getGlobalValue(const Symbol& _key)
351 {
352     return variables.getGlobalValue(_key);
353 }
354
355 void Context::setGlobalVisible(const Symbol& _key, bool bVisible)
356 {
357     variables.setGlobalVisible(_key, bVisible, m_iLevel);
358 }
359
360 void Context::setGlobal(const Symbol& _key)
361 {
362     variables.setGlobal(_key);
363     globals->push_back(_key);
364 }
365
366 void Context::removeGlobal(const Symbol& _key)
367 {
368     variables.removeGlobal(_key, m_iLevel);
369     globals->remove(_key);
370 }
371
372 void Context::removeGlobalAll()
373 {
374     std::list<Symbol>::iterator it = globals->begin();
375     while (it != globals->end())
376     {
377         removeGlobal(*it);
378         it = globals->begin();
379     }
380
381     globals->clear();
382 }
383
384 void Context::print(std::wostream& ostr, bool sorted) const
385 {
386     std::list<std::wstring> lstVar;
387     std::list<std::wstring> lstGlobal;
388     int iVarLenMax = 10; // initialise to the minimal value of padding
389     int iGlobalLenMax = 10; // initialise to the minimal value of padding
390     variables.getVarsNameForWho(lstVar, &iVarLenMax);
391     variables.getGlobalNameForWho(lstGlobal, &iGlobalLenMax);
392     libraries.getVarsNameForWho(&lstVar, &iVarLenMax);
393
394     if (sorted)
395     {
396         lstVar.sort();
397         lstGlobal.sort();
398     }
399
400 #define strSize 64
401     wchar_t wcsVarElem[strSize];
402     wchar_t wcsVarVariable[strSize];
403     wchar_t wcsGlobalElem[strSize];
404     wchar_t wcsGlobalVariable[strSize];
405
406     int iMemTotal = 0;
407     int iMemUsed = 0;
408     int nbMaxVar = 0;
409
410 #ifdef _MSC_VER
411     MEMORYSTATUSEX statex;
412     statex.dwLength = sizeof(statex);
413     GlobalMemoryStatusEx(&statex);
414     iMemTotal = (int)(statex.ullTotalPhys / (1024 * 1024));
415 #else
416     iMemTotal = getmemorysize();
417 #endif
418
419     ostr << _W("Your variables are:") << std::endl << std::endl;
420     std::list<std::wstring>::const_iterator it = lstVar.begin();
421     int iWidth = ConfigVariable::getConsoleWidth();
422     int iCurrentWidth = 0;
423     for (int i = 1; it != lstVar.end(); ++it, i++)
424     {
425         if (iCurrentWidth + iVarLenMax + 1 > iWidth)
426         {
427             ostr << std::endl;
428             iCurrentWidth = 0;
429         }
430         ostr << std::setw(iVarLenMax + 1) << *it;
431         iCurrentWidth += iVarLenMax + 1;
432     }
433
434     os_swprintf(wcsVarElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
435     ostr << std::endl << wcsVarElem;
436
437     os_swprintf(wcsVarVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstVar.size(), nbMaxVar);
438     ostr << wcsVarVariable << std::endl;
439
440     ostr << std::endl << _W("Your global variables are:") << std::endl << std::endl;
441     it = lstGlobal.begin();
442     for (int i = 1; it != lstGlobal.end(); ++it, i++)
443     {
444         ostr << std::setw(iGlobalLenMax + 1) << *it;
445         if (i % 4 == 0)
446         {
447             ostr << std::endl;
448         }
449     }
450
451     ostr << std::endl;
452
453     os_swprintf(wcsGlobalElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
454     ostr << std::endl << wcsGlobalElem;
455
456     os_swprintf(wcsGlobalVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstGlobal.size(), nbMaxVar);
457     ostr << wcsGlobalVariable;
458 }
459
460 int Context::getScopeLevel()
461 {
462     return m_iLevel;
463 }
464
465 bool Context::isValidVariableName(const wchar_t* wcsVarName)
466 {
467     static const wchar_t FORBIDDEN_CHARS[] = L" */\\.,;:^@><=+-&|()~\n\t'\"";
468     if (wcslen(wcsVarName) == 0 || std::wcspbrk(wcsVarName, FORBIDDEN_CHARS) || isdigit(wcsVarName[0]))
469     {
470         return false;
471     }
472     return true;
473 }
474
475 bool Context::isValidVariableName(const char* name)
476 {
477     bool isValid = false;
478     wchar_t* wcsname = to_wide_string(name);
479     if (wcsname)
480     {
481         isValid = isValidVariableName(wcsname);
482         FREE(wcsname);
483     }
484
485     return isValid;
486 }
487
488 int Context::getLibsToVariableBrowser(std::list<Library*>& lst)
489 {
490     libraries.getVarsToVariableBrowser(lst);
491
492     std::list<Library*> toremove;
493     //list lib that have a variable with the same name
494     for (auto lib : lst)
495     {
496         Variable* var = getOrCreate(lib->getSymbol());
497         if (var->empty() == false)
498         {
499             toremove.push_back(lib);
500         }
501     }
502
503     //remove
504     for (auto lib : toremove)
505     {
506         lst.remove(lib);
507     }
508
509     return static_cast<int>(lst.size());
510 }
511
512 int Context::getVarsToVariableBrowser(std::list<Variable*>& lst)
513 {
514     variables.getVarsToVariableBrowser(lst);
515     return static_cast<int>(lst.size());
516 }
517
518 void Context::updateProtection(bool protect)
519 {
520     if (varStack.empty() == false)
521     {
522         VarList* lst = varStack.top();
523         for (auto var : *lst)
524         {
525             if (var.second->empty() == false)
526             {
527                 ScopedVariable* pSV = var.second->top();
528                 //only for current scope but normally vars in VarStack are in the current scope
529                 if (pSV->m_iLevel == m_iLevel)
530                 {
531                     pSV->protect = protect;
532                 }
533                 else
534                 {
535                     std::wcerr << L"heu ... " << var.first.getName() << std::endl;
536                 }
537             }
538         }
539     }
540 }
541
542 void Context::protect()
543 {
544     updateProtection(true);
545 }
546
547 void Context::unprotect()
548 {
549     updateProtection(false);
550 }
551
552 bool Context::isprotected(const Symbol& key)
553 {
554     return isprotected(getOrCreate(key));
555 }
556
557 bool Context::isprotected(Variable* _var)
558 {
559     //don't check protection on "ans"
560     if (_var->getSymbol().getName() == L"ans")
561     {
562         return false;
563     }
564
565     if (_var->empty() == false)
566     {
567         ScopedVariable* pSV = _var->top();
568         if (pSV->m_iLevel == m_iLevel && pSV->protect)
569         {
570             return true;
571         }
572     }
573     return false;
574 }
575
576 int Context::protectedVars(std::list<std::wstring>& vars)
577 {
578     return variables.getProtectedVarsName(vars);
579 }
580 }