# What's in a word?

Like in any Forth, Dusk's main mechanism for creating new words is ":".

  : foo bar baz ;

What this does is:

1. Create a new dictionary entry named "foo".
2. On some platforms, create a word mark [doc/hal].
3. Enter compile mode.
4. Compile calls to "bar", then "baz".
5. Call "exit," [doc/hal].
6. Stop compile mode.

There are other ways to create words differently. For example, "entry ( name
dict -- )" creates an entry in dictionary "dict" without creating a word mark or
entering compile mode. "code ( "name" -- )" creates a dictionary entry and a
word mark, but doesn't enter compile mode.

Those are relatively straightforward mechanisms. There are other ones that are a
bit more special, described below.

## Find selectors

As with any Forth, Dusk has immediates. They work as expected and are bound the
the $80 bit of the length flag of the dictionary entry, like on many Forths.

But Dusk as a second flag, bound to the bit $40: find selector.

When that flag is active, it makes the word "find immediate", that is, the word
is called on "find". That word is expected to have the signature "( -- w )" and
yield the actual word that the find operation should yield.

This is used, for example, to yield a different word at compile time and at
run time (see below), to enable "scrying mode" (see below), or to enable the
"setter mode" [lib/bm].

This mechanism is active on almost all "find" related word, as well as during
the interpret and compile loops. The only exceptions are "findentry" and words
that specifically mention not applying find selectors. All other "find" words
can be assumed to apply that logic.

A word can be made into a find selector with the "findselector" word. A find
selector is, yes, executed immediately, but the word it yields isn't necessarily
so. During compilation, it will be only if its "immediate" flag is set. Example
dummy usage:

  : foo ."hello" ;
  : bar ."find!" ['] foo ; findselector
  bar \ prints "find!hello"
  : baz bar ; \ prints "find!"
  baz \ prints "hello"
  : bar ."find!" ['] foo ; findselector immediate
  : baz bar ; \ prints "find!hello"
  baz \ prints nothing

## Compiling dual behavior

Find selectors can be used to have words that behave differently in run time and
compile time. This can be done with the word "compiling ( compw regularw -- )"
which creates a find selector from two words:

  :> ."compiling!" ;
  :> ."running!" ;
  compiling foo
  foo \ prints "running!"
  : bar foo ; \ prints "compiling!"
  : bar ['] foo execute ; \ prints nothing
  bar \ prints "running!"

The words ":> ( -- w )" and "code> ( -- w )" are like their ":" and "code"
counterparts, but don't create any dictionary entry and yield a pointer to their
code to PS.

As you can see from the example, dynamic finds ("'", "[']", etc.) yield the
runtime versions of the words, even when called from a compiliation context.
The only exception to this is "[compile]".

## Inlinable words

This compiling dual behavior opens the door to easy word inlining with the word
"inline ( -- )":

  : drop, PSP) @+, ; inline drop

which is the equivalent of:

  : drop, PSP) @+, ;
  code> current execute exit,
  compiling drop

With this version of drop, a regular "drop" will be called at runtime or when
we use references of it. But when "drop" is used in a compilation context, a
straight "PSP) @+," will be compiled, no call will be made.

## Aliases

An alias is a shortcut to another word:

  alias noop myalias

Calling "myalias" is the same as calling "noop". An alias is a native jump to
its target, so there's almost no runtime overhead to using aliases.

You can change the target of an alias, you can use the word
"realias ( w tgt -- )" which makes target word "tgt" alias to word "w". Example:

  ' anotherword ' myalias realias

Note that while "tgt" is usually an alias, it doesn't have to be. You can make
a "hostile takeover" of a word with realias and brutally make it point
elsewhere. If you do, make sure that the word is big enough for a native jump.
For example, using realias on the word "noop", which only contains a "return"
op, would likely corrupt the dictionary entry of the following word.

Aliases have two main usages: dynamically pluggable words, or forward
declarations. For the latter type, there is also the syntactically more pleasant
word ":realias", which is a combination of, drum roll, ":" and "realias" and can
be used thus:

  alias abort foo \ Forward declaration
  : bar foo ;
  :realias foo bar ;

It is the equivalent of:

  alias abort foo \ Forward declaration
  : bar foo ;
  : _ bar ;
  current ' foo realias

except that further references to "foo" will link directly to the actual word
rather than going through the alias.

Aliases copy the immediate and findselector flags of their target, which means
that calling an alias to such words replicate the behaviors exactly.

## Binding and Scrying

Like any Forth, Dusk has does>, but it works slightly differently than the
traditional does> where it's a binding of a "create" and behavior.

Dusk's "does>" has one less level of indirection, that is, it can yield any
number as its "does parameter". Example:

  : foo does> . ;
  42 foo bar
  bar \ prints 42

The word "bar" is created by "does>", which has the signature ( n "name" -- ).

If you want to reproduce the "traditional" does>, you can do this:

  : foo here# swap , does> @ . ;
  42 foo bar
  bar \ prints 42

Note that we didn't use "create" because otherwise, two words would be created,
one by "create" and one by "does>".

"does>" is a wrapper around "bind ( w n "name")" which binds the word "w" to
parameter "n". Our first "does>" above is the equivalent of:

  ' . 42 bind bar
  bar \ prints 42

"immdoes>" is the exact same as "does>", but it makes the resulting word
immediate.

### Scrying

The binding created by bind is a conditional call that checks on the global
"SCRYING" variable. Each "check" resets the "SCRYING" flag to 0. When SCRYING is
1, the bind isn't called. Instead, the parameter is yielded, as would a simple
"create". Example:

  : foo does> . ;
  42 foo bar
  scry bar .x \ prints 0000002a
  bar \ prints 42

All words created with "bind" (does> and immdoes> among them) are "scryable".

Any word can be made "scryable" with "scrying? ( -- f )":

  : foo scrying? if 42 else 54 then ;
  foo . \ prints 54
  scry foo . \ prints 42

There's a "compiling" version of "scrying?", "scrying?," which compiles a very
fast version of the same check and instead of yielding a flag to PS, it sets the
Z flag, allowing for a brc, to follow. This word is suitable for implementing
find selectors. For example, this is the implementation of "bind":

  : bind ( w n "name" -- )
    code> over litn exit, ( w n scryw )
    code> rot litn rot bbr,
    code findselector
    litn scrying?, ifnz, swap i) @, [compile] then exit, ;

SCRYING being a global flag that keeps its value until toggled by a "scrying?",
one must be careful not to use "scry" with words that don't actually support
scrying. Doing so will corrupt the call of the next "scryable" word call and
will likely catastrophilosophically crash the system. Scrying is powerful but
dangerous!

If you scry a word that might not be "scryable", use "unscry" afterwards to
unset the SCRYING flag.

## Anonymous words with :~

Its a common pattern to define words that are used in very local context and
then never needed anymore. They can be called something like "_" to indicate
that their name don't matter and that they'll never be referenced anywhere.

This will, however, create a dictionary entry for "_". In addition to being a
bit wasteful, it's also an unwanted side effect in some cases, for example in
namespaces that represent a precise API. For example, operators in the C
compiler are defined in terms of namespaces and defining a "_" word in it
defines the "_" operator, something we don't want.

The ":~" and "~" words allow the definition and referencing of words without
creating dictionary entries:

  :~ 1+ . ;
  : print42 41 ~ ;

## :override

:override allows you to redefine a word while still using its previous behavior,
often to augment that behavior. Upon definition, the "~" pointer is updated to
provide the implementer with a way to reference the old word.

  : foo 1+ . ;
  42 foo \ prints 43
  :override foo 1+ ~ ;
  42 foo \ prints 44

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