# Immediate mechanics

## The "compileonly" flag

As with any Forth, words with the "immediate" flag are executed at compile time.
As with any Forth, immediate words can be called at runtime too.

It is sometimes useful to have those words have a different behavior depending
on whether we're compiling or not. Some Forths have a global "compiling?" flag,
but this simple system breaks down when such words are executed in the "in<"
handler or when dynamically calling such dual-behavior words.

In Dusk, we have a second flag, right next to the "immediate" flag, called the
"compileonly" flag. The idea is simple: if a word has the "compileonly" flag, it
can only be found, in the dictionary, through the "compile find", that is, the
find that executes repeatedly when we compile a word. Example:

  : foo ."regular" ;
  : foo ."compile only" ; compileonly
  foo \ prints "regular"
  : bar foo ; \ prints nothing, "foo" is not an immediate
  bar \ prints "compile only"

As you can see, "compileonly" words are "unfindable" through regular mechanisms.
The only way to find them is through one of these methods:

  * when compiling a word
  * through [compile]
  * when "compileonly!" is called right before a dictionary find

All other methods will fly right past through. Dictionary enumeration will still
see them though. For example, "words" [doc/mem/dict] will list them.

This mechanism works through the FINDMASK sysvars, which is generally $7f (masks
the immediate bit). When we want to look for a "compileonly" flag, we set this
variable to $3f, which will also mask the "compileonly" flag. Every call to
"findentry" will reset FINDMASK to its default value.

And that's all there is to this. In practice, "compileonly" and "immediate" are
use together the vast vast majority of the time, so there's a shortcut word
"coimm" that applies both flags at once.

### Inlinable words

With this "compileonly" flag, you can easily make your short-but-often used
words inlinable, that is, have their binary content being directly inserted into
the word that compiles your short word instead of a call to it. For example,
here's "drop" definition:

  : drop, PSP) @+, ;
  code drop drop, exit,
  : drop drop, ; coimm

"drop," is a "drop compiler" which unconditionally compiles a "drop" operation
(with HAL code [doc/hal]). That's fine and you can already use "drop," instead
of "drop" in your words to inline its content, but that's a bit ugly, right?

Therefore, what you can do is to create a "compileonly" drop that calls "drop,".
This way, you can use "drop" just fine in interpret mode, you can call it
indirectly by saving references to "' drop" around, it's still going to do the
"good old drop". But if you reference drop in a compilation context, then it's
going to call "drop," and compile an inlined version of "drop".

## Templates

Templates are immediate words that compile other words in a particular pattern
in order to reduce repetition of those patterns. For example, a common pattern
is to do something like "dup X swap Y" to apply words X and Y to a common
element. After a while, this pattern is repetitive (and even worse, when X and
Y are a series of words, the role of "dup" and "swap" can become less obvious),
so we have the template "bi" which achieves the same thing with "bi X | Y"

The central word of templates is "|", the template "slicer" and its mechanism is
disarmingly simple: "|" is an immediate alias to "execute". What a template word
such as "bi" does is, after having compiled it's "opening" words ("dup" in the
case of "bi"), pushes compiler words to PS for "|" to execute. Again, in the
case of "bi", the "|" compiles "swap".

Templates cannot be used in interpret mode.

To create your own template, all you have to do is to have something that looks
like "bi" implementation:

  : bi dup, ['] swap, ; immediate

List of builtin templates:

bi X | Y      --> dup X swap Y        a -- x y
bi+ X | Y     --> dup X over Y        a -- a x y
tri X | Y | Z --> dup X over Y rot Z  a -- x y z
dip X |       --> >r X r>             a b -- x b
