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 "FileExist.h"
31 static bool getMacroSourceFile(std::string* filename = nullptr);
35 void DebuggerVisitor::visit(const SeqExp &e)
37 std::list<Exp *>::const_iterator itExp;
39 debugger::DebuggerManager* manager = debugger::DebuggerManager::getInstance();
40 if(manager->isAborted())
42 // abort a running execution
43 throw ast::InternalAbort();
46 for (const auto & exp : e.getExps())
48 if (exp->isCommentExp())
59 if (e.isContinuable())
62 exp->setContinuable();
72 if (ConfigVariable::getEnableDebug() &&
73 manager->isInterrupted() == false) // avoid stopping execution if an execution is already paused
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"));
184 // no result ie: assignation
186 sprintf(pcError, _("Wrong breakpoint condition: A result expected.\n"));
187 bp->setConditionError(pcError);
189 else if(pIT->isTrue() == false)
193 stopExecution = false;
197 // condition is invalid or true
199 catch (ast::ScilabException& e)
203 if(ConfigVariable::isError())
205 bp->setConditionError(scilab::UTF8::toUTF8(ConfigVariable::getLastErrorMessage()));
206 ConfigVariable::clearLastError();
207 ConfigVariable::resetError();
211 bp->setConditionError(scilab::UTF8::toUTF8(e.GetErrorMessage()));
218 //we have a breakpoint !
219 //stop execution and wait signal from debugger to restart
222 //only one breakpoint can be "call" on same exp
228 if(stopExecution || manager->isPauseRequested())
230 manager->resetPauseRequest();
231 manager->stop(exp, iBreakPoint);
232 if (manager->isAborted())
234 throw ast::InternalAbort();
239 // interrupt me to execute a prioritary command
240 while (StaticRunner_isRunnerAvailable() == 1 && StaticRunner_isInterruptibleCommand() == 1)
242 StaticRunner_launch();
245 //copy from runvisitor::seqexp
248 //reset default values
250 int iExpectedSize = getExpectedSize();
253 setExpectedSize(iExpectedSize);
254 types::InternalType * pIT = getResult();
256 if(exp->isFunctionDec())
258 // In case of exec file, set the file name in the Macro to store where it is defined.
259 std::wstring strFile = ConfigVariable::getExecutedFile();
260 const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
262 if (strFile != L"" && // check if we are executing a script or a macro
263 lWhereAmI.empty() == false &&
264 lWhereAmI.back().m_file_name != nullptr && // check the last function execution is a macro
265 *(lWhereAmI.back().m_file_name) == strFile) // check the last execution is the same macro as the executed one
267 types::InternalType* pITMacro = symbol::Context::getInstance()->get(exp->getAs<FunctionDec>()->getSymbol());
270 types::Macro* pMacro = pITMacro->getAs<types::Macro>();
271 pMacro->setFileName(strFile);
278 bool bImplicitCall = false;
279 if (pIT->isCallable()) //to manage call without ()
281 types::Callable *pCall = pIT->getAs<types::Callable>();
282 types::typed_list out;
283 types::typed_list in;
284 types::optional_list opt;
288 //in this case of calling, we can return only one value
289 int iSaveExpectedSize = getExpectedSize();
292 pCall->invoke(in, opt, getExpectedSize(), out, *exp);
293 setExpectedSize(iSaveExpectedSize);
304 bImplicitCall = true;
306 catch (const InternalError& ie)
308 if (ConfigVariable::getLastErrorFunction() == L"")
310 ConfigVariable::setLastErrorFunction(pCall->getName());
311 ConfigVariable::setLastErrorLine(e.getLocation().first_line);
318 //don't output Simplevar and empty result
319 if (getResult() != NULL && (!exp->isSimpleVar() || bImplicitCall))
321 //symbol::Context::getInstance()->put(symbol::Symbol(L"ans"), *execMe.getResult());
322 types::InternalType* pITAns = getResult();
323 symbol::Context::getInstance()->put(m_pAns, pITAns);
324 if (exp->isVerbose() && ConfigVariable::isPrintOutput())
326 //TODO manage multiple returns
327 scilabWriteW(L" ans =\n\n");
328 std::wostringstream ostrName;
330 types::VariableToString(pITAns, ostrName.str().c_str());
337 if ((&e)->isBreakable() && exp->isBreak())
339 const_cast<SeqExp *>(&e)->setBreak();
344 if ((&e)->isContinuable() && exp->isContinue())
346 const_cast<SeqExp *>(&e)->setContinue();
347 exp->resetContinue();
351 if ((&e)->isReturnable() && exp->isReturn())
353 const_cast<SeqExp *>(&e)->setReturn();
358 // Stop execution at the end of the seqexp of the caller
359 // Do it at the end of the seqexp will make the debugger stop
360 // even if the caller is at the last line
361 // ie: the caller is followed by endfunction
362 if(manager->isStepOut())
364 manager->resetStepOut();
365 if(getMacroSourceFile() == false)
368 manager->setStepOut();
372 manager->stop(exp, iBreakPoint);
375 if (manager->isAborted())
377 throw ast::InternalAbort();
382 catch (const InternalError& ie)
384 // dont manage an error with the debugger
385 // in cases of try catch and errcatch
386 if(ConfigVariable::isSilentError())
391 ConfigVariable::fillWhereError(ie.GetErrorLocation().first_line);
393 const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
395 //where can be empty on last stepout, on first calling expression
396 if (lWhereAmI.size())
398 const std::wstring* filename = lWhereAmI.back().m_file_name;
400 if (filename == nullptr)
402 //error in a console script
403 std::wstring functionName = lWhereAmI.back().call->getName();
404 manager->errorInScript(functionName, exp);
408 manager->errorInFile(*filename, exp);
411 // Debugger just restart after been stopped on an error.
412 if (manager->isAborted())
414 throw ast::InternalAbort();
421 // If something other than NULL is given to setResult, then that would imply
422 // to make a cleanup in visit(ForExp) for example (e.getBody().accept(*this);)
427 if (e.getParent() == NULL && e.getExecFrom() == SeqExp::SCRIPT && (manager->isStepNext() || manager->isStepIn()))
429 const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
430 if (lWhereAmI.size())
432 std::wstring functionName = lWhereAmI.back().call->getName();
433 types::InternalType* pIT = symbol::Context::getInstance()->get(symbol::Symbol(functionName));
434 if (pIT && (pIT->isMacro() || pIT->isMacroFile()))
436 types::Macro* m = nullptr;
437 if (pIT->isMacroFile())
439 types::MacroFile* mf = pIT->getAs<types::MacroFile>();
444 m = pIT->getAs<types::Macro>();
447 //create a fake exp to represente end/enfunction
449 //will be deleted by CommentExp
450 std::wstring* comment = new std::wstring(L"end of function");
451 Location loc(m->getLastLine(), m->getLastLine(), 0, 0);
452 CommentExp fakeExp(loc, comment);
453 manager->stop(&fakeExp, -1);
455 if (manager->isAborted())
457 throw ast::InternalAbort();
460 //transform stepnext after endfunction as a stepout to show line marker on current statement
461 if (manager->isStepNext())
463 manager->resetStepNext();
464 manager->setStepOut();
466 else if (manager->isStepIn())
468 manager->resetStepIn();
469 manager->setStepOut();
477 // return false if a file .sci of a file .bin doesn't exists
478 // return true for others files or existing .sci
479 bool getMacroSourceFile(std::string* filename)
481 const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
482 // "Where" can be empty at the end of script execution
483 // this function is called when the script ends after a step out
484 if(lWhereAmI.empty())
489 if(lWhereAmI.back().m_file_name == nullptr)
494 std::string file = scilab::UTF8::toUTF8(*lWhereAmI.back().m_file_name);
495 if (file.rfind(".bin") != std::string::npos)
497 file.replace(file.size() - 4, 4, ".sci");
498 // stop on bp only if the file exist
499 if (!FileExist(file.data()))
505 if(filename != nullptr)
507 filename->assign(file);