Refactoring of ScilabException in AST, exec, execstr.
[scilab.git] / scilab / modules / functions / sci_gateway / cpp / sci_execstr.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2006 - INRIA - Antoine ELIAS
4 *
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution.  The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13 #include <string.h>
14 #include "parser.hxx"
15 #include "functions_gw.hxx"
16 #include "execvisitor.hxx"
17 #include "mutevisitor.hxx"
18 #include "yaspio.hxx"
19 #include "scilabexception.hxx"
20 #include "configvariable.hxx"
21
22 #include <iostream>
23 #include <fstream>
24 #include <string>
25
26 extern "C"
27 {
28 #include "MALLOC.h"
29 #include "os_wcsicmp.h"
30 #include "Scierror.h"
31 #include "localization.h"
32 }
33
34 #define MUTE_FLAG       L"n"
35 #define NO_MUTE_FLAG    L"m"
36
37 using namespace std;
38 using namespace types;
39 using namespace ast;
40 /*--------------------------------------------------------------------------*/
41 Function::ReturnValue sci_execstr(types::typed_list &in, int _iRetCount, types::typed_list &out)
42 {
43     int iErr            = 0;
44         bool bErrCatch          = false;
45     bool bMute          = true;
46         wchar_t* pstMsg     = NULL;
47         Exp* pExp           = NULL;
48         wchar_t *pstCommand = NULL;
49     Parser parser;
50
51         if(in.size() < 1 || in.size() > 3)
52         {
53         ScierrorW(999, _W("%ls: Wrong number of input arguments: %d to %d expected.\n"), L"execstr" , 1, 3);
54         return Function::Error;
55         }
56
57     //2nd parameter
58         if(in.size() > 1)
59         {//errcatch
60         if(in[1]->isString() == false || in[1]->getAs<types::String>()->getSize() != 1)
61         {
62             ScierrorW(999, _W("%ls: Wrong type for input argument #%d: A string expected.\n"), L"execstr", 2);
63             return Function::Error;
64         }
65
66         String* pS = in[1]->getAs<types::String>();
67         if(os_wcsicmp(pS->get(0), L"errcatch") == 0)
68         {
69             bErrCatch = true;
70         }
71         else
72         {
73             ScierrorW(999, _W("%ls: Wrong value for input argument #%d: 'errcatch' expected.\n"), L"execstr", 2);
74             return Function::Error;
75         }
76     }
77
78         //3rd parameter
79         if(in.size() == 3)
80         {
81         if(in[2]->isString() == false || in[2]->getAs<types::String>()->getSize() != 1)
82                 {
83             ScierrorW(999, _W("%ls: Wrong type for input argument #%d: A string expected.\n"), L"execstr", 3);
84             return Function::Error;
85         }
86
87                 if(os_wcsicmp(in[2]->getAs<types::String>()->get(0), MUTE_FLAG) == 0)
88         {
89             bMute = true;
90         }
91         else if(os_wcsicmp(in[2]->getAs<types::String>()->get(0), NO_MUTE_FLAG) == 0)
92         {
93             bMute = false;
94         }
95         else
96         {
97             ScierrorW(999, _W("%ls: Wrong value for input argument #%d: '%s' or '%s' expected.\n"), L"execstr", 3, MUTE_FLAG, NO_MUTE_FLAG);
98             return Function::Error;
99         }
100         }
101
102     //1st argument
103     if(in[0]->isDouble() && in[0]->getAs<Double>()->getSize() == 0)
104     {// execstr([])
105         out.push_back(Double::Empty());
106         return Function::OK;
107     }
108
109     if(in[0]->isString() == false || (in[0]->getAs<types::String>()->getRows() != 1 && in[0]->getAs<types::String>()->getCols() != 1))
110         {
111         ScierrorW(999, _W("%ls: Wrong type for input argument #%d: Vector of strings expected.\n"), L"execstr", 1);
112         return Function::Error;
113     }
114
115         String* pS = in[0]->getAs<types::String>();
116         int iTotalLen = pS->getSize(); //add \n after each string
117         for(int i = 0 ; i < pS->getSize() ; i++)
118         {
119                 iTotalLen += (int)wcslen(pS->get(i));
120         }
121
122         pstCommand = (wchar_t*)MALLOC(sizeof(wchar_t) * (iTotalLen + 1));//+1 for null termination
123
124         for(int i = 0, iPos = 0 ; i < pS->getSize() ; i++)
125         {
126                 wcscpy(pstCommand + iPos, pS->get(i));
127                 iPos = (int)wcslen(pstCommand);
128                 pstCommand[iPos++] = L'\n';
129                 pstCommand[iPos] = 0;
130         }
131
132         parser.parse(pstCommand);
133     FREE(pstCommand);
134         if(parser.getExitStatus() !=  Parser::Succeded)
135         {
136         ScierrorW(999, L"%s", parser.getErrorMessage());
137                 return Function::Error;
138         }
139
140         pExp = parser.getTree();
141
142         if(pExp == NULL)
143         {
144                 return Function::Error;
145         }
146
147     //save current prompt mode
148     int oldVal = ConfigVariable::getPromptMode();
149     if(bMute)
150     {
151         ConfigVariable::setPromptMode(-1);
152     }
153
154         std::list<Exp *>::iterator j;
155         std::list<Exp *>LExp = ((SeqExp*)pExp)->exps_get();
156
157         for(j = LExp.begin() ; j != LExp.end() ; j++)
158         {
159                 try
160                 {
161             //excecute script
162             ExecVisitor execMe;
163             (*j)->accept(execMe);
164
165             //to manage call without ()
166             if(execMe.result_get() != NULL && execMe.result_get()->getAsCallable())
167             {
168                 Callable *pCall = execMe.result_get()->getAsCallable();
169                 types::typed_list out;
170                 types::typed_list in;
171
172                 try
173                 {
174                     ExecVisitor execCall;
175                     Function::ReturnValue Ret = pCall->call(in, 1, out, &execCall);
176
177                     if(Ret == Callable::OK)
178                     {
179                         if(out.size() == 0)
180                         {
181                             execMe.result_set(NULL);
182                         }
183                         else if(out.size() == 1)
184                         {
185                             out[0]->DecreaseRef();
186                             execMe.result_set(out[0]);
187                         }
188                         else
189                         {
190                             for(int i = 0 ; i < static_cast<int>(out.size()) ; i++)
191                             {
192                                 out[i]->DecreaseRef();
193                                 execMe.result_set(i, out[i]);
194                             }
195                         }
196                     }
197                     else if(Ret == Callable::Error)
198                     {
199                         if(ConfigVariable::getLastErrorFunction() == L"")
200                         {
201                             ConfigVariable::setLastErrorFunction(pCall->getName());
202                         }
203
204                         if(pCall->isMacro() || pCall->isMacroFile())
205                         {
206                             wchar_t szError[bsiz];
207                             os_swprintf(szError, bsiz, _W("at line % 5d of function %ls called by :\n"), (*j)->location_get().first_line, pCall->getName().c_str());
208                             throw ScilabMessage(szError);
209                         }
210                         else
211                         {
212                             throw ScilabMessage();
213                         }
214                     }
215                 }
216                 catch(ScilabMessage sm)
217                 {
218                     wostringstream os;
219                     PrintVisitor printMe(os);
220                     (*j)->accept(printMe);
221                     os << std::endl << std::endl;
222                     if(ConfigVariable::getLastErrorFunction() == L"")
223                     {
224                         ConfigVariable::setLastErrorFunction(pCall->getName());
225                     }
226
227                     if(pCall->isMacro() || pCall->isMacroFile())
228                     {
229                         wstring szAllError;
230                         wchar_t szError[bsiz];
231                         os_swprintf(szError, bsiz, _W("at line % 5d of function %ls called by :\n"), sm.GetErrorLocation().first_line, pCall->getName().c_str());
232                         szAllError = szError + os.str();
233                         os_swprintf(szError, bsiz, _W("in  execstr instruction    called by :\n"));
234                         szAllError += szError;
235                         throw ScilabMessage(szAllError);
236                     }
237                     else
238                     {
239                         sm.SetErrorMessage(sm.GetErrorMessage() + os.str());
240                         throw sm;
241                     }
242                 }
243             }
244
245             //update ans variable.
246                         if(execMe.result_get() != NULL && execMe.result_get()->isDeletable())
247                         {
248                                 symbol::Context::getInstance()->put(symbol::Symbol(L"ans"), *execMe.result_get());
249                                 if( (*j)->is_verbose() && 
250                     bErrCatch == false)
251                                 {
252                                         std::wostringstream ostr;
253                                         ostr << L"ans = " << std::endl;
254                                         ostr << std::endl;
255                                         ostr << execMe.result_get()->toString(ConfigVariable::getFormat(), ConfigVariable::getConsoleWidth()) << std::endl;
256                                         YaspWriteW(ostr.str().c_str());
257                                 }
258                         }
259
260                         //if( !checkPrompt(iMode, EXEC_MODE_MUTE) &&
261    //             bErrCatch == false)
262                         //{
263                         //      YaspWriteW(L"\n");
264                         //}
265                 }
266         catch(ScilabMessage sm)
267         {
268             if(bErrCatch  == false && bMute == false)
269             {
270                 YaspErrorW(sm.GetErrorMessage().c_str());
271
272                 CallExp* pCall = dynamic_cast<CallExp*>(*j);
273                 if(pCall != NULL)
274                 {//to print call expression only of it is a macro
275                     ExecVisitor execFunc;
276                     pCall->name_get().accept(execFunc);
277
278                     if(execFunc.result_get() != NULL &&
279                         (execFunc.result_get()->isMacro() || execFunc.result_get()->isMacroFile()))
280                     {
281                         wostringstream os;
282
283                         //add function failed
284                         PrintVisitor printMe(os);
285                         pCall->accept(printMe);
286                         os << std::endl;
287
288                         //add info on file failed
289                         wchar_t szError[bsiz];
290                         os_swprintf(szError, bsiz, _W("at line % 5d of exec file called by :\n"), (*j)->location_get().first_line);
291                         os << szError;
292
293                         if(ConfigVariable::getLastErrorFunction() == L"")
294                         {
295                             ConfigVariable::setLastErrorFunction(execFunc.result_get()->getAsCallable()->getName());
296                         }
297
298                         //restore previous prompt mode
299                         ConfigVariable::setPromptMode(oldVal);
300                         throw ScilabMessage(os.str(), 0, (*j)->location_get());
301                     }
302                 }
303                 throw ScilabMessage((*j)->location_get());
304             }
305             else
306             {
307                 iErr = ConfigVariable::getLastErrorNumber();
308                 break;
309             }
310         }
311                 catch(ScilabError se)
312                 {
313             if(ConfigVariable::getLastErrorMessage() == L"")
314             {
315                 ConfigVariable::setLastErrorMessage(se.GetErrorMessage());
316                 ConfigVariable::setLastErrorNumber(se.GetErrorNumber());
317                 ConfigVariable::setLastErrorLine(se.GetErrorLocation().first_line);
318                 ConfigVariable::setLastErrorFunction(wstring(L""));
319             }
320
321             //store message
322             iErr = ConfigVariable::getLastErrorNumber();
323             if(bErrCatch == false)
324             {
325                 //in case of error, change mode to 2 ( prompt )
326                 ConfigVariable::setPromptMode(2);
327                 //write error
328                 YaspErrorW(se.GetErrorMessage().c_str());
329                 YaspErrorW(L"\n");
330
331                 //write positino
332                 wchar_t szError[bsiz];
333                 os_swprintf(szError, bsiz, _W("at line % 5d of exec file called by :\n"), (*j)->location_get().first_line);
334                 //restore previous prompt mode
335                 ConfigVariable::setPromptMode(oldVal);
336                 throw ScilabMessage(szError, 1, (*j)->location_get());
337             }
338             break;
339                 }
340         }
341
342     //restore previous prompt mode
343     ConfigVariable::setPromptMode(oldVal);
344
345     if(bErrCatch)
346     {
347         out.push_back(new Double(iErr));
348         //to lock last error information
349         ConfigVariable::setLastErrorCall();
350     }
351
352     delete parser.getTree();
353         return Function::OK;
354 }
355 /*--------------------------------------------------------------------------*/
356
357 /*
358                 catch(ScilabError se)
359                 {
360             if(bErrCatch && bMute == true)
361             {
362                 //set mode silent for errors
363                 ConfigVariable::setPromptMode(-1);
364             }
365
366             //store message
367             ScierrorW(ConfigVariable::getLastErrorNumber(), L"%ls", ConfigVariable::getLastErrorMessage().c_str());
368             iErr = ConfigVariable::getLastErrorNumber();
369             if(bErrCatch == false)
370             {
371                 delete parser.getTree();
372                             return Function::Error;
373             }
374             break;
375                 }
376 */
377
378 /*
379 */