Analysis: fix bug in listexp when in a vardec
[scilab.git] / scilab / modules / ast / src / cpp / analysis / VisitListExp.cpp
index 8dd4f6d..c623f95 100644 (file)
 namespace analysis
 {
 
-    void AnalysisVisitor::visit(ast::ListExp & e)
-    {
-        logger.log(L"ListExp", e.getLocation());
-        e.getStart().accept(*this);
-        Result & Rstart = e.getStart().getDecorator().getResult();
-        e.getEnd().accept(*this);
-        Result & Rend = e.getEnd().getDecorator().getResult();
-        e.getStep().accept(*this);
-        Result & Rstep = e.getStep().getDecorator().getResult();
-
-       if (e.getParent()->isVarDec())
-       {
-           GVN::Value * startRange;
-           GVN::Value * endRange;
-           if (Rstart.getConstant().getGVNValue(getGVN(), startRange) && Rend.getConstant().getGVNValue(getGVN(), endRange))
-           {
-               ast::VarDec & vd = *static_cast<ast::VarDec *>(e.getParent());
-               const symbol::Symbol & sym = vd.getSymbol();
-               TIType typ(dm.getGVN(), TIType::DOUBLE);
-               Result & res = e.getDecorator().setResult(Result(typ, -1));
-               res.setRange(SymbolicRange(getGVN(), startRange, endRange));
-               setResult(res);
-               return;
-           }
-       }
-       
-        double start, step, end;
-        if (Rstart.getConstant().getDblValue(start) && Rstep.getConstant().getDblValue(step) && Rend.getConstant().getDblValue(end))
-        {
-            double out;
-            int type = ForList64::checkList(start, end, step, out);
+void AnalysisVisitor::visit(ast::ListExp & e)
+{
+    logger.log(L"ListExp", e.getLocation());
+    if (e.getParent()->isVarDec())
+    {
+        visitInVarDecCtxt(e);
+        return;
+    }
 
-            switch (type)
-            {
+    e.getStart().accept(*this);
+    Result & Rstart = e.getStart().getDecorator().getResult();
+    e.getEnd().accept(*this);
+    Result & Rend = e.getEnd().getDecorator().getResult();
+    e.getStep().accept(*this);
+    Result & Rstep = e.getStep().getDecorator().getResult();
+
+    double start = 1;
+    double step = 1;
+    double end = 1;
+    if (Rstart.getConstant().getDblValue(start) && Rstep.getConstant().getDblValue(step) && Rend.getConstant().getDblValue(end))
+    {
+        // Start, Step & End are constant !
+        double out;
+        int type = ForList64::checkList(start, end, step, out);
+
+        switch (type)
+        {
             case 0:
                 e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
                 break;
@@ -69,116 +62,194 @@ namespace analysis
             }
             default:
                 break;
-            }
-            e.setValues(start, step, end, out);
-            setResult(e.getDecorator().res);
-
-            return;
         }
+        e.setValues(start, step, end, out);
+        setResult(e.getDecorator().res);
 
-        if (!Rstep.getConstant().getDblValue(step) || (step != -1 && step != 1))
-        {
-            Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
-            setResult(res);
-           return;
-        }
+        return;
+    }
 
-        if (!Rstart.getType().isscalar() || !Rend.getType().isscalar())
-        {
-            Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
-            setResult(res);
-           return;
-        }
+    if (step == 0 || tools::isNaN(step) || !tools::isFinite(step)
+            || tools::isNaN(start) || !tools::isFinite(start)
+            ||  tools::isNaN(end) || !tools::isFinite(end))
+    {
+        e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
+        return;
+    }
+
+    if (!Rstep.getConstant().getDblValue(step) || (step != -1 && step != 1))
+    {
+        Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
+        setResult(res);
+        return;
+    }
+
+    if (!Rstart.getType().isscalar() || !Rend.getType().isscalar())
+    {
+        Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
+        setResult(res);
+        return;
+    }
 
-        GVN::Value * gvnStart;
-        if (Rstart.getConstant().getDblValue(start))
+    GVN::Value * gvnStart;
+    if (Rstart.getConstant().getDblValue(start))
+    {
+        if (tools::getIntType(start) == tools::NOTANINT)
         {
-            if (tools::getIntType(start) == tools::NOTANINT)
-            {
-                gvnStart = getGVN().getValue((double)tools::cast<int>(start + step));
-            }
-            else
-            {
-                gvnStart = getGVN().getValue((double)tools::cast<int>(start));
-            }
+            gvnStart = getGVN().getValue((double)tools::cast<int>(start + step));
         }
         else
         {
-            gvnStart = Rstart.getConstant().getGVNValue();
-            if (!gvnStart)
-            {
-                Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
-                setResult(res);
-               return;
-            }
+            gvnStart = getGVN().getValue((double)tools::cast<int>(start));
         }
+    }
+    else
+    {
+        gvnStart = Rstart.getConstant().getGVNValue();
+        if (!gvnStart)
+        {
+            Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
+            setResult(res);
+            return;
+        }
+    }
 
-        GVN::Value * gvnEnd;
+    GVN::Value * gvnEnd;
 
-        if (Rend.getConstant().getDblValue(end))
+    if (Rend.getConstant().getDblValue(end))
+    {
+        if (tools::getIntType(end) == tools::NOTANINT)
         {
-            if (tools::getIntType(end) == tools::NOTANINT)
-            {
-                gvnEnd = getGVN().getValue((double)tools::cast<int>(end - step));
-            }
-            else
-            {
-                gvnEnd = getGVN().getValue((double)tools::cast<int>(end));
-            }
+            gvnEnd = getGVN().getValue((double)tools::cast<int>(end - step));
         }
         else
         {
-            gvnEnd = Rend.getConstant().getGVNValue();
-            if (!gvnEnd)
-            {
-                Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
-                setResult(res);
-               return;
-            }
+            gvnEnd = getGVN().getValue((double)tools::cast<int>(end));
         }
-
-        GVN::Value * ONEValue = getGVN().getValue(1);
-        SymbolicDimension ONE(getGVN(), ONEValue);
-        GVN::Value * v;
-
-        if (gvnStart->value == gvnEnd->value)
+    }
+    else
+    {
+        gvnEnd = Rend.getConstant().getGVNValue();
+        if (!gvnEnd)
         {
-            Result & res = e.getDecorator().setResult(Result(TIType(getGVN(), TIType::DOUBLE, ONE, ONE)));
+            Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
             setResult(res);
-           return;
+            return;
         }
+    }
 
-        if (step == 1)
+    GVN::Value * ONEValue = getGVN().getValue(1);
+    SymbolicDimension ONE(getGVN(), ONEValue);
+    GVN::Value * v;
+
+    if (gvnStart->value == gvnEnd->value)
+    {
+        Result & res = e.getDecorator().setResult(Result(TIType(getGVN(), TIType::DOUBLE, ONE, ONE)));
+        setResult(res);
+        return;
+    }
+
+    if (step == 1)
+    {
+        v = getGVN().getValue(OpValue::Kind::MINUS, *gvnEnd, *gvnStart);
+    }
+    else
+    {
+        v = getGVN().getValue(OpValue::Kind::MINUS, *gvnStart, *gvnEnd);
+    }
+    v = getGVN().getValue(OpValue::Kind::PLUS, *v, *ONEValue);
+
+    if (v->poly->constant < 0 && v->poly->isCoeffNegative(false))
+    {
+        TIType type(getGVN(), TIType::EMPTY);
+        e.getDecorator().res = Result(type);
+    }
+    else
+    {
+        bool res = getCM().check(ConstraintManager::POSITIVE, v);
+        if (res)
         {
-            v = getGVN().getValue(OpValue::Kind::MINUS, *gvnEnd, *gvnStart);
+            TIType type(getGVN(), TIType::DOUBLE, ONE, SymbolicDimension(getGVN(), v));
+            e.getDecorator().setResult(type);
         }
         else
         {
-            v = getGVN().getValue(OpValue::Kind::MINUS, *gvnStart, *gvnEnd);
+            Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
+            setResult(res);
+            return;
         }
-        v = getGVN().getValue(OpValue::Kind::PLUS, *v, *ONEValue);
+    }
 
-        if (v->poly->constant < 0 && v->poly->isCoeffNegative(false))
-        {
-            TIType type(getGVN(), TIType::EMPTY);
-            e.getDecorator().res = Result(type);
-        }
-        else
+    setResult(e.getDecorator().res);
+}
+
+void AnalysisVisitor::visitInVarDecCtxt(ast::ListExp & e)
+{
+    e.getStart().accept(*this);
+    Result & Rstart = e.getStart().getDecorator().getResult();
+    e.getEnd().accept(*this);
+    Result & Rend = e.getEnd().getDecorator().getResult();
+    e.getStep().accept(*this);
+    Result & Rstep = e.getStep().getDecorator().getResult();
+
+    double start = 1;
+    double step = 1;
+    double end = 1;
+    if ((Rstart.getConstant().getDblValue(start) || Rstep.getConstant().getDblValue(step)
+            || Rend.getConstant().getDblValue(end)) &&
+            (step == 0 || tools::isNaN(step) || !tools::isFinite(step)
+             || tools::isNaN(start) || !tools::isFinite(start)
+             ||  tools::isNaN(end) || !tools::isFinite(end)))
+    {
+        // We have an invalid list
+        e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
+        return;
+    }
+
+    ast::VarDec & vd = *static_cast<ast::VarDec *>(e.getParent());
+    const symbol::Symbol & sym = vd.getSymbol();
+    GVN::Value * startRange = nullptr;
+    GVN::Value * endRange = nullptr;
+    Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::DOUBLE), -1));
+
+    if (Rstart.getConstant().getGVNValue(getGVN(), startRange) && Rend.getConstant().getGVNValue(getGVN(), endRange))
+    {
+        // Start & End are GVN values
+        res.setRange(SymbolicRange(getGVN(), startRange, endRange));
+    }
+    else
+    {
+        SymbolicRange & rangeStart = Rstart.getRange();
+        if (rangeStart.isValid())
         {
-            bool res = getCM().check(ConstraintManager::POSITIVE, v);
-            if (res)
+            // Start is an iterator: for i=1:N, for j=i:N, ... in the second for "i" in "i:n" is an iterator
+            if (endRange || Rend.getConstant().getGVNValue(getGVN(), endRange))
             {
-                TIType type(getGVN(), TIType::DOUBLE, ONE, SymbolicDimension(getGVN(), v));
-                e.getDecorator().setResult(type);
+                // Start is an iterator and End is GVN value
+                res.setRange(SymbolicRange(getGVN(), rangeStart.getStart(), endRange));
             }
             else
             {
-                Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
-                setResult(res);
-               return;
+                SymbolicRange & rangeEnd = Rend.getRange();
+                if (rangeEnd.isValid())
+                {
+                    // Start & End are iterators
+                    res.setRange(SymbolicRange(getGVN(), rangeStart.getStart(), rangeEnd.getEnd()));
+                }
+            }
+        }
+        else if (startRange || Rstart.getConstant().getGVNValue(getGVN(), startRange))
+        {
+            // Start is a GVN value
+            SymbolicRange & rangeEnd = Rend.getRange();
+            if (rangeEnd.isValid())
+            {
+                // Start is a GVN value and End is an iterator
+                res.setRange(SymbolicRange(getGVN(), startRange, rangeEnd.getEnd()));
             }
         }
-
-        setResult(e.getDecorator().res);
     }
+
+    setResult(res);
+}
 }