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