Analysis: add info about $ and fix bug
[scilab.git] / scilab / modules / ast / includes / analysis / AnalysisVisitor.hxx
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 #ifndef __ANALYSIS_VISITOR_HXX__
14 #define __ANALYSIS_VISITOR_HXX__
15
16 #include <algorithm>
17 #include <limits>
18 #include <map>
19 #include <memory>
20 #include <stack>
21 #include <vector>
22
23 #include "visitor.hxx"
24 #include "prettyprintvisitor.hxx"
25 #include "execvisitor.hxx"
26 #include "printvisitor.hxx"
27 #include "allexp.hxx"
28 #include "allvar.hxx"
29 #include "analyzers/CallAnalyzer.hxx"
30 #include "checkers/Checkers.hxx"
31 #include "Chrono.hxx"
32 #include "DollarInfo.hxx"
33 #include "ForList.hxx"
34 #include "Result.hxx"
35 #include "TIType.hxx"
36 #include "ConstantVisitor.hxx"
37 #include "gvn/SymbolicList.hxx"
38 #include "FBlockEmittedListener.hxx"
39 #include "data/DataManager.hxx"
40 #include "data/PolymorphicMacroCache.hxx"
41 #include "gvn/ConstraintManager.hxx"
42 #include "logging/Logger.hxx"
43 #include "dynlib_ast.h"
44
45 namespace analysis
46 {
47
48 class EXTERN_AST AnalysisVisitor : public ast::Visitor, public Chrono
49 {
50
51 public:
52
53     typedef std::unordered_map<std::wstring, std::shared_ptr<CallAnalyzer>> MapSymCall;
54
55 private:
56
57     Result _result;
58     DataManager dm;
59     PolymorphicMacroCache pmc;
60     ConstraintManager cm;
61     ConstantVisitor cv;
62     ast::PrettyPrintVisitor dv;
63     ast::PrintVisitor pv;
64     std::vector<Result> multipleLHS;
65     logging::Logger logger;
66     std::vector<FBlockEmittedListener *> fblockListeners;
67     std::stack<ast::Exp *> loops;
68     std::stack<DollarInfo> argIndices;
69
70     static MapSymCall symscall;
71     static MapSymCall initCalls();
72
73 public:
74
75     static bool asDouble(ast::Exp & e, double & out);
76     static bool asDouble(types::InternalType * pIT, double & out);
77     static bool isDoubleConstant(const ast::Exp & e);
78     static bool asDoubleMatrix(ast::Exp & e, types::Double *& data);
79     static void analyze(ast::SelectExp & e);
80
81     AnalysisVisitor();
82     virtual ~AnalysisVisitor();
83
84     virtual AnalysisVisitor* clone()
85     {
86         return new AnalysisVisitor();
87     }
88
89     inline CallAnalyzer * getAnalyzer(const symbol::Symbol & sym)
90     {
91         MapSymCall::iterator it = symscall.find(sym.getName());
92         if (it == symscall.end())
93         {
94             return nullptr;
95         }
96         else
97         {
98             return it->second.get();
99         }
100     }
101
102     inline DataManager & getDM()
103     {
104         return dm;
105     }
106
107     inline GVN & getGVN()
108     {
109         return dm.getGVN();
110     }
111
112     inline PolymorphicMacroCache & getPMC()
113     {
114         return pmc;
115     }
116
117     inline ConstantVisitor & getCV()
118     {
119         return cv;
120     }
121
122     inline ast::PrintVisitor & getPV()
123     {
124         return pv;
125     }
126
127     inline ast::PrettyPrintVisitor & getDV()
128     {
129         return dv;
130     }
131
132     inline ast::ExecVisitor & getExec()
133     {
134         return cv.getExec();
135     }
136
137     inline void finalize()
138     {
139         //dm.finalize(nullptr);
140     }
141
142     inline void setResult(Result & val)
143     {
144         _result = val;
145     }
146
147     inline void setResult(Result && val)
148     {
149         _result = val;
150     }
151
152     inline Result & getResult()
153     {
154         return _result;
155     }
156
157     inline std::vector<Result> & getLHSContainer()
158     {
159         return multipleLHS;
160     }
161
162     inline ConstraintManager & getCM()
163     {
164         if (FunctionBlock * fblock = getDM().topFunction())
165         {
166             return fblock->getConstraintManager();
167         }
168         else
169         {
170             return cm;
171         }
172     }
173
174     inline ast::Exp * getCurrentLoop() const
175     {
176         if (!loops.empty())
177         {
178             return loops.top();
179         }
180
181         return nullptr;
182     }
183
184     inline void registerFBlockEmittedListener(FBlockEmittedListener * listener)
185     {
186         if (listener)
187         {
188             fblockListeners.push_back(listener);
189         }
190     }
191
192     inline void emitFunctionBlock(FunctionBlock & fblock)
193     {
194         for (auto listener : fblockListeners)
195         {
196             listener->action(fblock);
197         }
198     }
199
200     inline Info & getSymInfo(const symbol::Symbol & sym)
201     {
202         return dm.getInfo(sym);
203     }
204
205     void reset();
206     bool analyzeIndices(TIType & type, ast::CallExp & ce);
207
208     // Only for debug use
209     void print_info();
210     logging::Logger & getLogger();
211
212 private:
213
214     bool getDimension(SymbolicDimension & dim, ast::Exp & arg, bool & safe, SymbolicDimension & out);
215
216     /*
217        Workaround for a C++11 bug with Intel compiler
218        https://software.intel.com/fr-fr/forums/topic/514793
219     */
220     inline static TIType _check_plus(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
221     {
222         return Checkers::check_____add____(gvn, Ltype, Rtype);
223     }
224
225     inline static TIType _check_minus(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
226     {
227         return Checkers::check_____sub____(gvn, Ltype, Rtype);
228     }
229
230     inline static TIType _check_dottimes(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
231     {
232         return Checkers::check_____dottimes____(gvn, Ltype, Rtype);
233     }
234
235     inline static TIType _check_dotrdiv(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
236     {
237         return Checkers::check_____dotrdiv____(gvn, Ltype, Rtype);
238     }
239
240     inline static TIType _check_dotpower(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
241     {
242         return Checkers::check_____dotpower____(gvn, Ltype, Rtype);
243     }
244
245     inline static TIType _check_eq(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
246     {
247         return Checkers::check_____eq____(gvn, Ltype, Rtype);
248     }
249
250     inline static TIType _check_neq(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
251     {
252         return Checkers::check_____neq____(gvn, Ltype, Rtype);
253     }
254
255     inline static TIType _check_lt(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
256     {
257         return Checkers::check_____lt____(gvn, Ltype, Rtype);
258     }
259
260     inline static TIType _check_le(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
261     {
262         return Checkers::check_____le____(gvn, Ltype, Rtype);
263     }
264
265     inline static TIType _check_gt(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
266     {
267         return Checkers::check_____gt____(gvn, Ltype, Rtype);
268     }
269
270     inline static TIType _check_ge(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
271     {
272         return Checkers::check_____ge____(gvn, Ltype, Rtype);
273     }
274
275     inline static TIType _check_and(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
276     {
277         return Checkers::check_____and____(gvn, Ltype, Rtype);
278     }
279
280     inline static TIType _check_or(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
281     {
282         return Checkers::check_____or____(gvn, Ltype, Rtype);
283     }
284
285     inline static TIType _check_andand(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
286     {
287         return Checkers::check_____and____(gvn, Ltype, Rtype);
288     }
289
290     inline static TIType _check_oror(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
291     {
292         return Checkers::check_____or____(gvn, Ltype, Rtype);
293     }
294
295     template<TIType (F)(GVN &, const TIType &, const TIType &)>
296     inline TIType checkEWBinOp(TIType & LT, TIType & RT, const Result & LR, const Result & RR, bool & safe, int & tempId, ast::Exp * Lexp, ast::Exp * Rexp)
297     {
298         TIType resT = F(getGVN(), LT, RT);
299         if (resT.hasInvalidDims())
300         {
301             const bool ret = getCM().check(ConstraintManager::SAMEDIMS, LT.rows.getValue(), LT.cols.getValue(), RT.rows.getValue(), RT.cols.getValue());
302
303             if (ret)
304             {
305                 resT = F(getGVN(), LT, RT);
306                 safe = true;
307             }
308             else
309             {
310                 resT = resT.asUnknownMatrix();
311             }
312         }
313         else
314         {
315             safe = true;
316         }
317
318         tempId = getTmpIdForEWOp(resT, LR, RR, Lexp, Rexp);
319
320         if (resT.isscalar())
321         {
322             // TODO
323         }
324
325         return resT;
326     }
327
328     bool operGVNValues(ast::OpExp & oe);
329     bool operSymbolicRange(ast::OpExp & oe);
330
331     // get temp id for an element-wise operation
332     // A + (B + 1) => B+1 is a temp, A is not and we can reuse the temp to put the result of A + (B+1)
333     int getTmpIdForEWOp(const TIType & resT, const Result & LR, const Result & RR, ast::Exp * Lexp, ast::Exp * Rexp);
334     void visitArguments(const std::wstring & name, const unsigned int lhs, const TIType & calltype, ast::CallExp & e, const ast::exps_t & args);
335
336     void visit(ast::SelectExp & e);
337     void visit(ast::ListExp & e);
338     void visitInVarDecCtxt(ast::ListExp & e);
339     void visit(ast::MatrixExp & e);
340     void visit(ast::OpExp & e);
341     void visit(ast::NotExp & e);
342     void visit(ast::TransposeExp & e);
343     void visit(ast::AssignExp & e);
344     void visit(ast::IfExp & e);
345     void visit(ast::ForExp & e);
346     void visit(ast::CallExp & e);
347     void visit(ast::CallExp & e, const unsigned int lhs);
348     void visit(ast::SeqExp & e);
349     void visit(ast::DoubleExp & e);
350     void visit(ast::BoolExp & e);
351     void visit(ast::StringExp & e);
352     void visit(ast::SimpleVar & e);
353     void visit(ast::DollarVar & e);
354     void visit(ast::VarDec & e);
355
356     void visit(ast::MatrixLineExp & e)
357     {
358         /* treated in MatrixExp */
359     }
360     void visit(ast::OptimizedExp & e) { }
361     void visit(ast::MemfillExp & e) { }
362     void visit(ast::DAXPYExp & e) { }
363     void visit(ast::IntSelectExp & e) { }
364     void visit(ast::StringSelectExp & e) { }
365     void visit(ast::CommentExp & e) { }
366     void visit(ast::NilExp & e) { }
367     void visit(ast::ColonVar & e) { }
368
369     void visit(ast::ArrayListVar & e)
370     {
371         logger.log(L"ArrayListVar", e.getLocation());
372         const ast::exps_t & vars = e.getVars();
373         for (auto var : vars)
374         {
375             var->accept(*this);
376         }
377     }
378
379     void visit(ast::CellCallExp & e)
380     {
381         logger.log(L"CellCallExp", e.getLocation());
382         visit(static_cast<ast::CallExp &>(e));
383     }
384
385     void visit(ast::LogicalOpExp & e)
386     {
387         logger.log(L"LogicalOpExp", e.getLocation());
388         visit(static_cast<ast::OpExp &>(e));
389     }
390
391     void visit(ast::WhileExp & e)
392     {
393         logger.log(L"WhileExp", e.getLocation());
394         loops.push(&e);
395         e.getTest().accept(*this);
396         dm.releaseTmp(getResult().getTempId(), &e.getTest());
397         e.getBody().accept(*this);
398         loops.pop();
399     }
400
401     void visit(ast::BreakExp & e)
402     {
403         logger.log(L"BreakExp", e.getLocation());
404         // nothing to do
405     }
406
407     void visit(ast::ContinueExp & e)
408     {
409         logger.log(L"ContinueExp", e.getLocation());
410         // nothing to do
411     }
412
413     void visit(ast::TryCatchExp & e)
414     {
415         logger.log(L"TryCatchExp", e.getLocation());
416         e.getTry().accept(*this);
417         e.getCatch().accept(*this);
418     }
419
420     void visit(ast::CaseExp & e)
421     {
422         logger.log(L"CaseExp", e.getLocation());
423         e.getTest()->accept(*this);
424         e.getBody()->accept(*this);
425     }
426
427     void visit(ast::ReturnExp & e)
428     {
429         logger.log(L"ReturnExp", e.getLocation());
430         getDM().getCurrent()->setReturn(true);
431         // Bug with return;
432         //e.exp_get().accept(*this);
433
434     }
435
436     void visit(ast::FieldExp & e)
437     {
438         logger.log(L"FieldExp", e.getLocation());
439         // a.b.c <=> (a.b).c where a.b is the head and c is the tail
440
441         //e.head_get()->accept(*this);
442         //e.tail_get()->accept(*this);
443     }
444
445     void visit(ast::CellExp & e)
446     {
447         logger.log(L"CellExp", e.getLocation());
448         visit(static_cast<ast::MatrixExp &>(e));
449     }
450
451     void visit(ast::ArrayListExp & e)
452     {
453         logger.log(L"ArrayListExp", e.getLocation());
454         const ast::exps_t & exps = e.getExps();
455         for (const auto exp : e.getExps())
456         {
457             exp->accept(*this);
458         }
459     }
460
461     void visit(ast::AssignListExp & e)
462     {
463         logger.log(L"AssignListExp", e.getLocation());
464         visit(static_cast<ast::ArrayListExp &>(e));
465     }
466
467     void visit(ast::FunctionDec & e)
468     {
469         /*e.args_get().accept(*this);
470           e.returns_get().accept(*this);
471           e.body_get().accept(*this);*/
472         logger.log(L"FunctionDec", e.getLocation());
473         dm.macrodef(&e);
474     }
475 };
476
477 } // namespace analysis
478
479 #endif // __ANALYSIS_VISITOR_HXX__