I came across what was near-to-one of my first Rebol programs (the first one using PARSE).
It was an interpreter for a language called "Whitespace", where all the instructions are made out of tab, space, and newline characters. My idea was to use PARSE to actually evaluate the code:
https://github.com/hostilefork/whitespacers/blob/master/rebol/whitespace.reb
The idea of using parse as the interpreter is an interesting take...but the code is far too repetitive. It was clearly written before I knew much about COMPOSE or really using the generative side of things.
Ideas on Doing it "Right"?
Currently there's a split between the specification and the implementation. That might be desirable in some cases, but I don't think it's desirable here.
The instructions are grouped together, which lets them "inherit" their leading sequence. For example, putting push [space Number] and duplicate-top [lf space] in "Stack-Manipulation" container lets them inherit the leading space common to each instruction. Otherwise they'd have to be spelled out as [space space Number] and [space lf space].
But beyond that, being inside a grouping pulls them out of "global scope", which means the instructions aren't overwriting the definitions of things like add and subtract with the whitespace versions.
Reducing The Repetition
The first thing I think of is merging the functions with the whitespace spec, and doing it more dialect-style:
; The 2010 JavaScript-Like Way
...
push: [
command: [space Number]
description: {Push the number onto the stack}
]
duplicate-top: [
command: [lf space]
description: {Duplicate the top item on the stack}
]
...
push: func [value [integer!]] [
insert stack value
return none
]
duplicate-top: func [] [
insert stack first stack
return none
]
Being relatively liberal in syntax here, we can imagine doing this more like:
; A Modern Dialected Way
push: ??? [
{Push the number onto the stack}
space (value <number!>)
][
insert stack value
return none
]
duplicate-top: ??? [
{Duplicate the top item on the stack}
lf space
][
insert stack first stack
return none
]
This is a little push in the right direction. But we have some issues to think through.
-
Whatever we're building here as units of the language need to be "registered" in the complete list of operations. If they were global declarations run by the evaluator, then one of the things the
???
operator would have to do would be this registration. If they are not global, then registration could be done by their container that is invoking them. -
We still have to inherit the leading space that both of these instructions have. An interesting point in the PARSE branching is that we benefit from having the knowledge that these all start with space, so that the space can lead into these tests as alternates...e.g.
[space [lf space | space <Number>]]
will be more efficient than[space lf space | space space <Number>]
. -
If we decide that the container is the boss, then giving a name to
???
is not really necessary. But what happens if you leave it off?... Stack-Manipulation ... [ push: [ {Push the number onto the stack} space (value <number!>) ][ insert stack value return none ] ... ]
This is a counterintuitive mixture of a SET-WORD! with two blocks after it. How do we reconcile the idea of "declaration-like-things" inside of a container like this? The code needs to be in a block, the other things don't...so other notations are possible...
... Stack-Manipulation ... [ PUSH {Push the number onto the stack} space (value <number!>) [ insert stack value return none ] ... ]
I guess the easiest thing to do is to cave, and just come up with something for ???. It has the benefit that you can actually run your implementation of Stack-Manipulation through the evaluator and do normal assignments. So something like push: instruction [...] [...]
Yet there's something a bit dissatisfying about having to type INSTRUCTION redundantly each time...where you're also kind of claiming that word so it can't be used other ways.
Lots Of Other Questions...
I think it would be worthwhile to rework this, but it's worth taking note of how adrift you can get right out of the gate looking at it. There are lots of big questions that don't really have obvious answers.