(library (nmosh debugger condition-printer) (export condition-printer/deco debug-format with-condition-printer with-condition-printer/raise) (import (rnrs) (nmosh conditions) (nmosh global-flags) (nmosh pathutils) (srfi :48) (srfi :98) (primitives id-name id-debug id-maybe-library)) (define (guru-mode?) (get-global-flag '%nmosh-guru-mode)) (define color-output? (get-environment-variable "NMOSH_CLICOLOR")) ; almost as syntax->datum but allows symbol in l (define (strip l) (cond ((list? l) (map strip l)) ((vector? l) (vector-map strip l)) ((identifier? l) (id-name l)) (else l))) ; -> (nmosh debug) (define (debug-format debug) (define (extract-name name) (let ((l (string->list name))) (let* ((r (reverse l)) (a (car r)) (b (cadr r))) (if (char=? #\> a b) ; IT WON'T WORK (when supplied filename contains spc) (let loop ((cur '()) (s (cddr r))) (if (char=? #\space (car s)) (simplify-path (list->string cur)) (loop (cons (car s) cur) (cdr s)))) name)))) (cond ((and (list? debug) (= 2 (length debug))) (let ((name (car debug)) (line (cadr debug))) (format "~a:~d" (if (string? name) (extract-name name) "INVALID") (- line 1)))) (else #f))) ; STUB! (define (id->debuginfo e) (let ((name (id-name e)) (library (id-maybe-library e)) (debug (id-debug e))) (if debug (debug-format debug) #f))) (define (gather l) (define (next cur e) (if (member e cur) cur (if e (cons e cur) cur))) (define (itr cur e) (cond ((list? e) (fold-left itr cur e)) ((vector? e) (fold-left itr cur (vector->list e))) ((identifier? e) (next cur (id->debuginfo e))) (else cur))) (if (list? l) (fold-left itr '() l) (itr '() l))) (define-syntax with-condition-printer/raise (syntax-rules () ((_ arg ...) (guard (e (#t (if (condition? e) (begin (condition-printer e (current-error-port)) (raise e)) (display (list 'UNKNOWN-DATUM! e) (current-error-port))))) arg ...)))) (define-syntax with-condition-printer (syntax-rules () ((_ arg ...) (guard (e (#t ;always handles (if (condition? e) (condition-printer e (current-error-port)) (display (list 'UNKNOWN-DATUM! e) (current-error-port))))) arg ...)))) (define (safe-condition-who e) ; when who is #f... e.g.) eval (#f . #f) (guard (c (#t #f)) (condition-who e))) (define (ptake x l) ;; permissive SRFI-1 take ;; (ptake N #f) => #f ;; (ptake N x) => '() (cond ((not l) #f) ((not (pair? x)) '()) ((= x 1) (car x)) (else (cons (car x) (ptake (- x 1) (cdr l)))))) (define (syntax-trace-printer e port) (define (tab) (display " " port)) (let ((who (safe-condition-who e)) (message (condition-message e)) (form (syntax-violation-form e)) (subform (syntax-violation-subform e)) (trace (if (guru-mode?) (condition-syntax-trace e) (ptake 5 (condition-syntax-trace e)))) (syntax-form (condition-syntax-form e)) (syntax-subform (condition-syntax-subform e))) (display " Syntax error" port) (newline port) (display " who : " port) (display who port) (newline port) (display " message : " port) (display message port) (newline port) (cond ((and (not (guru-mode?)) ;FIXME move the blacklist proper place.. (member message '("Unbound export" "Attempt to export mutable variable"))) 'do-nothing) (else (when form (display " form : " port) (display form port) (when syntax-form (let ((l (gather syntax-form))) (when (< 0 (length l)) (display " " port) (display l port)))) (newline port)))) (when subform (display " subform : " port) (display subform port) (when syntax-subform (let ((l (gather syntax-subform))) (when (< 0 (length l)) (display " " port) (display l port)))) (newline port)) (when (pair? trace) (display " around : " port) (for-each (lambda (e) (display e port) (newline port) (display " " port)) (gather trace)) (newline port) (display " trace : \n" port) (for-each (lambda (e) (tab) (write (strip e) port) (newline port) (newline port)) trace)))) (define (condition-printer/deco e) (cond ((syntax-trace-condition? e) (syntax-trace-printer e (current-error-port))) (else (condition-printer/base e (current-error-port))))) ;------------------------------------------------------------------------- ; from mosh's psyntax (see lib/psyntax/psyntax/main.ss) ;------------------------------------------------------------------------- (define (rpad str pad n) (let ([rest (- n (string-length (format "~a" str)))]) (let loop ([rest rest] [ret (format "~a" str)]) (if (<= rest 0) ret (loop (- rest 1) (string-append ret pad)))))) (define (for-each-with-index proc lst) (do ((i 1 (+ i 1)) ; start with 1 (lst lst (cdr lst))) ((null? lst)) (proc i (car lst)))) (define (map-with-index proc lst) (let loop ([i 0] [lst lst] [ret '()]) (if (null? lst) (reverse ret) (loop (+ i 1) (cdr lst) (cons (proc i (car lst)) ret))))) (define (record->field-alist r) (define (ref rtd i x) (let ([val ((record-accessor rtd i) x)]) val)); NMOSH: do not ungensym here (let loop ([ret '()] [rtd (record-rtd r)]) (cond [rtd (loop (append ret (map-with-index (lambda (i field) (cons field (ref rtd i r))) (vector->list (record-type-field-names rtd)))) (record-type-parent rtd))] [else ret]))) (define (condition-printer/base e port) (define max-condition-len (apply max (map (lambda (c) (string-length (symbol->string (record-type-name (record-rtd c))))) (simple-conditions e)))) (display " Condition components!:\n" port) (for-each-with-index (lambda (i x) (let ([rtd (record-rtd x)] [fields-alist (record->field-alist x)]) (format port " ~d. ~a" i (rpad (symbol->string (record-type-name rtd)) " " max-condition-len)) (when (null? fields-alist) (newline port)) (let loop ([first #t] [fields-alist fields-alist]) (cond [(null? fields-alist) '()] [else (let ([field (car fields-alist)]) (unless first (display (rpad "" " " (+ 4 max-condition-len)) port)) (display " " port) ;(display (car field) port) ;(display ": " port) (write (cdr field) port) (newline port) (loop #f (cdr fields-alist))) ] )))) (simple-conditions e))) )