Analysis: fix bug in listexp when in a vardec
[scilab.git] / scilab / modules / ast / src / cpp / analysis / VisitListExp.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014 - 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 #include "tools.hxx"
15
16 namespace analysis
17 {
18
19 void AnalysisVisitor::visit(ast::ListExp & e)
20 {
21     logger.log(L"ListExp", e.getLocation());
22     if (e.getParent()->isVarDec())
23     {
24         visitInVarDecCtxt(e);
25         return;
26     }
27
28     e.getStart().accept(*this);
29     Result & Rstart = e.getStart().getDecorator().getResult();
30     e.getEnd().accept(*this);
31     Result & Rend = e.getEnd().getDecorator().getResult();
32     e.getStep().accept(*this);
33     Result & Rstep = e.getStep().getDecorator().getResult();
34
35     double start = 1;
36     double step = 1;
37     double end = 1;
38     if (Rstart.getConstant().getDblValue(start) && Rstep.getConstant().getDblValue(step) && Rend.getConstant().getDblValue(end))
39     {
40         // Start, Step & End are constant !
41         double out;
42         int type = ForList64::checkList(start, end, step, out);
43
44         switch (type)
45         {
46             case 0:
47                 e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
48                 break;
49             case 1:
50                 e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::DOUBLE), -1));
51                 break;
52             case 2:
53             {
54                 const uint64_t N = ForList64::size(start, end, step);
55                 TIType T(dm.getGVN(), TIType::DOUBLE, 1, N);
56                 if (N == 1)
57                 {
58                     out = start;
59                 }
60                 e.getDecorator().setResult(Result(T, dm.getTmpId(T, false)));
61                 break;
62             }
63             default:
64                 break;
65         }
66         e.setValues(start, step, end, out);
67         setResult(e.getDecorator().res);
68
69         return;
70     }
71
72     if (step == 0 || tools::isNaN(step) || !tools::isFinite(step)
73             || tools::isNaN(start) || !tools::isFinite(start)
74             ||  tools::isNaN(end) || !tools::isFinite(end))
75     {
76         e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
77         return;
78     }
79
80     if (!Rstep.getConstant().getDblValue(step) || (step != -1 && step != 1))
81     {
82         Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
83         setResult(res);
84         return;
85     }
86
87     if (!Rstart.getType().isscalar() || !Rend.getType().isscalar())
88     {
89         Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
90         setResult(res);
91         return;
92     }
93
94     GVN::Value * gvnStart;
95     if (Rstart.getConstant().getDblValue(start))
96     {
97         if (tools::getIntType(start) == tools::NOTANINT)
98         {
99             gvnStart = getGVN().getValue((double)tools::cast<int>(start + step));
100         }
101         else
102         {
103             gvnStart = getGVN().getValue((double)tools::cast<int>(start));
104         }
105     }
106     else
107     {
108         gvnStart = Rstart.getConstant().getGVNValue();
109         if (!gvnStart)
110         {
111             Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
112             setResult(res);
113             return;
114         }
115     }
116
117     GVN::Value * gvnEnd;
118
119     if (Rend.getConstant().getDblValue(end))
120     {
121         if (tools::getIntType(end) == tools::NOTANINT)
122         {
123             gvnEnd = getGVN().getValue((double)tools::cast<int>(end - step));
124         }
125         else
126         {
127             gvnEnd = getGVN().getValue((double)tools::cast<int>(end));
128         }
129     }
130     else
131     {
132         gvnEnd = Rend.getConstant().getGVNValue();
133         if (!gvnEnd)
134         {
135             Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
136             setResult(res);
137             return;
138         }
139     }
140
141     GVN::Value * ONEValue = getGVN().getValue(1);
142     SymbolicDimension ONE(getGVN(), ONEValue);
143     GVN::Value * v;
144
145     if (gvnStart->value == gvnEnd->value)
146     {
147         Result & res = e.getDecorator().setResult(Result(TIType(getGVN(), TIType::DOUBLE, ONE, ONE)));
148         setResult(res);
149         return;
150     }
151
152     if (step == 1)
153     {
154         v = getGVN().getValue(OpValue::Kind::MINUS, *gvnEnd, *gvnStart);
155     }
156     else
157     {
158         v = getGVN().getValue(OpValue::Kind::MINUS, *gvnStart, *gvnEnd);
159     }
160     v = getGVN().getValue(OpValue::Kind::PLUS, *v, *ONEValue);
161
162     if (v->poly->constant < 0 && v->poly->isCoeffNegative(false))
163     {
164         TIType type(getGVN(), TIType::EMPTY);
165         e.getDecorator().res = Result(type);
166     }
167     else
168     {
169         bool res = getCM().check(ConstraintManager::POSITIVE, v);
170         if (res)
171         {
172             TIType type(getGVN(), TIType::DOUBLE, ONE, SymbolicDimension(getGVN(), v));
173             e.getDecorator().setResult(type);
174         }
175         else
176         {
177             Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
178             setResult(res);
179             return;
180         }
181     }
182
183     setResult(e.getDecorator().res);
184 }
185
186 void AnalysisVisitor::visitInVarDecCtxt(ast::ListExp & e)
187 {
188     e.getStart().accept(*this);
189     Result & Rstart = e.getStart().getDecorator().getResult();
190     e.getEnd().accept(*this);
191     Result & Rend = e.getEnd().getDecorator().getResult();
192     e.getStep().accept(*this);
193     Result & Rstep = e.getStep().getDecorator().getResult();
194
195     double start = 1;
196     double step = 1;
197     double end = 1;
198     if ((Rstart.getConstant().getDblValue(start) || Rstep.getConstant().getDblValue(step)
199             || Rend.getConstant().getDblValue(end)) &&
200             (step == 0 || tools::isNaN(step) || !tools::isFinite(step)
201              || tools::isNaN(start) || !tools::isFinite(start)
202              ||  tools::isNaN(end) || !tools::isFinite(end)))
203     {
204         // We have an invalid list
205         e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
206         return;
207     }
208
209     ast::VarDec & vd = *static_cast<ast::VarDec *>(e.getParent());
210     const symbol::Symbol & sym = vd.getSymbol();
211     GVN::Value * startRange = nullptr;
212     GVN::Value * endRange = nullptr;
213     Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::DOUBLE), -1));
214
215     if (Rstart.getConstant().getGVNValue(getGVN(), startRange) && Rend.getConstant().getGVNValue(getGVN(), endRange))
216     {
217         // Start & End are GVN values
218         res.setRange(SymbolicRange(getGVN(), startRange, endRange));
219     }
220     else
221     {
222         SymbolicRange & rangeStart = Rstart.getRange();
223         if (rangeStart.isValid())
224         {
225             // Start is an iterator: for i=1:N, for j=i:N, ... in the second for "i" in "i:n" is an iterator
226             if (endRange || Rend.getConstant().getGVNValue(getGVN(), endRange))
227             {
228                 // Start is an iterator and End is GVN value
229                 res.setRange(SymbolicRange(getGVN(), rangeStart.getStart(), endRange));
230             }
231             else
232             {
233                 SymbolicRange & rangeEnd = Rend.getRange();
234                 if (rangeEnd.isValid())
235                 {
236                     // Start & End are iterators
237                     res.setRange(SymbolicRange(getGVN(), rangeStart.getStart(), rangeEnd.getEnd()));
238                 }
239             }
240         }
241         else if (startRange || Rstart.getConstant().getGVNValue(getGVN(), startRange))
242         {
243             // Start is a GVN value
244             SymbolicRange & rangeEnd = Rend.getRange();
245             if (rangeEnd.isValid())
246             {
247                 // Start is a GVN value and End is an iterator
248                 res.setRange(SymbolicRange(getGVN(), startRange, rangeEnd.getEnd()));
249             }
250         }
251     }
252
253     setResult(res);
254 }
255 }