Merge remote-tracking branch 'origin/master' into jit
[scilab.git] / scilab / modules / ast / src / cpp / ast / debuggervisitor.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
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 #include "debuggervisitor.hxx"
14 #include "debugmanager.hxx"
15 #include "printvisitor.hxx"
16 #include "execvisitor.hxx"
17 #include "threadId.hxx"
18
19 extern "C"
20 {
21 #include "filemanager_interface.h"
22 }
23
24 namespace ast
25 {
26 void DebuggerVisitor::visit(const SeqExp  &e)
27 {
28     RunVisitor* exec = NULL;
29     std::list<Exp *>::const_iterator itExp;
30     debugger::DebuggerMagager* manager = debugger::DebuggerMagager::getInstance();
31
32     if (ConfigVariable::getEnableDebug() == false)
33     {
34         //enable debugger for next execution
35         ConfigVariable::setEnableDebug(true);
36
37         ExecVisitor exec;
38         e.accept(exec);
39         return;
40     }
41
42     for (const auto& exp : e.getExps())
43     {
44         if (e.isBreakable())
45         {
46             exp->resetBreak();
47             exp->setBreakable();
48         }
49
50         if (e.isContinuable())
51         {
52             exp->resetContinue();
53             exp->setContinuable();
54         }
55
56         if (e.isReturnable())
57         {
58             exp->setReturnable();
59         }
60
61         //debugger check !
62         if (ConfigVariable::getEnableDebug())
63         {
64             std::vector<ConfigVariable::WhereEntry> lWhereAmI = ConfigVariable::getWhere();
65             int iLine = (exp->getLocation().first_line - ConfigVariable::getMacroFirstLines()) + 1;
66
67             //manage step next
68             if (manager->isStepNext())
69             {
70                 manager->resetStepNext();
71                 manager->stop(exp, -1);
72             }
73             else if (manager->isStepIn())
74             {
75                 manager->resetStepIn();
76                 manager->stop(exp, -1);
77             }
78             else if (manager->isStepOut())
79             {
80                 manager->resetStepOut();
81                 manager->stop(exp, -1);
82             }
83             else
84             {
85                 //set information from debugger commands
86                 if (lWhereAmI.size() != 0 && manager->getBreakPointCount() != 0)
87                 {
88                     debugger::Breakpoints bps = manager->getAllBreakPoint();
89                     std::wstring functionName = lWhereAmI.back().m_name;
90                     int i = -1;
91                     for (const auto& bp : bps)
92                     {
93                         ++i;
94                         if (bp->isEnable() == false)
95                         {
96                             continue;
97                         }
98
99                         if (functionName == bp->getFunctioName())
100                         {
101                             if (bp->getMacroLine() == -1)
102                             {
103                                 //first pass in macro.
104                                 //update first line with real value
105                                 bp->setMacroLine(iLine);
106                             }
107
108                             if (bp->getMacroLine() == iLine)
109                             {
110                                 //check condition
111                                 if (bp->getConditionExp() != NULL)
112                                 {
113                                     //do not use debuggervisitor !
114                                     symbol::Context* pCtx = symbol::Context::getInstance();
115                                     try
116                                     {
117                                         ExecVisitor execCond;
118                                         //protect current env during condition execution
119                                         pCtx->scope_begin();
120                                         bp->getConditionExp()->accept(execCond);
121                                         types::InternalType* pIT = pCtx->getCurrentLevel(symbol::Symbol(L"ans"));
122                                         if (pIT == NULL ||
123                                                 pIT->isBool() == false ||
124                                                 ((types::Bool*)pIT)->isScalar() == false ||
125                                                 ((types::Bool*)pIT)->get(0) == 0)
126                                         {
127                                             pCtx->scope_end();
128                                             //not a boolean, not scalar or false
129                                             continue;
130                                         }
131
132                                         pCtx->scope_end();
133                                         //ok condition is valid and true
134                                     }
135                                     catch (ast::ScilabException &/*e*/)
136                                     {
137                                         pCtx->scope_end();
138                                         //not work !
139                                         //invalid breakpoint
140                                         continue;
141                                     }
142                                 }
143
144                                 //we have a breakpoint !
145                                 //stop execution and wait signal from debugger to restart
146                                 manager->stop(exp, i);
147
148                                 //only one breakpoint can be "call" on same exp
149                                 break;
150                             }
151                         }
152                     }
153                 }
154             }
155             exec = this;
156         }
157         else
158         {
159             //change visitor to execvitor instead of debuggervisitor
160             exec = new ExecVisitor();
161         }
162
163         //copy from runvisitor::seqexp
164         try
165         {
166             //reset default values
167             setResult(NULL);
168             int iExpectedSize = getExpectedSize();
169             setExpectedSize(-1);
170             exp->accept(*exec);
171             setExpectedSize(iExpectedSize);
172             types::InternalType * pIT = getResult();
173
174             // In case of exec file, set the file name in the Macro to store where it is defined.
175             int iFileID = ConfigVariable::getExecutedFileID();
176             if (iFileID && exp->isFunctionDec())
177             {
178                 types::InternalType* pITMacro = symbol::Context::getInstance()->get(exp->getAs<ast::FunctionDec>()->getSymbol());
179                 if (pITMacro)
180                 {
181                     types::Macro* pMacro = pITMacro->getAs<types::Macro>();
182                     const wchar_t* filename = getfile_filename(iFileID);
183                     // scilab.quit is not open with mopen
184                     // in this case filename is NULL because FileManager have not been filled.
185                     if (filename)
186                     {
187                         pMacro->setFileName(filename);
188                     }
189                 }
190             }
191
192             if (pIT != NULL)
193             {
194                 bool bImplicitCall = false;
195                 if (pIT->isCallable()) //to manage call without ()
196                 {
197                     types::Callable *pCall = pIT->getAs<types::Callable>();
198                     types::typed_list out;
199                     types::typed_list in;
200                     types::optional_list opt;
201
202                     try
203                     {
204                         //in this case of calling, we can return only one values
205                         int iSaveExpectedSize = getExpectedSize();
206                         setExpectedSize(1);
207
208                         pCall->invoke(in, opt, getExpectedSize(), out, e);
209                         setExpectedSize(iSaveExpectedSize);
210
211                         if (out.size() == 0)
212                         {
213                             setResult(NULL);
214                         }
215                         else
216                         {
217                             setResult(out[0]);
218                         }
219
220                         bImplicitCall = true;
221                     }
222                     catch (const InternalError& ie)
223                     {
224                         if (ConfigVariable::getLastErrorFunction() == L"")
225                         {
226                             ConfigVariable::setLastErrorFunction(pCall->getName());
227                             ConfigVariable::setLastErrorLine(e.getLocation().first_line);
228                         }
229
230                         throw ie;
231                     }
232                 }
233
234                 //don't output Simplevar and empty result
235                 if (getResult() != NULL && (!exp->isSimpleVar() || bImplicitCall))
236                 {
237                     //symbol::Context::getInstance()->put(symbol::Symbol(L"ans"), *execMe.getResult());
238                     types::InternalType* pITAns = getResult();
239                     symbol::Context::getInstance()->put(m_pAns, pITAns);
240                     if (exp->isVerbose() && ConfigVariable::isPromptShow())
241                     {
242                         //TODO manage multiple returns
243                         scilabWriteW(L" ans  =\n\n");
244                         std::wostringstream ostrName;
245                         ostrName << L"ans";
246                         types::VariableToString(pITAns, ostrName.str().c_str());
247                     }
248                 }
249
250                 pIT->killMe();
251             }
252
253             if ((&e)->isBreakable() && exp->isBreak())
254             {
255                 const_cast<SeqExp *>(&e)->setBreak();
256                 exp->resetBreak();
257                 break;
258             }
259
260             if ((&e)->isContinuable() && exp->isContinue())
261             {
262                 const_cast<SeqExp *>(&e)->setContinue();
263                 exp->resetContinue();
264                 break;
265             }
266
267             if ((&e)->isReturnable() && exp->isReturn())
268             {
269                 const_cast<SeqExp *>(&e)->setReturn();
270                 exp->resetReturn();
271                 break;
272             }
273         }
274         catch (const InternalError& ie)
275         {
276             ConfigVariable::fillWhereError(ie.GetErrorLocation().first_line);
277
278             std::vector<ConfigVariable::WhereEntry> lWhereAmI = ConfigVariable::getWhere();
279
280             //where can be empty on last stepout, on first calling expression
281             if (lWhereAmI.size())
282             {
283                 std::wstring& filename = lWhereAmI.back().m_file_name;
284
285                 if (filename.empty())
286                 {
287                     //error in a console script
288                     std::wstring functionName = lWhereAmI.back().m_name;
289                     manager->errorInScript(functionName, exp);
290                 }
291                 else
292                 {
293                     manager->errorInFile(filename, exp);
294                 }
295             }
296
297             throw ie;
298         }
299
300         // If something other than NULL is given to setResult, then that would imply
301         // to make a cleanup in visit(ForExp) for example (e.getBody().accept(*this);)
302         setResult(NULL);
303
304     }
305
306     //propagate StepNext to parent SeqExp
307     if (ConfigVariable::getEnableDebug())
308     {
309     }
310 }
311 }
312