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