Cool. It all works nicely. It really helped me find logical errors in
I found just shadowing setq in cl-user worked fine too (instead of those
3 package statements).
(shadow 'setq 'cl-user)
(defun var-declared-in-ecl-env (var env)
(assoc var (car env)))
(defmacro setq (var value &rest rest &environment env)
(if (or (consp var) (var-declared-in-ecl-env var env))
`(cl:setq ,var ,value)
`(if (boundp ',var)
(cl:setq ,var ,value)
(error "Tried to assign a value to undefined variable ~A" ',var))))
`(progn ,form (setq ,@rest))
Juan Jose Garcia Ripoll wrote:
>On Thu, 2005-11-24 at 12:09 +1100, Dean O'Connor wrote:
>>I don't know if this is possible, but it would also be great if there
>>was a further option for setq to trip errors only at execution time.
>I'd rather not include that on "standard" ECL. SETQ is not really a
>function. It is a special form. Adding such option would mean adding a
>check for a global flag on many spots by, perhaps, redefining the
>ECL_SETQ macro. That would be a real performance hog. As I show below,
>however, your problem has a solution using standard Common Lisp plus
>some environment magic.
>>I my situation, my globals (dynamic specials) are created/bound in a
>>root function and accessed by functions called by that execution path.
>>(I am trying to use this method for allowing per thread "globals" on an
>> > (SETQ EXT:*ACTION-ON-UNDEFINED-VARIABLE* 'ERROR)
>> > (defun foo ()
>> (let ((*global* 1))
>> (declare (special *global*))
>> (print *global*)
>> (print *global*)))
>> > (defun bar ()
>> (setq *global* 2)
>> (setq undefined-local 3))
>>Undefined variable referenced in interpreted code.
>>Instead, if the defun of bar didn't throw an error, but when foo is
>>called, thus calling bar, only the 2nd setq fails, since at this point
>>*global* is bound, whereas undefined-local is not.
>The problem is that, even if FOO declares *GLOBAL* to be special,
>special declarations only has effect on the function in which it
>appears, not on the rest of functions. There is no magic flag that
>converts *GLOBAL* suddenly on a special variable, and functions to be
>called have no standard way of testing whether *GLOBAL* is a special
>variable. Not even in standard Common Lisp.
>Only thing I can recommend you is to do something like what I show in
>the attached file (foo.lsp), which redefines SETQ. When you load it in
>the interpreter, it will complain about the only undefined variable. You
>have, however, to use the new SETQ everywhere and ensure that any
>DEFVAR/DEFPARAMETER has a value (it is not enough to declare the
>variable special: it has to have a value to be detected at run time).
>;;; Loading #P"/home/jlr/foo.lsp"
>Tried to assign a value to undefined variable *D*
>Broken at EVAL.
>(when (find-package "MY-LISP")
> (delete-package "MY-LISP"))
> (:use "COMMON-LISP")
> (:shadow "SETQ"))
>(defun var-declared-in-ecl-env (var env)
> (assoc var (car env)))
>(defmacro setq (var value &rest rest &environment env)
> (let (form)
> (setf form
> (if (or (consp var) (var-declared-in-ecl-env var env))
> `(cl:setq ,var ,value)
> `(if (boundp ',var)
> (cl:setq ,var ,value)
> (error "Tried to assign a value to undefined variable ~A" ',var))))
> (if rest
> `(progn ,form (setq ,@rest))
>(let ((a 2))
> (setq a 2))
>(let ((*b* 2))
> (declare (special *b*))
> (setq *b* 2))
>(defvar *c* 2)
>(setq *c* 2)
>(setq *d* 3)