Smalltalk Syntax Macros
by John Dougan
Abstract
An initial design and implementation of a syntax macro system for Smalltalk is described.

Motivation
Initial
The initial motivation for looking into macros was somewhat trivial. I had heard the Common Lisp zealots talk about macros and how they made various things easier and how any language without proper syntax macros was inferior and beneath consideration. Being a self confessed Smalltalk zealot, I found this state of affairs annoying and decided that I would see if I could build a macro system for Smalltalk if for no other reason than to show that it could be done.

I received a number of interesting reactions to this plan when I mentioned it to other Smalltalk developers. Most of the reactions I read as a "Blub" response, the reaction Paul Graham described as happening when a programmer encounters a language or language feature higher up the power scale and doesn't appreciate it. These people would typically claim that it was not a necessary feature, everything you could do with macros could be done using various features of Smalltalk. I do not dispute this, save to observe that the same could be said for a Turing machine.

Discards
Possibly the biggest use of macros in Common Lisp is to remove the verbose lambda notation from programs. This usage is mostly not necessary in Smalltalk as the lower overhead block notation is used instead. Indeed, there have been attempts to bring a variation of the Smalltalk block notation into various Lisp versions.

Also discarded is any notion of hygienic macros as is commonly found in Scheme or Dylan. While potentially useful, it add complexity to the implementation that I don;'t want in a first effort.

Inline Literals
One of the points made in response to my declaration of intent was to point out the inline literal facility that was built into VisualAge Smalltalk. This enables the developer to have a chunk of Smalltalk code evaluated at compile time, the result of which is inserted into the bytecode as a literal. Some found it very useful, others found it not at all useful.

This should be an easy use case for any general macro facility to implement.

DSL
The first thing I thought that ST macros would be useful for is the creation of better DSLs for Smalltalk, as this is one of the important uses claimed for macros by the Common Lisp believers.

Martin Fowler has talked about DSLs at :
http://martinfowler.com/bliki/DomainSpecificLanguage.html
and shown example of implementing a DSL in both C#/XML and Ruby:
http://martinfowler.com/articles/languageWorkbench.html.
In response Rainer Joswig demoed Martin's example in Common Lisp at
http://lispm.dyndns.org/news?ID=NEWS-2005-07-08-1
using significantly less code. I ended up writing a couple VW Smalltalk versions of the example just to see how good or bad it would be and posted the result to the LASTUG list, receiving a thunderous silence in return.

Proxy
More recently, I have been writing a game in Croquet. One of the implementation choices in Croquet is the syntax for sending a message to an object that resides in a different object space than the sender. This is essentially the classic proxy pattern. A proxy can be considered to have two faces, that of itself and that of the object it is fronting for. Distinguishing which aspect a message send is to go to without ugly hard to read code has been a problem in ST for quite some time.

The usual mechanism for sending to the remote object is typically some variation of a #perform:withArgs: method. However this can be hard to read the intent of and rather verbose. In GemStone this verbosity was resolved by using the DNU handler and a common selector prefix. So to get the class of the local proxy object you would write [gsProxy class] and to get the class of the remote object you would write [gsProxy gsclass]. This method has the problem of accidental name collisions. What if there is a method that happens to start with the chosen prefix? There is also a performance issue since the DNU handler will have to parse out the desired selector from the sent selector.

In Croquet this issue is resolved by sending the message #future to the proxy then sending the message desired to the result. So in Croquet getting the class of the local proxy object would be [croqProxy class] and the class of the remote object would be [croqProxy future class]. But all is not as it seems. The compiler in Croquet, when it sees this future construct, is compiling [croqProxy future class] to [croqProxy futureDo: #class withArgs: {}] which is in essence a special purpose macro facility. After seeing this I realized that this mechanism could profitably be replaced by something more general, based on a macro system. The #future mechanism as implemented has a number of problems particularly in it's poor integration with the Squeak development tools. A proper macro system that resolves these issues would make it easier to build ..... in the future.

Var args
Standard Smalltalk syntax is quite rigid with regard to arguments and has no provision for what are referred to in other languages as varargs or optional arguments. A standardizing an alternate syntax would be a problem, however enhancing the syntax via a standardized macro facility could end run these issues.

Compiler Hints
Proxy can be regarded as a special case of this,


Design and Implementation
Collection Constructors
[10 . 100 . 10 squareRoot] `array
Influences
The bulk of the current design and implementation owes a great deal to Jonathan Bachrach and Brian Rice. Dr. Bachrach did a great del of work of adding macros to various programming languages (Java, Dylan, etc) and Mr. Rice implemented a macro system in his language Slate, which uses a Smalltalk-like syntax.

Most specifically, the Slate macro calling syntax and the Slate approach of making macro sends into message sends on parse trees that return a parse tree that is substituted into the method parse tree at the macro send point were lifted conceptually pretty directly.

Macro Syntax
To indicate a macro send in a chunk of code, a backquote is prepended onto the message selector. For example, to insert a compile time literal empty dictionary into the method the code would look like [ (Dictionary new) `literal ]

Another example returns the parse tree of the macro call receiver: [(self foo: (3 + 4)) `quote] .

Note that this diverges from the CL approach of making macro calls indistinguishable from normal functional calls. CL does it's binding earlier than ST, so it can tell macros from functions more easily.

The precedence of a macro call is currently the same as a regular message send of the same type. This may change as experience is gained.

Implementation
The implementation is of macros ass an additional class, MacroMessageSend and an extra step in the compilation process. Macro calls are compiled into MacroMessageSend instances and after the parsing step is done, these calls are expanded. Expansion is done from the root to the leaves.

Implementing the Literal example

ParseNode>>literal
^LiteralNode on: self asCodeString execute

Implementing the proxy example
3 changes: ProvyMessageSendNode, Add ValueNode>>proxy, refactor compiler to ask receriver on how to compile send

ValueNode>>proxy
^ProxyMessageSendNode on: self

statementNode>>compileSendTo: messageSend
messsgeSend normalthiingy: self.

ProvyMessageSendNode >>compileSendTo: messageSend
^messsageSend proxyThingy: self

Problems
Devtool Integration
Code inside macro may not be found/recognized by tools.
Recompilation issue
Keep the parse trees around? Or recompile and examine as necessary?
Keep a list of symbols in the final method?

ST syntax not well suited to this
Need to make Skeleton Syntax Trees for Smalltalk
`increment example
Special place of message in the code, unlike the lisp function.

Macro methods cluttering up the node classes
macros are methods on parse tree nodes
not terribly modular.

ST compilers/parse trees are not standardized
To make it work across any supporting ST would require standardizing aspects of the compiler
Define a standardizable SST which is then built into a platform specific AST?






References
General Macros
Macros as multi-stage computations: type-safe, generative, binding macros in MacroML
Macros that work
Programmabe Syntax Macros
Jonathan Bachrach
D-Expressions - Macros for Dylan
Java Syntactic Extender - Macros for Java
Java Syntactic Extender at Sourceforge
Slate Smalltalk and Brian Rice
Slate Smalltalk Home Page
The Slate Smallltalk Blog
Slate Language Tutorial
Slate Syntax
"Slate - Brian Rice" - Blog Post by James Robertson
Brian Rice's Home Page
Brian Rice's del.icio.us linkblog
"Development Direction"
Olin Shivers
The anatomy of a loop: a story of scope and control
Static analysis for syntax objects
Alt. Syntax
Literal
<10 literal>
<(Float pi * 2) literal>

10 literal
〖(Set with: 10 ) literal〗
〖literal (Float pi * 2)〗
〖literal (Set with: 10 )〗
〖(Float pi * 2) literal〗
〖literal (Set with: 10 )〗
〖literal (Set with: 10 )〗
〖(Set with: 〖(Set with: 10 ) unquote: 10〗 ) quote: 10〗
〖(Set with: (Set with: 10 ) `unquote: 10) quote: 10〗
〖literal (Set with: 10 )〗
〖literal (Set with: 10 )〗
〖literal (Set with: 10 )〗



() `literal

Array constructor
[10 . 20 . 10 squareRoot . x * 2] array
array [10 . 20 . 10 squareRoot . x * 2] 〉


clde Quotes


〖(a b: c) quote〗
〖(a b: c) quote〗