stk/Lib/trace.stk

160 lines
5.0 KiB
Plaintext

;;;;
;;;; t r a c e . s t k
;;;;
;;;; Copyright © 1997-1999 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
;;;;
;;;; Permission to use, copy, modify, distribute,and license this
;;;; software and its documentation for any purpose is hereby granted,
;;;; provided that existing copyright notices are retained in all
;;;; copies and that this notice is included verbatim in any
;;;; distributions. No written agreement, license, or royalty fee is
;;;; required for any of the authorized uses.
;;;; This software is provided ``AS IS'' without express or implied
;;;; warranty.
;;;;
;;;; Author: Erick Gallesio [eg@unice.fr]
;;;; Creation date: 26-Apr-1997 16:02
;;;; Last file update: 3-Sep-1999 19:55 (eg)
(require "hash")
(define-module Trace
(import Scheme STklos)
(define *traced-symbols* (make-hash-table equal?))
(define *indentation* 0)
(define *err-port* (current-error-port))
(define indent (lambda () (make-string *indentation* #\.)))
;;
;; Trace-primitive
;;
(define (trace-primitive symbol value)
(lambda l
(format *err-port* "~A -> ~A with args = ~S\n" (indent) symbol l)
(let ((res (apply value l)))
(format *err-port* "~A <- ~A returns ~S\n" (indent) symbol res)
res)))
;;
;; Trace-closure
;;
(define (trace-closure symbol value)
(define (trace-args closure args)
(let ((formals (cadr (procedure-body closure))))
(unless (null? formals)
(format *err-port* "with "))
(let Loop ((formals formals) (actuals args))
(cond
((null? formals) (unless (null? actuals)
(error "too many actual parameters for ~S"
symbol)))
((symbol? formals) (format *err-port* "~A = ~S\n" formals actuals))
((null? actuals) (unless (null? formals)
(error "too few actual parameters for ~S"
symbol)))
(else (format *err-port* "~A = ~S~A"
(car formals)
(car actuals)
(if (null? (cdr formals)) "\n" ", "))
(Loop (cdr formals) (cdr actuals)))))))
;;=== Body of trace-closure
(lambda l
;; We trace the closure in a dynamic-wind to restore indentation
;; on error
(dynamic-wind
(lambda () (set! *indentation* (+ *indentation* 2)))
(lambda ()
(format *err-port* "~A -> ~A " (indent) symbol)
(trace-args value l)
(let ((res (apply value l)))
(format *err-port* "~A <- ~A returns ~S\n" (indent) symbol res)
res))
(lambda () (set! *indentation* (- *indentation* 2))))))
;;
;; Trace-symbol
;;
(define (trace-symbol symbol proc env)
(unless (symbol? symbol) (error "trace: bad symbol: ~S" symbol))
; Verify if symbol is already traced
(let ((entry (hash-table-get *traced-symbols* (cons symbol env) #f)))
(when entry
; (car entry) contains the traced proc and (cdr entry) the untraced one
(let ((old (car entry)))
(if (and (procedure? old) (eq? old proc))
(error "trace: procedure ``~S'' is already traced" symbol)))))
;; Trace symbol
(let ((traced-proc (cond ; Order is important!!!
((generic? proc)(trace-generic symbol proc))
((primitive? proc)(trace-primitive symbol proc))
((procedure? proc)(trace-closure symbol proc))
(else (error "trace: cannot trace ~S" proc)))))
(hash-table-put! *traced-symbols* (cons symbol env) (cons traced-proc proc))
traced-proc))
;;
;; Untrace-symbol
;;
(define (untrace-symbol symbol env)
(unless (symbol? symbol) (error "untrace: bad symbol: ~S" symbol))
;; Verify if symbol is already traced
(let ((entry (hash-table-get *traced-symbols* (cons symbol env) #f)))
(if entry
(begin
(hash-table-remove! *traced-symbols* (cons symbol env))
(cdr entry))
(error "untrace: ~S is not traced" symbol))))
;;
;; Generic?
;;
;; A pseudo-predicate which returns always false, while STklos is
;; not initialized. If STklos is initialized it loads, if needed,
;; the code for tracing generic functions and returns a proper
;; value depending of
(define (generic? proc)
(if (symbol-bound? '<generic> (module-environment (find-module 'STklos)))
(begin
(require "trace-gf")
(is-a? proc <generic>))
#f))
;;;;
;;;; T R A C E / U N T R A C E
;;;;
(define-macro (trace . args)
(if (null? args)
(error "trace: no argument")
`(begin
,@(map (lambda (x)
`(set! ,x ((with-module Trace trace-symbol) ',x ,x
(the-environment))))
args))))
(define-macro (untrace . args)
(if (null? args)
(error "untrace: no argument")
`(begin
,@(map (lambda (x)
`(set! ,x ((with-module Trace untrace-symbol) ',x
(the-environment))))
args))))
)
;; Trace and untrace were defined as autoload in the STk module and
;; are defined as exported symbols from the Trace module. The autoload
;; will complain that the symbol was not defined. So, we define these
;; symbol in the current module to overload the autoload
(define trace (with-module Trace trace))
(define untrace (with-module Trace untrace))
(provide "trace")