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