[plt-scheme] "identifier used out of context" error
I'm writing a little procedure reflection package, that lets you
inspect the source code of a closure and query the current values of
its free variables. But I ran across an error I don't understand...
Here's the code (suggestions on how to improve it are welcome):
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Keep the source code around for procedure definitions.
;; Adapted from a post to the plt-scheme mailing list by Matthew Flatt.
;; Also allow access to the procedure's current environment bindings.
(module free-vars mzscheme
(provide free-vars)
;; A list of the free variables in an expression.
(define (free-vars stx)
(let syntax-loop ((stx (expand stx)))
(let ((e (syntax-e stx)))
(cond ((pair? e)
(if (eq? (syntax-e (car e)) '#%top)
(list (cdr e))
(let syntax-pair-loop ((e e))
(append (syntax-loop (car e))
(let ((e2 (cdr e)))
(cond ((null? e2) '())
((syntax? e2) (syntax-loop e2))
(else (syntax-pair-loop e2))))))))
((vector? e)
(apply append (map syntax-loop (vector->list e))))
(else '()))))))
(module proc-info mzscheme
(require-for-syntax free-vars)
(provide proc-expr
proc-env
env-value
(rename wrapper-lambda lambda))
(define-struct proc-info (expr env))
(define *proc-info-table* (make-hash-table 'weak))
(define (set-proc-info! proc expr env)
(hash-table-put! *proc-info-table* proc (make-proc-info expr env))
proc)
(define (proc-expr proc)
(proc-info-expr
(hash-table-get *proc-info-table* proc
(lambda () (error 'proc-expr
"primitive procedure: ~a" proc)))))
(define (proc-env proc)
(proc-info-env
(hash-table-get *proc-info-table* proc
(lambda () (error 'proc-env
"primitive procedure: ~a" proc)))))
(define-syntax wrapper-lambda
(let ()
(define (make-env stx)
(let ((fv (free-vars stx)))
(with-syntax (((var ...) fv))
(syntax (lambda (msg)
(case msg
((var) var)
...
(else (error 'env-value "Not bound: ~a" msg))
))))))
;;wrapper-lambda:
(lambda (stx)
(syntax-case stx ()
[(_ . rest)
(with-syntax ((env (make-env (syntax (lambda . rest)))))
(syntax (set-proc-info! (lambda . rest)
'(lambda . rest)
env)))]))))
(define (env-value env var)
(env var))
)
It seems to work okay for simple cases:
Welcome to MzScheme version 202.1, Copyright (c) 1995-2002 PLT
> (load "proc-info.scm")
> (require proc-info)
> (define x 37)
> (define thirty-seven (lambda () x))
> (thirty-seven)
37
> (proc-expr thirty-seven)
(lambda () x)
> (env-value (proc-env thirty-seven) 'x)
37
But when I try to query a non-top-level variable, I get this error:
> (define forty-two (let ((x 42)) (lambda () x)))
STDIN::216: compile: identifier used out of context in: x
What does this mean? Is it because I'm constructing a syntax object
(the case expression) from syntax objects that came from a different
expression? Is there any way to make this work?
--dougo at ccs.neu.edu