;;;; ;;;; t r a c e . s t k ;;;; ;;;; Copyright © 1997-1999 Erick Gallesio - I3S-CNRS/ESSI ;;;; ;;;; 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? ' (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 (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")