* Bug 14606 fixed: now `[names,mem]=who()` returns memory used by variables
[scilab.git] / scilab / modules / ast / src / cpp / types / tlist.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2010-2010 - 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
16 #include <cstring>
17 #include <sstream>
18 #include "exp.hxx"
19 #include "string.hxx"
20 #include "list.hxx"
21 #include "tlist.hxx"
22 #include "listundefined.hxx"
23 #include "callable.hxx"
24 #include "polynom.hxx"
25 #include "overload.hxx"
26 #include "configvariable.hxx"
27 #include "types_tools.hxx"
28 #include "scilabWrite.hxx"
29
30 #ifndef NDEBUG
31 #include "inspector.hxx"
32 #endif
33
34 extern "C"
35 {
36 #include "os_string.h"
37 }
38
39 namespace types
40 {
41 /**
42 ** Constructor & Destructor (public)
43 */
44 TList::TList() : List()
45 {
46 #ifndef NDEBUG
47     Inspector::addItem(this);
48 #endif
49 }
50
51 TList::~TList()
52 {
53 #ifndef NDEBUG
54     Inspector::removeItem(this);
55 #endif
56 }
57
58 bool TList::getMemory(int* _piSize, int* _piSizePlusType)
59 {
60     *_piSize = 0;
61     *_piSizePlusType = 0;
62     for (auto pData : *m_plData)
63     {
64         int piS, piSPT;
65         if (pData->getMemory(&piS, &piSPT))
66         {
67             *_piSize += piS;
68             *_piSizePlusType += piSPT;
69         }
70     }
71
72     *_piSizePlusType += sizeof(TList);
73     return true;
74 }
75
76 /**
77 ** Clone
78 ** Create a new List and Copy all values.
79 */
80 TList* TList::clone()
81 {
82     return new TList(this);
83 }
84
85 bool TList::exists(const std::wstring& _sKey)
86 {
87     if (getSize() < 1)
88     {
89         return false;
90     }
91
92     String* pS = getFieldNames();
93
94     //first field is the tlist type
95     for (int i = 1 ; i < pS->getSize() ; i++)
96     {
97         if (wcscmp(pS->get(i), _sKey.c_str()) == 0)
98         {
99             return true;
100         }
101     }
102     return false;
103 }
104
105 bool TList::invoke(typed_list & in, optional_list & /*opt*/, int _iRetCount, typed_list & out, const ast::Exp & e)
106 {
107     if (in.size() == 0)
108     {
109         out.push_back(this);
110         return true;
111     }
112     else if (in.size() == 1)
113     {
114         InternalType * arg = in[0];
115         InternalType * _out = NULL;
116         if (arg->isDouble() || arg->isInt() || arg->isBool() || arg->isImplicitList() || arg->isColon() || arg->isDollar())
117         {
118             _out = List::extract(&in);
119             if (_out == NULL)
120             {
121                 // invalid index
122                 return false;
123             }
124
125             List* pList = _out->getAs<types::List>();
126             for (int i = 0; i < pList->getSize(); i++)
127             {
128                 out.push_back(pList->get(i));
129             }
130
131             delete pList;
132         }
133         else if (arg->isString())
134         {
135             std::list<std::wstring> stFields;
136             String * pString = arg->getAs<types::String>();
137             for (int i = 0; i < pString->getSize(); ++i)
138             {
139                 stFields.push_back(pString->get(i));
140             }
141
142             _out = extractStrings(stFields);
143             if (_out == NULL)
144             {
145                 // invalid index
146                 return false;
147             }
148
149             List* pList = _out->getAs<types::List>();
150             for (int i = 0; i < pList->getSize(); i++)
151             {
152                 out.push_back(pList->get(i));
153             }
154
155             delete pList;
156         }
157         else if (arg->isPoly())
158         {
159             Polynom* pPoly = arg->getAs<Polynom>();
160             SinglePoly* pSinglePoly = pPoly->get(0);
161
162             int iMaxDim = 0;
163             double dblParse = -1 * pSinglePoly->get(0);
164             int iSize = getSize();
165
166             if (pSinglePoly->getRank() < 2 && dblParse >= 0 && dblParse < (double)iSize)
167             {
168                 out.push_back(get(iSize - 1 - dblParse));
169             }
170             else
171             {
172                 return false;
173             }
174         }
175
176         if (out.empty() == false)
177         {
178             return true;
179         }
180     }
181     Callable::ReturnValue ret;
182     // Overload of extraction need
183     // the tlist from where we extract
184     this->IncreaseRef();
185     in.push_back(this);
186
187     std::wstring stType = getShortTypeStr();
188     try
189     {
190         ret = Overload::call(L"%" + stType + L"_e", in, _iRetCount, out);
191     }
192     catch (const ast::InternalError &ie)
193     {
194         try
195         {
196             //to compatibility with scilab 5 code.
197             //tlist/mlist name are truncated to 8 first character
198             if (stType.size() > 8)
199             {
200                 std::wcout << (L"%" + stType.substr(0, 8) + L"_e") << std::endl;
201                 ret = Overload::call(L"%" + stType.substr(0, 8) + L"_e", in, _iRetCount, out);
202             }
203             else
204             {
205                 throw ie;
206             }
207         }
208         catch (ast::InternalError & /*se*/)
209         {
210             ret = Overload::call(L"%l_e", in, _iRetCount, out);
211         }
212     }
213
214     // Remove this from "in" for keep "in" unchanged.
215     this->DecreaseRef();
216     in.pop_back();
217
218     if (ret == Callable::Error)
219     {
220         throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
221     }
222
223     return true;
224 }
225
226 bool TList::extract(const std::wstring & name, InternalType *& out)
227 {
228     if (exists(name))
229     {
230         out = getField(name);
231         return true;
232     }
233
234     return false;
235 }
236
237 InternalType* TList::getField(const std::wstring& _sKey)
238 {
239     return List::get(getIndexFromString(_sKey));
240 }
241
242 int TList::getIndexFromString(const std::wstring& _sKey)
243 {
244     if (getSize() < 1)
245     {
246         return -1;
247     }
248
249     String* pS = getFieldNames();
250     //first field is the tlist type
251     for (int i = 1 ; i < pS->getSize() ; i++)
252     {
253         if (wcscmp(pS->get(i), _sKey.c_str()) == 0)
254         {
255             return i;
256         }
257     }
258     return -1;
259 }
260
261 InternalType* TList::extractStrings(const std::list<std::wstring>& _stFields)
262 {
263     int i = 0;
264     List* pLResult = new List();
265     std::list<std::wstring>::const_iterator it;
266     for (it = _stFields.begin() ; it != _stFields.end() ; it++)
267     {
268         if (exists(*it) == false)
269         {
270             return pLResult;
271         }
272     }
273
274     for (it = _stFields.begin() ; it != _stFields.end() ; it++, i++)
275     {
276         InternalType* pIT = getField(*it);
277         if (pIT == NULL)
278         {
279             delete pLResult;
280             return NULL;
281         }
282
283         pLResult->set(i, pIT);
284     }
285
286     return pLResult;
287 }
288
289 std::wstring TList::getTypeStr() const
290 {
291     if (getSize() < 1)
292     {
293         return L"";
294     }
295
296     return getFieldNames()->get(0);
297 }
298
299 std::wstring TList::getShortTypeStr() const
300 {
301     return getTypeStr();
302 }
303
304 TList* TList::set(const std::wstring& _sKey, InternalType* _pIT)
305 {
306     return List::set(getIndexFromString(_sKey), _pIT)->getAs<TList>();
307 }
308
309 TList* TList::set(const int _iIndex, InternalType* _pIT)
310 {
311     return List::set(_iIndex, _pIT)->getAs<TList>();
312 }
313
314 String* TList::getFieldNames() const
315 {
316     return (*m_plData)[0]->getAs<types::String>();
317 }
318
319 /**
320 ** toString to display TLists
321 */
322 bool TList::toString(std::wostringstream& ostr)
323 {
324     //call overload %type_p if exists
325     types::typed_list in;
326     types::typed_list out;
327
328     IncreaseRef();
329     in.push_back(this);
330
331     try
332     {
333         if (Overload::generateNameAndCall(L"p", in, 1, out) == Function::Error)
334         {
335             ConfigVariable::setError();
336         }
337
338         ostr.str(L"");
339         DecreaseRef();
340         return true;
341     }
342     catch (ast::InternalError& e)
343     {
344         if (e.GetErrorType() == ast::TYPE_ERROR)
345         {
346             DecreaseRef();
347             throw e;
348         }
349
350         // avoid error message about undefined overload %type_p
351         ConfigVariable::resetError();
352     }
353
354     DecreaseRef();
355
356     // special case for lss
357     if (getSize() != 0 &&
358             (*m_plData)[0]->isString() &&
359             (*m_plData)[0]->getAs<types::String>()->getSize() > 0 &&
360             wcscmp((*m_plData)[0]->getAs<types::String>()->get(0), L"lss") == 0)
361     {
362         wchar_t* wcsVarName = os_wcsdup(ostr.str().c_str());
363         int iPosition = 1;
364         const wchar_t * wcsDesc[7] = {L"  (state-space system:)", L"= A matrix =", L"= B matrix =", L"= C matrix =", L"= D matrix =", L"= X0 (initial state) =", L"= Time domain ="};
365         for (auto val : *m_plData)
366         {
367             std::wostringstream nextVarName;
368             ostr.str(L"");
369             nextVarName << " " << wcsVarName << L"(" << iPosition << L")";
370             ostr << std::endl << nextVarName.str() << wcsDesc[iPosition - 1] << std::endl << std::endl;
371             scilabWriteW(ostr.str().c_str());
372             VariableToString(val, nextVarName.str().c_str());
373             iPosition++;
374         }
375         ostr.str(L"");
376         free(wcsVarName);
377         return true;
378     }
379
380     // call normal toString
381     return List::toString(ostr);
382 }
383 } // end namespace types