Click here to Skip to main content
15,867,885 members
Articles / Programming Languages / Javascript

JavaScript REPL for Windows: Part 3 – Dynamic Breakpoints

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
31 Jan 2015CPOL3 min read 4.1K   1  
Adding the ability to set breakpoints dynamically from within JSREPL

This is part three of a three part post about JavaScript REPL console for Windows. In part one, I have explained motivation and some initial steps, in part two, I have added debug REPL and static breakpoints. In part three, I am going to add the ability to set breakpoints dynamically from within JSREPL.

As mentioned previously, the full source code of JSREPL is freely available under GPL 2 license on github.

Dynamic Breakpoints

While static breakpoints offer good benefits of being flexible, they are, well, static. When I am debugging a script, it is hard to predict where all the breakpoints would have to be placed. So, if I decide that I need another breakpoint in the middle of the debugging session, I need to edit the source code and restart the session.

It would be nice if I could set the breakpoints on the fly without the need to restart the session. It turns out, there is an easy way to do that for functions declared at the global scope; either global functions or anonymous functions referenced by global variables. Furthermore, it is even possible to do this for anonymous functions declared within such global functions, for example, object methods. There are some caveats to the latter part, though.

Well then, my JSREPL is getting three new commands:

  • bp – for adding new breakpoints
  • bd – for deleting breakpoints
  • bl – for listing breakpoints

The logic of adding a new breakpoint as well as removing one is quite simple – just figure out all the lines that the function needs to have breakpoints and generate a new string with source code for the function. Eval that at the global scope and subsequent invocations of the function will trigger breakpoints.

There is one fine point in all of this: whether function is anonymous or not. But that is easily determined by the parseFunction method from part two. If the function is anonymous, then the eval should be an assignment to a global variable. Otherwise, it is just a function declaration.

Figure 14. Method to update breakpoints.
JavaScript
1     updateFnBreaks: function (bpInfo, bpLine) {
2         var lineNos = Arr(bpInfo.breaks).map(function(eBr) { return eBr.line; }).a;
3         if (typeof(bpLine) != "undefined") {
4             lineNos.push(bpLine);
5         }
6         lineNos.sort();
7 
8         var fnLines = bpInfo.savedFunc.slice(0);    		// copy the array
9         var bpLabelPrefix = bpInfo.name + "(";
10         for (iLN in lineNos) {
11             var offset = lineNos[iLN] + parseInt(iLN); // compensating for lines inserted already
12             if (offset < fnLines.length) {
13                 var bpLabel = bpInfo.name + "(" + lineNos[iLN].toString() + ")";
14                 fnLines.splice(offset, 0 /*=toDelete*/, 
				"eval(dbgBreak(\"" + bpLabel + "\")) // <dbg_break>");
15             } else {
16                 println("ERROR: line ", lineNos[iLN], " is outside of the function");
17                 return null;
18             }
19         }
20         return fnLines.join("\n\r");
21     }

To illustrate the dynamic nature of the breakpoints, let’s look at another example. This time, we are dealing with class method.

Figure 15. Source code for the example of dynamic breakpoints.
JavaScript
1 classA = function (n) {
2     return {
3         name:  n,
4         who:  function () {
5             println("Name=", this.name);
6             return this.name;
7         }
8     };
9 };

In this case, I would like to set a breakpoint on line 6, but that is in the anonymous function, which happens to be a class method. Here is how that worked out for me:

Figure 16. Session log of dynamic breakpoint demo.
JavaScript
1 # list classA
2    0 function (n) {
3    1     return {
4    2         name:  n,
5    3         who:  function () {
6    4             println("Name=", this.name);
7    5             return this.name;
8    6         }
9    7     };
10    8 }
11 # bp classA 5
12 # var a1 = new classA("John")
13 
14 # a1.who()
15 Name=John
16 
17 dbg break"classA(5)"  ? – displays list of debugger commands.
18 dbg> w
19 Call stack:
20 
21 Level Function
22 ~~~~~ ~~~~~~~~~~~~
23     0 <anonymous>()
24 dbg> a1.name
25 John
26 dbg> g
27 John
28 # bl
29 Active breakpoints:
30 
31 Id  Function(line)
32 ~~~~ ~~~~~~~~~~~~~~
33    0 classA(5)
34 # bd 0
35 # bl
36 Active breakpoints:
37 
38 Id  Function(line)
39 ~~~~ ~~~~~~~~~~~~~~
40 # a1.who()
41 Name=John
42 
43 dbg break"classA(5)"  ? – displays list of debugger commands.
44 dbg> g
45 John
46 # var a2 = new classA("Peter")
47 
48 # a2.who()
49 Name=Peter
50 Peter
51 #

Setting the breakpoint (listing line 7) triggers the break into debug REPL (listing line 17). However, removing the breakpoint (listing line 43) does not remove the breakpoint from the method of object a1 (listing lines 40 – 44). However, creating a new instance of classA after removing the breakpoint acts as expected (listing line 48).

This is it. While there are some caveats to dynamic breakpoints, it is still a very useful addition to JSREPL.

Next Steps

JSREPL is a work in progress and will be for quite some time. I am refining the functionality and addressing more corner cases as I run into those. If you use JSREPL and run into issues, please report them on the github issues page.

I already have plans for the future – I would like to add enabled/disabled flag to the breakpoint, such that the breakpoints that cannot be deleted, could at least be disabled. I would like to add an indicator of the current breakpoint in the function source listing. The wiki on github needs updating as well.

Thank you for reading and happy debugging.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Microsoft Corporation
United States United States
Hard at work keeping your pixels bright and colorful - http://get.live.com

Comments and Discussions

 
-- There are no messages in this forum --