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