[ast] improved polynomial display with unicode superscripts
[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  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13 *
14 */
15 #include <iomanip>
16 #include <cctype>
17
18 #include "context.hxx"
19 #include "internal.hxx"
20 #include "function.hxx"
21 #include "macro.hxx"
22 #include "macrofile.hxx"
23 #include "variables.hxx"
24 #include "configvariable.hxx"
25
26 extern "C"
27 {
28 #include "getmemory.h"
29 #include "os_string.h"
30 }
31
32 namespace symbol
33 {
34 Context* Context::me = nullptr;
35
36 Context::Context()
37 {
38     m_iLevel = SCOPE_ALL;
39     globals = new std::list<Symbol>();
40     console = nullptr;
41 }
42
43 Context::~Context()
44 {
45     while (!varStack.empty())
46     {
47         VarList * pVL = varStack.top();
48         pVL->clear();
49         delete pVL;
50         varStack.pop();
51     }
52     if (globals)
53     {
54         delete globals;
55     }
56 }
57
58 Context* Context::getInstance(void)
59 {
60     if (me == nullptr)
61     {
62         me = new Context();
63     }
64     return me;
65 }
66
67 void Context::destroyInstance(void)
68 {
69     if (me)
70     {
71         delete me;
72         me = nullptr;
73     }
74 }
75
76 void Context::scope_begin()
77 {
78     m_iLevel++;
79     if (m_iLevel == SCOPE_CONSOLE)
80     {
81         console = new VarList();
82         varStack.push(console);
83     }
84     else
85     {
86         varStack.push(new VarList());
87     }
88 }
89
90 void Context::clearAll()
91 {
92     libraries.clearAll();
93     variables.clearAll();
94 }
95
96 void Context::scope_end()
97 {
98     //clear varList of current scope
99     if (varStack.empty() == false)
100     {
101         clearCurrentScope(true);
102     }
103
104     m_iLevel--;
105
106     if (m_iLevel < SCOPE_CONSOLE)
107     {
108         console = nullptr;
109     }
110 }
111
112 bool Context::clearCurrentScope(bool _bClose)
113 {
114     if (varStack.empty())
115     {
116         return true;
117     }
118
119     VarList* varList = varStack.top();
120     std::list<Symbol> toremove;
121     for (auto var : *varList)
122     {
123         if (var.second->empty() == false)
124         {
125             ScopedVariable* pSV = var.second->top();
126             if (pSV->m_iLevel == m_iLevel && (_bClose || pSV->protect == false))
127             {
128                 types::InternalType * pIT = pSV->m_pIT;
129                 if (pIT->isLibrary())
130                 {
131                     // at scilab exit, pIT have a ref == 2 because
132                     // it is contains in libraries and variables.
133                     // call remove will set ref to 1 then the next
134                     // pIT->DecreaseRef(); pIT->killMe(); will delete it.
135                     libraries.remove(var.first, m_iLevel);
136                 }
137
138                 pIT->DecreaseRef();
139                 pIT->killMe();
140
141                 var.second->pop();
142                 delete pSV;
143                 toremove.push_back(var.first);
144             }
145         }
146     }
147
148     if (_bClose)
149     {
150         delete varList;
151         varStack.pop();
152     }
153     else
154     {
155         for (auto var : toremove)
156         {
157             varList->erase(var);
158         }
159     }
160     return true;
161 }
162
163 Variable* Context::getOrCreate(const Symbol& _key)
164 {
165     return variables.getOrCreate(_key);
166 }
167
168 int Context::getLevel(const Symbol & _key) const
169 {
170     VarList::iterator it = varStack.top()->find(_key);
171     if (it != varStack.top()->end())
172     {
173         if (!it->second->empty())
174         {
175             return it->second->top()->m_iLevel;
176         }
177     }
178     else
179     {
180         const int ret = variables.getLevel(_key);
181         if (ret == SCOPE_ALL)
182         {
183             return libraries.getLevel(_key);
184         }
185         else
186         {
187             return ret;
188         }
189     }
190
191     return SCOPE_ALL;
192 }
193
194 types::InternalType* Context::get(const Symbol& _key)
195 {
196     return get(_key, SCOPE_ALL);
197 }
198
199 types::InternalType* Context::get(const Variable* _var)
200 {
201     types::InternalType* pIT = _var->get();
202     if (pIT == NULL)
203     {
204         //look in libraries
205         pIT = libraries.get(_var->getSymbol(), SCOPE_ALL);
206         if (pIT && pIT->isLibrary() == false)
207         {
208             put((Variable*)_var, pIT);
209         }
210     }
211
212     return pIT;
213 }
214
215 types::InternalType* Context::get(const Symbol& _key, int _iLevel)
216 {
217     types::InternalType* pIT = NULL;
218     if (_iLevel == m_iLevel || _iLevel == SCOPE_ALL)
219     {
220         //look for in current VarList
221         VarList::iterator it = varStack.top()->find(_key);
222         if (it != varStack.top()->end())
223         {
224             if (it->second->empty() == false)
225             {
226                 pIT = it->second->get();
227             }
228         }
229     }
230
231     if (pIT == NULL)
232     {
233         pIT = variables.get(_key, _iLevel);
234         if (pIT == NULL)
235         {
236             //find in libraries
237             pIT = libraries.get(_key, _iLevel);
238         }
239     }
240     return pIT;
241 }
242
243 types::InternalType* Context::getCurrentLevel(const Symbol& _key)
244 {
245     return variables.get(_key, m_iLevel);
246 }
247
248 types::InternalType* Context::getCurrentLevel(Variable* _var)
249 {
250     return variables.get(_var, m_iLevel);
251 }
252
253 types::InternalType* Context::getAllButCurrentLevel(const Symbol& _key)
254 {
255     return variables.getAllButCurrentLevel(_key, m_iLevel);
256 }
257
258 types::InternalType* Context::getAtLevel(const Symbol& _key, int level)
259 {
260     return variables.getAllButCurrentLevel(_key, level == SCOPE_ALL ? m_iLevel : level + 1);
261 }
262
263 types::InternalType* Context::getFunction(const Symbol& _key)
264 {
265     return get(_key);
266 }
267
268 int Context::getFunctionList(std::list<Symbol>& lst, const std::wstring& _stModuleName)
269 {
270     return variables.getFunctionList(lst, _stModuleName, m_iLevel);
271 }
272
273 int Context::getFunctionList(std::list<types::Callable *> & lst, std::wstring _stModuleName)
274 {
275     return variables.getFunctionList(lst, _stModuleName, m_iLevel);
276 }
277
278 int Context::getConsoleVarsName(std::list<std::wstring>& lst)
279 {
280     if (console)
281     {
282         for (const auto & var : *console)
283         {
284             lst.push_back(var.first.getName());
285         }
286     }
287
288     return static_cast<int>(lst.size());
289 }
290
291 int Context::getVarsName(std::list<std::wstring>& lst)
292 {
293     variables.getVarsName(lst);
294     libraries.getVarsName(lst);
295
296     return static_cast<int>(lst.size());
297 }
298
299 int Context::getMacrosName(std::list<std::wstring>& lst)
300 {
301     variables.getMacrosName(lst);
302     libraries.getMacrosName(lst);
303     return static_cast<int>(lst.size());
304 }
305
306 int Context::getFunctionsName(std::list<std::wstring>& lst)
307 {
308     return variables.getFunctionsName(lst);
309 }
310
311 int Context::getVarsInfoForWho(std::list<std::pair<std::wstring, int>>& lst, bool bSorted)
312 {
313     int iZero = 0;
314     variables.getVarsInfoForWho(lst, &iZero, bSorted);
315     return static_cast<int>(lst.size());
316 }
317
318 int Context::getGlobalInfoForWho(std::list<std::pair<std::wstring, int>>& lst, bool bSorted)
319 {
320     int iZero = 0;
321     variables.getGlobalInfoForWho(lst, &iZero, bSorted);
322     return static_cast<int>(lst.size());
323 }
324
325 int Context::getWhereIs(std::list<std::wstring>& lst, const std::wstring& _str)
326 {
327     return libraries.whereis(lst, Symbol(_str));
328 }
329
330 int Context::getLibrariesList(std::list<std::wstring>& lst)
331 {
332     return libraries.librarieslist(lst);
333 }
334
335 bool Context::put(Variable* _var, types::InternalType* _pIT)
336 {
337     if (_pIT->isLibrary())
338     {
339         Library* lib = libraries.getOrCreate(_var->getSymbol());
340         lib->put((types::Library*)_pIT, m_iLevel);
341     }
342
343     if (_var->put(_pIT, m_iLevel) == false)
344     {
345         return false;
346     }
347
348     if (varStack.empty() == false)
349     {
350         (*varStack.top())[_var->getSymbol()] = _var;
351     }
352
353     return true;
354 }
355
356 bool Context::put(const Symbol& _key, types::InternalType* _pIT)
357 {
358     Variable* var = variables.getOrCreate(_key);
359
360     if (var->empty())
361     {
362         //box is empty, check if a macro from a library have this name.
363         //in this case, add it to context before set new value.
364         types::InternalType* pIT = get(_key);
365         if (pIT && (pIT->isMacroFile() || pIT->isMacro()))
366         {
367             put(var, pIT);
368             return put(var, _pIT);
369         }
370     }
371
372     return put(var, _pIT);
373 }
374
375 bool Context::remove(const Symbol& _key)
376 {
377     bool ret = variables.remove(_key, m_iLevel);
378
379     if (ret)
380     {
381         varStack.top()->erase(_key);
382     }
383
384     ret = ret | libraries.remove(_key, m_iLevel);
385     return ret;
386 }
387
388 bool Context::removeAll()
389 {
390     return clearCurrentScope(false);
391 }
392
393 bool Context::putInPreviousScope(Variable* _var, types::InternalType* _pIT)
394 {
395     //add variable in previous scope
396     if (variables.putInPreviousScope(_var, _pIT, m_iLevel - 1) == false)
397     {
398         return false;
399     }
400
401     //add variable in stack of using variables
402     if (varStack.empty() == false)
403     {
404         VarList * list = varStack.top();
405         varStack.pop();
406         if (varStack.empty() == false)
407         {
408             (*varStack.top())[_var->getSymbol()] = _var;
409         }
410         varStack.push(list);
411     }
412
413     if (_pIT->isLibrary())
414     {
415         libraries.putInPreviousScope(_var->getSymbol(), _pIT->getAs<types::Library>(), m_iLevel - 1);
416     }
417     return true;
418 }
419
420 bool Context::addFunction(types::Function *_info)
421 {
422     Variable* var = variables.getOrCreate(Symbol(_info->getName()));
423     variables.putInPreviousScope(var, _info, SCOPE_GATEWAY);
424     return true;
425 }
426
427 bool Context::addMacro(types::Macro *_info)
428 {
429     return put(Symbol(_info->getName()), _info);
430 }
431
432 bool Context::addMacroFile(types::MacroFile *_info)
433 {
434     return put(Symbol(_info->getName()), _info);
435 }
436
437 bool Context::isGlobalVisible(const Symbol& _key)
438 {
439     return variables.isGlobalVisible(_key, m_iLevel);
440 }
441
442 /*return global variable existance status*/
443 bool Context::isGlobal(const Symbol& _key)
444 {
445     return variables.isGlobal(_key, m_iLevel);
446 }
447
448 types::InternalType* Context::getGlobalValue(const Symbol& _key)
449 {
450     return variables.getGlobalValue(_key);
451 }
452
453 void Context::setGlobalVisible(const Symbol& _key, bool bVisible)
454 {
455     variables.setGlobalVisible(_key, bVisible, m_iLevel);
456 }
457
458 void Context::setGlobal(const Symbol& _key)
459 {
460     variables.setGlobal(_key);
461     globals->push_back(_key);
462 }
463
464 bool Context::removeGlobal(const Symbol& _key)
465 {
466     // skip permanant variables : %modalWarning, %toolboxes, %toolboxes_dir
467     if (_key.getName() == L"%modalWarning"  ||
468             _key.getName() == L"%toolboxes"     ||
469             _key.getName() == L"%toolboxes_dir")
470     {
471         return false;
472     }
473
474     variables.removeGlobal(_key, m_iLevel);
475     globals->remove(_key);
476     return true;
477 }
478
479 void Context::removeGlobalAll()
480 {
481     std::list<Symbol>::iterator it = globals->begin();
482
483     while (it != globals->end())
484     {
485         if (removeGlobal(*it) == false)
486         {
487             globals->remove(*it);
488         }
489
490         it = globals->begin();
491     }
492
493     globals->clear();
494
495     globals->emplace_back(L"%modalWarning");
496     globals->emplace_back(L"%toolboxes");
497     globals->emplace_back(L"%toolboxes_dir");
498 }
499
500 void Context::print(std::wostream& ostr, bool sorted) const
501 {
502     std::list<std::pair<std::wstring, int>> lstVar;
503     std::list<std::pair<std::wstring, int>> lstGlobal;
504     int iVarLenMax = 10; // initialise to the minimal value of padding
505     int iGlobalLenMax = 10; // initialise to the minimal value of padding
506     variables.getVarsInfoForWho(lstVar, &iVarLenMax);
507     variables.getGlobalInfoForWho(lstGlobal, &iGlobalLenMax);
508     //libraries.getVarsNameForWho(&lstVar, &iVarLenMax);
509
510     if (sorted)
511     {
512         lstVar.sort();
513         lstGlobal.sort();
514     }
515
516
517 #define strSize 64
518     wchar_t wcsVarElem[strSize];
519     wchar_t wcsVarVariable[strSize];
520     wchar_t wcsGlobalElem[strSize];
521     wchar_t wcsGlobalVariable[strSize];
522
523     int iMemTotal = 0;
524     int iMemUsed = 0;
525     int nbMaxVar = 0;
526
527 #ifdef _MSC_VER
528     MEMORYSTATUSEX statex;
529     statex.dwLength = sizeof(statex);
530     GlobalMemoryStatusEx(&statex);
531     iMemTotal = (int)(statex.ullTotalPhys / (1024 * 1024));
532 #else
533     iMemTotal = getmemorysize();
534 #endif
535
536     ostr << _W("Your variables are:") << std::endl << std::endl;
537     std::list<std::pair<std::wstring, int>>::const_iterator it = lstVar.begin();
538     int iWidth = ConfigVariable::getConsoleWidth();
539     int iCurrentWidth = 0;
540     for (int i = 1; it != lstVar.end(); ++it, i++)
541     {
542         if (iCurrentWidth + iVarLenMax + 1 > iWidth)
543         {
544             ostr << std::endl;
545             iCurrentWidth = 0;
546         }
547         ostr << std::setw(iVarLenMax + 1) << it->first;
548         iCurrentWidth += iVarLenMax + 1;
549     }
550
551     os_swprintf(wcsVarElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
552     ostr << std::endl << wcsVarElem;
553
554     os_swprintf(wcsVarVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstVar.size(), nbMaxVar);
555     ostr << wcsVarVariable << std::endl;
556
557     ostr << std::endl << _W("Your global variables are:") << std::endl << std::endl;
558     it = lstGlobal.begin();
559     for (int i = 1; it != lstGlobal.end(); ++it, i++)
560     {
561         ostr << std::setw(iGlobalLenMax + 1) << it->first;
562         if (i % 4 == 0)
563         {
564             ostr << std::endl;
565         }
566     }
567
568     ostr << std::endl;
569
570     os_swprintf(wcsGlobalElem, strSize, _W(" using %10d elements out of  %10d.\n").c_str(), iMemUsed, iMemTotal);
571     ostr << std::endl << wcsGlobalElem;
572
573     os_swprintf(wcsGlobalVariable, strSize, _W(" and   %10d variables out of %10d.\n").c_str(), lstGlobal.size(), nbMaxVar);
574     ostr << wcsGlobalVariable;
575 }
576
577 int Context::getScopeLevel()
578 {
579     return m_iLevel;
580 }
581
582 bool Context::isValidVariableName(const wchar_t* wcsVarName)
583 {
584     static const wchar_t FORBIDDEN_CHARS[] = L" */\\.,;:^@><=+-&|()~\n\t'\"";
585     if (wcslen(wcsVarName) == 0 || std::wcspbrk(wcsVarName, FORBIDDEN_CHARS) || isdigit(wcsVarName[0]))
586     {
587         return false;
588     }
589     return true;
590 }
591
592 bool Context::isValidVariableName(const char* name)
593 {
594     bool isValid = false;
595     wchar_t* wcsname = to_wide_string(name);
596     if (wcsname)
597     {
598         isValid = isValidVariableName(wcsname);
599         FREE(wcsname);
600     }
601
602     return isValid;
603 }
604
605 int Context::getLibsToVariableBrowser(std::list<Library*>& lst)
606 {
607     libraries.getVarsToVariableBrowser(lst);
608
609     std::list<Library*> toremove;
610     //list lib that have a variable with the same name
611     for (auto lib : lst)
612     {
613         Variable* var = getOrCreate(lib->getSymbol());
614         if (var->empty() == false)
615         {
616             toremove.push_back(lib);
617         }
618     }
619
620     //remove
621     for (auto lib : toremove)
622     {
623         lst.remove(lib);
624     }
625
626     return static_cast<int>(lst.size());
627 }
628
629 int Context::getVarsToVariableBrowser(std::list<Variable*>& lst)
630 {
631     variables.getVarsToVariableBrowser(lst);
632     return static_cast<int>(lst.size());
633 }
634
635 int Context::getCurrentScope(std::list<std::pair<std::wstring, int>>& lst, bool bSorted)
636 {
637     return variables.getCurrentScope(lst, m_iLevel, bSorted);
638 }
639
640 void Context::updateProtection(bool protect)
641 {
642     if (varStack.empty() == false)
643     {
644         VarList* lst = varStack.top();
645         for (auto var : *lst)
646         {
647             if (var.second->empty() == false)
648             {
649                 ScopedVariable* pSV = var.second->top();
650                 //only for current scope but normally vars in VarStack are in the current scope
651                 if (pSV->m_iLevel == m_iLevel)
652                 {
653                     pSV->protect = protect;
654                 }
655                 else
656                 {
657                     std::wcerr << L"heu ... " << var.first.getName() << std::endl;
658                 }
659             }
660         }
661     }
662 }
663
664 void Context::protect()
665 {
666     updateProtection(true);
667 }
668
669 void Context::unprotect()
670 {
671     updateProtection(false);
672 }
673
674 bool Context::isprotected(const Symbol& key)
675 {
676     return isprotected(getOrCreate(key));
677 }
678
679 bool Context::isprotected(Variable* _var)
680 {
681     //don't check protection on "ans"
682     if (_var->getSymbol().getName() == L"ans")
683     {
684         return false;
685     }
686
687     if (_var->empty() == false)
688     {
689         ScopedVariable* pSV = _var->top();
690         if (pSV->m_iLevel == m_iLevel && pSV->protect)
691         {
692             return true;
693         }
694     }
695     return false;
696 }
697
698 int Context::protectedVars(std::list<std::wstring>& vars)
699 {
700     return variables.getProtectedVarsName(vars);
701 }
702 }