add size in constantvisitor
[scilab.git] / scilab / modules / ast / src / cpp / analysis / ConstantVisitor.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - 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 "ConstantVisitor.hxx"
18 #include "double.hxx"
19
20 namespace analysis
21 {
22
23 std::unordered_set<std::wstring> ConstantVisitor::constants = init();
24
25 void ConstantVisitor::visit(ast::SimpleVar & e)
26 {
27     bool isConstant = false;
28     if (evalSymbols)
29     {
30         const symbol::Symbol & sym = e.getSymbol();
31         const std::wstring & name = sym.getName();
32         if (constants.find(name) != constants.end() && symbol::Context::getInstance()->isOriginalSymbol(sym))
33         {
34             if (types::InternalType * pIT = symbol::Context::getInstance()->get(sym))
35             {
36                 e.replace(pIT->getExp(e.getLocation()));
37                 isConstant = true;
38             }
39         }
40         else if (parent)
41         {
42             if (FunctionBlock * fblock = parent->getDM().topFunction())
43             {
44                 ast::Exp * loop = parent->getCurrentLoop();
45                 if (!fblock->getLoopAnalyzer().isAssigned(loop, sym))
46                 {
47                     // We propagate the constant only if we aren't in a loop which modifies the sym
48                     Info & info = parent->getDM().read(sym, &e);
49                     ConstantValue & constant = info.getConstant();
50                     const ConstantValue::Kind kind = constant.getKind();
51                     if (kind == ConstantValue::GVNVAL)
52                     {
53                         double val;
54                         if (constant.getDblValue(val))
55                         {
56                             e.replace(new ast::DoubleExp(e.getLocation(), val));
57                             isConstant = true;
58                         }
59                     }
60                     else if (kind == ConstantValue::ITVAL)
61                     {
62                         types::InternalType * pIT = constant.getIT();
63                         if (ast::Exp * exp = pIT->getExp(e.getLocation()))
64                         {
65                             e.replace(exp);
66                             isConstant = true;
67                         }
68                     }
69                 }
70             }
71         }
72     }
73
74     setResult(isConstant);
75 }
76
77 void ConstantVisitor::visit(ast::OpExp & e)
78 {
79     e.getLeft().accept(*this);
80     const bool constL = getResult();
81     e.getRight().accept(*this);
82     const bool constR = getResult();
83
84     if (constL && constR)
85     {
86         setResult(execAndReplace(e));
87         return;
88     }
89     else if (constL || constR)
90     {
91         const ast::Exp::ExpType ty = e.getParent()->getType();
92         if (ty == ast::Exp::IFEXP || ty == ast::Exp::WHILEEXP)
93         {
94             ast::OpExp::Oper oper = e.getOper();
95             if (oper == ast::OpExp::Oper::logicalShortCutAnd || oper == ast::OpExp::Oper::logicalAnd)
96             {
97                 if (constL)
98                 {
99                     e.getLeft().accept(exec);
100                     if (exec.getResult()->isTrue())
101                     {
102                         e.replace(e.getRight().clone());
103                     }
104                     else
105                     {
106                         types::InternalType * b = new types::Bool(0);
107                         e.replace(b->getExp(e.getLocation()));
108                         setResult(true);
109                         return;
110                     }
111                 }
112                 else
113                 {
114                     e.getRight().accept(exec);
115                     if (exec.getResult()->isTrue())
116                     {
117                         e.replace(e.getLeft().clone());
118                     }
119                     else
120                     {
121                         types::InternalType * b = new types::Bool(0);
122                         e.replace(b->getExp(e.getLocation()));
123                         setResult(true);
124                         return;
125                     }
126                 }
127             }
128             else if (oper == ast::OpExp::Oper::logicalShortCutOr || oper == ast::OpExp::Oper::logicalOr)
129             {
130                 if (constL)
131                 {
132                     e.getLeft().accept(exec);
133                     if (exec.getResult()->isTrue())
134                     {
135                         types::InternalType * b = new types::Bool(1);
136                         e.replace(b->getExp(e.getLocation()));
137                         setResult(true);
138                         return;
139                     }
140                     else
141                     {
142                         e.replace(e.getRight().clone());
143                     }
144                 }
145                 else
146                 {
147                     e.getRight().accept(exec);
148                     if (exec.getResult()->isTrue())
149                     {
150                         types::InternalType * b = new types::Bool(1);
151                         e.replace(b->getExp(e.getLocation()));
152                         setResult(true);
153                         return;
154                     }
155                     else
156                     {
157                         e.replace(e.getLeft().clone());
158                     }
159                 }
160             }
161         }
162     }
163
164     setResult(false);
165 }
166
167 void ConstantVisitor::visit(ast::LogicalOpExp & e)
168 {
169     visit(static_cast<ast::OpExp &>(e));
170 }
171
172 void ConstantVisitor::visit(ast::CallExp & e)
173 {
174     bool isConstant = false;
175
176     if (evalSymbols)
177     {
178         ast::SimpleVar & var = static_cast<ast::SimpleVar &>(e.getName());
179         const symbol::Symbol & sym = var.getSymbol();
180         if (symbol::Context::getInstance()->isOriginalSymbol(sym))
181         {
182             const std::wstring & name = sym.getName();
183             ast::exps_t args = e.getArgs();
184
185             bool allConstant = true;
186             for (auto arg : args)
187             {
188                 arg->accept(*this);
189                 if (allConstant && !getResult())
190                 {
191                     allConstant = false;
192                 }
193             }
194
195             if (allConstant && Checkers::isConst(name, args.size()))
196             {
197                 if (name == L"argn")
198                 {
199                     if (parent && parent->getAnalyzer(sym)->analyze(*parent, lhs, e))
200                     {
201                         if (lhs == 1)
202                         {
203                             double val;
204                             parent->getResult().getConstant().getDblValue(val);
205                             e.replace(new ast::DoubleExp(e.getLocation(), val));
206                             isConstant = true;
207                         }
208                         else
209                         {
210                             double val;
211                             ast::exps_t * exps = new ast::exps_t();
212                             exps->reserve(2);
213                             std::vector<Result> & res = parent->getLHSContainer();
214                             res.front().getConstant().getDblValue(val);
215                             exps->push_back(new ast::DoubleExp(e.getLocation(), val));
216                             res.back().getConstant().getDblValue(val);
217                             exps->push_back(new ast::DoubleExp(e.getLocation(), val));
218                             e.replace(new ast::ArrayListExp(e.getLocation(), *exps));
219                             isConstant = true;
220                         }
221                     }
222                 }
223                 else
224                 {
225                     isConstant = execAndReplace(e);
226                 }
227             }
228
229             if (parent && args.size() == 1)
230             {
231                 if (name == L"type" || name == L"inttype")
232                 {
233                     if (parent->getAnalyzer(sym)->analyze(*parent, 1, e))
234                     {
235                         double val;
236                         parent->getResult().getConstant().getDblValue(val);
237                         e.replace(new ast::DoubleExp(e.getLocation(), val));
238                         isConstant = true;
239                     }
240                 }
241                 else if (name == L"typeof")
242                 {
243                     if (parent->getAnalyzer(sym)->analyze(*parent, 1, e))
244                     {
245                         std::wstring wstr;
246                         if (parent->getResult().getConstant().getStrValue(wstr))
247                         {
248                             e.replace(new ast::StringExp(e.getLocation(), wstr));
249                             isConstant = true;
250                         }
251                     }
252                 }
253                 else if (name == L"isreal" || name == L"isscalar")
254                 {
255                     if (parent->getAnalyzer(sym)->analyze(*parent, 1, e))
256                     {
257                         bool val;
258                         parent->getResult().getConstant().getBoolValue(val);
259                         e.replace(new ast::BoolExp(e.getLocation(), val));
260                         isConstant = true;
261                     }
262                 }
263                 else if (name == L"size")
264                 {
265                     if (parent->getAnalyzer(sym)->analyze(*parent, lhs, e))
266                     {
267                         switch (lhs)
268                         {
269                             case 1: // a = size(x)
270                             {
271                                 std::vector<Result> & res = parent->getLHSContainer();
272                                 double row;
273                                 res.front().getConstant().getDblValue(row);
274
275                                 double col;
276                                 res.back().getConstant().getDblValue(col);
277
278                                 types::Double* pIT = new types::Double(1, 2);
279                                 pIT->get()[0] = row;
280                                 pIT->get()[1] = col;
281                                 e.replace(new ast::DoubleExp(e.getLocation(), pIT));
282                                 isConstant = true;
283                                 break;
284                             }
285                             case 2: // [a, b] = size(x)
286                             {
287                                 double val;
288                                 ast::exps_t * exps = new ast::exps_t();
289                                 exps->reserve(2);
290                                 std::vector<Result> & res = parent->getLHSContainer();
291                                 res.front().getConstant().getDblValue(val);
292                                 exps->push_back(new ast::DoubleExp(e.getLocation(), val));
293                                 res.back().getConstant().getDblValue(val);
294                                 exps->push_back(new ast::DoubleExp(e.getLocation(), val));
295                                 e.replace(new ast::ArrayListExp(e.getLocation(), *exps));
296                                 isConstant = true;
297                                 break;
298                             }
299                         }
300                     }
301                 }
302             }
303             else if (parent && args.size() == 2)
304             {
305                 if (name == L"size")
306                 {
307                     if (parent->getAnalyzer(sym)->analyze(*parent, lhs, e))
308                     {
309                         //a = size(x, "dims") or a = size(x, dim)
310                         double val;
311                         parent->getResult().getConstant().getDblValue(val);
312                         e.replace(new ast::DoubleExp(e.getLocation(), val));
313                         isConstant = true;
314                     }
315                 }
316             }
317         }
318     }
319
320     setResult(isConstant);
321 }
322
323 void ConstantVisitor::visit(ast::MatrixExp & e)
324 {
325     const ast::exps_t & lines = e.getLines();
326     if (lines.empty())
327     {
328         setResult(execAndReplace(e));
329     }
330     else
331     {
332         for (auto line : lines)
333         {
334             const ast::exps_t & columns = static_cast<ast::MatrixLineExp *>(line)->getColumns();
335             for (auto column : columns)
336             {
337                 column->accept(*this);
338                 if (!getResult())
339                 {
340                     return;
341                 }
342             }
343         }
344         setResult(execAndReplace(e));
345     }
346 }
347
348 void ConstantVisitor::visit(ast::NotExp & e)
349 {
350     e.getExp().accept(*this);
351     if (getResult())
352     {
353         setResult(execAndReplace(e));
354     }
355     else
356     {
357         setResult(false);
358     }
359 }
360
361 void ConstantVisitor::visit(ast::TransposeExp & e)
362 {
363     e.getExp().accept(*this);
364     if (getResult())
365     {
366         setResult(execAndReplace(e));
367     }
368     else
369     {
370         setResult(false);
371     }
372 }
373
374 void ConstantVisitor::visit(ast::CellExp & e)
375 {
376     visit(static_cast<ast::MatrixExp &>(e));
377 }
378
379 void ConstantVisitor::visit(ast::ListExp & e)
380 {
381     e.getStart().accept(*this);
382     const bool startConst = getResult();
383     e.getStep().accept(*this);
384     const bool stepConst = getResult();
385     e.getEnd().accept(*this);
386     const bool endConst = getResult();
387
388     if (startConst && stepConst && endConst)
389     {
390         setResult(execAndReplace(e));
391     }
392     else
393     {
394         setResult(false);
395     }
396 }
397
398 void ConstantVisitor::visit(ast::IfExp & e)
399 {
400 }
401
402 void ConstantVisitor::visit(ast::DollarVar & e)
403 {
404     setResult(false);
405 }
406
407 void ConstantVisitor::visit(ast::ColonVar & e)
408 {
409     setResult(false);
410 }
411
412 void ConstantVisitor::visit(ast::ArrayListVar & e)
413 {
414 }
415
416 void ConstantVisitor::visit(ast::DoubleExp & e)
417 {
418     setResult(true);
419 }
420
421 void ConstantVisitor::visit(ast::BoolExp & e)
422 {
423     setResult(true);
424 }
425
426 void ConstantVisitor::visit(ast::StringExp & e)
427 {
428     setResult(true);
429 }
430
431 void ConstantVisitor::visit(ast::CommentExp & e)
432 {
433     // ignored
434 }
435
436 void ConstantVisitor::visit(ast::NilExp & e)
437 {
438     // nothing to do
439 }
440
441 void ConstantVisitor::visit(ast::CellCallExp & e)
442 {
443     setResult(false);
444 }
445
446 void ConstantVisitor::visit(ast::AssignExp & e)
447 {
448 }
449
450 void ConstantVisitor::visit(ast::WhileExp & e)
451 {
452 }
453
454 void ConstantVisitor::visit(ast::ForExp & e)
455 {
456 }
457
458 void ConstantVisitor::visit(ast::BreakExp & e)
459 {
460     // nothing to do
461 }
462
463 void ConstantVisitor::visit(ast::ContinueExp & e)
464 {
465     // nothing to do
466 }
467
468 void ConstantVisitor::visit(ast::TryCatchExp & e)
469 {
470 }
471
472 void ConstantVisitor::visit(ast::SelectExp & e)
473 {
474 }
475
476 void ConstantVisitor::visit(ast::CaseExp & e)
477 {
478 }
479
480 void ConstantVisitor::visit(ast::ReturnExp & e)
481 {
482 }
483
484 void ConstantVisitor::visit(ast::FieldExp & e)
485 {
486 }
487
488 void ConstantVisitor::visit(ast::MatrixLineExp & e)
489 {
490 }
491
492 void ConstantVisitor::visit(ast::SeqExp & e)
493 {
494 }
495
496 void ConstantVisitor::visit(ast::ArrayListExp & e)
497 {
498 }
499
500 void ConstantVisitor::visit(ast::AssignListExp & e)
501 {
502 }
503
504 void ConstantVisitor::visit(ast::VarDec & e)
505 {
506 }
507
508 void ConstantVisitor::visit(ast::FunctionDec & e)
509 {
510 }
511
512 void ConstantVisitor::visit(ast::OptimizedExp & e)
513 {
514 }
515
516 void ConstantVisitor::visit(ast::MemfillExp & e)
517 {
518 }
519
520 void ConstantVisitor::visit(ast::DAXPYExp & e)
521 {
522 }
523
524 void ConstantVisitor::visit(ast::IntSelectExp & e)
525 {
526 }
527
528 void ConstantVisitor::visit(ast::StringSelectExp & e)
529 {
530 }
531
532 std::unordered_set<std::wstring> ConstantVisitor::init()
533 {
534     std::unordered_set<std::wstring> _constants;
535     _constants.emplace(L"%pi");
536     _constants.emplace(L"%eps");
537     _constants.emplace(L"%e");
538     _constants.emplace(L"%i");
539     _constants.emplace(L"%nan");
540     _constants.emplace(L"%inf");
541     _constants.emplace(L"%t");
542     _constants.emplace(L"%f");
543     _constants.emplace(L"%T");
544     _constants.emplace(L"%F");
545     _constants.emplace(L"SCI");
546     _constants.emplace(L"WSCI");
547     _constants.emplace(L"SCIHOME");
548     _constants.emplace(L"TMPDIR");
549
550     return _constants;
551 }
552 }