2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2008-2008 - DIGITEO - Antoine ELIAS
5 * Copyright (C) 2012 - 2016 - Scilab Enterprises
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.
18 #include "context.hxx"
19 #include "internal.hxx"
20 #include "function.hxx"
22 #include "macrofile.hxx"
23 #include "variables.hxx"
24 #include "configvariable.hxx"
28 #include "getmemory.h"
29 #include "os_string.h"
34 Context* Context::me = nullptr;
39 globals = new std::list<Symbol>();
45 while (!varStack.empty())
47 VarList * pVL = varStack.top();
58 Context* Context::getInstance(void)
67 void Context::destroyInstance(void)
76 void Context::scope_begin()
79 if (m_iLevel == SCOPE_CONSOLE)
81 console = new VarList();
82 varStack.push(console);
86 varStack.push(new VarList());
90 void Context::clearAll()
96 void Context::scope_end()
98 //clear varList of current scope
99 if (varStack.empty() == false)
101 clearCurrentScope(true);
106 if (m_iLevel < SCOPE_CONSOLE)
112 bool Context::clearCurrentScope(bool _bClose)
114 if (varStack.empty())
119 VarList* varList = varStack.top();
120 std::list<Symbol> toremove;
121 for (auto var : *varList)
123 if (var.second->empty() == false)
125 ScopedVariable* pSV = var.second->top();
126 if (pSV->m_iLevel == m_iLevel && (_bClose || pSV->protect == false))
128 types::InternalType * pIT = pSV->m_pIT;
129 if (pIT->isLibrary())
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);
143 toremove.push_back(var.first);
155 for (auto var : toremove)
163 Variable* Context::getOrCreate(const Symbol& _key)
165 return variables.getOrCreate(_key);
168 int Context::getLevel(const Symbol & _key) const
170 VarList::iterator it = varStack.top()->find(_key);
171 if (it != varStack.top()->end())
173 if (!it->second->empty())
175 return it->second->top()->m_iLevel;
180 const int ret = variables.getLevel(_key);
181 if (ret == SCOPE_ALL)
183 return libraries.getLevel(_key);
194 types::InternalType* Context::get(const Symbol& _key)
196 return get(_key, SCOPE_ALL);
199 types::InternalType* Context::get(const Variable* _var)
201 types::InternalType* pIT = _var->get();
205 pIT = libraries.get(_var->getSymbol(), SCOPE_ALL);
206 if (pIT && pIT->isLibrary() == false)
208 put((Variable*)_var, pIT);
215 types::InternalType* Context::get(const Symbol& _key, int _iLevel)
217 types::InternalType* pIT = NULL;
218 if (_iLevel == m_iLevel || _iLevel == SCOPE_ALL)
220 //look for in current VarList
221 VarList::iterator it = varStack.top()->find(_key);
222 if (it != varStack.top()->end())
224 if (it->second->empty() == false)
226 pIT = it->second->get();
233 pIT = variables.get(_key, _iLevel);
237 pIT = libraries.get(_key, _iLevel);
243 types::InternalType* Context::getCurrentLevel(const Symbol& _key)
245 return variables.get(_key, m_iLevel);
248 types::InternalType* Context::getCurrentLevel(Variable* _var)
250 return variables.get(_var, m_iLevel);
253 types::InternalType* Context::getAllButCurrentLevel(const Symbol& _key)
255 return variables.getAllButCurrentLevel(_key, m_iLevel);
258 types::InternalType* Context::getAtLevel(const Symbol& _key, int level)
260 return variables.getAllButCurrentLevel(_key, level == SCOPE_ALL ? m_iLevel : level + 1);
263 types::InternalType* Context::getFunction(const Symbol& _key)
268 int Context::getFunctionList(std::list<Symbol>& lst, const std::wstring& _stModuleName)
270 return variables.getFunctionList(lst, _stModuleName, m_iLevel);
273 int Context::getFunctionList(std::list<types::Callable *> & lst, std::wstring _stModuleName)
275 return variables.getFunctionList(lst, _stModuleName, m_iLevel);
278 int Context::getConsoleVarsName(std::list<std::wstring>& lst)
282 for (const auto & var : *console)
284 lst.push_back(var.first.getName());
288 return static_cast<int>(lst.size());
291 int Context::getVarsName(std::list<std::wstring>& lst)
293 variables.getVarsName(lst);
294 libraries.getVarsName(lst);
296 return static_cast<int>(lst.size());
299 int Context::getMacrosName(std::list<std::wstring>& lst)
301 variables.getMacrosName(lst);
302 libraries.getMacrosName(lst);
303 return static_cast<int>(lst.size());
306 int Context::getFunctionsName(std::list<std::wstring>& lst)
308 return variables.getFunctionsName(lst);
311 int Context::getVarsInfoForWho(std::list<std::pair<std::wstring, int>>& lst, bool bSorted)
314 variables.getVarsInfoForWho(lst, &iZero, bSorted);
315 return static_cast<int>(lst.size());
318 int Context::getGlobalInfoForWho(std::list<std::pair<std::wstring, int>>& lst, bool bSorted)
321 variables.getGlobalInfoForWho(lst, &iZero, bSorted);
322 return static_cast<int>(lst.size());
325 int Context::getWhereIs(std::list<std::wstring>& lst, const std::wstring& _str)
327 return libraries.whereis(lst, Symbol(_str));
330 int Context::getLibrariesList(std::list<std::wstring>& lst)
332 return libraries.librarieslist(lst);
335 bool Context::put(Variable* _var, types::InternalType* _pIT)
337 if (_pIT->isLibrary())
339 Library* lib = libraries.getOrCreate(_var->getSymbol());
340 lib->put((types::Library*)_pIT, m_iLevel);
343 if (_var->put(_pIT, m_iLevel) == false)
348 if (varStack.empty() == false)
350 (*varStack.top())[_var->getSymbol()] = _var;
356 bool Context::put(const Symbol& _key, types::InternalType* _pIT)
358 Variable* var = variables.getOrCreate(_key);
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()))
368 return put(var, _pIT);
372 return put(var, _pIT);
375 bool Context::remove(const Symbol& _key)
377 bool ret = variables.remove(_key, m_iLevel);
381 varStack.top()->erase(_key);
384 ret = ret | libraries.remove(_key, m_iLevel);
388 bool Context::removeAll()
390 return clearCurrentScope(false);
393 bool Context::putInPreviousScope(Variable* _var, types::InternalType* _pIT)
395 //add variable in previous scope
396 if (variables.putInPreviousScope(_var, _pIT, m_iLevel - 1) == false)
401 //add variable in stack of using variables
402 if (varStack.empty() == false)
404 VarList * list = varStack.top();
406 if (varStack.empty() == false)
408 (*varStack.top())[_var->getSymbol()] = _var;
413 if (_pIT->isLibrary())
415 libraries.putInPreviousScope(_var->getSymbol(), _pIT->getAs<types::Library>(), m_iLevel - 1);
420 bool Context::addFunction(types::Function *_info)
422 Variable* var = variables.getOrCreate(Symbol(_info->getName()));
423 variables.putInPreviousScope(var, _info, SCOPE_GATEWAY);
427 bool Context::addMacro(types::Macro *_info)
429 return put(Symbol(_info->getName()), _info);
432 bool Context::addMacroFile(types::MacroFile *_info)
434 return put(Symbol(_info->getName()), _info);
437 bool Context::isGlobalVisible(const Symbol& _key)
439 return variables.isGlobalVisible(_key, m_iLevel);
442 /*return global variable existance status*/
443 bool Context::isGlobal(const Symbol& _key)
445 return variables.isGlobal(_key, m_iLevel);
448 types::InternalType* Context::getGlobalValue(const Symbol& _key)
450 return variables.getGlobalValue(_key);
453 void Context::setGlobalVisible(const Symbol& _key, bool bVisible)
455 variables.setGlobalVisible(_key, bVisible, m_iLevel);
458 void Context::setGlobal(const Symbol& _key)
460 variables.setGlobal(_key);
461 globals->push_back(_key);
464 bool Context::removeGlobal(const Symbol& _key)
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")
474 variables.removeGlobal(_key, m_iLevel);
475 globals->remove(_key);
479 void Context::removeGlobalAll()
481 std::list<Symbol>::iterator it = globals->begin();
483 while (it != globals->end())
485 if (removeGlobal(*it) == false)
487 globals->remove(*it);
490 it = globals->begin();
495 globals->emplace_back(L"%modalWarning");
496 globals->emplace_back(L"%toolboxes");
497 globals->emplace_back(L"%toolboxes_dir");
500 void Context::print(std::wostream& ostr, bool sorted) const
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);
518 wchar_t wcsVarElem[strSize];
519 wchar_t wcsVarVariable[strSize];
520 wchar_t wcsGlobalElem[strSize];
521 wchar_t wcsGlobalVariable[strSize];
528 MEMORYSTATUSEX statex;
529 statex.dwLength = sizeof(statex);
530 GlobalMemoryStatusEx(&statex);
531 iMemTotal = (int)(statex.ullTotalPhys / (1024 * 1024));
533 iMemTotal = getmemorysize();
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++)
542 if (iCurrentWidth + iVarLenMax + 1 > iWidth)
547 ostr << std::setw(iVarLenMax + 1) << it->first;
548 iCurrentWidth += iVarLenMax + 1;
551 os_swprintf(wcsVarElem, strSize, _W(" using %10d elements out of %10d.\n").c_str(), iMemUsed, iMemTotal);
552 ostr << std::endl << wcsVarElem;
554 os_swprintf(wcsVarVariable, strSize, _W(" and %10d variables out of %10d.\n").c_str(), lstVar.size(), nbMaxVar);
555 ostr << wcsVarVariable << std::endl;
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++)
561 ostr << std::setw(iGlobalLenMax + 1) << it->first;
570 os_swprintf(wcsGlobalElem, strSize, _W(" using %10d elements out of %10d.\n").c_str(), iMemUsed, iMemTotal);
571 ostr << std::endl << wcsGlobalElem;
573 os_swprintf(wcsGlobalVariable, strSize, _W(" and %10d variables out of %10d.\n").c_str(), lstGlobal.size(), nbMaxVar);
574 ostr << wcsGlobalVariable;
577 int Context::getScopeLevel()
582 bool Context::isValidVariableName(const wchar_t* wcsVarName)
584 static const wchar_t FORBIDDEN_CHARS[] = L" */\\.,;:^@><=+-&|()~\n\t'\"";
585 if (wcslen(wcsVarName) == 0 || std::wcspbrk(wcsVarName, FORBIDDEN_CHARS) || isdigit(wcsVarName[0]))
592 bool Context::isValidVariableName(const char* name)
594 bool isValid = false;
595 wchar_t* wcsname = to_wide_string(name);
598 isValid = isValidVariableName(wcsname);
605 int Context::getLibsToVariableBrowser(std::list<Library*>& lst)
607 libraries.getVarsToVariableBrowser(lst);
609 std::list<Library*> toremove;
610 //list lib that have a variable with the same name
613 Variable* var = getOrCreate(lib->getSymbol());
614 if (var->empty() == false)
616 toremove.push_back(lib);
621 for (auto lib : toremove)
626 return static_cast<int>(lst.size());
629 int Context::getVarsToVariableBrowser(std::list<Variable*>& lst)
631 variables.getVarsToVariableBrowser(lst);
632 return static_cast<int>(lst.size());
635 int Context::getCurrentScope(std::list<std::pair<std::wstring, int>>& lst, bool bSorted)
637 return variables.getCurrentScope(lst, m_iLevel, bSorted);
640 void Context::updateProtection(bool protect)
642 if (varStack.empty() == false)
644 VarList* lst = varStack.top();
645 for (auto var : *lst)
647 if (var.second->empty() == false)
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)
653 pSV->protect = protect;
657 std::wcerr << L"heu ... " << var.first.getName() << std::endl;
664 void Context::protect()
666 updateProtection(true);
669 void Context::unprotect()
671 updateProtection(false);
674 bool Context::isprotected(const Symbol& key)
676 return isprotected(getOrCreate(key));
679 bool Context::isprotected(Variable* _var)
681 //don't check protection on "ans"
682 if (_var->getSymbol().getName() == L"ans")
687 if (_var->empty() == false)
689 ScopedVariable* pSV = _var->top();
690 if (pSV->m_iLevel == m_iLevel && pSV->protect)
698 int Context::protectedVars(std::list<std::wstring>& vars)
700 return variables.getProtectedVarsName(vars);