* Bug 15374 fixed: now trivial infinite loop can be interrupted
[scilab.git] / scilab / modules / ast / src / cpp / ast / run_SeqExp.hpp
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 *
14 */
15
16 #include <fstream>
17 //file included in runvisitor.cpp
18 namespace ast {
19
20 template <class T>
21 void RunVisitorT<T>::visitprivate(const SeqExp  &e)
22 {
23     CoverageInstance::invokeAndStartChrono((void*)&e);
24     int lastLine = 0;
25     ast::exps_t exps = e.getExps();
26     ast::exps_t::const_iterator it = exps.begin();
27     ast::exps_t::const_iterator itEnd = exps.end();
28
29
30     /*stuff of printf input during execution*/
31     std::string str;
32     int iCurrentLine = -1; //no data in str
33
34     std::ifstream* file = nullptr;
35     if (e.getExecFrom() == SeqExp::EXEC)
36     {
37         //open input file to print exp from it
38         int iFileID = ConfigVariable::getExecutedFileID();
39         if (iFileID)
40         {
41             const wchar_t* filename = getfile_filename(iFileID);
42             if (filename)
43             {
44                 char* cfilename = wide_string_to_UTF8(filename);
45                 file = new std::ifstream(cfilename);
46                 FREE(cfilename);
47             }
48         }
49     }
50
51     if (exps.size() == 0)
52     {
53         if (ConfigVariable::isExecutionBreak())
54         {
55             ConfigVariable::resetExecutionBreak();
56             if (ConfigVariable::isPrintInteractive())
57             {
58                 ClearTemporaryPrompt();
59             }
60
61             StorePrioritaryCommand("pause");
62             ThreadManagement::WaitForRunMeSignal();
63         }
64
65         // interrupt me to execute a prioritary command
66         while (StaticRunner_isInterruptibleCommand() == 1 && StaticRunner_isRunnerAvailable() == 1)
67         {
68             StaticRunner_launch();
69             StaticRunner_setInterruptibleCommand(1);
70         }
71
72         if (file)
73         {
74             file->close();
75             delete file;
76         }
77
78         CoverageInstance::stopChrono((void*)&e);
79         return;
80     }
81
82     for (; it != itEnd; ++it)
83     {
84         if (ConfigVariable::isExecutionBreak())
85         {
86             ConfigVariable::resetExecutionBreak();
87             if (ConfigVariable::isPrintInteractive())
88             {
89                 ClearTemporaryPrompt();
90             }
91
92             StorePrioritaryCommand("pause");
93             ThreadManagement::WaitForRunMeSignal();
94         }
95
96         // interrupt me to execute a prioritary command
97         while (StaticRunner_isInterruptibleCommand() == 1 && StaticRunner_isRunnerAvailable() == 1)
98         {
99             StaticRunner_launch();
100             StaticRunner_setInterruptibleCommand(1);
101         }
102
103         //printf input expression line following mode configuration
104         if (file && ConfigVariable::isPrintInput())
105         {
106             Location loc = (*it)->getLocation();
107             if (iCurrentLine + 1 < loc.first_line)
108             {
109                 //get prompt
110                 std::string stPrompt = GetCurrentPrompt();
111                 if (ConfigVariable::isPrintInteractive())
112                 {
113                     stPrompt = SCIPROMPT_PAUSE;
114                 }
115
116                 ast::exps_t::const_iterator k = it;
117                 int iLastLine = loc.last_line;
118                 int iCurrentCol = 0; //no data in str
119                 do
120                 {
121                     str = printExp(*file, *k, stPrompt, &iCurrentLine, &iCurrentCol, str);
122                     iLastLine = (*k)->getLocation().last_line;
123                     k++;
124                 } while (k != exps.end() && (*k)->getLocation().first_line == iLastLine);
125             }
126         }
127
128         if ((*it)->isCommentExp())
129         {
130             continue;
131         }
132
133         try
134         {
135             //reset default values
136             setResult(NULL);
137             int iExpectedSize = getExpectedSize();
138             setExpectedSize(-1);
139             (*it)->accept(*this);
140             setExpectedSize(iExpectedSize);
141             types::InternalType * pIT = getResult();
142
143             // In case of exec file, set the file name in the Macro to store where it is defined.
144             int iFileID = ConfigVariable::getExecutedFileID();
145             if (iFileID && (*it)->isFunctionDec())
146             {
147                 types::InternalType* pITMacro = symbol::Context::getInstance()->get((*it)->getAs<FunctionDec>()->getSymbol());
148                 if (pITMacro)
149                 {
150                     types::Macro* pMacro = pITMacro->getAs<types::Macro>();
151                     const wchar_t* filename = getfile_filename(iFileID);
152                     // scilab.quit is not open with mopen
153                     // in this case filename is NULL because FileManager have not been filled.
154                     if (filename)
155                     {
156                         pMacro->setFileName(filename);
157                     }
158                 }
159             }
160
161             if (pIT != NULL)
162             {
163                 bool bImplicitCall = false;
164                 if (pIT->isCallable()) //to manage call without ()
165                 {
166                     types::Callable *pCall = pIT->getAs<types::Callable>();
167                     types::typed_list out;
168                     types::typed_list in;
169                     types::optional_list opt;
170
171                     try
172                     {
173                         //in this case of calling, we can return at most one value
174                         int iSaveExpectedSize = getExpectedSize();
175                         setExpectedSize(0);
176
177                         pCall->invoke(in, opt, getExpectedSize(), out, **it);
178                         setExpectedSize(iSaveExpectedSize);
179
180                         if (out.size() == 0)
181                         {
182                             setResult(NULL);
183                         }
184                         else
185                         {
186                             setResult(out[0]);
187                         }
188
189                         bImplicitCall = true;
190                     }
191                     catch (const InternalError& ie)
192                     {
193                         if (ConfigVariable::getLastErrorFunction() == L"")
194                         {
195                             ConfigVariable::setLastErrorFunction(pCall->getName());
196                             ConfigVariable::setLastErrorLine(e.getLocation().first_line);
197                         }
198                         CoverageInstance::stopChrono((void*)&e);
199                         throw ie;
200                     }
201                 }
202                 else if (pIT->isImplicitList())
203                 {
204                     //expand implicit when possible
205                     types::ImplicitList* pIL = pIT->getAs<types::ImplicitList>();
206                     if (pIL->isComputable())
207                     {
208                         types::InternalType* p = pIL->extractFullMatrix();
209                         if (p)
210                         {
211                             setResult(p);
212                         }
213                     }
214                 }
215
216                 //don't output Simplevar and empty result
217                 if (getResult() != NULL && (!(*it)->isSimpleVar() || bImplicitCall))
218                 {
219                     //symbol::Context::getInstance()->put(symbol::Symbol(L"ans"), *execMe.getResult());
220                     types::InternalType* pITAns = getResult();
221                     symbol::Context::getInstance()->put(m_pAns, pITAns);
222                     if ((*it)->isVerbose() && ConfigVariable::isPrintOutput())
223                     {
224                         //TODO manage multiple returns
225                         scilabWriteW(L" ans  =\n");
226                         if (ConfigVariable::isPrintCompact() == false)
227                         {
228                             scilabWriteW(L"\n");
229                         }
230                         std::wostringstream ostrName;
231                         ostrName << L"ans";
232                         VariableToString(pITAns, ostrName.str().c_str());
233                     }
234                 }
235
236                 pIT->killMe();
237             }
238
239             if (ConfigVariable::isPrintInteractive())
240             {
241                 Location loc = (*it)->getLocation();
242                 if (lastLine < loc.first_line)
243                 {
244                     //break execution
245                     SetTemporaryPrompt(SCIPROMPT_PAUSE);
246
247                     // The console thread must not parse the next console input.
248                     ConfigVariable::setScilabCommand(0);
249
250                     // Get the console input filled by the console thread.
251                     char* pcConsoleReadStr = ConfigVariable::getConsoleReadStr();
252                     ThreadManagement::SendConsoleExecDoneSignal();
253                     while (pcConsoleReadStr == NULL)
254                     {
255                         pcConsoleReadStr = ConfigVariable::getConsoleReadStr();
256                         ThreadManagement::SendConsoleExecDoneSignal();
257                     }
258
259                     // reset flag to default value
260                     ConfigVariable::setScilabCommand(1);
261
262                     if (pcConsoleReadStr && pcConsoleReadStr[0] == 'p' && pcConsoleReadStr[1] == '\0')
263                     {
264                         //mode pause
265                         ConfigVariable::setExecutionBreak();
266                     }
267                 }
268
269                 lastLine = loc.last_line;
270             }
271
272             if ((&e)->isBreakable() && (*it)->isBreak())
273             {
274                 const_cast<SeqExp *>(&e)->setBreak();
275                 (*it)->resetBreak();
276                 break;
277             }
278
279             if ((&e)->isContinuable() && (*it)->isContinue())
280             {
281                 const_cast<SeqExp *>(&e)->setContinue();
282                 (*it)->resetContinue();
283                 break;
284             }
285
286             if ((&e)->isReturnable() && (*it)->isReturn())
287             {
288                 const_cast<SeqExp *>(&e)->setReturn();
289                 (*it)->resetReturn();
290                 break;
291             }
292         }
293         catch (const InternalError& ie)
294         {
295             ConfigVariable::fillWhereError(ie.GetErrorLocation().first_line);
296             CoverageInstance::stopChrono((void*)&e);
297             if (file)
298             {
299                 file->close();
300                 delete file;
301             }
302
303             throw ie;
304         }
305         catch (const InternalAbort& ia)
306         {
307             if (file)
308             {
309                 file->close();
310                 delete file;
311             }
312             throw ia;
313         }
314         // If something other than NULL is given to setResult, then that would imply
315         // to make a cleanup in visit(ForExp) for example (e.getBody().accept(*this);)
316         setResult(NULL);
317     }
318
319     if (file)
320     {
321         file->close();
322         delete file;
323     }
324     CoverageInstance::stopChrono((void*)&e);
325 }
326
327
328 } /* namespace ast */