cd032c160261c37824b60c7f9d1535c3ccfc35cd
[scilab.git] / scilab / modules / ast / src / cpp / types / types_tools.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2011 - 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
13 #include "alltypes.hxx"
14 #include "types_tools.hxx"
15 #include "overload.hxx"
16 #include "execvisitor.hxx"
17 extern "C"
18 {
19 #include "os_string.h"
20 }
21
22 namespace types
23 {
24 //check argument types and compute, dimensions, count of combinations, max indexes
25 int checkIndexesArguments(InternalType* _pRef, typed_list* _pArgsIn, typed_list* _pArgsOut, int* _piMaxDim, int* _piCountDim)
26 {
27     int iDims           = static_cast<int>(_pArgsIn->size());
28     int iSeqCount       = 1;
29     bool bUndefine      = false;
30
31     for (int i = 0 ; i < iDims ; i++)
32     {
33         bool bDeleteNeeded  = false;
34         InternalType* pIT = (*_pArgsIn)[i];
35         Double *pCurrentArg = NULL;
36
37         if (pIT->isDouble())
38         {
39             pCurrentArg = pIT->getAs<Double>();
40             if (pCurrentArg->isEmpty())
41             {
42                 return 0;
43             }
44
45             if (pCurrentArg->isIdentity())
46             {
47                 //extract with eye() <=> :
48                 pIT = new Colon();
49                 bDeleteNeeded = true;
50             }
51             else if (pIT->isDeletable())
52             {
53                 // Clone pIT when this ref is equal to zero
54                 // will prevent double delete.
55                 pCurrentArg = pIT->clone()->getAs<Double>();
56             }
57
58             //check valid values neg or complex
59             if (pCurrentArg->isComplex())
60             {
61                 if (pCurrentArg->isDeletable())
62                 {
63                     pCurrentArg->killMe();
64                 }
65                 pCurrentArg = NULL;
66             }
67
68             if (pCurrentArg)
69             {
70                 int size = pCurrentArg->getSize();
71                 double* dbl = pCurrentArg->get();
72                 for (int j = 0; j < size; ++j)
73                 {
74                     if (dbl[j] < 0)
75                     {
76                         if (pCurrentArg->isDeletable())
77                         {
78                             pCurrentArg->killMe();
79                         }
80                         pCurrentArg = NULL;
81                         break;
82                     }
83                 }
84             }
85         }
86
87         if (pIT->isColon() || pIT->isImplicitList())
88         {
89             //: or a:b:c
90             ImplicitList* pIL = pIT->getAs<ImplicitList>()->clone()->getAs<ImplicitList>();
91             if (pIL->isComputable() == false)
92             {
93                 //: or $
94                 if (_pRef == NULL)
95                 {
96                     //not enough information to compute indexes.
97                     _pArgsOut->push_back(NULL);
98                     bUndefine = true;
99                     pIL->killMe();;
100                     continue;
101                 }
102                 //evalute polynom with "MaxDim"
103                 int iMaxDim = _pRef->getAs<GenericType>()->getVarMaxDim(i, iDims);
104 #if defined(_SCILAB_DEBUGREF_)
105                 Double* pdbl = new Double(iMaxDim);
106 #else
107                 Double dbl(iMaxDim);
108 #endif
109                 if (pIL->getStart()->isPoly())
110                 {
111                     Polynom *poPoly     = pIL->getStart()->getAs<types::Polynom>();
112 #if defined(_SCILAB_DEBUGREF_)
113                     pIL->setStart(poPoly->evaluate(pdbl));
114 #else
115                     pIL->setStart(poPoly->evaluate(&dbl));
116 #endif
117                 }
118                 if (pIL->getStep()->isPoly())
119                 {
120                     Polynom *poPoly     = pIL->getStep()->getAs<types::Polynom>();
121 #if defined(_SCILAB_DEBUGREF_)
122                     pIL->setStep(poPoly->evaluate(pdbl));
123 #else
124                     pIL->setStep(poPoly->evaluate(&dbl));
125 #endif
126                 }
127                 if (pIL->getEnd()->isPoly())
128                 {
129                     Polynom *poPoly     = pIL->getEnd()->getAs<types::Polynom>();
130 #if defined(_SCILAB_DEBUGREF_)
131                     pIL->setEnd(poPoly->evaluate(pdbl));
132 #else
133                     pIL->setEnd(poPoly->evaluate(&dbl));
134 #endif
135                 }
136
137 #if defined(_SCILAB_DEBUGREF_)
138                 pdbl->killMe();
139 #endif
140             }
141
142
143             pCurrentArg = pIL->extractFullMatrix()->getAs<Double>();
144             pIL->killMe();
145         }
146         else if (pIT->isString())
147         {
148             String* pStr = pIT->getAs<String>();
149             if (_pRef->isStruct())
150             {
151                 Struct* pStruct = _pRef->getAs<Struct>();
152
153                 if (_pArgsIn->size() != 1 || pStr->isScalar() == false)
154                 {
155                     bUndefine = true;
156                     continue;
157                 }
158
159                 wchar_t* pFieldName = pStr->get(0);
160
161                 // pCurrent arg is indexed to 1 unlike the return of "getFieldIndex"
162                 int iIndex = pStruct->get(0)->getFieldIndex(pFieldName) + 1;
163                 if (iIndex == -1)
164                 {
165                     bUndefine = true;
166                     continue;
167                 }
168
169                 pCurrentArg = new Double((double)iIndex);
170             }
171             else if (_pRef->isTList())
172             {
173                 // List can't be extract by field and MList must call overload
174                 TList* pTL = _pRef->getAs<TList>();
175                 pCurrentArg = new Double(pStr->getDims(), pStr->getDimsArray());
176                 double* pdbl = pCurrentArg->get();
177                 for (int i = 0; i < pStr->getSize(); i++)
178                 {
179                     wchar_t* pFieldName = pStr->get(i);
180                     int iIndex = pTL->getIndexFromString(pFieldName);
181                     if (iIndex == -1)
182                     {
183                         bUndefine = true;
184                         continue;
185                     }
186                     pdbl[i] = (double)(iIndex + 1);
187                 }
188             }
189             else if (_pRef->isList())
190             {
191                 bUndefine = true;
192                 break;
193             }
194             else if (_pRef->isCell())
195             {
196             }
197         }
198         else if (pIT->isPoly())
199         {
200             //$
201             Polynom* pMP = pIT->getAs<types::Polynom>();
202             int iMaxDim     = 0;
203             //if pRef == NULL, use 0 insteadof, to allow a($+1) on new variable
204             if (_pRef)
205             {
206                 iMaxDim     = _pRef->getAs<GenericType>()->getVarMaxDim(i, iDims);
207             }
208
209 #ifdef _SCILAB_DEBUGREF_
210             Double* pdbl = new Double(iMaxDim); // $
211             pCurrentArg = pMP->evaluate(pdbl);
212             pdbl->killMe();
213 #else
214             Double dbl(iMaxDim); // $
215             pCurrentArg = pMP->evaluate(&dbl);
216 #endif
217         }
218         else if (pIT->isBool())
219         {
220             //[T F F T F]
221             Bool *pB    = pIT->getAs<types::Bool>();
222             int *piB    = pB->get();
223             const int size = pB->getSize();
224
225             //find true item count
226             int iItemCount = 0;
227             for (int j = 0 ; j < size; j++)
228             {
229                 if (piB[j])
230                 {
231                     iItemCount++;
232                 }
233             }
234
235             //allow new Double variable
236             Double* pDbl    = new Double(1, iItemCount);
237             double* pdbl    = pDbl->getReal();
238
239             int j = 0;
240             for (int l = 0 ; l < size; l++)
241             {
242                 if (piB[l])
243                 {
244                     pdbl[j++] = l + 1;
245                 }
246             }
247             pCurrentArg = pDbl;
248         }
249
250         if (bDeleteNeeded)
251         {
252             pIT->killMe();
253         }
254
255         if (pCurrentArg)
256         {
257             const int iCountDim = pCurrentArg->getSize();
258             _piMaxDim[i] = 0;
259             for (int j = 0 ; j < iCountDim ; j++)
260             {
261                 //checks if size < size(int)
262                 if (pCurrentArg->get(j) >= INT_MAX)
263                 {
264                     wchar_t szError[bsiz];
265                     os_swprintf(szError, bsiz, _W("variable size exceeded : less than %d expected.\n").c_str(), INT_MAX);
266                     throw ast::ScilabError(szError);
267                 }
268
269                 const int d = static_cast<int>(pCurrentArg->get(j));
270                 if (d > _piMaxDim[i])
271                 {
272                     _piMaxDim[i] = d;
273                 }
274             }
275
276             iSeqCount *= iCountDim;
277             if (_piCountDim)
278             {
279                 _piCountDim[i] = iCountDim;
280             }
281         }
282         else
283         {
284             wchar_t szError[bsiz];
285             os_swprintf(szError, bsiz, _W("Invalid index.\n").c_str());
286
287             cleanIndexesArguments(_pArgsIn, _pArgsOut);
288
289             throw ast::ScilabError(szError);
290         }
291         _pArgsOut->push_back(pCurrentArg);
292
293     }
294
295
296     //return 0 to force extract to create an empty matrix
297     if (_pRef &&  _pRef->isDouble() && _pRef->getAs<Double>()->isEmpty())
298     {
299         return 0;
300     }
301
302     //returns a negative value if at least one parameter is undefined
303     //case with : or $ for creation by insertion
304     return (!bUndefine ? iSeqCount : -iSeqCount);
305 }
306
307 void cleanIndexesArguments(typed_list* _pArgsOrig, typed_list* _pArgsNew)
308 {
309     if (_pArgsNew)
310     {
311         //free pArg content
312         for (int iArg = 0; iArg < _pArgsNew->size(); iArg++)
313         {
314             if ((*_pArgsNew)[iArg] != (*_pArgsOrig)[iArg])
315             {
316                 (*_pArgsNew)[iArg]->killMe();
317             }
318         }
319
320         _pArgsNew->clear();
321     }
322 }
323
324 void getIndexesWithDims(int _iIndex, int* _piIndexes, int* _piDims, int _iDims)
325 {
326     int iMul = 1;
327     for (int i = 0 ; i < _iDims ; i++)
328     {
329         _piIndexes[i] = (int)(_iIndex / iMul) % _piDims[i];
330         iMul *= _piDims[i];
331     }
332
333     //matrix [2,4,3]
334     //index = 12 ( 0,2,1) = 1 * 4 * 2 + 2 * 2 + 0 = 12
335     //loop 1
336     // (12 / 1) % 2 -> 0
337     //loop 2
338     // (12 / 2) % 4 -> 2
339     //loop 3
340     // (12 / 8) % 3 -> 1
341
342     //matrix [3,4,3]
343     //index = 22
344     //loop 1
345     // (22 / 1) % 3 -> 1
346     //loop 2
347     // (22 / 3) % 4 -> 3
348     //loop 3
349     // (22 / 12) % 3 -> 1
350
351     //matrix [3,4,3]
352     //index = 35
353     //loop 1
354     // (35 / 1) % 3 -> 2
355     //loop 2
356     // (35 / 3) % 4 -> 3
357     //loop 3
358     // (35 / 12) % 3 -> 2
359 }
360
361
362 int getIndexWithDims(int* _piIndexes, int* _piDims, int _iDims)
363 {
364     int idx = 0;
365     int iMult = 1;
366     for (int i = 0 ; i < _iDims ; i++)
367     {
368         idx += _piIndexes[i] * iMult;
369         iMult *= _piDims[i];
370     }
371     return idx;
372 }
373
374 types::Function::ReturnValue VariableToString(types::InternalType* pIT, const wchar_t* wcsVarName)
375 {
376     if (pIT->hasToString() == false)
377     {
378         types::Function::ReturnValue ret = types::Function::Error;
379         //call overload %type_p
380         types::typed_list in;
381         types::typed_list out;
382         ast::ExecVisitor exec;
383
384         pIT->IncreaseRef();
385         in.push_back(pIT);
386
387         try
388         {
389             ret = Overload::generateNameAndCall(L"p", in, 1, out, &exec);
390             pIT->DecreaseRef();
391             return ret;
392         }
393         catch (ast::ScilabError &e)
394         {
395             pIT->DecreaseRef();
396             throw e;
397         }
398     }
399     else
400     {
401         std::wostringstream ostr;
402         if (pIT->isFunction())
403         {
404             pIT->getAs<types::Function>()->toString(ostr);
405         }
406         else if (pIT->isList() || pIT->isCallable())
407         {
408             ostr << wcsVarName;
409         }
410
411         //to manage lines information
412         int iLines = ConfigVariable::getConsoleLines();
413
414         bool bFinish = false;
415         do
416         {
417             //block by block
418             bFinish = pIT->toString(ostr);
419             if (ConfigVariable::isError())
420             {
421                 ConfigVariable::resetError();
422                 ostr.str(L"");
423                 return types::Function::Error;
424             }
425
426             if (bFinish == false && iLines != 0)
427             {
428                 //show message on prompt
429                 bFinish = linesmore() == 1;
430             }
431
432             scilabForcedWriteW(ostr.str().c_str());
433             ostr.str(L"");
434         }
435         while (bFinish == false);
436
437         pIT->clearPrintState();
438         return types::Function::OK;
439     }
440 }
441 }