343b2b4e96a71ac21b96b3ec418694fa84e51e66
[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::map<Symbol, Variable*>::iterator it = varList->begin();
104     for (; it != varList->end() ; ++it)
105     {
106         if (it->second->empty() == false && it->second->top()->m_iLevel == m_iLevel)
107         {
108             ScopedVariable * pSV = it->second->top();
109             types::InternalType * pIT = pSV->m_pIT;
110             pIT->DecreaseRef();
111             pIT->killMe();
112             it->second->pop();
113             delete pSV;
114         }
115     }
116
117     varList->clear();
118
119     if (_bClose)
120     {
121         delete varList;
122         varStack.pop();
123     }
124
125     return true;
126 }
127
128 Variable* Context::getOrCreate(const Symbol& _key)
129 {
130     return variables.getOrCreate(_key);
131 }
132
133 types::InternalType* Context::get(const Symbol& _key)
134 {
135     return get(_key, -1);
136 }
137
138 types::InternalType* Context::get(const Variable* _var)
139 {
140     types::InternalType* pIT = _var->get();
141     if (pIT == NULL)
142     {
143         //look in libraries
144         pIT = libraries.get(_var->getSymbol(), -1);
145         if (pIT && pIT->isLibrary() == false)
146         {
147             put((Variable*)_var, pIT);
148         }
149     }
150
151     return pIT;
152 }
153
154 types::InternalType* Context::get(const Symbol& _key, int _iLevel)
155 {
156     types::InternalType* pIT = NULL;
157     if (_iLevel == m_iLevel || _iLevel == -1)
158     {
159         //look for in current VarList
160         VarList::iterator it = varStack.top()->find(_key);
161         if (it != varStack.top()->end())
162         {
163             if (it->second->empty() == false)
164             {
165                 return it->second->top()->m_pIT;
166             }
167         }
168     }
169
170     if (pIT == NULL)
171     {
172         pIT = variables.get(_key, _iLevel);
173         if (pIT == NULL)
174         {
175             //find in libraries
176             pIT = libraries.get(_key, _iLevel);
177         }
178     }
179
180     return pIT;
181 }
182
183 types::InternalType* Context::getCurrentLevel(const Symbol& _key)
184 {
185     return variables.get(_key, m_iLevel);
186 }
187
188 types::InternalType* Context::getAllButCurrentLevel(const Symbol& _key)
189 {
190     return variables.getAllButCurrentLevel(_key, m_iLevel);
191 }
192
193 types::InternalType* Context::getFunction(const Symbol& _key)
194 {
195     return get(_key);
196 }
197
198 std::list<Symbol>* Context::getFunctionList(std::wstring _stModuleName)
199 {
200     return variables.getFunctionList(_stModuleName, m_iLevel);
201 }
202
203 std::list<std::wstring>* Context::getVarsName()
204 {
205     std::list<std::wstring>* vars = variables.getVarsName();
206     std::list<std::wstring>* libs = libraries.getVarsName();
207     vars->insert(vars->end(), libs->begin(), libs->end());
208     delete libs;
209
210     for (auto it = globals->begin(), itEnd = globals->end(); it != itEnd; ++it)
211     {
212         vars->push_back((*it).getName());
213     }
214     return vars;
215 }
216
217 std::list<std::wstring>* Context::getMacrosName()
218 {
219     std::list<std::wstring>* vars = variables.getMacrosName();
220     std::list<std::wstring>* libs = libraries.getMacrosName();
221     vars->insert(vars->end(), libs->begin(), libs->end());
222     delete libs;
223     return vars;
224 }
225
226 std::list<std::wstring>* Context::getFunctionsName()
227 {
228     return variables.getFunctionsName();
229 }
230
231 std::list<std::wstring>* Context::getVarsNameForWho(bool bSorted)
232 {
233     std::list<std::wstring>* lstVar = new std::list<std::wstring>();
234     int iZero = 0;
235     variables.getVarsNameForWho(lstVar, &iZero, NULL, &iZero, bSorted);
236     return lstVar;
237 }
238
239 std::list<std::wstring>* Context::getGlobalNameForWho(bool bSorted)
240 {
241     std::list<std::wstring>* lstVar = new std::list<std::wstring>();
242     int iZero = 0;
243     variables.getVarsNameForWho(NULL, &iZero, lstVar, &iZero, bSorted);
244     return lstVar;
245 }
246
247 void Context::put(Variable* _var, types::InternalType* _pIT)
248 {
249     if (_pIT->isLibrary())
250     {
251         Library* lib = libraries.getOrCreate(_var->getSymbol());
252         lib->put((types::Library*)_pIT, m_iLevel);
253     }
254     else
255     {
256         _var->put(_pIT, m_iLevel);
257         if (varStack.empty() == false)
258         {
259             (*varStack.top())[_var->getSymbol()] = _var;
260         }
261     }
262 }
263
264 void Context::put(const Symbol& _key, types::InternalType* _pIT)
265 {
266     Variable* var = variables.getOrCreate(_key);
267     put(var, _pIT);
268 }
269
270 bool Context::remove(const Symbol& _key)
271 {
272     bool ret = variables.remove(_key, m_iLevel);
273
274     if (ret)
275     {
276         varStack.top()->erase(_key);
277     }
278
279     ret = ret | libraries.remove(_key, m_iLevel);
280     return ret;
281 }
282
283 bool Context::removeAll()
284 {
285     return clearCurrentScope(false);
286 }
287
288 bool Context::putInPreviousScope(Variable* _var, types::InternalType* _pIT)
289 {
290     //add variable in previous scope
291     variables.putInPreviousScope(_var, _pIT, m_iLevel - 1);
292
293     //add variable in stack of using variables
294     if (varStack.empty() == false)
295     {
296         VarList * list = varStack.top();
297         varStack.pop();
298         if (varStack.empty() == false)
299         {
300             (*varStack.top())[_var->getSymbol()] = _var;
301             varStack.push(list);
302         }
303     }
304     return true;
305 }
306
307 bool Context::addFunction(types::Function *_info)
308 {
309     Variable* var = variables.getOrCreate(Symbol(_info->getName()));
310     variables.putInPreviousScope(var, _info, 0);
311     return true;
312 }
313
314 bool Context::addMacro(types::Macro *_info)
315 {
316     put(Symbol(_info->getName()), _info);
317     return true;
318 }
319
320 bool Context::addMacroFile(types::MacroFile *_info)
321 {
322     put(Symbol(_info->getName()), _info);
323     return true;
324 }
325
326 bool Context::isGlobalVisible(const Symbol& _key)
327 {
328     return variables.isGlobalVisible(_key, m_iLevel);
329 }
330
331 /*return global variable existance status*/
332 bool Context::isGlobal(const Symbol& _key)
333 {
334     return variables.isGlobal(_key, m_iLevel);
335 }
336
337 types::InternalType* Context::getGlobalValue(const Symbol& _key)
338 {
339     return variables.getGlobalValue(_key);
340 }
341
342 void Context::setGlobalVisible(const Symbol& _key, bool bVisible)
343 {
344     variables.setGlobalVisible(_key, bVisible, m_iLevel);
345 }
346
347 void Context::setGlobal(const Symbol& _key)
348 {
349     variables.setGlobal(_key);
350     globals->push_back(_key);
351 }
352
353 void Context::removeGlobal(const Symbol& _key)
354 {
355     variables.removeGlobal(_key, m_iLevel);
356     globals->remove(_key);
357 }
358
359 void Context::removeGlobalAll()
360 {
361     std::list<Symbol>::iterator it = globals->begin();
362     while (it != globals->end())
363     {
364         removeGlobal(*it);
365         it = globals->begin();
366     }
367
368     globals->clear();
369 }
370
371 void Context::print(std::wostream& ostr, bool sorted) const
372 {
373     std::list<std::wstring> lstVar;
374     std::list<std::wstring> lstGlobal;
375     int iVarLenMax = 10; // initialise to the minimal value of padding
376     int iGlobalLenMax = 10; // initialise to the minimal value of padding
377     variables.getVarsNameForWho(&lstVar, &iVarLenMax, &lstGlobal, &iGlobalLenMax);
378     libraries.getVarsNameForWho(&lstVar, &iVarLenMax);
379
380     if (sorted)
381     {
382         lstVar.sort();
383         lstGlobal.sort();
384     }
385
386 #define strSize 64
387     wchar_t wcsVarElem[strSize];
388     wchar_t wcsVarVariable[strSize];
389     wchar_t wcsGlobalElem[strSize];
390     wchar_t wcsGlobalVariable[strSize];
391
392     int iMemTotal = 0;
393     int iMemUsed  = 0;
394     int nbMaxVar  = 0;
395
396 #ifdef _MSC_VER
397     MEMORYSTATUSEX statex;
398     statex.dwLength = sizeof(statex);
399     GlobalMemoryStatusEx (&statex);
400     iMemTotal = (int)(statex.ullTotalPhys / (1024 * 1024));
401 #else
402     iMemTotal = getmemorysize();
403 #endif
404
405     ostr << _W("Your variables are:") << std::endl << std::endl;
406     std::list<std::wstring>::const_iterator it = lstVar.begin();
407     int iWidth = ConfigVariable::getConsoleWidth();
408     int iCurrentWidth = 0;
409     for (int i = 1; it != lstVar.end(); ++it, i++)
410     {
411         if (iCurrentWidth + iVarLenMax + 1 > iWidth)
412         {
413             ostr << std::endl;
414             iCurrentWidth = 0;
415         }
416         ostr << std::setw(iVarLenMax + 1) << *it;
417         iCurrentWidth += iVarLenMax + 1;
418     }
419
420     os_swprintf(wcsVarElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
421     ostr << std::endl << wcsVarElem;
422
423     os_swprintf(wcsVarVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstVar.size(), nbMaxVar);
424     ostr << wcsVarVariable << std::endl;
425
426     ostr << std::endl << _W("Your global variables are:") << std::endl << std::endl;
427     it = lstGlobal.begin();
428     for (int i = 1; it != lstGlobal.end(); ++it, i++)
429     {
430         ostr << std::setw(iGlobalLenMax + 1) << *it;
431         if (i % 4 == 0)
432         {
433             ostr << std::endl;
434         }
435     }
436
437     ostr << std::endl;
438
439     os_swprintf(wcsGlobalElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
440     ostr << std::endl << wcsGlobalElem;
441
442     os_swprintf(wcsGlobalVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstGlobal.size(), nbMaxVar);
443     ostr << wcsGlobalVariable;
444 }
445
446 int Context::getScopeLevel()
447 {
448     return m_iLevel;
449 }
450
451 bool Context::isValidVariableName(const wchar_t* wcsVarName)
452 {
453     static const wchar_t FORBIDDEN_CHARS[] = L" */\\.,;:^@><=+-&|()~\n\t'\"";
454     if (wcslen(wcsVarName) == 0 || std::wcspbrk(wcsVarName, FORBIDDEN_CHARS) || isdigit(wcsVarName[0]))
455     {
456         return false;
457     }
458     return true;
459 }
460
461 bool Context::isValidVariableName(const char* name)
462 {
463     bool isValid = false;
464     wchar_t* wcsname = to_wide_string(name);
465     if (wcsname)
466     {
467         isValid = isValidVariableName(wcsname);
468         FREE(wcsname);
469     }
470
471     return isValid;
472 }
473 }