[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

issue SYNTACTIC-ENVIRONMENT-ACCESS, version 4



    > What is worse, while AUGMENT-ENVIRONMENT fully captures the
    > functionality of SYMBOL-MACROLET, and MACROLET, it behaves very oddly
    > with regard to LET and FLET.  In particular, if I understand it right,
    > it could be used to set things up so that the compiler thought a given
    > variable was a local varible, but it does nothing to actually create the
    > variable so things can be stored in it.  What does this even mean?

    The result of AUGMENT-ENVIRONMENT can be passed to MACROEXPAND or the
    various environment accessors, but it is not intended that the compiler
    or evaluator would ever see it.  In fact, there is no way proposed that
    an environment object can be given to the compiler.

Yes, I should have put that differently.

  In particular, if I understand it right, AUGMENT-ENVIRONMENT could
  be used to set things up so that inner macroexpansions using the
  environment think a given variable is a lexical variable, but it
  does nothing to actually create the variable so things can be stored
  in it.  What does this even mean?

Consider the following example.  It is not clear exactly what some
macro might do with the knowledge that a variable is local, so I have
just made something up.  However, whatever a macro did with this
information, it would not do the right thing if the information was
wrong, and AUGMENT-ENVIRONMENT makes it very easy for the information
to be wrong.

(defmacro bind-if-not-lexical (var &body body &environment env)
  (if (eq (variable-kind var env) :lexical) `(progn , . body)
      `(let (var) , . body)))

I would expect that the code in the body of the macro
bind-if-not-lexical could depend on var being lexical.

So I could write something like the following:

(defmacro swap (x y &optional (using (gensym)))
  `(bind-if-not-lexical ,using 
     (setq ,using ,x ,x ,y ,y ,using)))

and have the following work correctly:

(defun dumb-test (x y &aux z)
  (funny-macro a
    (swap x y z)
    (swap x y a)))

However, what if funny-macro is defined as follows?

(defmacro funny-macro (var &body body &environment env)
  (setq env (augment-environment :variable (list var)))
  `(progn , .(mapcar #'(lambda (f) (macroexpand f env))
                     body)))

We are going to end up referring to the unbound variable a.

This is to be contrasted with the following

(defmacro funny-macro2 (var &body body &environment env)
  (setq env (augment-environment :variable (list var)))
  `(let (,var) , .(mapcar #'(lambda (f) (macroexpand f env))
           	          body)))

Which is of course all right.  At the very least it must be said very
carefully that you cannot go using augment-environment to say things
unless they are true.  With variables this is an odd thing to say
because anything that is true about a variable for some external
reason will already be entered into the environment and therefore
there would be no reason to bother to say anything.  The only case
where it would ever make sense to use augment-environment is ones like
the one above.  And you can always do something like the following instead.

(defmacro funny-macro3 (var &body body)
  `(let (,var) , . body))

or if things are really complex

(defmacro funny-macro4 (var &body body)
  `(let (,var) (funny-macro4* ',arbitrary-state-info , . body)))
(defmacro funny-macro4* (state-info &body body &environment env)
  <arbitrary-processing>)

(The point here being that you have to save some info for when you get
control back after the real macro-processer gets the environment set
up right.)

Note that this problem does not come up in the :symbol-macro and
:macro case because all of the activity is purely confined to the
macro expansion phase of things and therefore in a very real sense
something you say to augment-environment is true simply because you
say it is true.

With declarations things still at least make sense in that you might
have figured somthing out that is true, but is not yet in the
environment. 

-----

In summary, it just seems to me that AUGMENT-ENVIRONMENT is not at all
the same kind of thing as the accessors.  I can use the accessors any
way I like and things are fine, but I have to be very careful with
AUGMENT-ENVIRONMENT.  

If the intention is just to expose a subprimitive that can be used to
support code walkers, then at a minimum I suggest that this be
said loud and clear and that the inputs for :variable and :function be
made syntactically identical to Let/prog/do etc. and flet/labels
binding lists so that code walking will be easy to do.  (You did this
with the other three keywords.)

Better yet I suggest getting to the heart of the matter with a form
called something like 

WALK-INTO ENV FORM FN

FORM must be one of the key forms that alters the environment
(i.e, let,let*,flet,macrolet,prog, etc.).  Walk-into augments its
environment argument as FORM dictates including all declarations.  It
then calls FN with two arguments, the body of FORM and the augmented
environment.  It returns a copy of FORM with the body replaced by
whatever FN returns.  Using this, you could rewrite funny-macro4 as follows

(defmacro funny-macro4+ (var &body body &environment env)
  (walk-into env `(let (,var) , . body)
             #'(lambda (body env)  <arbitrary-processing>)))

You can get into trouble with this too by consing up some special code
and contriving not to put it into the final, but at least the
intention is clear.  Also it would be a lot easier to use for code walking.