2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
5 * Copyright (C) 2012 - 2016 - Scilab Enterprises
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.
16 #include "debuggervisitor.hxx"
17 #include "debugmanager.hxx"
18 #include "printvisitor.hxx"
19 #include "execvisitor.hxx"
20 #include "threadId.hxx"
21 #include "macrofile.hxx"
22 #include "commentexp.hxx"
28 #include "filemanager_interface.h"
29 #include "FileExist.h"
32 static bool getMacroSourceFile(std::string* filename = nullptr);
36 void DebuggerVisitor::visit(const SeqExp &e)
38 std::list<Exp *>::const_iterator itExp;
40 debugger::DebuggerManager* manager = debugger::DebuggerManager::getInstance();
41 if(manager->isAborted())
43 // abort a running execution
44 throw ast::InternalAbort();
47 for (const auto & exp : e.getExps())
49 if (exp->isCommentExp())
60 if (e.isContinuable())
63 exp->setContinuable();
73 if (ConfigVariable::getEnableDebug())
75 bool stopExecution = false;
76 if (manager->isStepIn())
78 manager->resetStepIn();
80 if(getMacroSourceFile() == false)
82 stopExecution = false;
86 else if (manager->isStepNext())
88 manager->resetStepNext();
90 if(getMacroSourceFile() == false)
92 stopExecution = false;
93 manager->setStepOut();
98 const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
99 //set information from debugger commands
100 if (lWhereAmI.size() != 0 && manager->getBreakPointCount() != 0)
102 debugger::Breakpoints& bps = manager->getAllBreakPoint();
105 for (const auto & bp : bps)
108 if (bp->isEnable() == false)
113 // look for a breakpoint on this line and update breakpoint information when possible
114 int iLine = exp->getLocation().first_line - ConfigVariable::getMacroFirstLines();
117 char* functionName = wide_string_to_UTF8(lWhereAmI.back().call->getName().data());
118 if (bp->getFunctioName().compare(functionName) == 0)
120 if (bp->getMacroLine() == 0)
122 //first pass in macro.
123 //update first line with real value
124 bp->setMacroLine(iLine);
127 stopExecution = bp->getMacroLine() == iLine;
132 else if (bp->hasFile())
134 if (bp->getFileLine() == exp->getLocation().first_line)
136 std::string pFileName;
137 bool hasSource = getMacroSourceFile(&pFileName);
138 if (hasSource && bp->getFileName() == pFileName)
140 stopExecution = true;
141 // set function information
142 if (lWhereAmI.back().call->getFirstLine())
144 bp->setFunctionName(scilab::UTF8::toUTF8(lWhereAmI.back().call->getName()));
145 bp->setMacroLine(iLine);
151 if(stopExecution == false)
153 // no breakpoint for this line
157 // Set the begin of line if not yet done
158 if(bp->getBeginLine() == 0)
160 bp->setBeginLine(exp->getLocation().first_column);
162 // check if this exp is at the begin of the breakpoint line
163 else if(bp->getBeginLine() != exp->getLocation().first_column)
165 // stop only if we are at the line begins
166 stopExecution = false;
171 if (bp->getConditionExp() != NULL)
173 //do not use debuggervisitor !
174 symbol::Context* pCtx = symbol::Context::getInstance();
177 ExecVisitor execCond;
178 //protect current env during condition execution
180 bp->getConditionExp()->accept(execCond);
181 types::InternalType* pIT = pCtx->getCurrentLevel(symbol::Symbol(L"ans"));
183 pIT->isBool() == false ||
184 ((types::Bool*)pIT)->isScalar() == false ||
185 ((types::Bool*)pIT)->get(0) == 0)
188 //not a boolean, not scalar or false
189 stopExecution = false;
194 //ok condition is valid and true
196 catch (ast::ScilabException &/*e*/)
199 stopExecution = false;
206 //we have a breakpoint !
207 //stop execution and wait signal from debugger to restart
210 //only one breakpoint can be "call" on same exp
218 manager->stop(exp, iBreakPoint);
219 if (manager->isAborted())
221 throw ast::InternalAbort();
226 // interrupt me to execute a prioritary command
227 while (StaticRunner_isRunnerAvailable() == 1 && StaticRunner_isInterruptibleCommand() == 1)
229 StaticRunner_launch();
232 //copy from runvisitor::seqexp
235 //reset default values
237 int iExpectedSize = getExpectedSize();
240 setExpectedSize(iExpectedSize);
241 types::InternalType * pIT = getResult();
243 // In case of exec file, set the file name in the Macro to store where it is defined.
244 int iFileID = ConfigVariable::getExecutedFileID();
245 if (iFileID && exp->isFunctionDec())
247 types::InternalType* pITMacro = symbol::Context::getInstance()->get(exp->getAs<ast::FunctionDec>()->getSymbol());
250 types::Macro* pMacro = pITMacro->getAs<types::Macro>();
251 const wchar_t* filename = getfile_filename(iFileID);
252 // scilab.quit is not open with mopen
253 // in this case filename is NULL because FileManager have not been filled.
256 pMacro->setFileName(filename);
263 bool bImplicitCall = false;
264 if (pIT->isCallable()) //to manage call without ()
266 types::Callable *pCall = pIT->getAs<types::Callable>();
267 types::typed_list out;
268 types::typed_list in;
269 types::optional_list opt;
273 //in this case of calling, we can return only one value
274 int iSaveExpectedSize = getExpectedSize();
277 pCall->invoke(in, opt, getExpectedSize(), out, *exp);
278 setExpectedSize(iSaveExpectedSize);
289 bImplicitCall = true;
291 catch (const InternalError& ie)
293 if (ConfigVariable::getLastErrorFunction() == L"")
295 ConfigVariable::setLastErrorFunction(pCall->getName());
296 ConfigVariable::setLastErrorLine(e.getLocation().first_line);
303 //don't output Simplevar and empty result
304 if (getResult() != NULL && (!exp->isSimpleVar() || bImplicitCall))
306 //symbol::Context::getInstance()->put(symbol::Symbol(L"ans"), *execMe.getResult());
307 types::InternalType* pITAns = getResult();
308 symbol::Context::getInstance()->put(m_pAns, pITAns);
309 if (exp->isVerbose() && ConfigVariable::isPrintOutput())
311 //TODO manage multiple returns
312 scilabWriteW(L" ans =\n\n");
313 std::wostringstream ostrName;
315 types::VariableToString(pITAns, ostrName.str().c_str());
322 if ((&e)->isBreakable() && exp->isBreak())
324 const_cast<SeqExp *>(&e)->setBreak();
329 if ((&e)->isContinuable() && exp->isContinue())
331 const_cast<SeqExp *>(&e)->setContinue();
332 exp->resetContinue();
336 if ((&e)->isReturnable() && exp->isReturn())
338 const_cast<SeqExp *>(&e)->setReturn();
343 // Stop execution at the end of the seqexp of the caller
344 // Do it at the end of the seqexp will make the debugger stop
345 // even if the caller is at the last line
346 // ie: the caller is followed by endfunction
347 if(manager->isStepOut())
349 manager->resetStepOut();
350 if(getMacroSourceFile() == false)
353 manager->setStepOut();
357 manager->stop(exp, iBreakPoint);
360 if (manager->isAborted())
362 throw ast::InternalAbort();
367 catch (const InternalError& ie)
369 ConfigVariable::fillWhereError(ie.GetErrorLocation().first_line);
371 const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
373 //where can be empty on last stepout, on first calling expression
374 if (lWhereAmI.size())
376 const std::wstring* filename = lWhereAmI.back().m_file_name;
378 if (filename == nullptr)
380 //error in a console script
381 std::wstring functionName = lWhereAmI.back().call->getName();
382 manager->errorInScript(functionName, exp);
386 manager->errorInFile(*filename, exp);
389 // Debugger just restart after been stopped on an error.
390 if (manager->isAborted())
392 throw ast::InternalAbort();
399 // If something other than NULL is given to setResult, then that would imply
400 // to make a cleanup in visit(ForExp) for example (e.getBody().accept(*this);)
405 if (e.getParent() == NULL && e.getExecFrom() == SeqExp::SCRIPT && (manager->isStepNext() || manager->isStepIn()))
407 const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
408 if (lWhereAmI.size())
410 std::wstring functionName = lWhereAmI.back().call->getName();
411 types::InternalType* pIT = symbol::Context::getInstance()->get(symbol::Symbol(functionName));
412 if (pIT && (pIT->isMacro() || pIT->isMacroFile()))
414 types::Macro* m = nullptr;
415 if (pIT->isMacroFile())
417 types::MacroFile* mf = pIT->getAs<types::MacroFile>();
422 m = pIT->getAs<types::Macro>();
425 //create a fake exp to represente end/enfunction
427 //will be deleted by CommentExp
428 std::wstring* comment = new std::wstring(L"end of function");
429 Location loc(m->getLastLine(), m->getLastLine(), 0, 0);
430 CommentExp fakeExp(loc, comment);
431 manager->stop(&fakeExp, -1);
433 if (manager->isAborted())
435 throw ast::InternalAbort();
438 //transform stepnext after endfunction as a stepout to show line marker on current statement
439 if (manager->isStepNext())
441 manager->resetStepNext();
442 manager->setStepOut();
444 else if (manager->isStepIn())
446 manager->resetStepIn();
447 manager->setStepOut();
455 // return false if a file .sci of a file .bin doesn't exists
456 // return true for others files or existing .sci
457 bool getMacroSourceFile(std::string* filename)
459 const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
460 std::string file = scilab::UTF8::toUTF8(*lWhereAmI.back().m_file_name);
461 if (file.rfind(".bin") != std::string::npos)
463 file.replace(file.size() - 4, 4, ".sci");
464 // stop on bp only if the file exist
465 if (!FileExist(file.data()))
471 if(filename != nullptr)
473 filename->assign(file);