Blocks from strings
Brian T Rice
water at tunes.org
Wed Dec 31 17:42:10 UTC 2003
This is a general comment, not just to Lex, about this kind of issue.
In Slate, we deal with this using syntax-level methods. For example,
[| :x | x + 1] `quote
gives you the syntax tree for that block: a blockNode, a collection of
names of the inputs and then locals, and then the body is a messageSend
node (or a statementSequenceNode) with arguments going farther down and so
If you want to perform substitution, you `unquote the internal term:
[| :x | x + y `unquote] `quote
calling evaluate on it or evaluateIn: will answer a block with the
parameter substituted in.
Note that none of this is magic. The only special part is the `
punctuation which tells the parser that the selector it precedes applies
to the parsed form of its arguments rather than their evaluation. So quote
and unquote are just methods on SyntaxNode, as well as evaluate or
evaluateIn:. You could also easily use the built-in syntax-walking methods
to implement something like replaceVar:with: which could be written as,
say... (pseudo-code in the style of Squeak following)
self@(SyntaxNode traits) replaceVar: varName with: expr
[| :node | (node isVarNode and: [node name = varName])
ifTrue: [expr] ifFalse: [node]].
And what transform: does is run a block on node-and-children recursively,
substituting the block results in place of each node as it finds it.
The Slate manual has a section devoted to explaining the basics of macros,
although it still needs work (like a code template example as I gave here
As for the holey block solution...
On Tue, 30 Dec 2003, Lex Spoon wrote:
> Nevin Pratt <nevin at smalltalkpro.com> wrote:
> > How do I programmatically create a block from a string?
> > The block's context would be the method that is creating the block.
> As a starting point, how about the simple Compiler evaluate ?
> Compiler evaluate: '[:x | x + 1]'
> By the way, if your ultimate goal is to programmatically create blocks
> out of chunks of code, then you can use blocks to hold the small chunks
> of code and then use "holey blocks" to combine them. For example, here
> is a holey block:
> [ Transcript show: 'at start'.
> hole value.
> Transcript show: 'at end ].
> This holey block (not a technical term :)) has a free variable named
> "hole" which can be filled in with different values. Here is a longer
> method that uses a holey block:
> createBlock: hole1 with: hole2
> ^[ Transcript show: 'at start'.
> hole1 value.
> Transcript show: 'in middle'.
> hole2 value.
> Transcript show: 'at end ].
> Each call to the method will create a new block, and the holes of the
> block will be filled in with different chunks of code. hole1 and hole2
> should themselves be blocks that have no arguments.
> As a general warning, using strings to represent stuff tends to cause
> extra difficulties compared to using objects that are richer. For
> example, you can have parse errors in strings at runtime, but the
> compiler will not let you have a parse error in a holey block.
> Furthermore, if you use a debugger while a holey block is running, you
> can trace where everything came from within the debugger; with strings,
> the debugger will be much less helpful.
> So, unless you ultimate requirement involves strings, you probably want
> to use blocks instead, and you probably want to create larger blocks by
> using these "holey blocks".
Well, the ultimate requirement is sometimes to avoid capturing a lexical
context that you don't want to. So I'd just call that "source" instead of
"strings". And of course I do prefer the macro solution; using strings by
comparison feels like pre-processor usage in a C environment.
Brian T. Rice
LOGOS Research and Development
More information about the Squeak-dev