;;; Ikarus Scheme -- A compiler for R6RS Scheme. ;;; Copyright (C) 2006,2007,2008 Abdulaziz Ghuloum ;;; ;;; This program is free software: you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License version 3 as ;;; published by the Free Software Foundation. ;;; ;;; This program is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . (library (ikarus trace) (export make-traced-procedure) (import (except (ikarus) make-traced-procedure)) (define k* '()) (define display-prefix (lambda (ls t) (unless (null? ls) (display (if t "|" " ")) (display-prefix (cdr ls) (not t))))) (define display-trace (lambda (k* v) (display-prefix k* #t) (write v) (newline))) (define make-traced-procedure (case-lambda [(name proc) (make-traced-procedure name proc (lambda (x) x))] [(name proc filter) (lambda args (call/cf (lambda (f) (cond [(memq f k*) => (lambda (ls) (display-trace ls (filter (cons name args))) (apply proc args))] [else (display-trace (cons 1 k*) (filter (cons name args))) (dynamic-wind (lambda () (set! k* (cons f k*))) (lambda () (call-with-values (lambda () (call/cf (lambda (nf) (set! f nf) (set-car! k* nf) (apply proc args)))) (lambda v* (display-prefix k* #t) (unless (null? v*) (let ([v* (filter v*)]) (write (car v*)) (let f ([v* (cdr v*)]) (unless (null? v*) (write-char #\space) (write (car v*)) (f (cdr v*)))))) (newline) (apply values v*)))) (lambda () (set! k* (cdr k*))))]))))]))) #!eof (define traced-symbols '()) (define untrace-symbol! (lambda (s) (define loop (lambda (ls) (cond [(null? ls) '()] [(eq? s (caar ls)) (let ([a (cdar ls)]) (when (eq? (cdr a) (symbol-value s)) (set-symbol-value! s (car a))) (cdr ls))] [else (cons (car ls) (loop (cdr ls)))]))) (set! traced-symbols (loop traced-symbols)))) (define trace-symbol! (lambda (s) (cond [(assq s traced-symbols) => (lambda (pr) (let ([a (cdr pr)] [v (symbol-value s)]) (unless (eq? (cdr a) v) (unless (procedure? v) (die 'trace "the top-level value is not a procedure" s v)) (let ([p (make-traced-procedure s v)]) (set-car! a v) (set-cdr! a p) (set-symbol-value! s p)))))] [else (unless (symbol-bound? s) (die 'trace "unbound" s)) (let ([v (symbol-value s)]) (unless (procedure? v) (die 'trace "the top-level value is not a procedure" s v)) (let ([p (make-traced-procedure s v)]) (set! traced-symbols (cons (cons s (cons v p)) traced-symbols)) (set-symbol-value! s p)))]))) Try: (trace-define fact (lambda (n) (if (zero? n) 1 (* n (fact (sub1 n)))))) (fact 5) (trace-define (fact n m) (cond [(zero? n) m] [else (fact (sub1 n) (* n m))])) (fact 5 1) (trace-define (fact n m k) (cond [(zero? n) (k m)] [else (begin (fact (sub1 n) (* n m) k) 0)])) (call/cc (lambda (k) (fact 6 1 (trace-lambda escape (v) (k v))))) (call/cc (lambda k* (trace-define (fact n) (cond [(zero? n) (call/cc (lambda (k) (set! k* (cons k k*)) 1))] [else (* n (fact (sub1 n)))])) (fact 9) (let ([k (car k*)]) (set! k* (cdr k*)) (k 100000)))) (trace-define (infinite-loop n) (infinite-loop (add1 n))) (infinite-loop 0)