;;;; ;;;; t r a c e . s t k ;;;; ;;;; Copyright © 1997-1998 Erick Gallesio - I3S-CNRS/ESSI ;;;; ;;;; Permission to use, copy, and/or distribute this software and its ;;;; documentation for any purpose and without fee is hereby granted, provided ;;;; that both the above copyright notice and this permission notice appear in ;;;; all copies and derived works. Fees for distribution or use of this ;;;; software or derived works may only be charged with express written ;;;; permission of the copyright holder. ;;;; This software is provided ``as is'' without express or implied warranty. ;;;; ;;;; $Id: trace.stk 1.2 Sun, 18 Jan 1998 19:17:48 +0000 eg $ ;;;; ;;;; Author: Erick Gallesio [eg@unice.fr] ;;;; Creation date: 26-Apr-1997 16:02 ;;;; Last file update: 18-Jan-1998 19:53 (require "hash") (define-module Trace (import Scheme STklos) (define *traced-symbols* (make-hash-table)) (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) (unless (symbol? symbol) (error "trace: bad symbol: ~S" symbol)) ; Verify if symbol is already traced (let ((entry (hash-table-get *traced-symbols* symbol #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)) ((procedure? proc)(trace-closure symbol proc)) ((primitive? proc)(trace-primitive symbol proc)) (else (error "trace: cannot trace ~S" proc))))) (hash-table-put! *traced-symbols* symbol (cons traced-proc proc)) traced-proc)) ;; ;; Untrace-symbol ;; (define (untrace-symbol symbol) (unless (symbol? symbol) (error "untrace: bad symbol: ~S" symbol)) ;; Verify if symbol is already traced (let ((entry (hash-table-get *traced-symbols* symbol #f))) (if entry (begin (hash-table-remove! *traced-symbols* symbol) (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? ' (module-environment (find-module 'STklos))) (begin (require "trace-gf") (is-a? proc )) #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))) args)))) (define-macro (untrace . args) (if (null? args) (error "untrace: no argument") `(begin ,@(map (lambda (x) `(set! ,x ((with-module Trace untrace-symbol) ',x))) 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")