7254991a127f4f9e1f05b6f20d3b1c4408048670
[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 std::list<std::wstring>* Context::getWhereIs(const std::wstring& _str)
248 {
249     return libraries.whereis(Symbol(_str));
250 }
251
252 void Context::put(Variable* _var, types::InternalType* _pIT)
253 {
254     if (_pIT->isLibrary())
255     {
256         Library* lib = libraries.getOrCreate(_var->getSymbol());
257         lib->put((types::Library*)_pIT, m_iLevel);
258     }
259     else
260     {
261         _var->put(_pIT, m_iLevel);
262         if (varStack.empty() == false)
263         {
264             (*varStack.top())[_var->getSymbol()] = _var;
265         }
266     }
267 }
268
269 void Context::put(const Symbol& _key, types::InternalType* _pIT)
270 {
271     Variable* var = variables.getOrCreate(_key);
272     put(var, _pIT);
273 }
274
275 bool Context::remove(const Symbol& _key)
276 {
277     bool ret = variables.remove(_key, m_iLevel);
278
279     if (ret)
280     {
281         varStack.top()->erase(_key);
282     }
283
284     ret = ret | libraries.remove(_key, m_iLevel);
285     return ret;
286 }
287
288 bool Context::removeAll()
289 {
290     return clearCurrentScope(false);
291 }
292
293 bool Context::putInPreviousScope(Variable* _var, types::InternalType* _pIT)
294 {
295     //add variable in previous scope
296     variables.putInPreviousScope(_var, _pIT, m_iLevel - 1);
297
298     //add variable in stack of using variables
299     if (varStack.empty() == false)
300     {
301         VarList * list = varStack.top();
302         varStack.pop();
303         if (varStack.empty() == false)
304         {
305             (*varStack.top())[_var->getSymbol()] = _var;
306             varStack.push(list);
307         }
308     }
309     return true;
310 }
311
312 bool Context::addFunction(types::Function *_info)
313 {
314     Variable* var = variables.getOrCreate(Symbol(_info->getName()));
315     variables.putInPreviousScope(var, _info, 0);
316     return true;
317 }
318
319 bool Context::addMacro(types::Macro *_info)
320 {
321     put(Symbol(_info->getName()), _info);
322     return true;
323 }
324
325 bool Context::addMacroFile(types::MacroFile *_info)
326 {
327     put(Symbol(_info->getName()), _info);
328     return true;
329 }
330
331 bool Context::isGlobalVisible(const Symbol& _key)
332 {
333     return variables.isGlobalVisible(_key, m_iLevel);
334 }
335
336 /*return global variable existance status*/
337 bool Context::isGlobal(const Symbol& _key)
338 {
339     return variables.isGlobal(_key, m_iLevel);
340 }
341
342 types::InternalType* Context::getGlobalValue(const Symbol& _key)
343 {
344     return variables.getGlobalValue(_key);
345 }
346
347 void Context::setGlobalVisible(const Symbol& _key, bool bVisible)
348 {
349     variables.setGlobalVisible(_key, bVisible, m_iLevel);
350 }
351
352 void Context::setGlobal(const Symbol& _key)
353 {
354     variables.setGlobal(_key);
355     globals->push_back(_key);
356 }
357
358 void Context::removeGlobal(const Symbol& _key)
359 {
360     variables.removeGlobal(_key, m_iLevel);
361     globals->remove(_key);
362 }
363
364 void Context::removeGlobalAll()
365 {
366     std::list<Symbol>::iterator it = globals->begin();
367     while (it != globals->end())
368     {
369         removeGlobal(*it);
370         it = globals->begin();
371     }
372
373     globals->clear();
374 }
375
376 void Context::print(std::wostream& ostr, bool sorted) const
377 {
378     std::list<std::wstring> lstVar;
379     std::list<std::wstring> lstGlobal;
380     int iVarLenMax = 10; // initialise to the minimal value of padding
381     int iGlobalLenMax = 10; // initialise to the minimal value of padding
382     variables.getVarsNameForWho(&lstVar, &iVarLenMax, &lstGlobal, &iGlobalLenMax);
383     libraries.getVarsNameForWho(&lstVar, &iVarLenMax);
384
385     if (sorted)
386     {
387         lstVar.sort();
388         lstGlobal.sort();
389     }
390
391 #define strSize 64
392     wchar_t wcsVarElem[strSize];
393     wchar_t wcsVarVariable[strSize];
394     wchar_t wcsGlobalElem[strSize];
395     wchar_t wcsGlobalVariable[strSize];
396
397     int iMemTotal = 0;
398     int iMemUsed  = 0;
399     int nbMaxVar  = 0;
400
401 #ifdef _MSC_VER
402     MEMORYSTATUSEX statex;
403     statex.dwLength = sizeof(statex);
404     GlobalMemoryStatusEx (&statex);
405     iMemTotal = (int)(statex.ullTotalPhys / (1024 * 1024));
406 #else
407     iMemTotal = getmemorysize();
408 #endif
409
410     ostr << _W("Your variables are:") << std::endl << std::endl;
411     std::list<std::wstring>::const_iterator it = lstVar.begin();
412     int iWidth = ConfigVariable::getConsoleWidth();
413     int iCurrentWidth = 0;
414     for (int i = 1; it != lstVar.end(); ++it, i++)
415     {
416         if (iCurrentWidth + iVarLenMax + 1 > iWidth)
417         {
418             ostr << std::endl;
419             iCurrentWidth = 0;
420         }
421         ostr << std::setw(iVarLenMax + 1) << *it;
422         iCurrentWidth += iVarLenMax + 1;
423     }
424
425     os_swprintf(wcsVarElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
426     ostr << std::endl << wcsVarElem;
427
428     os_swprintf(wcsVarVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstVar.size(), nbMaxVar);
429     ostr << wcsVarVariable << std::endl;
430
431     ostr << std::endl << _W("Your global variables are:") << std::endl << std::endl;
432     it = lstGlobal.begin();
433     for (int i = 1; it != lstGlobal.end(); ++it, i++)
434     {
435         ostr << std::setw(iGlobalLenMax + 1) << *it;
436         if (i % 4 == 0)
437         {
438             ostr << std::endl;
439         }
440     }
441
442     ostr << std::endl;
443
444     os_swprintf(wcsGlobalElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
445     ostr << std::endl << wcsGlobalElem;
446
447     os_swprintf(wcsGlobalVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstGlobal.size(), nbMaxVar);
448     ostr << wcsGlobalVariable;
449 }
450
451 int Context::getScopeLevel()
452 {
453     return m_iLevel;
454 }
455
456 bool Context::isValidVariableName(const wchar_t* wcsVarName)
457 {
458     static const wchar_t FORBIDDEN_CHARS[] = L" */\\.,;:^@><=+-&|()~\n\t'\"";
459     if (wcslen(wcsVarName) == 0 || std::wcspbrk(wcsVarName, FORBIDDEN_CHARS) || isdigit(wcsVarName[0]))
460     {
461         return false;
462     }
463     return true;
464 }
465
466 bool Context::isValidVariableName(const char* name)
467 {
468     bool isValid = false;
469     wchar_t* wcsname = to_wide_string(name);
470     if (wcsname)
471     {
472         isValid = isValidVariableName(wcsname);
473         FREE(wcsname);
474     }
475
476     return isValid;
477 }
478 }