debugger: error in try/catch and errcatch fixed
[scilab.git] / scilab / modules / ast / src / cpp / ast / debuggervisitor.cpp
index bd803c0..762d9b6 100644 (file)
 #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())
     {
@@ -61,18 +69,29 @@ 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
             {
@@ -114,28 +133,15 @@ void DebuggerVisitor::visit(const SeqExp  &e)
                         {
                             if (bp->getFileLine() == exp->getLocation().first_line)
                             {
-                                std::wstring pstrFileName = *lWhereAmI.back().m_file_name;
-                                char* fileName = wide_string_to_UTF8(pstrFileName.data());
-
-                                if (pstrFileName.rfind(L".bin") != std::string::npos)
-                                {
-                                    pstrFileName.replace(pstrFileName.size() - 4, 4, L".sci");
-                                    // stop on bp only if the file exist
-                                    if (FileExistW(pstrFileName.data()))
-                                    {
-                                        FREE(fileName);
-                                        fileName = wide_string_to_UTF8(pstrFileName.data());
-                                    }
-                                }
-
-                                if (bp->getFileName().compare(fileName) == 0)
+                                std::string pFileName;
+                                bool hasSource = getMacroSourceFile(&pFileName);
+                                if (hasSource && bp->getFileName() == pFileName)
                                 {
-                                    char* functionName = wide_string_to_UTF8(lWhereAmI.back().call->getName().data());
                                     stopExecution = true;
                                     // set function information
                                     if (lWhereAmI.back().call->getFirstLine())
                                     {
-                                        bp->setFunctionName(functionName);
+                                        bp->setFunctionName(scilab::UTF8::toUTF8(lWhereAmI.back().call->getName()));
                                         bp->setMacroLine(iLine);
                                     }
                                 }
@@ -173,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 !
@@ -207,8 +225,9 @@ void DebuggerVisitor::visit(const SeqExp  &e)
                 }
             }
 
-            if(stopExecution)
+            if(stopExecution || manager->isPauseRequested())
             {
+                manager->resetPauseRequest();
                 manager->stop(exp, iBreakPoint);
                 if (manager->isAborted())
                 {
@@ -217,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
         {
@@ -228,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);
                     }
                 }
             }
@@ -335,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();
@@ -345,6 +381,13 @@ 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);
 
             const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
@@ -381,7 +424,7 @@ void DebuggerVisitor::visit(const SeqExp  &e)
 
     }
 
-    if (e.getParent() == NULL && e.getExecFrom() == SeqExp::SCRIPT && manager->isStepNext())
+    if (e.getParent() == NULL && e.getExecFrom() == SeqExp::SCRIPT && (manager->isStepNext() || manager->isStepIn()))
     {
         const std::vector<ConfigVariable::WhereEntry>& lWhereAmI = ConfigVariable::getWhere();
         if (lWhereAmI.size())
@@ -420,8 +463,49 @@ void DebuggerVisitor::visit(const SeqExp  &e)
                     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;
+}