I want to send this out to the list for discussion before I add it in to
the document. I would appreciate questions and suggestions that will
clarify the description.
Before I get in to this, I want to *beg* everyone NOT to digress into
the hygienic vs. non-hygienic macro argument. In regards to this issue I
have three comments:
1. Nobody has ever built a perfect macro system. All of the hygienic
macro systems that I have used are (in my opinion) essentially
incomprehensible, and *none* of them stop you from shooting yourself in
the foot. If I'm going to shoot my foot off anyway, I prefer to do it
using a simpler mechanism. The scheme community has spent at least 20
years on this issue without finding a decent solution.
2. We are not making any commitment that DEFMACRO will stay in the
language at all, or that it will remain the same in future
implementations. If you choose to use it, you are engaging in language
design at your own risk.
3. DEFMACRO is going in as an experimental tool. We want to have this to
simplify the compiler and to better understand what syntactic forms are
compelling from a convenience perspective. The goal is to reduce the
size of the parser and the semantic specification.
** The DEFMACRO Form
The DEFMACRO form operates on S-expressions. A macro is introduced by
defining a procedure using a special form:
(defmacro (macro-name single-arg) body)
This definition is initially treated similarly to
(define (macro-name single-arg) body)
however, the signature of the resulting procedure must be
(fn (s-expr) s-expr)
any other signature is a compile-time error. The compiler makes a note
that this identifier is now bound to a macro.
The type s-expr is predefined in the BitC library as something like the
following:
(defunion s-expr (s-list l : (list s-expr))
(symbol string) (intlit int) ...)
[where there is a constructor for each literal type]
** Input Processing Model
In order to support DEFMACRO in BitC, we need to introduce some new
layers of syntactic processing. There is now a low-level reader that
reads one top-level form at a time and returns an s-expr. Note this
means that all convenience forms such as
a.b
a[ndx]
expr : type
must now have a canonical translation into s-expr form with associated
reserved words in the language.
Given the s-expr, the macro processor is now applied in a fashion
similar to that of expression evaluation. Macro processing on a given s-
expr S proceeds by first applying macro expansion to all of the elements
of S. After this, if the first element of the S is an identifier that
resolves to a macro, then S is replaced with the result of evaluating
((car S) S)
That is, the macro function receives the entire form S, including the
name of the macro itself, and not just the rest of the form. Once the
replacement form is returned, it is re-processed by the expander.
This allows one macro to rewrite a form into a new form beginning with a
different macro. It also, regrettably, permits infinite macro loops.
When all macro expansion has completed, the surviving form is handed to
the AST parser, which constructs an AST for further processing. The AST
is then processed in the usual way according to the meaning of the
surviving form, always assuming that it results in a valid parse.
All reasoning about the behavior of a program proceeds from the AST.
That is, we do not attempt to reason about the pre-expanded form of the
program at all. DEFMACRO is purely lexical and pre-semantic.
Note that at the level of macro expansion, any semantics associated with
reserved words has not yet been defined. As far as the input s-expr is
concerned, the word 'tuple' is just another identifier, as is the word
'if'.
shap
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev