update matrix insert and insertNew with :
[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                 if ((*_pArgsNew)[iArg])
317                 {
318                     (*_pArgsNew)[iArg]->killMe();
319                 }
320             }
321         }
322
323         _pArgsNew->clear();
324     }
325 }
326
327 void getIndexesWithDims(int _iIndex, int* _piIndexes, int* _piDims, int _iDims)
328 {
329     int iMul = 1;
330     for (int i = 0 ; i < _iDims ; i++)
331     {
332         _piIndexes[i] = (int)(_iIndex / iMul) % _piDims[i];
333         iMul *= _piDims[i];
334     }
335
336     //matrix [2,4,3]
337     //index = 12 ( 0,2,1) = 1 * 4 * 2 + 2 * 2 + 0 = 12
338     //loop 1
339     // (12 / 1) % 2 -> 0
340     //loop 2
341     // (12 / 2) % 4 -> 2
342     //loop 3
343     // (12 / 8) % 3 -> 1
344
345     //matrix [3,4,3]
346     //index = 22
347     //loop 1
348     // (22 / 1) % 3 -> 1
349     //loop 2
350     // (22 / 3) % 4 -> 3
351     //loop 3
352     // (22 / 12) % 3 -> 1
353
354     //matrix [3,4,3]
355     //index = 35
356     //loop 1
357     // (35 / 1) % 3 -> 2
358     //loop 2
359     // (35 / 3) % 4 -> 3
360     //loop 3
361     // (35 / 12) % 3 -> 2
362 }
363
364
365 int getIndexWithDims(int* _piIndexes, int* _piDims, int _iDims)
366 {
367     int idx = 0;
368     int iMult = 1;
369     for (int i = 0 ; i < _iDims ; i++)
370     {
371         idx += _piIndexes[i] * iMult;
372         iMult *= _piDims[i];
373     }
374     return idx;
375 }
376
377 types::Function::ReturnValue VariableToString(types::InternalType* pIT, const wchar_t* wcsVarName)
378 {
379     if (pIT->hasToString() == false)
380     {
381         types::Function::ReturnValue ret = types::Function::Error;
382         //call overload %type_p
383         types::typed_list in;
384         types::typed_list out;
385         ast::ExecVisitor exec;
386
387         pIT->IncreaseRef();
388         in.push_back(pIT);
389
390         try
391         {
392             ret = Overload::generateNameAndCall(L"p", in, 1, out, &exec);
393             pIT->DecreaseRef();
394             return ret;
395         }
396         catch (ast::ScilabError &e)
397         {
398             pIT->DecreaseRef();
399             throw e;
400         }
401     }
402     else
403     {
404         std::wostringstream ostr;
405         if (pIT->isFunction())
406         {
407             pIT->getAs<types::Function>()->toString(ostr);
408         }
409         else if (pIT->isList() || pIT->isCallable())
410         {
411             ostr << wcsVarName;
412         }
413
414         //to manage lines information
415         int iLines = ConfigVariable::getConsoleLines();
416
417         bool bFinish = false;
418         do
419         {
420             //block by block
421             bFinish = pIT->toString(ostr);
422             if (ConfigVariable::isError())
423             {
424                 ConfigVariable::resetError();
425                 ostr.str(L"");
426                 return types::Function::Error;
427             }
428
429             if (bFinish == false && iLines != 0)
430             {
431                 //show message on prompt
432                 bFinish = linesmore() == 1;
433             }
434
435             scilabForcedWriteW(ostr.str().c_str());
436             ostr.str(L"");
437         }
438         while (bFinish == false);
439
440         pIT->clearPrintState();
441         return types::Function::OK;
442     }
443 }
444 }