155 lines
4.9 KiB
Plaintext
155 lines
4.9 KiB
Plaintext
;;;;
|
|
;;;; t r a c e . s t k
|
|
;;;;
|
|
;;;; Copyright © 1997-1998 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
|
|
;;;;
|
|
;;;; 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 20:17:48 +0100 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? '<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))) 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")
|