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