mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-26 05:07:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Janet
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Janet
		
	
	
	
	
	
| ###
 | |
| ### A useful debugger library for Janet. Should be used
 | |
| ### inside a debug repl. This has been moved into the core.
 | |
| ###
 | |
| 
 | |
| (defn .fiber
 | |
|   "Get the current fiber being debugged."
 | |
|   []
 | |
|   (dyn :fiber))
 | |
| 
 | |
| (defn .stack
 | |
|   "Print the current fiber stack"
 | |
|   []
 | |
|   (print)
 | |
|   (with-dyns [:err-color false] (debug/stacktrace (.fiber) ""))
 | |
|   (print))
 | |
| 
 | |
| (defn .frame
 | |
|   "Show a stack frame"
 | |
|   [&opt n]
 | |
|   (def stack (debug/stack (.fiber)))
 | |
|   (in stack (or n 0)))
 | |
| 
 | |
| (defn .fn
 | |
|   "Get the current function"
 | |
|   [&opt n]
 | |
|   (in (.frame n) :function))
 | |
| 
 | |
| (defn .slots
 | |
|   "Get an array of slots in a stack frame"
 | |
|   [&opt n]
 | |
|   (in (.frame n) :slots))
 | |
| 
 | |
| (defn .slot
 | |
|   "Get the value of the nth slot."
 | |
|   [&opt nth frame-idx]
 | |
|   (in (.slots frame-idx) (or nth 0)))
 | |
| 
 | |
| (defn .quit
 | |
|   "Resume (dyn :fiber) with the value passed to it after exiting the debugger."
 | |
|   [&opt val]
 | |
|   (setdyn :exit true)
 | |
|   (setdyn :resume-value val)
 | |
|   nil)
 | |
| 
 | |
| (defn .disasm
 | |
|   "Gets the assembly for the current function."
 | |
|   [&opt n]
 | |
|   (def frame (.frame n))
 | |
|   (def func (frame :function))
 | |
|   (disasm func))
 | |
| 
 | |
| (defn .bytecode
 | |
|   "Get the bytecode for the current function."
 | |
|   [&opt n]
 | |
|   ((.disasm n) 'bytecode))
 | |
| 
 | |
| (defn .ppasm
 | |
|   "Pretty prints the assembly for the current function"
 | |
|   [&opt n]
 | |
|   (def frame (.frame n))
 | |
|   (def func (frame :function))
 | |
|   (def dasm (disasm func))
 | |
|   (def bytecode (dasm 'bytecode))
 | |
|   (def pc (frame :pc))
 | |
|   (def sourcemap (dasm 'sourcemap))
 | |
|   (var last-loc [-2 -2])
 | |
|   (print "\n  function:   " (dasm 'name) " [" (in dasm 'source "") "]")
 | |
|   (when-let [constants (dasm 'constants)]
 | |
|     (printf "  constants:  %.4Q" constants))
 | |
|   (printf "  slots:      %.4Q\n" (frame :slots))
 | |
|   (def padding (string/repeat " " 20))
 | |
|   (loop [i :range [0 (length bytecode)]
 | |
|          :let [instr (bytecode i)]]
 | |
|     (prin (if (= (tuple/type instr) :brackets) "*" " "))
 | |
|     (prin (if (= i pc) "> " "  "))
 | |
|     (prinf "\e[33m%.20s\e[0m" (string (string/join (map string instr) " ") padding))
 | |
|     (when sourcemap
 | |
|       (let [[sl sc] (sourcemap i)
 | |
|             loc [sl sc]]
 | |
|         (when (not= loc last-loc)
 | |
|           (set last-loc loc)
 | |
|           (prin " # line " sl ", column " sc))))
 | |
|     (print))
 | |
|   (print))
 | |
| 
 | |
| (defn .source
 | |
|   "Show the source code for the function being debugged."
 | |
|   [&opt n]
 | |
|   (def frame (.frame n))
 | |
|   (def s (frame :source))
 | |
|   (def all-source (slurp s))
 | |
|   (print "\n\e[33m" all-source "\e[0m\n"))
 | |
| 
 | |
| (defn .breakall
 | |
|   "Set breakpoints on all instructions in the current function."
 | |
|   [&opt n]
 | |
|   (def fun (.fn n))
 | |
|   (def bytecode (.bytecode n))
 | |
|   (for i 0 (length bytecode)
 | |
|     (debug/fbreak fun i))
 | |
|   (print "Set " (length bytecode) " breakpoints in " fun))
 | |
| 
 | |
| (defn .clearall
 | |
|   "Clear all breakpoints on the current function."
 | |
|   [&opt n]
 | |
|   (def fun (.fn n))
 | |
|   (def bytecode (.bytecode n))
 | |
|   (for i 0 (length bytecode)
 | |
|     (debug/unfbreak fun i))
 | |
|   (print "Cleared " (length bytecode) " breakpoints in " fun))
 | |
| 
 | |
| (defn .break
 | |
|   "Set breakpoint at the current pc."
 | |
|   []
 | |
|   (def frame (.frame))
 | |
|   (def fun (frame :function))
 | |
|   (def pc (frame :pc))
 | |
|   (debug/fbreak fun pc)
 | |
|   (print "Set breakpoint in " fun " at pc=" pc))
 | |
| 
 | |
| (defn .clear
 | |
|   "Clear the current breakpoint"
 | |
|   []
 | |
|   (def frame (.frame))
 | |
|   (def fun (frame :function))
 | |
|   (def pc (frame :pc))
 | |
|   (debug/unfbreak fun pc)
 | |
|   (print "Cleared breakpoint in " fun " at pc=" pc))
 | |
| 
 | |
| (defn .next
 | |
|   "Go to the next breakpoint."
 | |
|   [&opt n]
 | |
|   (var res nil)
 | |
|   (for i 0 (or n 1)
 | |
|     (set res (resume (.fiber))))
 | |
|   res)
 | |
| 
 | |
| (defn .nextc
 | |
|   "Go to the next breakpoint, clearing the current breakpoint."
 | |
|   [&opt n]
 | |
|   (.clear)
 | |
|   (.next n))
 | |
| 
 | |
| (defn .step
 | |
|   "Execute the next n instructions."
 | |
|   [&opt n]
 | |
|   (var res nil)
 | |
|   (for i 0 (or n 1)
 | |
|     (set res (debug/step (.fiber))))
 | |
|   res)
 | 
