# Immediate mechanics

## Immediate compile/runtime selection

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 a compiling words compiles another compiling word.

Dusk OS' handling of this selection is a bit like the binary width modulators,
it's the word ":compiling":

  : foo ." runtime!" ;
  :compiling ." compile!" ;
  foo \ Prints "runtime!"
  : bar foo ; \ Prints "compile!" as soon as "foo" is reached.

":compiling" creates a metadata entry for the current word which contains the
payload to execute when the immediate word is compiled. When an immediate word
doesn't have such metadata, the runtime and compile time behaviors are the same.

The ":compiling" word applies "immediate" to its target, so applying it
explicitly is spurious.

When the "[compile]" word targets a word with a "compiling" metadata, it's this
word that is going to be compiled. That selection happens at compile time.

If you want to compile an immediate word and select its runtime behavior
instead, use "[rcompile]".

### Inlinable words

With this :compiling words above, 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, :compiling drop, ;

"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 graft a :compiling metadata to your "drop" word
which calls "drop,". If you type "drop" in runtime mode, "drop" is called. If
"drop" is encountered at compilation, the code for "drop" is compiled.

The :compiling system does the right thing in other situations too. For example,
if you pass a reference to drop to a dynamic table, it's the "runtime" drop that
is going to end up being called, not the compiler. So everything is fine and
dandy. Have fun inlining!

## 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
