This is the mail archive of the cgen@sources.redhat.com mailing list for the CGEN project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Ooh boy. (elm-get and elm-set)


I think the most challenging part of making CGEN portable will be the
uses of procedure->memoizing-macro in cos.scm.

(elm-get OBJECT SLOT-NAME) fetches the value of the slot named
SLOT-NAME in OBJECT, where SLOT-NAME is a symbol.  For example:

        (elm-get insn 'iflds-values)

Doing this entails fetching the object's class, looking up the slot
name in its field list, and fetching the corresponding element from
the object itself.

But most uses of elm-get are methods fetching the value of one of
self's fields:

        (elm-get self 'values)

In such cases, since we know the type of SELF --- it's the class of
which we're defining a method, we should be able to look up the slot
name at compile time, and expand to something faster like:

        (vector-ref self SLOT-INDEX)

CGEN does this by taking advantage of some very unusual behavior
specific to Guile (and its predecessor, SCM, I think).  I've included
the Guile manual description of acros, macros, and mmacros below.
CGEN uses a mmacro to find the value of 'self' at run-time the first
time the expression is evaluated, look up its type, and then replace
itself with the appropriate code.  That is, the first run-time value
of 'self' is used to patch the code.

Wow.  Hats off to Doug --- and I don't mean that in some kind of
sarcastic, express-my-totalitarian-comfort-zone-in-coding-standards
bondage-and-discipline-type-system-fanatic kind of way.  When I read
descriptions of MacLisp and InterLisp, or Alan Kay's early history of
Smalltalk, or Donald Knuth's explanation of why he wants to use
assembly code in The Art of Computer Programming, I see how many
potentially fruitful lines of exploration the modern overdeveloped
sense of programming language propriety has cut off, and I weep.  How
brief our Renaissance was!  Doug's hack seems to me like a little
reminder of those times.

That said, it's not R5RS Scheme.  :)


Here's how I'm thinking about bringing it into line:

First, we'll make syntax for defining classes, so that a class's
field list will be genuinely available at expansion time.  For
separate compilation, that's critical.

Then we introduce syntax for defining methods.

Then, (elm-get self NAME) and (elm-set self NAME VAL) are only supposed to
be used in methods, so we can have the define-method macro introduce 
local (non-hygienic) definitions for elm-get an elm-set that check for
constant names and do the appropriate expansion.

How does that sound?


----

   Internally, Guile uses three different flavors of macros.  The three
flavors are called "acro" (or "syntax"), "macro" and "mmacro".

   Given the expression

     (foo ...)

with `foo' being some flavor of macro, one of the following things will
happen when the expression is evaluated.

   * When `foo' has been defined to be an "acro", the procedure used in
     the acro definition of `foo' is passed the whole expression and
     the current lexical environment, and whatever that procedure
     returns is the value of evaluating the expression.  You can think
     of this a procedure that receives its argument as an unevaluated
     expression.

   * When `foo' has been defined to be a "macro", the procedure used in
     the macro definition of `foo' is passed the whole expression and
     the current lexical environment, and whatever that procedure
     returns is evaluated again.  That is, the procedure should return
     a valid Scheme expression.

   * When `foo' has been defined to be a "mmacro", the procedure used
     in the mmacro definition of `foo' is passed the whole expression
     and the current lexical environment, and whatever that procedure
     returns replaces the original expression.  Evaluation then starts
     over from the new expression that has just been returned.

   The key difference between a "macro" and a "mmacro" is that the
expression returned by a "mmacro" procedure is remembered (or
"memoized") so that the expansion does not need to be done again next
time the containing code is evaluated.

   The primitives `procedure->syntax', `procedure->macro' and
`procedure->memoizing-macro' are used to construct acros, macros and
mmacros respectively.  However, if you do not have a very special
reason to use one of these primitives, you should avoid them: they are
very specific to Guile's current implementation and therefore likely to
change.  Use `defmacro', `define-macro' (*note Macros::) or
`define-syntax' (*note Syntax Rules::) instead.  (In low level terms,
`defmacro', `define-macro' and `define-syntax' are all implemented as
mmacros.)



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]