Building Debugger for The Source (DEMO) - Using esprima.parse for parser and ace editor for editor. How to test the debugger?
- Download all files.
- Download src-noconflict - https://github.com/ajaxorg/ace-builds/ (this is for the editor).
- Put Ace.html outside with src_noconflict.
- Put all other files into src_noconflict.
- Run Ace and test.
To understand more about the interpreter, it is recommended to go through:
- Understand Metacircular Evaluator (http://www.comp.nus.edu.sg/~cs1101s/sicp/).
- esprima.parser - since esprima.parser will be used, it is recommended to experiment with esprima parser to understand how the syntax will be dealt in the interpreter (http://esprima.org/demo/parse.html#).
- Go through yield + function* (generator) of EcmaScript6 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators).
- Scan through the code of interpreter from the function evaluate(input_text,stmt,env).
To understand more about the Debugger Demo, it is recommended to go through: ace.editor (https://ace.c9.io/#nav=embedding)
More information about files:
- ace.html: a web-page to test the debugger.
- interpreter.js: the interpreter.
a) list.js.
b) misc.js.
c) object.js.
d) stream.js. - debugger.js: the debugger.
Specific information about each file:
- ace.html:
a) Embedding Ace editor. (https://ace.c9.io/#nav=embedding)
b) Add / remove breakpoints.
i) Add / remove breakpoints by clicking on the margin(http://stackoverflow.com/questions/16864236/how-to-mark-line-numbers-in-javascript-ace-editor).
ii) Store breakpoints as a set of line number. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
c) Illustrating method:
i) runButton():
> Run the program.
> Send the code and breakpoints to the debugger.
> If there is breakpoints, then will stop at the breakpoints (debug mode on).
> Else execute the whole program.
ii) next():
> Only work if it is in debug mode.
> Run the next statement - However, sometimes need to next() many times to go to next statement.
iii) resetBreakpoints():
> Clear all breakpoints
iv) resume():
> Only work if it is in debug mode.
> Run to the next breakpoint.
> Or finish if there is no breakpoint. - debugger.js:
a) Global variables:
i) debug_on: check debug mode whether it is on or not.
ii) debugger_result: contain the status of the program. It is a generator if it has not finished executing, else it is the result to the console.
iii) debugger_marker: marker on the debugging line. (https://ace.c9.io/#nav=api&api=edit_session for further understanding.
b) Functions:
i) make_debugger: function that connects the code on the editor with the interpreter.
ii) debugger_next: function that associates with next() in the editor.
a) Debug mode off: Execute until find a breakpoint, else execute the whole program.
b) Debug mode on: Go to next statement, However, sometimes need to next() many times to go to next statement.
*** Reason: To take the return value of a generator, we need to run next until done = true, the corresponding value is the result. However, with a lot of generator relates to each other, taking the return value leads to more next. ***
iii) watch: return the value associated with the input variable in the nearest frame.
iv) line_to_mark: get the current line number which the generator stops.
v) get_current_val: return debugger_result.
vi) on_debug/off_debug: mark on/off debug mode.
vii) variables_table: create the variable - value table of the current frame. - interpreter.js:
a) Structure: similar to the original interpreter in SICP.
b) Changes:
i) Syntax: suitable for Esprima Parser.
ii) EcmaScript6 : declare local variables by "let".
iii) Functions to evaluate each kind of statement have become generator.
iV) More gloabal functions to associate with debugger.js.
c) Generator: 2 ways of dealing.
i) Just care about the result: use a while generator.done != true loop do generator.next() until generator.done == true then result = generator.value. (However, if there is a breakpoint then it will work like ii) from the breakpoint.
ii) Want to run next by next: use a while generator.done != true loop do (yield; generator.next()) until generator.done == true then result = generator.value.