add checkNamedArguments function to get unexpected named arguments.
[scilab.git] / scilab / modules / core / sci_gateway / cpp / sci_debug.cpp
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 "core_gw.hxx"
17 #include "function.hxx"
18 #include "string.hxx"
19 #include "printvisitor.hxx"
20 #include "execvisitor.hxx"
21 #include "debuggervisitor.hxx"
22 #include "configvariable.hxx"
23 #include "debugmanager.hxx"
24 #include "threadId.hxx"
25
26 extern "C"
27 {
28 #include "Scierror.h"
29 #include "sciprint.h"
30 #include "Thread_Wrapper.h"
31 }
32
33 enum EnumCommand
34 {
35     AbortCommand,
36     BreakCommand,
37     ContinueCommand,
38     DisableCommand,
39     DeleteCommand,
40     EnableCommand,
41     HelpCommand,
42     HelpShortCommand,
43     ListCommand,
44     NextCommand,
45     QuitCommand,
46     ShowCommand,
47     StepInCommand,
48     StepOutCommand,
49     UnknowCommand,
50     WhereCommand
51 };
52
53 const char fname[] = "debug";
54 const std::string HELP_DEBUG_COMMAND("help debug");
55
56 void print_help();
57 EnumCommand getCommand(const std::wstring& command);
58
59 types::Function::ReturnValue sci_debug(types::typed_list &in, int _iRetCount, types::typed_list &out)
60 {
61     if (in.size() == 0)
62     {
63         //debugger already active
64         if (ConfigVariable::getEnableDebug())
65         {
66             return types::Function::OK;
67         }
68
69         //debugger can be lauch only on console scope level
70         if (symbol::Context::getInstance()->getScopeLevel() != SCOPE_CONSOLE)
71         {
72             Scierror(999, _("%s: Debugger can be activated only at console scope level\n"), fname);
73             return types::Function::Error;
74         }
75
76         ConfigVariable::setEnableDebug(true);
77         ConfigVariable::setDefaultVisitor(new ast::DebuggerVisitor());
78         return types::Function::OK;
79     }
80
81     if (ConfigVariable::getEnableDebug() == false)
82     {
83         Scierror(999, _("%s: Debugger is not running. Call \"%s\" without parameter first.\n"), fname, fname);
84         return types::Function::Error;
85     }
86
87     int iRhs = (int)in.size();
88     for (int i = 0; i < iRhs; i++)
89     {
90         if (in[i]->isString() == false || ((types::String*)in[i])->isScalar() == false)
91         {
92             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), fname, i + 1);
93             return types::Function::Error;
94         }
95     }
96
97     debugger::DebuggerMagager* manager = debugger::DebuggerMagager::getInstance();
98
99     std::wstring command(((types::String*)in[0])->get(0));
100     switch (getCommand(command))
101     {
102         case AbortCommand:
103         {
104             if (iRhs > 1)
105             {
106                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "abort", 0);
107                 return types::Function::Error;
108             }
109
110             //abort
111             if (manager->isInterrupted())
112             {
113                 manager->abort();
114             }
115             else
116             {
117                 sciprint("debugger is not paused\n");
118             }
119
120             return types::Function::OK;
121         }
122         case BreakCommand:
123         {
124             if (iRhs < 2 || iRhs > 4)
125             {
126                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "breakpoint", 1, 3);
127                 return types::Function::Error;
128             }
129
130             //breakpoint
131             wchar_t* pwstFunctionName = NULL;
132             int iLine = -1;
133             wchar_t* pwstCondition = NULL;
134             debugger::Breakpoint* bp = NULL;
135             //function name
136             if (iRhs > 1)
137             {
138                 //do not check name
139                 //we can set breakpoint before function declaration
140                 //for embedded function for example
141                 pwstFunctionName = ((types::String*)in[1])->get(0);
142             }
143
144             if (iRhs > 2)
145             {
146                 wchar_t* pwstLineNumber = ((types::String*)in[2])->get(0);
147                 wchar_t* pwstEnd = NULL;
148                 iLine = wcstol(pwstLineNumber, &pwstEnd, 10);
149                 if (pwstEnd == NULL || *pwstEnd != 0)
150                 {
151                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "breakpoint", 2);
152                     return types::Function::Error;
153                 }
154             }
155
156             if (iRhs > 3)
157             {
158                 pwstCondition = ((types::String*)in[3])->get(0);
159                 bp = new debugger::Breakpoint(pwstFunctionName, iLine, pwstCondition);
160             }
161             else
162             {
163                 bp = new debugger::Breakpoint(pwstFunctionName, iLine);
164             }
165
166             manager->addBreakPoint(bp);
167             return types::Function::OK;
168         }
169         case ContinueCommand:
170         {
171             if (iRhs > 1)
172             {
173                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "continue", 0);
174                 return types::Function::Error;
175             }
176
177             //continue
178             if (manager->isInterrupted())
179             {
180                 manager->resume();
181             }
182             else
183             {
184                 sciprint("debugger is not paused\n");
185             }
186
187             return types::Function::OK;
188         }
189         case DisableCommand:
190         {
191             if (iRhs > 2)
192             {
193                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "disable", 0, 1);
194                 return types::Function::Error;
195             }
196
197             //disable
198             if (iRhs == 2)
199             {
200                 wchar_t* pEnd = NULL;
201                 int iBp = (int)wcstol(((types::String*)in[1])->get(0), &pEnd, 10);
202                 if (pEnd == NULL || *pEnd != 0)
203                 {
204                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "disable", 1);
205                     return types::Function::Error;
206                 }
207
208                 if (manager->getBreakPoint(iBp) == NULL)
209                 {
210                     Scierror(999, _("%s: Unable to retrieve information about breakpoint %d.\n"), "disable", iBp);
211                     return types::Function::Error;
212                 }
213
214                 manager->disableBreakPoint(iBp);
215             }
216             else
217             {
218                 manager->disableAllBreakPoints();
219             }
220
221             return types::Function::OK;
222         }
223         case DeleteCommand :
224         {
225             if (iRhs > 2)
226             {
227                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "delete", 0, 1);
228                 return types::Function::Error;
229             }
230
231             //delete
232             if (iRhs == 2)
233             {
234                 wchar_t* pEnd = NULL;
235                 int iBp = (int)wcstol(((types::String*)in[1])->get(0), &pEnd, 10);
236                 if (pEnd == NULL || *pEnd != 0)
237                 {
238                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "disable", 1);
239                     return types::Function::Error;
240                 }
241
242                 if (manager->getBreakPoint(iBp) == NULL)
243                 {
244                     Scierror(999, _("%s: Unable to retrieve information about breakpoint %d.\n"), "delete", iBp);
245                     return types::Function::Error;
246                 }
247
248                 manager->removeBreakPoint(iBp);
249             }
250             else
251             {
252                 manager->removeAllBreakPoints();
253             }
254
255             return types::Function::OK;
256         }
257         case EnableCommand:
258         {
259             if (iRhs > 2)
260             {
261                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "enable", 0, 1);
262                 return types::Function::Error;
263             }
264
265             //enable
266             if (iRhs == 2)
267             {
268                 wchar_t* pEnd = NULL;
269                 int iBp = (int)wcstol(((types::String*)in[1])->get(0), &pEnd, 10);
270                 if (pEnd == NULL || *pEnd != 0)
271                 {
272                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "enable", 1);
273                     return types::Function::Error;
274                 }
275
276                 if (manager->getBreakPoint(iBp) == NULL)
277                 {
278                     Scierror(999, _("%s: Unable to retrieve information about breakpoint %d.\n"), "enable", iBp);
279                     return types::Function::Error;
280                 }
281
282                 manager->enableBreakPoint(iBp);
283             }
284             else
285             {
286                 manager->enableAllBreakPoints();
287             }
288
289             return types::Function::OK;
290         }
291         case HelpCommand:
292         {
293             if (iRhs > 1)
294             {
295                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "help", 0);
296                 return types::Function::Error;
297             }
298
299             if (ConfigVariable::getScilabMode() == SCILAB_NW || ConfigVariable::getScilabMode() == SCILAB_STD)
300             {
301                 StorePrioritaryCommand(HELP_DEBUG_COMMAND.data());
302                 return types::Function::OK;
303             }
304
305             //continue tp HelpShortCommand
306         }
307         case HelpShortCommand:
308         {
309             if (iRhs > 1)
310             {
311                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "help", 0);
312                 return types::Function::Error;
313             }
314
315             //help
316             print_help();
317             return types::Function::OK;
318         }
319         case ListCommand:
320         {
321             if (iRhs > 1)
322             {
323                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "list", 0);
324                 return types::Function::Error;
325             }
326
327             if (manager->isInterrupted())
328             {
329                 std::wostringstream ostr;
330                 ast::PrintVisitor pp(ostr, true, true, true);
331                 manager->getExp()->accept(pp);
332                 sciprint(_("%ls"), ostr.str().data());
333             }
334             else
335             {
336                 sciprint("debugger is not paused\n");
337             }
338             return types::Function::OK;
339         }
340         case StepInCommand:
341         {
342             if (iRhs > 1)
343             {
344                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "stepin", 0);
345                 return types::Function::Error;
346             }
347
348             if (manager->isInterrupted())
349             {
350                 manager->setStepIn();
351                 manager->resume();
352             }
353             return types::Function::OK;
354         }
355         case NextCommand:
356         {
357             if (iRhs > 1)
358             {
359                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "next", 0);
360                 return types::Function::Error;
361             }
362
363             if (manager->isInterrupted())
364             {
365                 manager->setStepNext();
366                 manager->resume();
367             }
368             else
369             {
370                 sciprint("debugger is not paused\n");
371             }
372             return types::Function::OK;
373         }
374         case StepOutCommand:
375         {
376             if (iRhs > 1)
377             {
378                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "stepout", 0);
379                 return types::Function::Error;
380             }
381
382             //need to level to go stepout
383             if (manager->isInterrupted())
384             {
385                 manager->setStepOut();
386                 manager->resume();
387             }
388             else
389             {
390                 sciprint("debugger is not paused\n");
391             }
392             return types::Function::OK;
393         }
394         case QuitCommand:
395         {
396             if (iRhs > 1)
397             {
398                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "quit", 0);
399                 return types::Function::Error;
400             }
401
402             //quit : disable debugger + abort + quit
403             ConfigVariable::setEnableDebug(false);
404             ConfigVariable::setDefaultVisitor(new ast::ExecVisitor());
405             manager->abort();
406             manager->sendQuit();
407             return types::Function::OK;
408         }
409         case ShowCommand:
410         {
411             if (iRhs > 2)
412             {
413                 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "show", 0, 1);
414                 return types::Function::Error;
415             }
416
417             sciprint("% 3ls % 7ls %24ls % 5ls %ls\n\n", L"num", L"enable", L"function name", L"line", L"condition");
418
419             if (iRhs > 1)
420             {
421                 wchar_t* pEnd = NULL;
422                 int iBp = (int)wcstol(((types::String*)in[1])->get(0), &pEnd, 10);
423                 if (pEnd == NULL || *pEnd != 0)
424                 {
425                     Scierror(999, _("%s: Wrong value for input argument #%d: Scalar positive integer expected.\n"), "disable", 1);
426                     return types::Function::Error;
427                 }
428
429                 debugger::Breakpoint* bp = manager->getBreakPoint(iBp);
430                 if (bp == NULL)
431                 {
432                     Scierror(999, _("%s: Unable to retrieve information about breakpoint %d.\n"), "showbreakpoint", iBp);
433                     return types::Function::Error;
434                 }
435
436                 if (bp->isMacro())
437                 {
438                     std::wstring condition = bp->getCondition();
439                     sciprint("% 3d % 7s %24ls % 5d %ls\n", iBp, bp->isEnable() ? "true" : "false", bp->getFunctioName().c_str(), bp->getMacroLine(),
440                              condition.size() < 30 ? condition.c_str() :
441                              (std::wstring(condition.begin(), condition.begin() + 27) + L"...").c_str());
442                 }
443             }
444             else
445             {
446                 debugger::Breakpoints bps = manager->getAllBreakPoint();
447                 debugger::Breakpoints::iterator it = bps.begin();
448                 for (int i = 0; it != bps.end(); ++it, ++i)
449                 {
450                     debugger::Breakpoint* bp = *it;
451                     if (bp->isMacro())
452                     {
453                         std::wstring condition = bp->getCondition();
454                         sciprint("% 3d % 7s %24ls % 5d %ls\n", i, bp->isEnable() ? "true" : "false", bp->getFunctioName().c_str(), bp->getMacroLine(),
455                                  condition.size() < 30 ? condition.c_str() :
456                                  (std::wstring(condition.begin(), condition.begin() + 27) + L"...").c_str());
457                     }
458                 }
459             }
460
461             return types::Function::OK;
462         }
463         case WhereCommand:
464         {
465             if (iRhs > 1)
466             {
467                 Scierror(999, _("%s: Wrong number of input arguments: %d expected.\n"), "where", 0);
468                 return types::Function::Error;
469             }
470
471             if (manager->isInterrupted() == false)
472             {
473                 sciprint("debugger is not paused\n");
474                 return types::Function::OK;
475             }
476
477             int curLine = (manager->getExp()->getLocation().first_line - ConfigVariable::getMacroFirstLines()) + 1;
478
479             //where
480             int i = 0;
481             sciprint("%s\n", _("callstack:"));
482
483             std::wostringstream ostr;
484             ast::PrintVisitor pp(ostr, true, true, true);
485             manager->getExp()->accept(pp);
486 #define BT_PRINT "#%-5d%ls (line %d)\n"
487             sciprint("#%-5d%ls\n", 0, ostr.str().data());
488
489             ConfigVariable::WhereVector where = ConfigVariable::getWhere();
490             auto it1 = where.rbegin();
491             auto it2 = ++where.rbegin();
492
493             sciprint(_(BT_PRINT), 1, it2->call->getName().data(), curLine);
494             ++it1;
495             ++it2;
496             for (int j = 2; it2 != where.rend(); it1++, it2++, j++)
497             {
498                 sciprint(_(BT_PRINT), j, it2->call->getName().data(), it1->m_line);
499             }
500
501             return types::Function::OK;
502         }
503
504         case UnknowCommand:
505         default :
506             break;
507     }
508
509     sciprint("Unknown command \"%ls\".\n\n", command.c_str());
510     sciprint("use 'h' for more information\n\n");
511     return types::Function::OK;
512 }
513
514 void print_help()
515 {
516     //a,b,c,d,h,i,n,o,q,s,w
517
518     sciprint(_("debug commands : \n"));
519     sciprint("  h                            : %s.\n", _("show this help"));
520     sciprint("  help                         : %s.\n", _("open debug documentation page"));
521     sciprint("\n");
522     sciprint("  (q)uit                       : %s.\n", _("stop debugging"));
523     sciprint("  (w)here or bt                : %s.\n", _("show callstack"));
524     sciprint("\n");
525     sciprint("  (e)xec cmd                   : %s.\n", _("execute cmd"));
526     sciprint("  (r)un cmd                    : %s.\n", _("execute cmd"));
527     sciprint("\n");
528     sciprint("  (d)isp var                   : %s.\n", _("display variable"));
529     sciprint("  (p)rint var                  : %s.\n", _("display variable"));
530     sciprint("\n");
531     sciprint("  (c)ontinue                   : %s.\n", _("continue execution"));
532     sciprint("  (a)bort                      : %s.\n", _("abort execution"));
533     sciprint("  step(n)ext or next           : %s.\n", _("continue to next statement"));
534     sciprint("  step(i)n or in               : %s.\n", _("step into function"));
535     sciprint("  step(o)ut or out             : %s.\n", _("step outside function"));
536     sciprint("\n");
537     sciprint("  (b)reakpoint or break\n     func [line [\"condition\"]] : %s.\n", _("add a breakpoint"));
538     sciprint("  (del)ete                     : %s.\n", _("delete all breakpoints"));
539     sciprint("  (del)ete n                   : %s.\n", _("delete a specific breakpoint"));
540     sciprint("  enable                       : %s.\n", _("enable all breakpoints"));
541     sciprint("  enable n                     : %s.\n", _("enable a specific breakpoint"));
542     sciprint("  disable                      : %s.\n", _("disable all breakpoints"));
543     sciprint("  disable n                    : %s.\n", _("disable a specific breakpoint"));
544     sciprint("  (s)how                       : %s.\n", _("show all breakpoints"));
545     sciprint("  (s)how n                     : %s.\n", _("show a specific breakpoint"));
546     sciprint("\n");
547     sciprint(_("  for more details, show help page.\n"));
548 }
549
550 EnumCommand getCommand(const std::wstring& command)
551 {
552     wchar_t c = command[0];
553
554     switch (c)
555     {
556         case L'a':
557         {
558             if (command.size() == 1 || command == L"abort")
559             {
560                 return AbortCommand;
561             }
562             break;
563         }
564         case 'b':
565         {
566             if (command.size() == 1 || command == L"break" || command == L"breakpoint")
567             {
568                 return BreakCommand;
569             }
570
571             if (command == L"bt")
572             {
573                 return WhereCommand;
574             }
575             break;
576         }
577         case L'c':
578         {
579             if (command.size() == 1 || command == L"continue")
580             {
581                 return ContinueCommand;
582             }
583             break;
584         }
585         case L'd':
586         {
587             if (command == L"disable")
588             {
589                 return DisableCommand;
590             }
591
592             if (command == L"del" || command == L"delete")
593             {
594                 return DeleteCommand;
595             }
596             break;
597         }
598         case L'e':
599         {
600             if (command == L"enable")
601             {
602                 return EnableCommand;
603             }
604             break;
605         }
606         case L'h':
607         {
608             if (command.size() == 1)
609             {
610                 return HelpShortCommand;
611             }
612
613             if (command == L"help")
614             {
615                 return HelpCommand;
616             }
617
618             break;
619         }
620         case L'l':
621         {
622             if (command.size() == 1 || command == L"list")
623             {
624                 return ListCommand;
625             }
626             break;
627         }
628         case L'i':
629         {
630             if (command.size() == 1 || command == L"in")
631             {
632                 return StepInCommand;
633             }
634             break;
635         }
636         case L'n':
637         {
638             if (command.size() == 1 || command == L"next")
639             {
640                 return NextCommand;
641             }
642             break;
643         }
644         case L'o':
645         {
646             if (command.size() == 1 || command == L"out")
647             {
648                 return StepOutCommand;
649             }
650             break;
651         }
652         case L'q':
653         {
654             if (command.size() == 1 || command == L"quit")
655             {
656                 return QuitCommand;
657             }
658             break;
659         }
660         case L's':
661         {
662             if (command.size() == 1 || command == L"show")
663             {
664                 return ShowCommand;
665             }
666             if (command == L"stepnext")
667             {
668                 return NextCommand;
669             }
670             if (command == L"stepin")
671             {
672                 return StepInCommand;
673             }
674             if (command == L"stepout")
675             {
676                 return StepOutCommand;
677             }
678             break;
679         }
680         case L'w':
681         {
682             if (command.size() == 1 || command == L"where")
683             {
684                 return WhereCommand;
685             }
686             break;
687         }
688     }
689
690     return UnknowCommand;
691 }