Analysis: add info about $ and fix bug
[scilab.git] / scilab / modules / ast / src / cpp / analysis / IndexAnalyzer.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - Scilab Enterprises - Calixte DENIZET
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 "AnalysisVisitor.hxx"
14
15 namespace analysis
16 {
17
18 bool AnalysisVisitor::analyzeIndices(TIType & type, ast::CallExp & ce)
19 {
20     const ast::exps_t args = ce.getArgs();
21     const unsigned int size = args.size();
22
23     if (size >= 3)
24     {
25         // Not handle yet...
26         // TODO
27         return false;
28     }
29
30     if (size == 0)
31     {
32         Result & res = ce.getDecorator().setResult(type);
33         setResult(res);
34         return true;
35     }
36
37     SymbolicDimension first, second;
38     bool safe, ret;
39
40     argIndices.emplace(static_cast<ast::SimpleVar &>(ce.getName()).getSymbol(), 1);
41     if (size == 1)
42     {
43         // when there is one argument, a(?) is equivalent to A(?,1)
44         // where A = matrix(a, r_a * c_a, 1)
45
46         SymbolicDimension rows(type.rows);
47         second = SymbolicDimension(getGVN(), 1.);
48         if (type.cols != 1)
49         {
50             rows *= type.cols;
51         }
52
53         ret = getDimension(rows, *args.front(), safe, first);
54     }
55     else
56     {
57         bool _safe;
58         ret = getDimension(type.rows, *args.front(), _safe, first);
59         if (ret)
60         {
61             argIndices.top().getIndex() = 2;
62             ret = getDimension(type.cols, *args.back(), safe, second);
63             safe = safe && _safe;
64         }
65         else
66         {
67             safe = _safe;
68         }
69     }
70     argIndices.pop();
71
72     if (ret)
73     {
74         TIType typ(getGVN(), type.type, first, second);
75         Result & _res = ce.getDecorator().setResult(typ);
76         setResult(_res);
77         ce.getDecorator().safe = safe;
78     }
79
80     return ret;
81 }
82
83
84 bool AnalysisVisitor::getDimension(SymbolicDimension & dim, ast::Exp & arg, bool & safe, SymbolicDimension & out)
85 {
86     switch (arg.getType())
87     {
88         case ast::Exp::COLONVAR :
89         {
90             out = dim;
91             safe = true;
92             arg.getDecorator().setDollarInfo(argIndices.top());
93             return true;
94         }
95         case ast::Exp::DOLLARVAR : // a($)
96         {
97             out = SymbolicDimension(getGVN(), 1.);
98             safe = true;
99             arg.getDecorator().setDollarInfo(argIndices.top());
100             return true;
101         }
102         case ast::Exp::DOUBLEEXP : // a(12) or a([1 2])
103         {
104             ast::DoubleExp & de = static_cast<ast::DoubleExp &>(arg);
105             if (types::InternalType * const pIT = de.getConstant())
106             {
107                 if (pIT->isDouble())
108                 {
109                     types::Double * const pDbl = static_cast<types::Double *>(pIT);
110                     if (pDbl->isEmpty())
111                     {
112                         out = SymbolicDimension(getGVN(), 0.);
113                         safe = true;
114                         return true;
115                     }
116
117                     const double * real = pDbl->getReal();
118                     const int size = pDbl->getSize();
119                     int64_t max;
120                     if (tools::asInteger(real[0], max))
121                     {
122                         int64_t min = max;
123                         if (!pDbl->isComplex())
124                         {
125                             for (int i = 0; i < size; ++i)
126                             {
127                                 int64_t _real;
128                                 if (tools::asInteger(real[i], _real))
129                                 {
130                                     if (_real < min)
131                                     {
132                                         min = _real;
133                                     }
134                                     else if (_real > max)
135                                     {
136                                         max = _real;
137                                     }
138                                 }
139                                 else
140                                 {
141                                     return false;
142                                 }
143                             }
144
145                             out = SymbolicDimension(getGVN(), size);
146                             safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
147                             return true;
148                         }
149                         else
150                         {
151                             const double * imag = pDbl->getImg();
152                             int i;
153                             for (i = 0; i < size; ++i)
154                             {
155                                 if (imag[i])
156                                 {
157                                     break;
158                                 }
159                                 int64_t _real;
160                                 if (tools::asInteger(real[i], _real))
161                                 {
162                                     if (_real < min)
163                                     {
164                                         min = _real;
165                                     }
166                                     else if (_real > max)
167                                     {
168                                         max = _real;
169                                     }
170                                 }
171                             }
172
173                             if (i == size)
174                             {
175                                 out = SymbolicDimension(getGVN(), size);
176                                 safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
177                                 return true;
178                             }
179                             else
180                             {
181                                 return false;
182                             }
183                         }
184                     }
185                     else
186                     {
187                         return false;
188                     }
189                 }
190                 else if (pIT->isImplicitList())
191                 {
192                     types::ImplicitList * const pIL = static_cast<types::ImplicitList *>(pIT);
193                     double start, step, end;
194                     if (AnalysisVisitor::asDouble(pIL->getStart(), start) && AnalysisVisitor::asDouble(pIL->getStep(), step) && AnalysisVisitor::asDouble(pIL->getEnd(), end))
195                     {
196                         double single;
197                         const int type = ForList64::checkList(start, end, step, single);
198
199                         switch (type)
200                         {
201                             case 0 :
202                             {
203                                 out = SymbolicDimension(getGVN(), 0.);
204                                 safe = true;
205                                 return true;
206                             }
207                             case 1 :
208                             {
209                                 out = SymbolicDimension(getGVN(), 1.);
210                                 safe = false;
211                                 return true;
212                             }
213                             case 2 :
214                             {
215                                 const uint64_t N = ForList64::size(start, end, step);
216                                 uint64_t max, min;
217                                 if (step > 0)
218                                 {
219                                     min = start;
220                                     max = (uint64_t)(start + (N - 1) * step);
221                                 }
222                                 else
223                                 {
224                                     max = start;
225                                     min = (uint64_t)(start + (N - 1) * step);
226                                 }
227
228                                 out = SymbolicDimension(getGVN(), N);
229                                 safe = (min >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue((int64_t)max));
230                                 return true;
231                             }
232                         }
233                     }
234                 }
235             }
236             else
237             {
238                 out = SymbolicDimension(getGVN(), 1.);
239                 safe = (de.getValue() >= 1) && getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(de.getValue()));
240                 return true;
241             }
242             return false;
243         }
244         case ast::Exp::BOOLEXP : // a(a > 1) => a([%f %t %t]) => a([2 3])
245         {
246             ast::BoolExp & be = static_cast<ast::BoolExp &>(arg);
247             if (types::InternalType * const pIT = be.getConstant())
248             {
249                 if (pIT->isBool())
250                 {
251                     types::Bool * const pBool = static_cast<types::Bool *>(pIT);
252                     const int size = pBool->getSize();
253                     const int * data = pBool->get();
254                     int max = -1;
255                     int count = 0;
256                     for (int i = 0; i < size; ++i)
257                     {
258                         if (data[i])
259                         {
260                             ++count;
261                             max = i;
262                         }
263                     }
264
265                     out = SymbolicDimension(getGVN(), count);
266                     safe = getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
267                     return true;
268                 }
269             }
270             else
271             {
272                 if (be.getValue())
273                 {
274                     out = SymbolicDimension(getGVN(), 1.);
275                 }
276                 else
277                 {
278                     out = SymbolicDimension(getGVN(), 0.);
279                 }
280                 safe = true;
281                 return true;
282             }
283             return false;
284         }
285         case ast::Exp::LISTEXP :
286         {
287             ast::ListExp & le = static_cast<ast::ListExp &>(arg);
288             SymbolicList sl;
289             if (SymbolicList::get(*this, le, sl))
290             {
291                 if (sl.isSymbolic())
292                 {
293                     sl.evalDollar(getGVN(), dim.getValue());
294                 }
295                 TIType typ;
296                 if (sl.getType(getGVN(), typ))
297                 {
298                     out = SymbolicDimension(getGVN(), typ.cols.getValue());
299                     safe = false;//getCM().check(ConstraintManager::GREATER, dim.getValue(), getGVN().getValue(max));
300                     return true;
301                 }
302             }
303             return false;
304         }
305         default :
306         {
307             arg.accept(*this);
308             Result & _res = getResult();
309             SymbolicRange & range = _res.getRange();
310             if (range.isValid())
311             {
312                 //std::wcerr << *range.getStart()->poly << ":" << *range.getEnd()->poly << ",," << *dim.getValue()->poly << std::endl;
313                 safe = getCM().check(ConstraintManager::VALID_RANGE, range.getStart(), range.getEnd(), getGVN().getValue(1), dim.getValue());
314                 out = _res.getType().rows * _res.getType().cols;
315
316                 return true;
317             }
318
319             if (GVN::Value * const v = _res.getConstant().getGVNValue())
320             {
321                 GVN::Value * w = v;
322                 if (GVN::Value * const dollar = getGVN().getExistingValue(symbol::Symbol(L"$")))
323                 {
324                     if (GVN::Value * const x = SymbolicList::evalDollar(getGVN(), v, dollar, dim.getValue()))
325                     {
326                         w = x;
327                     }
328                 }
329                 bool b = getCM().check(ConstraintManager::GREATER, dim.getValue(), w);
330                 if (b)
331                 {
332                     safe = getCM().check(ConstraintManager::STRICT_POSITIVE, w);
333                 }
334                 else
335                 {
336                     safe = false;
337                 }
338                 out = SymbolicDimension(getGVN(), 1);
339                 return true;
340             }
341
342             // To use with find
343             // e.g. a(find(a > 0)): find(a > 0) return a matrix where the max index is rc(a) so the extraction is safe
344             if (_res.getType().ismatrix() && _res.getType().type != TIType::BOOLEAN)
345             {
346                 out = _res.getType().rows * _res.getType().cols;
347                 SymbolicDimension & maxIndex = _res.getMaxIndex();
348                 if (maxIndex.isValid())
349                 {
350                     safe = getCM().check(ConstraintManager::GREATER, dim.getValue(), maxIndex.getValue());
351                 }
352                 else
353                 {
354                     safe = false;
355                 }
356                 return true;
357             }
358             return false;
359         }
360     }
361 }
362
363
364 }