[plt-scheme] "identifier used out of context" error

From: Doug Orleans (dougo at ccs.neu.edu)
Date: Mon Sep 9 02:43:06 EDT 2002

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



Posted on the users mailing list.