#lang scheme/base
(require (for-syntax scheme/base
(file "syntax.ss"))
scheme/contract
scheme/match
scheme/path
scheme/pretty
(only-in srfi/1/list take-right)
srfi/13/string
(file "base.ss")
(file "contract.ss"))
(define debug-enabled?
(make-parameter #t))
(define (default-debug-printer message value)
(define value-string
(with-pretty-indent " "
(pretty-format value)))
(printf "~a:~n~a~n" message value-string))
(define current-debug-printer
(make-parameter default-debug-printer))
(define (debug message value)
(when (debug-enabled?)
((current-debug-printer) message value))
value)
(define (debug* message proc . args)
(define value (apply proc args))
(when (debug-enabled?)
((current-debug-printer) message value))
value)
(define-syntax (define-debug stx)
(syntax-case stx ()
[(_ id val)
#`(define id (debug (symbol->string 'id) val))]))
(define-syntax (let-debug stx)
(syntax-case stx ()
[(_ ([var val] ...) exp ...)
#'(let ([var (debug (symbol->string 'var) val)] ...)
exp ...)]))
(define-syntax (let*-debug stx)
(syntax-case stx ()
[(_ ([var val] ...) exp ...)
#'(let* ([var (debug (symbol->string 'var) val)] ...)
exp ...)]))
(define-syntax (letrec-debug stx)
(syntax-case stx ()
[(_ ([var val] ...) exp ...)
#'(letrec ([var (debug (symbol->string 'var) val)] ...)
exp ...)]))
(define-syntax with-pretty-indent
(syntax-rules ()
[(_ indent expr ...)
(let* ([indent-string indent]
[indent-amount (string-length indent-string)])
(parameterize ([pretty-print-print-line
(lambda (line out offset width)
(cond [(eq? line 0) (display indent-string out)
indent-amount]
[(number? line) (if (number? width)
(begin
(newline out)
(display indent-string out)
indent-amount)
(begin
0))]
[else (when (number? width)
(newline out))
0]))])
expr ...))]))
(define (exn-context exn)
(map (match-lambda
[(list-rest name srcloc)
(string->symbol
(if srcloc
(format "~a:~a:~a:~a"
(path->short-string (srcloc-source srcloc))
(srcloc-line srcloc)
(srcloc-column srcloc)
(or name '??))
(format "??:??:??:~a"
(or name '??))))])
(continuation-mark-set->context (exn-continuation-marks exn))))
(define (path->short-string path)
(define path-elements
(foldr (lambda (element accum)
(cond [(path? element) (cons (path->string element) accum)]
[(eq? element 'same) accum]
[(eq? element 'up) (cons ".." accum)]))
null
(explode-path (simplify-path path))))
(define num-elements
(length path-elements))
(string-join (take-right path-elements (min 3 num-elements)) "/"))
(provide define-debug
let-debug
let*-debug
letrec-debug
with-pretty-indent)
(provide/contract
[debug-enabled? (parameter/c boolean?)]
[current-debug-printer (parameter/c (-> string? any/c void?))]
[debug (-> string? any/c any)]
[debug* (->* (string? procedure?) () #:rest any/c any)]
[exn-context (-> exn? (listof symbol?))])