160 lines
5.0 KiB
Plaintext
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")
|