You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sugar/sugar/debug.rkt

185 lines
7.0 KiB
Racket

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

#lang racket/base
(require racket/string
(for-syntax racket/base)
"define.rkt")
(provide+safe report report/time time-name
report/line report/file
report* report*/line report*/file
report-apply repeat time-repeat time-repeat* time-name time-named time-avg compare)
(define (stringify-results expr-results)
(format (if (= 1 (length expr-results))
"~a"
"(values ~a)") (string-join (for/list ([r (in-list expr-results)])
(format "~v" r)) " ")))
(define-syntax (report stx)
(syntax-case stx ()
[(MACRO EXPR) #'(MACRO EXPR EXPR)]
[(_ EXPR NAME)
#'(let ([expr-results (call-with-values (λ () EXPR) list)])
(eprintf "~a = ~a\n" 'NAME (stringify-results expr-results))
(apply values expr-results))]))
(define-syntax (report/time stx)
(syntax-case stx ()
[(MACRO EXPR) #'(MACRO EXPR EXPR)]
[(_ EXPR NAME)
#'(let* ([op (open-output-string)]
[expr-results (parameterize ([current-output-port op])
(time (call-with-values (λ () EXPR) list)))])
(eprintf "~a = ~a [~a]\n" 'NAME (stringify-results expr-results) (string-trim (get-output-string op)))
(apply values expr-results))]))
(define-syntax (report/line stx)
(syntax-case stx ()
[(MACRO EXPR) #'(MACRO EXPR EXPR)]
[(_ EXPR NAME)
#`(let ([expr-results (call-with-values (λ () EXPR) list)])
(eprintf "~a = ~a on line ~a\n" 'NAME (stringify-results expr-results) #,(syntax-line #'EXPR))
(apply values expr-results))]))
(define-syntax (report/file stx)
(syntax-case stx ()
[(MACRO EXPR) #'(MACRO EXPR EXPR)]
[(_ EXPR NAME)
#`(let ([expr-results (call-with-values (λ () EXPR) list)])
(eprintf "~a = ~a on line ~a in \"~a\"\n" 'NAME (stringify-results expr-results)
#,(syntax-line #'EXPR)
'#,(syntax-source #'EXPR))
(apply values expr-results))]))
(define-syntax-rule (define-multi-version MULTI-NAME NAME)
(define-syntax-rule (MULTI-NAME x (... ...))
(begin (NAME x) (... ...))))
(define-multi-version report* report)
(define-multi-version report*/line report/line)
(define-multi-version report*/file report/file)
(define-syntax (report-apply stx)
(syntax-case stx ()
[(_ PROC EXPR)
#'(let ([lst EXPR])
(report (apply PROC lst) (apply PROC EXPR))
lst)]
[(_ PROC EXPR #:line)
#'(let ([lst EXPR])
(report (apply PROC lst) (apply PROC EXPR) #:line)
lst)]))
(define-syntax-rule (repeat NUM EXPR ...)
(for/last ([i (in-range NUM)])
EXPR ...))
(define-syntax-rule (time-repeat NUM EXPR ...)
(time (repeat NUM EXPR ...)))
(define (parse-time-str str)
(for/list ([num (in-port read (open-input-string str))]
#:when (number? num))
num))
(define-syntax-rule (time-avg NUM EXPR ...)
(let ([n NUM])
(define-values (strs results)
(for/lists (strs results)
([i n])
(let* ([op (open-output-string)]
[expr-results (parameterize ([current-output-port op])
(time (call-with-values (λ () EXPR ...) values)))])
(values (get-output-string op) expr-results))))
(displayln (apply format "~a: cpu time: ~a real time: ~a gc time: ~a (avg of ~a)"
(append
(list (car '(EXPR ...)))
(for/list ([vals (apply map list (map parse-time-str strs))])
(floor (/ (apply + vals) n)))
(list n))))
(car (reverse results))))
(define-syntax (time-repeat* stx)
(syntax-case stx ()
[(_ NUM EXPR ...)
#'(let ([n NUM])
(values (time-repeat n EXPR) ...))]))
(define-syntax (time-name stx)
(syntax-case stx ()
[(_ NAME EXPR ...)
#'(let* ([op (open-output-string)]
[expr-results (parameterize ([current-output-port op])
(time (call-with-values (λ () EXPR ...) values)))])
(display (format "~a: ~a" 'NAME (get-output-string op)))
expr-results)]))
(define-syntax (time-named stx)
(syntax-case stx ()
[(_ EXPR ...)
#'(let* ([op (open-output-string)]
[expr-results (parameterize ([current-output-port op])
(time (call-with-values (λ () EXPR ...) values)))])
(display (format "~a: ~a" (car '(EXPR ...)) (get-output-string op)))
expr-results)]))
(define-syntax (compare stx)
(syntax-case stx ()
[(_ EXPR ID ID-ALT ...)
#'(values EXPR (let ([ID ID-ALT]) EXPR) ...)]))
(module reader racket/base
(require syntax/module-reader racket/syntax version/utils)
(provide (rename-out [debug-read read]
[debug-read-syntax read-syntax]
[debug-get-info get-info]))
(define current-metalang-scope-flipper (make-parameter values))
(define (wrap-reader reader)
(λ args
(parameterize ([current-readtable (make-debug-readtable (current-readtable))]
[current-metalang-scope-flipper (make-syntax-introducer)])
(define stx (apply reader args))
(define proc (if (and (syntax? stx) (version<=? "6.2.900.4" (version)))
(current-metalang-scope-flipper)
values))
(proc stx))))
(define-values (debug-read debug-read-syntax debug-get-info)
(make-meta-reader
'sugar/debug
"language path"
(λ (bstr) ; copy of `lang-reader-module-paths`, only available since 6.7
(let* ([str (bytes->string/latin-1 bstr)]
[sym (string->symbol str)])
(and (module-path? sym)
(vector
;; try submod first:
`(submod ,sym reader)
;; fall back to /lang/reader:
(string->symbol (string-append str "/lang/reader"))))))
wrap-reader
wrap-reader
(λ (proc)
(λ (key defval)
(case key
[else (if proc (proc key defval) defval)])))))
(define report-char #\R)
(define (make-debug-readtable [rt (current-readtable)])
(make-readtable rt report-char 'dispatch-macro report-proc))
(define (another-report-char? ip) (and (char=? (peek-char ip) report-char) (read-char ip)))
(define (report-proc trigger-char ip src ln col pos)
(define flip-metalang-scope (current-metalang-scope-flipper))
(flip-metalang-scope (with-syntax ([REPORT-ID (cond
[(not (another-report-char? ip)) 'report] ; #R...
[(not (another-report-char? ip)) 'report/line] ; #RR...
[else 'report/file])] ; #RRR...
[STX (flip-metalang-scope (read-syntax/recursive src ip))])
#'(let ()
(local-require (only-in sugar/debug REPORT-ID))
(REPORT-ID STX))))))