fix trouble after https://codereview.scilab.org/#/c/16442
[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 "elem_common.h"
20 #include "os_string.h"
21 }
22
23 namespace types
24 {
25 template<typename T>
26 void getIndexes(T* val, std::vector<int>& vec)
27 {
28     typename T::type* p = val->get();
29     int size = val->getSize();
30     for (int i = 0; i < size; ++i)
31     {
32         vec.push_back(static_cast<int>(p[i]));
33     }
34 }
35
36 template<typename T>
37 double getIndex(T* val)
38 {
39     typename T::type* p = val->get();
40     return static_cast<double>(p[0]);
41 }
42
43 double getIndex(InternalType* val)
44 {
45     switch (val->getType())
46     {
47         //scalar
48         case InternalType::ScilabDouble:
49         {
50             return getIndex(val->getAs<Double>());
51         }
52         case InternalType::ScilabInt8:
53         {
54             return getIndex(val->getAs<Int8>());
55         }
56         case InternalType::ScilabInt16:
57         {
58             return getIndex(val->getAs<Int16>());
59         }
60         case InternalType::ScilabInt32:
61         {
62             return getIndex(val->getAs<Int32>());
63         }
64         case InternalType::ScilabInt64:
65         {
66             return getIndex(val->getAs<Int64>());
67         }
68         case InternalType::ScilabUInt8:
69         {
70             return getIndex(val->getAs<UInt8>());
71         }
72         case InternalType::ScilabUInt16:
73         {
74             return getIndex(val->getAs<UInt16>());
75         }
76         case InternalType::ScilabUInt32:
77         {
78             return getIndex(val->getAs<UInt32>());
79         }
80         case InternalType::ScilabUInt64:
81         {
82             return getIndex(val->getAs<UInt64>());
83         }
84     }
85
86     return 0;
87 }
88
89 //get only scalar index
90 bool getScalarIndex(GenericType* _pRef, typed_list* _pArgsIn, int* index)
91 {
92     //input size must be equal to ref dims
93     int dimsRef = _pRef->getDims();
94     int dimsIn = static_cast<int>(_pArgsIn->size());
95
96     //same dims and less than internal limit
97     if (dimsIn != 1 && dimsIn != dimsRef || dimsIn > MAX_DIMS)
98     {
99         return false;
100     }
101
102     int* pdims = _pRef->getDimsArray();
103     int ind[MAX_DIMS];
104     for (int i = 0; i < dimsIn; ++i)
105     {
106         InternalType* in = (*_pArgsIn)[i];
107         //input arg type must be scalar double, int8, int16, ...
108         if (in->isGenericType() && in->getAs<GenericType>()->isScalar())
109         {
110             ind[i] = static_cast<int>(getIndex(in)) - 1;
111             if (ind[i] == -1)
112             {
113                 return false;
114             }
115         }
116         else
117         {
118             //failed, so use entire process
119             return false;
120         }
121     }
122
123     //int idx = ind[0];
124     //if (dimsIn > 1 && idx >= pdims[0])
125     //{
126     //    return false;
127     //}
128
129     int idx = 0;
130     int previousDims = 1;
131     for (int i = 0; i < dimsIn; ++i)
132     {
133         if (dimsIn != 1 && ind[i] >= pdims[i])
134         {
135             return false;
136         }
137
138         idx += ind[i] * previousDims;
139         previousDims *= pdims[i];
140     }
141
142     *index = idx;
143     return true;
144 }
145
146 static double evalute(InternalType* pIT, int sizeRef)
147 {
148     double real;
149     double img;
150     if (pIT->getId() == InternalType::IdScalarPolynom)
151     {
152         SinglePoly* pSP = pIT->getAs<Polynom>()->get()[0];
153         pSP->evaluate(sizeRef, 0, &real, &img);
154     }
155     else
156     {
157         real = getIndex(pIT);
158     }
159
160     return real;
161 }
162 //get index from implicit or colon index + scalar
163 bool getImplicitIndex(GenericType* _pRef, typed_list* _pArgsIn, std::vector<int>& index)
164 {
165     int dimsRef = _pRef->getDims();
166     int dimsIn = static_cast<int>(_pArgsIn->size());
167     bool viewAsVector = dimsIn == 1;
168     //same dims and less than internal limit
169     if (dimsIn != 1 && dimsIn != dimsRef || dimsIn > MAX_DIMS)
170     {
171         return false;
172     }
173
174     int* pdims = _pRef->getDimsArray();
175     //input arg type must be computable ( double, $, :, ... )
176     std::list<std::vector<int>> lstIdx;
177     int finalSize = 1;
178     for (int i = 0; i < dimsIn; ++i)
179     {
180         InternalType* in = (*_pArgsIn)[i];
181         if (in->isGenericType() && in->getAs<GenericType>()->isScalar())
182         {
183             int idx = static_cast<int>(getIndex(in)) - 1;
184             if (idx == -1)
185             {
186                 return false;
187             }
188
189             lstIdx.emplace_back(1, idx);
190         }
191         else if (in->isColon())
192         {
193             vector<int> idx(2);
194             idx[0] = -1;
195             idx[1] = viewAsVector ? _pRef->getSize() : pdims[i];
196             lstIdx.push_back(idx);
197             finalSize *= idx[1];
198         }
199         else if (in->isImplicitList())
200         {
201             ImplicitList* pIL = in->getAs<ImplicitList>();
202             InternalType* piStart = pIL->getStart();
203             InternalType* piStep = pIL->getStep();
204             InternalType* piEnd = pIL->getEnd();
205
206             if (piStart->isDouble() && piStep->isDouble() && piEnd->isPoly())
207             {
208                 if (piStart->getAs<Double>()->get()[0] == 1 && piStep->getAs<Double>()->get()[0] == 1)
209                 {
210                     SinglePoly* end = piEnd->getAs<Polynom>()->get()[0];
211                     if (end->getRank() == 1 && end->get()[0] == 0 && end->get()[1] == 1)
212                     {
213                         vector<int> idx(2);
214                         idx[0] = -1;
215                         idx[1] = viewAsVector ? _pRef->getSize() : pdims[i];
216                         lstIdx.push_back(idx);
217                         finalSize *= idx[1];
218                     }
219                 }
220             }
221             else
222             {
223                 int sizeRef = viewAsVector ? _pRef->getSize() : pdims[i];
224                 double start = evalute(pIL->getStart(), sizeRef);
225                 double step = evalute(pIL->getStep(), sizeRef);
226                 double end = evalute(pIL->getEnd(), sizeRef);
227
228                 //printf("%.2f : %.2f : %.2f\n", start, step, end);
229
230                 int size = (end - start) / step + 1;
231                 vector<int> idx(size);
232
233                 if (size == 0)
234                 {
235                     //manage implicit that return []
236                     index.clear();
237                     return true;
238                 }
239
240                 int* pi = idx.data();
241                 pi[0] = start - 1; //0-indexed
242                 for (int j = 1; j < size; ++j)
243                 {
244                     pi[j] = pi[j - 1] + step;
245                 }
246
247                 lstIdx.push_back(idx);
248                 finalSize *= size;
249             }
250         }
251         else
252         {
253             return false;
254         }
255     }
256
257     index.resize(finalSize, 0);
258     //printf("finalSize : %d\n", finalSize);
259     //compute tuples
260     int previousSize = 1;
261     int currentDim = 0;
262     int previousDims = 1;
263     while (lstIdx.empty() == false)
264     {
265         std::vector<int>& v = lstIdx.front();
266         int currentSize = v.size();
267         const int* pv = v.data();
268
269         bool colon = false;
270         if (pv[0] == -1 && currentSize == 2)
271         {
272             currentSize = pv[1];
273             int occ = finalSize / (currentSize * previousSize);
274             for (int n = 0; n < occ; ++n)
275             {
276                 int idx = currentSize * previousSize * n;
277                 for (int m = 0; m < currentSize; ++m)
278                 {
279                     if (dimsIn > 1 && m >= pdims[currentDim])
280                     {
281                         return false;
282                     }
283                     int idx2 = idx + previousSize * m;
284                     int idx3 = previousDims * m;
285                     for (int j = 0; j < previousSize; ++j)
286                     {
287                         index[idx2 + j] += idx3;
288                         //printf("\tindex[%d] = %d\n", idx2 + i, previousSize * v[m]);
289                     }
290                 }
291             }
292         }
293         else
294         {
295             //printf("currentSize : %d\n", currentSize);
296             //printf("previousSize : %d\n", previousSize);
297             //printf("n : %d\n", finalSize / (currentSize * previousSize));
298             int occ = finalSize / (currentSize * previousSize);
299             for (int n = 0; n < occ; ++n)
300             {
301                 int idx = currentSize * previousSize * n;
302                 for (int m = 0; m < currentSize; ++m)
303                 {
304                     if (dimsIn > 1 && pv[m] >= pdims[currentDim])
305                     {
306                         return false;
307                     }
308                     int idx2 = idx + previousSize * m;
309                     int idx3 = previousDims * pv[m];
310                     for (int j = 0; j < previousSize; ++j)
311                     {
312                         index[idx2 + j] += idx3;
313                         //printf("\tindex[%d] = %d\n", idx2 + i, previousSize * v[m]);
314                     }
315                 }
316             }
317         }
318
319         previousSize *= currentSize;
320         previousDims *= pdims[currentDim];
321         ++currentDim;
322         //remove used vector
323         lstIdx.pop_front();
324     }
325
326     return true;
327 }
328
329 //check argument types and compute, dimensions, count of combinations, max indexes
330 int checkIndexesArguments(InternalType* _pRef, typed_list* _pArgsIn, typed_list* _pArgsOut, int* _piMaxDim, int* _piCountDim)
331 {
332     int iDims = static_cast<int>(_pArgsIn->size());
333     int iSeqCount = 1;
334     bool bUndefine = false;
335
336     for (int i = 0; i < iDims; i++)
337     {
338         bool bDeleteNeeded = false;
339         InternalType* pIT = (*_pArgsIn)[i];
340         Double *pCurrentArg = NULL;
341
342         if (pIT->isDouble())
343         {
344             pCurrentArg = pIT->getAs<Double>();
345             if (pCurrentArg->isEmpty())
346             {
347                 return 0;
348             }
349
350             if (pCurrentArg->isIdentity())
351             {
352                 //extract with eye() <=> :
353                 pIT = new Colon();
354                 bDeleteNeeded = true;
355             }
356             else if (pIT->isDeletable())
357             {
358                 // Clone pIT when this ref is equal to zero
359                 // will prevent double delete.
360                 pCurrentArg = pIT->clone()->getAs<Double>();
361             }
362
363             //check valid values neg or complex
364             if (pCurrentArg->isComplex())
365             {
366                 if (pCurrentArg->isDeletable())
367                 {
368                     pCurrentArg->killMe();
369                 }
370                 pCurrentArg = NULL;
371             }
372
373             if (pCurrentArg)
374             {
375                 int size = pCurrentArg->getSize();
376                 double* dbl = pCurrentArg->get();
377                 for (int j = 0; j < size; ++j)
378                 {
379                     if (dbl[j] < 0)
380                     {
381                         if (pCurrentArg->isDeletable())
382                         {
383                             pCurrentArg->killMe();
384                         }
385                         pCurrentArg = NULL;
386                         break;
387                     }
388                 }
389             }
390         }
391
392         //previous  if can update pIT to Colon
393         if (pIT->isColon() || pIT->isImplicitList())
394         {
395             //: or a:b:c
396             ImplicitList* pIL = pIT->getAs<ImplicitList>()->clone()->getAs<ImplicitList>();
397             if (pIL->isComputable() == false)
398             {
399                 //: or $
400                 if (_pRef == NULL)
401                 {
402                     //not enough information to compute indexes.
403                     _pArgsOut->push_back(NULL);
404                     bUndefine = true;
405                     pIL->killMe();;
406                     continue;
407                 }
408                 //evalute polynom with "MaxDim"
409                 int iMaxDim = _pRef->getAs<GenericType>()->getVarMaxDim(i, iDims);
410 #if defined(_SCILAB_DEBUGREF_)
411                 Double* pdbl = new Double(iMaxDim);
412 #else
413                 Double dbl(iMaxDim);
414 #endif
415                 if (pIL->getStart()->isPoly())
416                 {
417                     Polynom *poPoly = pIL->getStart()->getAs<types::Polynom>();
418 #if defined(_SCILAB_DEBUGREF_)
419                     pIL->setStart(poPoly->evaluate(pdbl));
420 #else
421                     pIL->setStart(poPoly->evaluate(&dbl));
422 #endif
423                 }
424                 if (pIL->getStep()->isPoly())
425                 {
426                     Polynom *poPoly = pIL->getStep()->getAs<types::Polynom>();
427 #if defined(_SCILAB_DEBUGREF_)
428                     pIL->setStep(poPoly->evaluate(pdbl));
429 #else
430                     pIL->setStep(poPoly->evaluate(&dbl));
431 #endif
432                 }
433                 if (pIL->getEnd()->isPoly())
434                 {
435                     Polynom *poPoly = pIL->getEnd()->getAs<types::Polynom>();
436 #if defined(_SCILAB_DEBUGREF_)
437                     pIL->setEnd(poPoly->evaluate(pdbl));
438 #else
439                     pIL->setEnd(poPoly->evaluate(&dbl));
440 #endif
441                 }
442
443 #if defined(_SCILAB_DEBUGREF_)
444                 pdbl->killMe();
445 #endif
446             }
447
448
449             pCurrentArg = pIL->extractFullMatrix()->getAs<Double>();
450             pIL->killMe();
451         }
452         else if (pIT->isString())
453         {
454             String* pStr = pIT->getAs<String>();
455             if (_pRef->isStruct())
456             {
457                 Struct* pStruct = _pRef->getAs<Struct>();
458
459                 if (_pArgsIn->size() != 1 || pStr->isScalar() == false)
460                 {
461                     bUndefine = true;
462                     continue;
463                 }
464
465                 wchar_t* pFieldName = pStr->get(0);
466
467                 // pCurrent arg is indexed to 1 unlike the return of "getFieldIndex"
468                 int iIndex = pStruct->get(0)->getFieldIndex(pFieldName) + 1;
469                 if (iIndex == -1)
470                 {
471                     bUndefine = true;
472                     continue;
473                 }
474
475                 pCurrentArg = new Double((double)iIndex);
476             }
477             else if (_pRef->isTList())
478             {
479                 // List can't be extract by field and MList must call overload
480                 TList* pTL = _pRef->getAs<TList>();
481                 pCurrentArg = new Double(pStr->getDims(), pStr->getDimsArray());
482                 double* pdbl = pCurrentArg->get();
483                 for (int i = 0; i < pStr->getSize(); i++)
484                 {
485                     wchar_t* pFieldName = pStr->get(i);
486                     int iIndex = pTL->getIndexFromString(pFieldName);
487                     if (iIndex == -1)
488                     {
489                         bUndefine = true;
490                         continue;
491                     }
492                     pdbl[i] = (double)(iIndex + 1);
493                 }
494             }
495             else if (_pRef->isList())
496             {
497                 bUndefine = true;
498                 break;
499             }
500             else if (_pRef->isCell())
501             {
502             }
503         }
504         else if (pIT->isPoly())
505         {
506             //$
507             Polynom* pMP = pIT->getAs<types::Polynom>();
508             int iMaxDim = 0;
509             //if pRef == NULL, use 0 insteadof, to allow a($+1) on new variable
510             if (_pRef)
511             {
512                 iMaxDim = _pRef->getAs<GenericType>()->getVarMaxDim(i, iDims);
513             }
514
515 #ifdef _SCILAB_DEBUGREF_
516             Double* pdbl = new Double(iMaxDim); // $
517             pCurrentArg = pMP->evaluate(pdbl);
518             pdbl->killMe();
519 #else
520             Double dbl(iMaxDim); // $
521             pCurrentArg = pMP->evaluate(&dbl);
522 #endif
523         }
524         else if (pIT->isBool())
525         {
526             //[T F F T F]
527             Bool *pB = pIT->getAs<types::Bool>();
528             int *piB = pB->get();
529             const int size = pB->getSize();
530
531             //find true item count
532             int iItemCount = 0;
533             for (int j = 0; j < size; j++)
534             {
535                 if (piB[j])
536                 {
537                     iItemCount++;
538                 }
539             }
540
541             //allow new Double variable
542             Double* pDbl = new Double(1, iItemCount);
543             double* pdbl = pDbl->getReal();
544
545             int j = 0;
546             for (int l = 0; l < size; l++)
547             {
548                 if (piB[l])
549                 {
550                     pdbl[j++] = l + 1;
551                 }
552             }
553             pCurrentArg = pDbl;
554         }
555
556         if (bDeleteNeeded)
557         {
558             pIT->killMe();
559         }
560
561         if (pCurrentArg)
562         {
563             const int iCountDim = pCurrentArg->getSize();
564             _piMaxDim[i] = 0;
565             for (int j = 0; j < iCountDim; j++)
566             {
567                 //checks if size < size(int)
568                 if (pCurrentArg->get(j) >= INT_MAX)
569                 {
570                     wchar_t szError[bsiz];
571                     os_swprintf(szError, bsiz, _W("variable size exceeded : less than %d expected.\n").c_str(), INT_MAX);
572                     throw ast::ScilabError(szError);
573                 }
574
575                 int d = static_cast<int>(pCurrentArg->get(j));
576                 if (d > _piMaxDim[i])
577                 {
578                     _piMaxDim[i] = d;
579                 }
580             }
581
582             iSeqCount *= iCountDim;
583             if (_piCountDim)
584             {
585                 _piCountDim[i] = iCountDim;
586             }
587         }
588         else
589         {
590             wchar_t szError[bsiz];
591             os_swprintf(szError, bsiz, _W("Invalid index.\n").c_str());
592
593             delete[] _piMaxDim;
594             delete[] _piCountDim;
595             cleanIndexesArguments(_pArgsIn, _pArgsOut);
596
597             throw ast::ScilabError(szError);
598         }
599         _pArgsOut->push_back(pCurrentArg);
600
601     }
602
603
604     //return 0 to force extract to create an empty matrix
605     if (_pRef &&  _pRef->isDouble() && _pRef->getAs<Double>()->isEmpty())
606     {
607         return 0;
608     }
609
610     //returns a negative value if at least one parameter is undefined
611     //case with : or $ for creation by insertion
612     return (!bUndefine ? iSeqCount : -iSeqCount);
613 }
614
615 void cleanIndexesArguments(typed_list* _pArgsOrig, typed_list* _pArgsNew)
616 {
617     if (_pArgsNew)
618     {
619         //free pArg content
620         for (int iArg = 0; iArg < _pArgsNew->size(); iArg++)
621         {
622             if ((*_pArgsNew)[iArg] != (*_pArgsOrig)[iArg])
623             {
624                 if ((*_pArgsNew)[iArg])
625                 {
626                     (*_pArgsNew)[iArg]->killMe();
627                 }
628             }
629         }
630
631         _pArgsNew->clear();
632     }
633 }
634
635 void getIndexesWithDims(int _iIndex, int* _piIndexes, int* _piDims, int _iDims)
636 {
637     int iMul = 1;
638     for (int i = 0; i < _iDims; i++)
639     {
640         _piIndexes[i] = (int)(_iIndex / iMul) % _piDims[i];
641         iMul *= _piDims[i];
642     }
643
644     //matrix [2,4,3]
645     //index = 12 ( 0,2,1) = 1 * 4 * 2 + 2 * 2 + 0 = 12
646     //loop 1
647     // (12 / 1) % 2 -> 0
648     //loop 2
649     // (12 / 2) % 4 -> 2
650     //loop 3
651     // (12 / 8) % 3 -> 1
652
653     //matrix [3,4,3]
654     //index = 22
655     //loop 1
656     // (22 / 1) % 3 -> 1
657     //loop 2
658     // (22 / 3) % 4 -> 3
659     //loop 3
660     // (22 / 12) % 3 -> 1
661
662     //matrix [3,4,3]
663     //index = 35
664     //loop 1
665     // (35 / 1) % 3 -> 2
666     //loop 2
667     // (35 / 3) % 4 -> 3
668     //loop 3
669     // (35 / 12) % 3 -> 2
670 }
671
672
673 int getIndexWithDims(int* _piIndexes, int* _piDims, int _iDims)
674 {
675     int idx = 0;
676     int iMult = 1;
677     for (int i = 0; i < _iDims; i++)
678     {
679         idx += _piIndexes[i] * iMult;
680         iMult *= _piDims[i];
681     }
682     return idx;
683 }
684
685 types::Function::ReturnValue VariableToString(types::InternalType* pIT, const wchar_t* wcsVarName)
686 {
687     if (pIT->hasToString() == false)
688     {
689         types::Function::ReturnValue ret = types::Function::Error;
690         //call overload %type_p
691         types::typed_list in;
692         types::typed_list out;
693         ast::ExecVisitor exec;
694
695         pIT->IncreaseRef();
696         in.push_back(pIT);
697
698         try
699         {
700             ret = Overload::generateNameAndCall(L"p", in, 1, out, &exec);
701             pIT->DecreaseRef();
702             return ret;
703         }
704         catch (ast::ScilabError &e)
705         {
706             pIT->DecreaseRef();
707             throw e;
708         }
709     }
710     else
711     {
712         std::wostringstream ostr;
713         if (pIT->isFunction())
714         {
715             pIT->getAs<types::Function>()->toString(ostr);
716         }
717         else if (pIT->isList() || pIT->isCallable())
718         {
719             ostr << wcsVarName;
720         }
721
722         //to manage lines information
723         int iLines = ConfigVariable::getConsoleLines();
724
725         bool bFinish = false;
726         do
727         {
728             //block by block
729             bFinish = pIT->toString(ostr);
730             if (ConfigVariable::isError())
731             {
732                 ConfigVariable::resetError();
733                 ostr.str(L"");
734                 return types::Function::Error;
735             }
736
737             if (bFinish == false && iLines != 0)
738             {
739                 //show message on prompt
740                 bFinish = linesmore() == 1;
741             }
742
743             scilabForcedWriteW(ostr.str().c_str());
744             ostr.str(L"");
745         }
746         while (bFinish == false);
747
748         pIT->clearPrintState();
749         return types::Function::OK;
750     }
751 }
752 }