Analysis: fix bug in listexp when in a vardec
[scilab.git] / scilab / modules / ast / src / cpp / analysis / SizeAnalyzer.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 "analyzers/SizeAnalyzer.hxx"
15 #include "call/SizeCall.hxx"
16 #include "tools.hxx"
17 #include "double.hxx"
18
19 namespace analysis
20 {
21 bool SizeAnalyzer::analyze(AnalysisVisitor & visitor, const unsigned int lhs, ast::CallExp & e)
22 {
23     if (lhs > 2)
24     {
25         return false;
26     }
27
28     const ast::exps_t args = e.getArgs();
29     enum Kind
30     {
31         ROWS, COLS, ROWSTIMESCOLS, ROWSCOLS, ONE, BOTH
32     } kind;
33     const std::size_t size = args.size();
34     if (size == 0 || size >= 3)
35     {
36         return false;
37     }
38
39     ast::Exp * first = *args.begin();
40     if (!first)
41     {
42         return false;
43     }
44     first->accept(visitor);
45     Result & res = visitor.getResult();
46     if (!res.getType().ismatrix())
47     {
48         visitor.getDM().releaseTmp(res.getTempId());
49         return false;
50     }
51
52     switch (size)
53     {
54         case 1:
55             if (lhs == 1)
56             {
57                 kind = BOTH;
58             }
59             else if (lhs == 2)
60             {
61                 kind = ROWSCOLS;
62             }
63             break;
64         case 2:
65         {
66             ast::Exp * second = *std::next(args.begin());
67             if (second && lhs == 1)
68             {
69                 if (second->isStringExp())
70                 {
71                     const std::wstring & arg2 = static_cast<ast::StringExp *>(second)->getValue();
72                     if (arg2 == L"r")
73                     {
74                         kind = ROWS;
75                     }
76                     else if (arg2 == L"c")
77                     {
78                         kind = COLS;
79                     }
80                     else if (arg2 == L"*")
81                     {
82                         kind = ROWSTIMESCOLS;
83                     }
84                     else
85                     {
86                         visitor.getDM().releaseTmp(res.getTempId());
87                         return false;
88                     }
89                 }
90                 else if (second->isDoubleExp())
91                 {
92                     const double arg2 = static_cast<ast::DoubleExp *>(second)->getValue();
93                     if (arg2 == 1)
94                     {
95                         kind = ROWS;
96                     }
97                     else if (arg2 == 2)
98                     {
99                         kind = COLS;
100                     }
101                     else if (arg2 >= 3)
102                     {
103                         // TODO: we should handle hypermatrix
104                         kind = ONE;
105                     }
106                     else
107                     {
108                         visitor.getDM().releaseTmp(res.getTempId());
109                         return false;
110                     }
111                 }
112             }
113             else
114             {
115                 visitor.getDM().releaseTmp(res.getTempId());
116                 return false;
117             }
118             break;
119         }
120         default:
121             visitor.getDM().releaseTmp(res.getTempId());
122             return false;
123     }
124
125     TIType type(visitor.getGVN(), TIType::DOUBLE);
126
127     switch (kind)
128     {
129         case ROWS:
130         {
131             SymbolicDimension & rows = res.getType().rows;
132             Result & _res = e.getDecorator().setResult(type);
133             _res.getConstant() = rows.getValue();
134             e.getDecorator().setCall(new SizeCall(SizeCall::R));
135             visitor.setResult(_res);
136             break;
137         }
138         case COLS:
139         {
140             SymbolicDimension & cols = res.getType().cols;
141             Result & _res = e.getDecorator().setResult(type);
142             _res.getConstant() = cols.getValue();
143             e.getDecorator().setCall(new SizeCall(SizeCall::C));
144             visitor.setResult(_res);
145             break;
146         }
147         case ROWSTIMESCOLS:
148         {
149             SymbolicDimension & rows = res.getType().rows;
150             SymbolicDimension & cols = res.getType().cols;
151             SymbolicDimension prod = rows * cols;
152             Result & _res = e.getDecorator().setResult(type);
153             _res.getConstant() = prod.getValue();
154             e.getDecorator().setCall(new SizeCall(SizeCall::RC));
155             visitor.setResult(_res);
156             break;
157         }
158         case ROWSCOLS:
159         {
160             SymbolicDimension & rows = res.getType().rows;
161             SymbolicDimension & cols = res.getType().cols;
162             std::vector<Result> & mlhs = visitor.getLHSContainer();
163             mlhs.clear();
164             mlhs.reserve(2);
165             mlhs.emplace_back(type);
166             mlhs.back().getConstant() = rows.getValue();
167             mlhs.emplace_back(type);
168             mlhs.back().getConstant() = cols.getValue();
169
170             e.getDecorator().setCall(new SizeCall(SizeCall::R_C));
171             break;
172         }
173         case ONE:
174         {
175             Result & _res = e.getDecorator().setResult(type);
176             _res.getConstant() = new types::Double(1);
177             e.getDecorator().setCall(new SizeCall(SizeCall::ONE));
178             visitor.setResult(_res);
179             break;
180         }
181         case BOTH:
182         {
183             TIType _type(visitor.getGVN(), TIType::DOUBLE, 1, 2);
184             Result & _res = e.getDecorator().setResult(_type);
185             e.getDecorator().setCall(new SizeCall(SizeCall::BOTH));
186             visitor.setResult(_res);
187             break;
188         }
189     }
190
191     return true;
192 }
193 }