debugger: error in try/catch and errcatch fixed
[scilab.git] / scilab / modules / ast / src / cpp / ast / debuggervisitor.cpp
index 97029a2..762d9b6 100644 (file)
 #include "printvisitor.hxx"
 #include "execvisitor.hxx"
 #include "threadId.hxx"
+#include "macrofile.hxx"
+#include "commentexp.hxx"
+#include "UTF8.hxx"
+#include "runner.hxx"
 
 extern "C"
 {
-#include "filemanager_interface.h"
 #include "FileExist.h"
 }
 
+static bool getMacroSourceFile(std::string* filename = nullptr);
+
 namespace ast
 {
 void DebuggerVisitor::visit(const SeqExp  &e)
 {
     std::list<Exp *>::const_iterator itExp;
+
     debugger::DebuggerManager* manager = debugger::DebuggerManager::getInstance();
-    manager->resetAborted();
+    if(manager->isAborted())
+    {
+        // abort a running execution
+        throw ast::InternalAbort();
+    }
 
     for (const auto & exp : e.getExps())
     {
+        if (exp->isCommentExp())
+        {
+            continue;
+        }
+
         if (e.isBreakable())
         {
             exp->resetBreak();
@@ -54,26 +69,37 @@ void DebuggerVisitor::visit(const SeqExp  &e)
 
         //debugger check !
         int iBreakPoint = -1;
-        if (ConfigVariable::getEnableDebug())
+        if (ConfigVariable::getEnableDebug() &&
+            manager->isInterrupted() == false) // avoid stopping execution if an execution is already paused
         {
             bool stopExecution = false;
             if (manager->isStepIn())
             {
                 manager->resetStepIn();
                 stopExecution = true;
+                if(getMacroSourceFile() == false)
+                {
+                    stopExecution = false;
+                    manager->setStepIn();
+                }
             }
             else if (manager->isStepNext())
             {
                 manager->resetStepNext();
                 stopExecution = true;
+                if(getMacroSourceFile() == false)
+                {
+                    stopExecution = false;
+                    manager->setStepOut();
+                }
             }
             else
             {
-                std::vector<ConfigVariable::WhereEntry> lWhereAmI = ConfigVariable::getWhere();
+                const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
                 //set information from debugger commands
                 if (lWhereAmI.size() != 0 && manager->getBreakPointCount() != 0)
                 {
-                    debugger::Breakpoints bps = manager->getAllBreakPoint();
+                    debugger::Breakpoints& bps = manager->getAllBreakPoint();
 
                     int i = -1;
                     for (const auto & bp : bps)
@@ -85,52 +111,43 @@ void DebuggerVisitor::visit(const SeqExp  &e)
                         }
 
                         // look for a breakpoint on this line and update breakpoint information when possible
-                        char* functionName = wide_string_to_UTF8(lWhereAmI.back().call->getName().data());
-                        std::wstring pstrFileName = lWhereAmI.back().m_file_name;
-                        char* fileName = wide_string_to_UTF8(pstrFileName.data());
-
                         int iLine = exp->getLocation().first_line - ConfigVariable::getMacroFirstLines();
-                        if (bp->hasMacro() &&
-                            bp->getFunctioName().compare(functionName) == 0)
-                        {
-                            if (bp->getMacroLine() == 0)
-                            {
-                                //first pass in macro.
-                                //update first line with real value
-                                bp->setMacroLine(iLine);
-                            }
-
-                            stopExecution = bp->getMacroLine() == iLine;
-                        }
-                        else if(bp->hasFile() &&
-                                bp->getFileLine() == exp->getLocation().first_line)
+                        if (bp->hasMacro())
                         {
-                            if(pstrFileName.rfind(L".bin") != std::string::npos)
+                            char* functionName = wide_string_to_UTF8(lWhereAmI.back().call->getName().data());
+                            if (bp->getFunctioName().compare(functionName) == 0)
                             {
-                                pstrFileName.replace(pstrFileName.size() - 4, 4, L".sci");
-                                // stop on bp only if the file exist
-                                if (FileExistW(pstrFileName.data()))
+                                if (bp->getMacroLine() == 0)
                                 {
-                                    FREE(fileName);
-                                    fileName = wide_string_to_UTF8(pstrFileName.data());
+                                    //first pass in macro.
+                                    //update first line with real value
+                                    bp->setMacroLine(iLine);
                                 }
+
+                                stopExecution = bp->getMacroLine() == iLine;
                             }
 
-                            if(bp->getFileName().compare(fileName) == 0)
+                            FREE(functionName);
+                        }
+                        else if (bp->hasFile())
+                        {
+                            if (bp->getFileLine() == exp->getLocation().first_line)
                             {
-                                stopExecution = true;
-                                // set function information
-                                if(lWhereAmI.back().call->getFirstLine())
+                                std::string pFileName;
+                                bool hasSource = getMacroSourceFile(&pFileName);
+                                if (hasSource && bp->getFileName() == pFileName)
                                 {
-                                    bp->setFunctionName(functionName);
-                                    bp->setMacroLine(iLine);
+                                    stopExecution = true;
+                                    // set function information
+                                    if (lWhereAmI.back().call->getFirstLine())
+                                    {
+                                        bp->setFunctionName(scilab::UTF8::toUTF8(lWhereAmI.back().call->getName()));
+                                        bp->setMacroLine(iLine);
+                                    }
                                 }
                             }
                         }
 
-                        FREE(functionName);
-                        FREE(fileName);
-
                         if(stopExecution == false)
                         {
                             // no breakpoint for this line
@@ -162,28 +179,40 @@ void DebuggerVisitor::visit(const SeqExp  &e)
                                 pCtx->scope_begin();
                                 bp->getConditionExp()->accept(execCond);
                                 types::InternalType* pIT = pCtx->getCurrentLevel(symbol::Symbol(L"ans"));
-                                if (pIT == NULL ||
-                                        pIT->isBool() == false ||
-                                        ((types::Bool*)pIT)->isScalar() == false ||
-                                        ((types::Bool*)pIT)->get(0) == 0)
+                                if (pIT == NULL)
+                                {
+                                    // no result ie: assignation
+                                    char pcError[256];
+                                    sprintf(pcError, _("Wrong breakpoint condition: A result expected.\n"));
+                                    bp->setConditionError(pcError);
+                                }
+                                else if(pIT->isTrue() == false)
                                 {
+                                    // bool scalar false
                                     pCtx->scope_end();
-                                    //not a boolean, not scalar or false
                                     stopExecution = false;
                                     continue;
                                 }
 
-                                pCtx->scope_end();
-                                //ok condition is valid and true
+                                // condition is invalid or true
                             }
-                            catch (ast::ScilabException &/*e*/)
+                            catch (ast::ScilabException& e)
                             {
-                                pCtx->scope_end();
-                                stopExecution = false;
                                 //not work !
                                 //invalid breakpoint
-                                continue;
+                                if(ConfigVariable::isError())
+                                {
+                                    bp->setConditionError(scilab::UTF8::toUTF8(ConfigVariable::getLastErrorMessage()));
+                                    ConfigVariable::clearLastError();
+                                    ConfigVariable::resetError();
+                                }
+                                else
+                                {
+                                    bp->setConditionError(scilab::UTF8::toUTF8(e.GetErrorMessage()));
+                                }
                             }
+
+                            pCtx->scope_end();
                         }
 
                         //we have a breakpoint !
@@ -196,8 +225,9 @@ void DebuggerVisitor::visit(const SeqExp  &e)
                 }
             }
 
-            if(stopExecution)
+            if(stopExecution || manager->isPauseRequested())
             {
+                manager->resetPauseRequest();
                 manager->stop(exp, iBreakPoint);
                 if (manager->isAborted())
                 {
@@ -206,6 +236,12 @@ void DebuggerVisitor::visit(const SeqExp  &e)
             }
         }
 
+        // interrupt me to execute a prioritary command
+        while (StaticRunner_isRunnerAvailable() == 1 && StaticRunner_isInterruptibleCommand() == 1)
+        {
+            StaticRunner_launch();
+        }
+
         //copy from runvisitor::seqexp
         try
         {
@@ -217,20 +253,22 @@ void DebuggerVisitor::visit(const SeqExp  &e)
             setExpectedSize(iExpectedSize);
             types::InternalType * pIT = getResult();
 
-            // In case of exec file, set the file name in the Macro to store where it is defined.
-            int iFileID = ConfigVariable::getExecutedFileID();
-            if (iFileID && exp->isFunctionDec())
+            if(exp->isFunctionDec())
             {
-                types::InternalType* pITMacro = symbol::Context::getInstance()->get(exp->getAs<ast::FunctionDec>()->getSymbol());
-                if (pITMacro)
+                // In case of exec file, set the file name in the Macro to store where it is defined.
+                std::wstring strFile = ConfigVariable::getExecutedFile();
+                const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
+
+                if (strFile != L"" &&  // check if we are executing a script or a macro
+                    lWhereAmI.empty() == false &&
+                    lWhereAmI.back().m_file_name != nullptr && // check the last function execution is a macro
+                    *(lWhereAmI.back().m_file_name) == strFile) // check the last execution is the same macro as the executed one
                 {
-                    types::Macro* pMacro = pITMacro->getAs<types::Macro>();
-                    const wchar_t* filename = getfile_filename(iFileID);
-                    // scilab.quit is not open with mopen
-                    // in this case filename is NULL because FileManager have not been filled.
-                    if (filename)
+                    types::InternalType* pITMacro = symbol::Context::getInstance()->get(exp->getAs<FunctionDec>()->getSymbol());
+                    if (pITMacro)
                     {
-                        pMacro->setFileName(filename);
+                        types::Macro* pMacro = pITMacro->getAs<types::Macro>();
+                        pMacro->setFileName(strFile);
                     }
                 }
             }
@@ -324,7 +362,16 @@ void DebuggerVisitor::visit(const SeqExp  &e)
             if(manager->isStepOut())
             {
                 manager->resetStepOut();
-                manager->stop(exp, iBreakPoint);
+                if(getMacroSourceFile() == false)
+                {
+                    // no sources
+                    manager->setStepOut();
+                }
+                else
+                {
+                    manager->stop(exp, iBreakPoint);
+                }
+
                 if (manager->isAborted())
                 {
                     throw ast::InternalAbort();
@@ -334,16 +381,23 @@ void DebuggerVisitor::visit(const SeqExp  &e)
         }
         catch (const InternalError& ie)
         {
+            // dont manage an error with the debugger
+            // in cases of try catch and errcatch
+            if(ConfigVariable::isSilentError())
+            {
+                throw ie;
+            }
+
             ConfigVariable::fillWhereError(ie.GetErrorLocation().first_line);
 
-            std::vector<ConfigVariable::WhereEntry> lWhereAmI = ConfigVariable::getWhere();
+            const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
 
             //where can be empty on last stepout, on first calling expression
             if (lWhereAmI.size())
             {
-                std::wstring& filename = lWhereAmI.back().m_file_name;
+                const std::wstring* filename = lWhereAmI.back().m_file_name;
 
-                if (filename.empty())
+                if (filename == nullptr)
                 {
                     //error in a console script
                     std::wstring functionName = lWhereAmI.back().call->getName();
@@ -351,7 +405,7 @@ void DebuggerVisitor::visit(const SeqExp  &e)
                 }
                 else
                 {
-                    manager->errorInFile(filename, exp);
+                    manager->errorInFile(*filename, exp);
                 }
 
                 // Debugger just restart after been stopped on an error.
@@ -369,5 +423,89 @@ void DebuggerVisitor::visit(const SeqExp  &e)
         setResult(NULL);
 
     }
+
+    if (e.getParent() == NULL && e.getExecFrom() == SeqExp::SCRIPT && (manager->isStepNext() || manager->isStepIn()))
+    {
+        const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
+        if (lWhereAmI.size())
+        {
+            std::wstring functionName = lWhereAmI.back().call->getName();
+            types::InternalType* pIT = symbol::Context::getInstance()->get(symbol::Symbol(functionName));
+            if (pIT && (pIT->isMacro() || pIT->isMacroFile()))
+            {
+                types::Macro* m = nullptr;
+                if (pIT->isMacroFile())
+                {
+                    types::MacroFile* mf = pIT->getAs<types::MacroFile>();
+                    m = mf->getMacro();
+                }
+                else
+                {
+                    m = pIT->getAs<types::Macro>();
+                }
+
+                //create a fake exp to represente end/enfunction
+
+                //will be deleted by CommentExp
+                std::wstring* comment = new std::wstring(L"end of function");
+                Location loc(m->getLastLine(), m->getLastLine(), 0, 0);
+                CommentExp fakeExp(loc, comment);
+                manager->stop(&fakeExp, -1);
+
+                if (manager->isAborted())
+                {
+                    throw ast::InternalAbort();
+                }
+
+                //transform stepnext after endfunction as a stepout to show line marker on current statement
+                if (manager->isStepNext())
+                {
+                    manager->resetStepNext();
+                    manager->setStepOut();
+                }
+                else if (manager->isStepIn())
+                {
+                    manager->resetStepIn();
+                    manager->setStepOut();
+                }
+            }
+        }
+    }
+}
 }
+
+// return false if a file .sci of a file .bin doesn't exists
+// return true for others files or existing .sci
+bool getMacroSourceFile(std::string* filename)
+{
+    const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
+    // "Where" can be empty at the end of script execution
+    // this function is called when the script ends after a step out
+    if(lWhereAmI.empty())
+    {
+        return false;
+    }
+
+    if(lWhereAmI.back().m_file_name == nullptr)
+    {
+        return false;
+    }
+
+    std::string file = scilab::UTF8::toUTF8(*lWhereAmI.back().m_file_name);
+    if (file.rfind(".bin") != std::string::npos)
+    {
+        file.replace(file.size() - 4, 4, ".sci");
+        // stop on bp only if the file exist
+        if (!FileExist(file.data()))
+        {
+            return false;
+        }
+    }
+
+    if(filename != nullptr)
+    {
+        filename->assign(file);
+    }
+
+    return true;
 }