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