Lexer: slightly improve strings & comments lexing
[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
323     if (_pIT->isLibrary())
324     {
325         libraries.putInPreviousScope(_var->getSymbol(), _pIT->getAs<types::Library>(), m_iLevel - 1);
326     }
327     return true;
328 }
329
330 bool Context::addFunction(types::Function *_info)
331 {
332     Variable* var = variables.getOrCreate(Symbol(_info->getName()));
333     variables.putInPreviousScope(var, _info, 0);
334     return true;
335 }
336
337 bool Context::addMacro(types::Macro *_info)
338 {
339     put(Symbol(_info->getName()), _info);
340     return true;
341 }
342
343 bool Context::addMacroFile(types::MacroFile *_info)
344 {
345     put(Symbol(_info->getName()), _info);
346     return true;
347 }
348
349 bool Context::isGlobalVisible(const Symbol& _key)
350 {
351     return variables.isGlobalVisible(_key, m_iLevel);
352 }
353
354 /*return global variable existance status*/
355 bool Context::isGlobal(const Symbol& _key)
356 {
357     return variables.isGlobal(_key, m_iLevel);
358 }
359
360 types::InternalType* Context::getGlobalValue(const Symbol& _key)
361 {
362     return variables.getGlobalValue(_key);
363 }
364
365 void Context::setGlobalVisible(const Symbol& _key, bool bVisible)
366 {
367     variables.setGlobalVisible(_key, bVisible, m_iLevel);
368 }
369
370 void Context::setGlobal(const Symbol& _key)
371 {
372     variables.setGlobal(_key);
373     globals->push_back(_key);
374 }
375
376 void Context::removeGlobal(const Symbol& _key)
377 {
378     variables.removeGlobal(_key, m_iLevel);
379     globals->remove(_key);
380 }
381
382 void Context::removeGlobalAll()
383 {
384     std::list<Symbol>::iterator it = globals->begin();
385     while (it != globals->end())
386     {
387         removeGlobal(*it);
388         it = globals->begin();
389     }
390
391     globals->clear();
392 }
393
394 void Context::print(std::wostream& ostr, bool sorted) const
395 {
396     std::list<std::wstring> lstVar;
397     std::list<std::wstring> lstGlobal;
398     int iVarLenMax = 10; // initialise to the minimal value of padding
399     int iGlobalLenMax = 10; // initialise to the minimal value of padding
400     variables.getVarsNameForWho(lstVar, &iVarLenMax);
401     variables.getGlobalNameForWho(lstGlobal, &iGlobalLenMax);
402     libraries.getVarsNameForWho(&lstVar, &iVarLenMax);
403
404     if (sorted)
405     {
406         lstVar.sort();
407         lstGlobal.sort();
408     }
409
410 #define strSize 64
411     wchar_t wcsVarElem[strSize];
412     wchar_t wcsVarVariable[strSize];
413     wchar_t wcsGlobalElem[strSize];
414     wchar_t wcsGlobalVariable[strSize];
415
416     int iMemTotal = 0;
417     int iMemUsed = 0;
418     int nbMaxVar = 0;
419
420 #ifdef _MSC_VER
421     MEMORYSTATUSEX statex;
422     statex.dwLength = sizeof(statex);
423     GlobalMemoryStatusEx(&statex);
424     iMemTotal = (int)(statex.ullTotalPhys / (1024 * 1024));
425 #else
426     iMemTotal = getmemorysize();
427 #endif
428
429     ostr << _W("Your variables are:") << std::endl << std::endl;
430     std::list<std::wstring>::const_iterator it = lstVar.begin();
431     int iWidth = ConfigVariable::getConsoleWidth();
432     int iCurrentWidth = 0;
433     for (int i = 1; it != lstVar.end(); ++it, i++)
434     {
435         if (iCurrentWidth + iVarLenMax + 1 > iWidth)
436         {
437             ostr << std::endl;
438             iCurrentWidth = 0;
439         }
440         ostr << std::setw(iVarLenMax + 1) << *it;
441         iCurrentWidth += iVarLenMax + 1;
442     }
443
444     os_swprintf(wcsVarElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
445     ostr << std::endl << wcsVarElem;
446
447     os_swprintf(wcsVarVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstVar.size(), nbMaxVar);
448     ostr << wcsVarVariable << std::endl;
449
450     ostr << std::endl << _W("Your global variables are:") << std::endl << std::endl;
451     it = lstGlobal.begin();
452     for (int i = 1; it != lstGlobal.end(); ++it, i++)
453     {
454         ostr << std::setw(iGlobalLenMax + 1) << *it;
455         if (i % 4 == 0)
456         {
457             ostr << std::endl;
458         }
459     }
460
461     ostr << std::endl;
462
463     os_swprintf(wcsGlobalElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
464     ostr << std::endl << wcsGlobalElem;
465
466     os_swprintf(wcsGlobalVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstGlobal.size(), nbMaxVar);
467     ostr << wcsGlobalVariable;
468 }
469
470 int Context::getScopeLevel()
471 {
472     return m_iLevel;
473 }
474
475 bool Context::isValidVariableName(const wchar_t* wcsVarName)
476 {
477     static const wchar_t FORBIDDEN_CHARS[] = L" */\\.,;:^@><=+-&|()~\n\t'\"";
478     if (wcslen(wcsVarName) == 0 || std::wcspbrk(wcsVarName, FORBIDDEN_CHARS) || isdigit(wcsVarName[0]))
479     {
480         return false;
481     }
482     return true;
483 }
484
485 bool Context::isValidVariableName(const char* name)
486 {
487     bool isValid = false;
488     wchar_t* wcsname = to_wide_string(name);
489     if (wcsname)
490     {
491         isValid = isValidVariableName(wcsname);
492         FREE(wcsname);
493     }
494
495     return isValid;
496 }
497
498 int Context::getLibsToVariableBrowser(std::list<Library*>& lst)
499 {
500     libraries.getVarsToVariableBrowser(lst);
501
502     std::list<Library*> toremove;
503     //list lib that have a variable with the same name
504     for (auto lib : lst)
505     {
506         Variable* var = getOrCreate(lib->getSymbol());
507         if (var->empty() == false)
508         {
509             toremove.push_back(lib);
510         }
511     }
512
513     //remove
514     for (auto lib : toremove)
515     {
516         lst.remove(lib);
517     }
518
519     return static_cast<int>(lst.size());
520 }
521
522 int Context::getVarsToVariableBrowser(std::list<Variable*>& lst)
523 {
524     variables.getVarsToVariableBrowser(lst);
525     return static_cast<int>(lst.size());
526 }
527
528 void Context::updateProtection(bool protect)
529 {
530     if (varStack.empty() == false)
531     {
532         VarList* lst = varStack.top();
533         for (auto var : *lst)
534         {
535             if (var.second->empty() == false)
536             {
537                 ScopedVariable* pSV = var.second->top();
538                 //only for current scope but normally vars in VarStack are in the current scope
539                 if (pSV->m_iLevel == m_iLevel)
540                 {
541                     pSV->protect = protect;
542                 }
543                 else
544                 {
545                     std::wcerr << L"heu ... " << var.first.getName() << std::endl;
546                 }
547             }
548         }
549     }
550 }
551
552 void Context::protect()
553 {
554     updateProtection(true);
555 }
556
557 void Context::unprotect()
558 {
559     updateProtection(false);
560 }
561
562 bool Context::isprotected(const Symbol& key)
563 {
564     return isprotected(getOrCreate(key));
565 }
566
567 bool Context::isprotected(Variable* _var)
568 {
569     //don't check protection on "ans"
570     if (_var->getSymbol().getName() == L"ans")
571     {
572         return false;
573     }
574
575     if (_var->empty() == false)
576     {
577         ScopedVariable* pSV = _var->top();
578         if (pSV->m_iLevel == m_iLevel && pSV->protect)
579         {
580             return true;
581         }
582     }
583     return false;
584 }
585
586 int Context::protectedVars(std::list<std::wstring>& vars)
587 {
588     return variables.getProtectedVarsName(vars);
589 }
590 }