bbb7f0240adf1fe9e3e2fb265fe51baaef2ca455
[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                 types::InternalType * pIT = pSV->m_pIT;
112                 if (pIT->isLibrary())
113                 {
114                     // at scilab exit, pIT have a ref == 2 because
115                     // it is contains in libraries and variables.
116                     // call remove will set ref to 1 then the next
117                     // pIT->DecreaseRef(); pIT->killMe(); will delete it.
118                     libraries.remove(var.first, m_iLevel);
119                 }
120
121                 pIT->DecreaseRef();
122                 pIT->killMe();
123
124                 var.second->pop();
125                 delete pSV;
126                 toremove.push_back(var.first);
127             }
128         }
129     }
130
131     if (_bClose)
132     {
133         delete varList;
134         varStack.pop();
135     }
136     else
137     {
138         for (auto var : toremove)
139         {
140             varList->erase(var);
141         }
142     }
143     return true;
144 }
145
146 Variable* Context::getOrCreate(const Symbol& _key)
147 {
148     return variables.getOrCreate(_key);
149 }
150
151 int Context::getLevel(const Symbol & _key) const
152 {
153     VarList::iterator it = varStack.top()->find(_key);
154     if (it != varStack.top()->end())
155     {
156         if (!it->second->empty())
157         {
158             return it->second->top()->m_iLevel;
159         }
160     }
161     else
162     {
163         const int ret = variables.getLevel(_key);
164         if (ret == -1)
165         {
166             return libraries.getLevel(_key);
167         }
168         else
169         {
170             return ret;
171         }
172     }
173
174     return -1;
175 }
176
177 types::InternalType* Context::get(const Symbol& _key)
178 {
179     return get(_key, -1);
180 }
181
182 types::InternalType* Context::get(const Variable* _var)
183 {
184     types::InternalType* pIT = _var->get();
185     if (pIT == NULL)
186     {
187         //look in libraries
188         pIT = libraries.get(_var->getSymbol(), -1);
189         if (pIT && pIT->isLibrary() == false)
190         {
191             put((Variable*)_var, pIT);
192         }
193     }
194
195     return pIT;
196 }
197
198 types::InternalType* Context::get(const Symbol& _key, int _iLevel)
199 {
200     types::InternalType* pIT = NULL;
201     if (_iLevel == m_iLevel || _iLevel == -1)
202     {
203         //look for in current VarList
204         VarList::iterator it = varStack.top()->find(_key);
205         if (it != varStack.top()->end())
206         {
207             if (it->second->empty() == false)
208             {
209                 pIT = it->second->get();
210             }
211         }
212     }
213
214     if (pIT == NULL)
215     {
216         pIT = variables.get(_key, _iLevel);
217         if (pIT == NULL)
218         {
219             //find in libraries
220             pIT = libraries.get(_key, _iLevel);
221         }
222     }
223     return pIT;
224 }
225
226 types::InternalType* Context::getCurrentLevel(const Symbol& _key)
227 {
228     return variables.get(_key, m_iLevel);
229 }
230
231 types::InternalType* Context::getCurrentLevel(Variable* _var)
232 {
233     return variables.get(_var, m_iLevel);
234 }
235
236 types::InternalType* Context::getAllButCurrentLevel(const Symbol& _key)
237 {
238     return variables.getAllButCurrentLevel(_key, m_iLevel);
239 }
240
241 types::InternalType* Context::getFunction(const Symbol& _key)
242 {
243     return get(_key);
244 }
245
246 int Context::getFunctionList(std::list<Symbol>& lst, std::wstring _stModuleName)
247 {
248     return variables.getFunctionList(lst, _stModuleName, m_iLevel);
249 }
250
251 int Context::getVarsName(std::list<std::wstring>& lst)
252 {
253     variables.getVarsName(lst);
254     libraries.getVarsName(lst);
255
256     return static_cast<int>(lst.size());
257 }
258
259 int Context::getMacrosName(std::list<std::wstring>& lst)
260 {
261     variables.getMacrosName(lst);
262     libraries.getMacrosName(lst);
263     return static_cast<int>(lst.size());
264 }
265
266 int Context::getFunctionsName(std::list<std::wstring>& lst)
267 {
268     return variables.getFunctionsName(lst);
269 }
270
271 int Context::getVarsNameForWho(std::list<std::wstring>& lst, bool bSorted)
272 {
273     int iZero = 0;
274     variables.getVarsNameForWho(lst, &iZero, bSorted);
275     return static_cast<int>(lst.size());
276 }
277
278 int Context::getGlobalNameForWho(std::list<std::wstring>& lst, bool bSorted)
279 {
280     int iZero = 0;
281     variables.getGlobalNameForWho(lst, &iZero, bSorted);
282     return static_cast<int>(lst.size());
283 }
284
285 int Context::getWhereIs(std::list<std::wstring>& lst, const std::wstring& _str)
286 {
287     return libraries.whereis(lst, Symbol(_str));
288 }
289
290 int Context::getLibrariesList(std::list<std::wstring>& lst)
291 {
292     return libraries.librarieslist(lst);
293 }
294
295 void Context::put(Variable* _var, types::InternalType* _pIT)
296 {
297     if (_pIT->isLibrary())
298     {
299         Library* lib = libraries.getOrCreate(_var->getSymbol());
300         lib->put((types::Library*)_pIT, m_iLevel);
301     }
302
303     _var->put(_pIT, m_iLevel);
304     if (varStack.empty() == false)
305     {
306         (*varStack.top())[_var->getSymbol()] = _var;
307     }
308 }
309
310 void Context::put(const Symbol& _key, types::InternalType* _pIT)
311 {
312     Variable* var = variables.getOrCreate(_key);
313     put(var, _pIT);
314 }
315
316 bool Context::remove(const Symbol& _key)
317 {
318     bool ret = variables.remove(_key, m_iLevel);
319
320     if (ret)
321     {
322         varStack.top()->erase(_key);
323     }
324
325     ret = ret | libraries.remove(_key, m_iLevel);
326     return ret;
327 }
328
329 bool Context::removeAll()
330 {
331     return clearCurrentScope(false);
332 }
333
334 bool Context::putInPreviousScope(Variable* _var, types::InternalType* _pIT)
335 {
336     //add variable in previous scope
337     variables.putInPreviousScope(_var, _pIT, m_iLevel - 1);
338
339     //add variable in stack of using variables
340     if (varStack.empty() == false)
341     {
342         VarList * list = varStack.top();
343         varStack.pop();
344         if (varStack.empty() == false)
345         {
346             (*varStack.top())[_var->getSymbol()] = _var;
347         }
348         varStack.push(list);
349     }
350
351     if (_pIT->isLibrary())
352     {
353         libraries.putInPreviousScope(_var->getSymbol(), _pIT->getAs<types::Library>(), m_iLevel - 1);
354     }
355     return true;
356 }
357
358 bool Context::addFunction(types::Function *_info)
359 {
360     Variable* var = variables.getOrCreate(Symbol(_info->getName()));
361     variables.putInPreviousScope(var, _info, 0);
362     return true;
363 }
364
365 bool Context::addMacro(types::Macro *_info)
366 {
367     put(Symbol(_info->getName()), _info);
368     return true;
369 }
370
371 bool Context::addMacroFile(types::MacroFile *_info)
372 {
373     put(Symbol(_info->getName()), _info);
374     return true;
375 }
376
377 bool Context::isGlobalVisible(const Symbol& _key)
378 {
379     return variables.isGlobalVisible(_key, m_iLevel);
380 }
381
382 /*return global variable existance status*/
383 bool Context::isGlobal(const Symbol& _key)
384 {
385     return variables.isGlobal(_key, m_iLevel);
386 }
387
388 types::InternalType* Context::getGlobalValue(const Symbol& _key)
389 {
390     return variables.getGlobalValue(_key);
391 }
392
393 void Context::setGlobalVisible(const Symbol& _key, bool bVisible)
394 {
395     variables.setGlobalVisible(_key, bVisible, m_iLevel);
396 }
397
398 void Context::setGlobal(const Symbol& _key)
399 {
400     variables.setGlobal(_key);
401     globals->push_back(_key);
402 }
403
404 void Context::removeGlobal(const Symbol& _key)
405 {
406     variables.removeGlobal(_key, m_iLevel);
407     globals->remove(_key);
408 }
409
410 void Context::removeGlobalAll()
411 {
412     std::list<Symbol>::iterator it = globals->begin();
413     while (it != globals->end())
414     {
415         removeGlobal(*it);
416         it = globals->begin();
417     }
418
419     globals->clear();
420 }
421
422 void Context::print(std::wostream& ostr, bool sorted) const
423 {
424     std::list<std::wstring> lstVar;
425     std::list<std::wstring> lstGlobal;
426     int iVarLenMax = 10; // initialise to the minimal value of padding
427     int iGlobalLenMax = 10; // initialise to the minimal value of padding
428     variables.getVarsNameForWho(lstVar, &iVarLenMax);
429     variables.getGlobalNameForWho(lstGlobal, &iGlobalLenMax);
430     libraries.getVarsNameForWho(&lstVar, &iVarLenMax);
431
432     if (sorted)
433     {
434         lstVar.sort();
435         lstGlobal.sort();
436     }
437
438 #define strSize 64
439     wchar_t wcsVarElem[strSize];
440     wchar_t wcsVarVariable[strSize];
441     wchar_t wcsGlobalElem[strSize];
442     wchar_t wcsGlobalVariable[strSize];
443
444     int iMemTotal = 0;
445     int iMemUsed = 0;
446     int nbMaxVar = 0;
447
448 #ifdef _MSC_VER
449     MEMORYSTATUSEX statex;
450     statex.dwLength = sizeof(statex);
451     GlobalMemoryStatusEx(&statex);
452     iMemTotal = (int)(statex.ullTotalPhys / (1024 * 1024));
453 #else
454     iMemTotal = getmemorysize();
455 #endif
456
457     ostr << _W("Your variables are:") << std::endl << std::endl;
458     std::list<std::wstring>::const_iterator it = lstVar.begin();
459     int iWidth = ConfigVariable::getConsoleWidth();
460     int iCurrentWidth = 0;
461     for (int i = 1; it != lstVar.end(); ++it, i++)
462     {
463         if (iCurrentWidth + iVarLenMax + 1 > iWidth)
464         {
465             ostr << std::endl;
466             iCurrentWidth = 0;
467         }
468         ostr << std::setw(iVarLenMax + 1) << *it;
469         iCurrentWidth += iVarLenMax + 1;
470     }
471
472     os_swprintf(wcsVarElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
473     ostr << std::endl << wcsVarElem;
474
475     os_swprintf(wcsVarVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstVar.size(), nbMaxVar);
476     ostr << wcsVarVariable << std::endl;
477
478     ostr << std::endl << _W("Your global variables are:") << std::endl << std::endl;
479     it = lstGlobal.begin();
480     for (int i = 1; it != lstGlobal.end(); ++it, i++)
481     {
482         ostr << std::setw(iGlobalLenMax + 1) << *it;
483         if (i % 4 == 0)
484         {
485             ostr << std::endl;
486         }
487     }
488
489     ostr << std::endl;
490
491     os_swprintf(wcsGlobalElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
492     ostr << std::endl << wcsGlobalElem;
493
494     os_swprintf(wcsGlobalVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstGlobal.size(), nbMaxVar);
495     ostr << wcsGlobalVariable;
496 }
497
498 int Context::getScopeLevel()
499 {
500     return m_iLevel;
501 }
502
503 bool Context::isValidVariableName(const wchar_t* wcsVarName)
504 {
505     static const wchar_t FORBIDDEN_CHARS[] = L" */\\.,;:^@><=+-&|()~\n\t'\"";
506     if (wcslen(wcsVarName) == 0 || std::wcspbrk(wcsVarName, FORBIDDEN_CHARS) || isdigit(wcsVarName[0]))
507     {
508         return false;
509     }
510     return true;
511 }
512
513 bool Context::isValidVariableName(const char* name)
514 {
515     bool isValid = false;
516     wchar_t* wcsname = to_wide_string(name);
517     if (wcsname)
518     {
519         isValid = isValidVariableName(wcsname);
520         FREE(wcsname);
521     }
522
523     return isValid;
524 }
525
526 int Context::getLibsToVariableBrowser(std::list<Library*>& lst)
527 {
528     libraries.getVarsToVariableBrowser(lst);
529
530     std::list<Library*> toremove;
531     //list lib that have a variable with the same name
532     for (auto lib : lst)
533     {
534         Variable* var = getOrCreate(lib->getSymbol());
535         if (var->empty() == false)
536         {
537             toremove.push_back(lib);
538         }
539     }
540
541     //remove
542     for (auto lib : toremove)
543     {
544         lst.remove(lib);
545     }
546
547     return static_cast<int>(lst.size());
548 }
549
550 int Context::getVarsToVariableBrowser(std::list<Variable*>& lst)
551 {
552     variables.getVarsToVariableBrowser(lst);
553     return static_cast<int>(lst.size());
554 }
555
556 void Context::updateProtection(bool protect)
557 {
558     if (varStack.empty() == false)
559     {
560         VarList* lst = varStack.top();
561         for (auto var : *lst)
562         {
563             if (var.second->empty() == false)
564             {
565                 ScopedVariable* pSV = var.second->top();
566                 //only for current scope but normally vars in VarStack are in the current scope
567                 if (pSV->m_iLevel == m_iLevel)
568                 {
569                     pSV->protect = protect;
570                 }
571                 else
572                 {
573                     std::wcerr << L"heu ... " << var.first.getName() << std::endl;
574                 }
575             }
576         }
577     }
578 }
579
580 void Context::protect()
581 {
582     updateProtection(true);
583 }
584
585 void Context::unprotect()
586 {
587     updateProtection(false);
588 }
589
590 bool Context::isprotected(const Symbol& key)
591 {
592     return isprotected(getOrCreate(key));
593 }
594
595 bool Context::isprotected(Variable* _var)
596 {
597     //don't check protection on "ans"
598     if (_var->getSymbol().getName() == L"ans")
599     {
600         return false;
601     }
602
603     if (_var->empty() == false)
604     {
605         ScopedVariable* pSV = _var->top();
606         if (pSV->m_iLevel == m_iLevel && pSV->protect)
607         {
608             return true;
609         }
610     }
611     return false;
612 }
613
614 int Context::protectedVars(std::list<std::wstring>& vars)
615 {
616     return variables.getProtectedVarsName(vars);
617 }
618 }