# Big Moustache

*Tea for two and two for tea...*

Don't you think that the "{" character looks like a mustache? A whole lot of
them means a big moustache.

This library is a way of compiling fancy *and* fast memory accesses. The syntax
of such memory accesses is:

  <action>{<modifiers>}

"<action>" is mandatory, "<modifiers>" is optional. Default target is HAL's
[doc/hal] W register.

For example, "@{c+4}" is the equivalent of "4 + c@", but compiled in efficient
HAL.

That generated HAL is really efficient and is the main reason why Big Moustache
exists. The syntactic sugar is nice, but it alone isn't worth it. All those
moustaches are really fast.

Not all actions/modifiers combinations make sense. When they don't, their usage
lead to undefined behavior. Incompatibilities are explicitly stated in the
documentation below. The rest is compatible.

Moustaches are for compiling accesses, not interpreting them. That being said,
we make an exception for some actions, that is "@ ! @!" which can be used in
interpret mode. That's sometimes quite useful. However, interpret mode
moustaches cannot be used with modifiers "R F A P".

## Target

We call "target" the address or value that the modifiers inside a moustache
designate. By default, and like the HAL does, targets contain a single level of
indirection.

For example, "@{'data}" targets the memory at the address that the word "data"
will yield at the moment the moustache is compiled. "@{}" targets the memory
pointed by the address in the W register at runtime. "@{&}" targets the W
register directly.

Examples and equivalences:

  -{}      --> @ swap -
  *{&}     --> *
  +{'data} --> [ data litn ] @ +

### Managing W

There's a fundamental difference between W and non-W targets. Moustaches will
have a different signature depending on whether they target W or not.

For example, "@{}", which targets W and is the equivalent of a straight "@", has
the signature ( a -- n ). However, "@{R+4}", which targets RSP, has a signature
( -- n ). Similarly, "!{+4}" has a signature ( n a -- ) where "!{'foo}" has a
signature ( n -- ).

The principle is the same for all actions. See "Stack signature matrix" below
for a full list of signatures.

## Actions

Possible actions are:

  Access       @ ! @! @A
  Arithmetics  + - swap- * / lshift rshift and or xor = <> < > <= >=
  Special      execute value

As a general rule, actions have the same stack effect as their regular Forth
word counterpart, but operand order varies. When there's a "left" operand, it
will generally be the moustache target. The right operand will either be a
number being popped from PS or a literal supplied in the moustache.

For example, the signature of the system word "-" is "( a b -- a-b )". In the
equivalent moustache action, "a" is the target and "b" is the "other" operand,
which is this case is taken from PS. Therefore, the equivalent of "-" in Big
Moustache is "swap-{&}".

It is also important to remember that moustache targets usually have a level of
indirection. For example, the signature of "-{+4}" isn't actually ( n n -- n ),
but rather ( n a -- n ) and is equivalent to "4 + @ swap -" (in efficient HAL).

### Access actions

The @ ! @! actions are straightforward and pretty much do the same thing as
their regular word counterpart.

"@{}" can't be used with "#". "@!{}" *can* be used with "#" and will have the
effect of pushing a new element to PS. For example, "@!{'foo}" has the signature
( n -- n ) while "@!{'foo #42}" has ( -- n ).

Neither of "@" "!" or "@!" can be used with the "!" or "&" modifiers.

"@A" fetches to the A register instead of the W one. Its signature is different
because it doesn't push anything to PS. See below for details.

### Arithmetics actions

Arithmetic actions all follow the same logic and support all the modifiers.
They're the most "regular" of the actions.

One thing to remember is the order of the operands. The target comes first. The
plain english of an arithmetic moustache is "apply 'other' on 'target'", for
example "subtract 'other' from 'target'" or "is 'target' greater than 'other'?".
Here are some examples and their naive equivalents:

  -{&}      --> swap -
  -{&k}     --> over -
  <{&}      --> >
  -{& #42}  --> 42 swap -

### execute

The "execute" action allow indirect calls with offsets. They support only a
select few modifiers. If the target is W, a "drop" will be compiled before the
branch. It is incompatible with "# c w !" modifiers.

For example, "execute{+4}" is the equivalent of "4 + @ execute".

### value

"value{}" has its own paragraph below.

## Modifiers

Things become interesting when we add modifiers in the mix. Broadly speaking,
they try to expose as much of the HAL machinery as possible, but in terser
semantics.

  Target      R F P A '<val>
  Offset      +<val> -<val>
  Literal     #<val>
  Width       c w s<val> n<val>
  Flags       ! & k
  Recall      ><val>

Modifiers with <val> parameters are parsed with "wordorquote", their whole
content interpreted as Forth code with the expected signature ( -- n ).

Modifiers order doesn't matter except for ">".

### Target

Target modifiers change the target of the moustache (which is W by default).

"R" is for "RSP". For example, "@{R+4}" will fetch the second element from the
RS.

"F" means "Frame". This is RSP as it was at the beginning of the word, as
tracked by [rcnt] (see below). For example, "{F-4}" is the equivalent of the
"V1" local variable (see below). "{F-16}" is equivalent to "V4". It doesn't make
sense to address "F" with a positive or null offset because it refers to the
caller's return stack, which is supposed to be opaque to us.

"P" is for "PSP". See "PSP dynamics" below.

"A" means "Address Register" (from the HAL). See paragraph below.

"'" means "Memory address". "<val>" is a hardcoded memory address. It is
important to remember that "<val>" is evaluated at compile time, with its result
being stored as a number in the moustache.

Examples:

  +{R#1}         --> r@ 1+
  +{R+4 !#1}     --> r> r> 1+ >r >r
  +{!'foo}       --> foo +!
  W@A @{+4} @{A} --> @+ swap @ swap

### Offset

Offset, in bytes, is specified by the "+" or "-" modifiers. That number of bytes
will be added to the address before the memory access is made.

### Literal

When this modifier is set, the "n" operand of the action is replaced with a
compile-time literal. For example, "-{+4#42}" is the equivalent of
"4 + @ 42 swap -" (but much more efficient, of course).

### Width

A moustache's default width is 4 bytes (native 32-bit access). You can make a
moustache's access with into 8-bit or 16-bit with "c" or "w". It works pretty
much exactly like "8b)" and "16b)". If the moustache has a "c", the access is
8-bit, if it has a "w", it's 16-bit.

The "s<val>" and "n<val>" modifiers are used for describing an array. See
"Working with arrays" below. "s" sets the width of the moustache to an arbitrary
number and represents the size in bytes of a single element of the array. "n"
sets the "nbelem" field of the moustache and represents the number of elements
in the array.

Although the "s" and "n" don't actually set the "&" modifier, it's difficult to
imagine a possibly valid use case for "s" and/or "n" without a "&". As soon as
a moustache width is something else than 1, 2 or 4, indirect access is broken.

### Flags

"!" is the "store" flag. Instead of yielding the result to PS, it will store it
to the same address as specified. For example, "+{!}" is the equivalent of
"+!".

"&" is the "deref" flag. It indicates that instead of working with a source
address, we work on a value directly. For example, "lshift{&#3}" is the
equivalent of "3 lshift". Incompatible with "!".

"k" is the "keep" flag. When set the "argument" of the action (that is, the "not
the target" part of arithmetic actions or the "!" action), which always comes
from PS, is not consumed. For example, "!{k}" is the equivalent of "over swap
!". This only works on arithmetic, "!" and "@!" actions. Incompatible with "#".

### The ">" modifier

This modifier allows you to load a moustache from a value{}. This effectively
allow you to bind moustaches to names, for example, as field specifications.
This modifier copies the specified moustache as-is, completely overwriting
whatever was there. This means that the ">" modifier should always be the first
one of the moustache. Example:

  create data 42 le, $1234 le,
  value{c+4} some8bfield
  : foo @{>some8bfield} ;
  data foo .x \ prints 00000034

## Whitespaces inside moustaches

As a general rule, whitespaces aren't needed inside moustaches. However,
"wordorquote" which is used for parsing "<val>" modifiers, needs a whitespace
boundary if it's not quoted.

However, Big Moustache adds a special treatment for the last modifier allowing
it to not end with a whitespace.

This means that if you only have one "<val>" modifier, you can put it last and
thus avoid whitespaces. If you have more than one, the one that isn't the last
needs a whitespace after its "<val>" unless it's a quoted val.

Spurious spaces (spaces that aren't required as per the rules above) are
silently ignored.

Examples:

  @{+foo}
  @{+foo #bar}
  @{+"foo bar"#baz}

## Stack signature matrix

Keeping up with all possible stack effects for all possible combinations of
actions and modifiers can get dizzying, so here's a matrix to help out. "***"
means an invalid combination.

All arithmetic actions have the same signature and A/F/R/P/' targets also have
the same signature, so only "A" is represented.

         {}        {A}     {k}         {Ak}      {#}     {A#}
@        a -- n    -- n    ***         ***       ***     ***
!        n a --    n --    n a -- n    n -- n    a --    --
@!       n a -- n  n -- n  n a -- n n  n -- n n  a -- n  -- n
@A       a --      --      ***         ***       ***     ***
+        n a -- r  n -- r  n a -- n r  n -- n r  a -- n  n -- r
execute  a --      --      ***         ***       ***     ***

The store, which only makes sense in arithmetic actions, have these
signatures:

{!}    n a --
{!k}   n a -- n
{!#}   a --
{!A}   n --
{!Ak}  n -- n
{!A#}  --
{!A#k} -- n

## Working with the A register

Exposing HAL's A register is one of the great aspects making moustaches
powerful. It can decrease PS juggling a lot.

You can set the A register with "@A{}". There's also the shortcut "W@A" which
is equivalent to "@A{&}".

Then, you can use the "A" modifier in your moustaches. For exmple, let's say
that you have a pointer to a struct with fields "foo" and "bar" on PS and you'd
like to unpack that pointer to the values of foo and bar on PS. You could do
this:

  dup foo swap bar ( ptr -- foo bar )

*or* you could save yourself a dup and a swap and do:

  W@A foo @{>bar A} ( ptr -- foo bar )

It's useful to remember that the A register can serve more than once! Once
you've the A register set, you can reuse that address in a following moustache
using the "A" target. Just be aware of A lifetime rules [doc/hal], that is that
almost all words will destroy its value!

Some words do preserve it, as is explained in [doc/hal]. Look for *A* flags next
to word signatures in documentation.

Moustaches also make the promise of never touching the A register, except of
course for actions/modifiers that explicitly change it.

The S register is extensively used by moustaches and is never preserved. It is
thus not exposed by the moustache API.

## PSP dynamics

Using the "P" target can be tricky and one must be perfectly aware of PSP
dynamics before doing so. Let's use an example PS state:

  4 3 2 1

"1" is W, "2" is where PSP points to.

The {P} target works exactly like the {R} or the {A} target, that is, in this
example, a moustache {P} would target "2", {P+4} would target "3", {P+8} would
target "4".

So far, so good.

However, actions affect the stack! Now this is tricky. For example, @{P} has a
signature ( -- n ) and !{P} has the stack signature ( n -- ). What does {P}
target? (Quick answer: @{P} targets "1" and !{P} targets "2")

To answer this question, one must be aware of moustache logic when comes the
time to grow or shrink PS: growth happens before the action, shrink happens
after it.

When you think about it, it's logical: when you need to grow PS to accomodate an
action, it *has* to happen beforehand. When you need to shrink PS after having
consumed elements from it, it *has* to happen afterwards.

So, here are a few examples, again with a "4 3 2 1" PS:

Moustache   Target  Stack afterwards

@{P+4}      2       4 3 2 1 2
!{P+4}      3       4 1 2
+{P+4}      3       4 3 2 4
!{P+4 #42}  3       4 42 2 1
+{P+4 #42}  2       4 3 2 1 44
+{P+4 !}    3       4 4 2
+{P+4 !#42} 3       4 44 2 1

The "!{P+4}" moustache is particularly mind twisting, so here it is in detail:

1. The signature of the action is ( n -- ), so it's a shrink-by-1 action.
2. This means that the address where we write "n" is the PS slot where there is
   currently a "3".
3. The "n" in the action will be "1", our current top of stack.
4. We write "1" in the address where the "3" is. Stack is "4 1 2 1".
5. We shrink PS by 1. Stack is "4 1 2".

## Binding moustaches to names

"value{...} name" evaluates the specified moustache and then saves it to memory,
bound to "name". Calling "name" is the equivalent of calling the "@{}" action on
the specified moustache.For example, "value{+4} foo" creates "foo" which is the
functional equivalent to "@{+4}".

But it's more than that. That address can be used by the ">" to "recall" that moustache in a particular
action. For example "!{>foo}" is the equivalent of "@{+4}".

Values also have "setters" (see below) meaning that they can be used with "to".
Doing so is the exact equivalent of using the "!" action.

And on top of that, there's also "value" which is a value{} that allocates its
own 32-bit and use that memory address as a target. Full example:

  create data 42 ,
  value{'data} myval
  myval . \ prints 42
  !{>myval #54}
  data @ . \ prints 54
  myval . \ prints 54

  42 value otherval
  otherval . \ prints 42
  !{>otherval #54}
  otherval . \ prints 54

Values can be scried [doc/usage/word]. When they are, they yield a pointer to
their moustache.

### Custom value actions

It's possible to create value{}-like words with custom getters and setters (@
and ! actions) through the word "}value". This allows things like "bigendian{}"
[mem/endian] and "ioport{}" [drv/pc/ioport].

Custom getter is activated both when making a "naked call" on the value or when
using the @{} action. Custom setter is activated on the !{} action or the "to"
modifier (see below).

Using any other action than "@" or "!" on a custom value results in a moustache
error.

You create a custom value with "}value ( actions m -- )". "m" is the moustache
to compile, most likely obtained through "m<, ( -- m )". "actions" is a 16 bytes
tables of 4 pointers to words: getter-compiler, getter, setter-compiler, setter.

There's a table called "defactions" that contain the default implementations for
those actions. To give you an idea, the word "value{" is defined thus:

  : value{ defactions m<, }value ;

Getter and setter compilers both have the same ( -- ) signature. They expect
"curmoustache" to be set to the moustache to compile. They compile their thing
and they're done.

Getters have the signature ( a -- n ) and setters, ( n a -- ). They also expect
"curmoustache" to be set to the moustache to get or set. "a" comes from }addr
which is implicitly called by the @{} or !{} action.

Creating a custom action is inherently a pretty mind boggling task. It is
suggested to look at [mem/endian] for a good example of how it's done.

### Setter semantics

This unit also defines the immediate word "to" along with what is called "setter
semantics". Any word, not only values, can have a setter routine. That setter
is activated when "to" is called right before invoking it. This works at compile
time too. For values, "to" is the exact equivalent to "!{}". For other words,
it might have another meaning.

To implement a setter, you use "to?," like this:

  :> ."getting!" ;
  :> ."setting!" ;
  code foo findselector
    litn to?, ifz, swap i) @, then exit,
  foo \ prints "getting!"
  to foo \ prints "setting!"
  : bar foo to foo ;
  bar \ prints "getting!setting!"

## Working with arrays

The "s" and "n" modifiers allows one to describe an array with moustaches. This
allows one to use the "[]" action from [hal/muldiv].

Let's look at an example where we have a struct "Bar" which contains an array of
structs "Foo". We could describe them thus:

  \ Foo
  value{}   foo1
  value{+4} foo2
  8 const FOOSZ

  \ Bar
  value{} bar1
  value{+4 &sFOOSZ n42} foos
  value{+12} bar2

As you can see, the field "foos" represents an array of 42 "inlined" structs
within the Bar struct. Let's imagine that we have a "Bar" instance named "bar"
and that we want to print the "foo1" field of its 12th "foo" element:

  11 bar []{>foos} foo1 .

This could also work and would be faster if your index is constant:

  bar []{>foos #11} foo1 .

What happens if "foos", instead of being an "inlined" array, is a pointer to an
array? Moustaches, being a direct mapping to HAL parameters, don't support
multiple indirections, so there's no way to describe this in a single moustache.
However, what you can do is to describe a second moustache "foos*" to elegantly
handle that indirection. Let's redefine Bar:

  \ Bar
  value{} bar1
  value{+4} foos
  value{+8} bar2
  value{&sFOOSZ n42} foos*

In these new fields, "foos" is a pointer to an array and "foos*" describe that
array. How do we use that?

  11 bar foos []{>foos*} foo1 .

And if you're in a tight loop, you can save a PS push/pop in the above pattern
with the A register:

  11 @A{'bar} @A{>foos A} []{>foos* A} foo1 .

## Local variables

It's a common pattern, to avoid PS juggling, to place an element on RS (Return
Stack) and recall that element with r@. It works well, but unfortunately, this
only works with a single element. Another drawback is that this element can be
"buried" by a pattern (a loop for example) that needs to place something on RS.
Example:

  : print100times ( n -- ) >r 100 0 do r@ . spc> loop rdrop ;

is not going to work as expected because of the loop's usage of a RS slot.
Instead, you need to do:

  : print100times ( n -- ) >r 100 0 do @{R+8} . spc> loop rdrop ;

This works but is impractical. Keeping track of RS and using different offsets
within the word to refer to the same slot results in confusing code.

A common workaround to this is to declare a "private" value near the word and
store temporary values in there.

  0 value myval
  : print100times ( n -- ) !{>myval} 100 0 do myval . spc> loop ;

It works too, but because those values are statically allocated, this can't be
done in words that require recursion. Also, it's a bit verbose.

Local variables are there to the rescue! There are 4 of them: V1 V2 V3 V4. They
work like "@{R}", but the RS elements are indexed *backwards*. For example,
let's imagine this word:

  : foo 1 >r 2 >r 3 >r 4 >r @{R+12} . 2rdrop 2rdrop ;

This snippet will print "1" because at this point, RS looks like this, stack
growing left:

  4    3    2    1    ...
  R+0  R+4  R+8  R+12

This code is tricky, because if we add or remove a RS slot, for example, if we
want to change the code above to print 10 times, it would have to look like
this:

  : foo 1 >r 2 >r 3 >r 4 >r 10 0 do @{R+20} . loop 2rdrop 2rdrop ;

because we have to know that "do" uses two RS slots. This gets confusing real
fast.

For any word, at compile time, Dusk tracks how it moves the RS with the "[rcnt]"
counter. So, most of the time, you can rely on a word to know where its RS
"bottom" is. We call this the Frame, which is the "F" moustache target. This
means that the stack can be shown thus:

  F-16 F-12 F-8  F-4  F+0
  4    3    2    1    ...
  R+0  R+4  R+8  R+12

Using that knowledge, we can do:

  : foo 1 >r 2 >r 3 >r 4 >r @{F-4} . 2rdrop 2rdrop ;
  : foo 1 >r 2 >r 3 >r 4 >r 10 0 do @{F-4} . loop 2rdrop 2rdrop ;

This will now print "1" regardless of the number of RS slots we use on top of
the "1".

Local variables are built on top of this and there are 4 of them. Here they are:

  value{F-4} V1
  value{F-8} V2
  value{F-12} V3
  value{F-16} V4

and that's all there is to it. Moustache access to "framed" RS slots.

  : foo 1 >r 2 >r 3 >r 4 >r V1 . 2rdrop 2rdrop ;

Unlike words using static variables, words using variables can recurse just
fine. They are also impervious to being "buried" because they remember their
"slot" at compile time and adjust their compilation accordingly.

When using local variables, you are responsible for pushing and popping to/from
RS.

More examples:

  : foo ( a b c -- ) >r >r >r V1 . spc> V2 . spc> V3 . 2rdrop rdrop ;

  1 2 3 foo \ prints "3 2 1"

  : inc ( a -- a+1 ) >r +{>V1 !#1} V1 rdrop ;
  42 inc . \ prints 43

  \ this works too
  : inc5 ( a -- a+5 ) >r 5 0 do +{>V1 !#1} loop V1 rdrop ;
  42 inc5 . \ prints 47

### Manual [rcnt] adjustments

The "R counter" that determines local variable slots at compile time is
oblivious to conditional code or loops. It's not common to have code that
conditionally maintain separate RS levels (they always need to stay balanced, of
course), but it can happen. For example, in early "exit" paths, we often have to
include a few "rdrop" before the "exit" call. If you have a fancy word that
returns a variable number of arguments, you might end up with >r and r> in
loops. All of this messes up the "R counter". You can manually adjust it through
the [rcnt] variable. For example, if you want your next ">r" to push to V1, you
would precede it with "[ 0 [rcnt] ! ]". Example case:

  : foo ( n -- )
    dup >r 42 = if rdrop ."answer to universe" exit then
    \ The conditional "rdrop" messed with [rcnt], we need manual adjustment
    [ -4 [rcnt] ! ]
    V1 . rdrop ;

## API

<action>{} *I*
  Execute or compile a moustache.

W@A *I*
  Compile a copy of the W register into the A register.

){} ( -- halop )
  Interpret a moustache and yield the associated halop. For example,
  "){>foo} @," in interpret mode is the equivalent of "@{>foo}" in compile mode.

  This word cannot be compiled for fundamental reasons: halops are ephemeral
  because of the literal bank system. If we allowed halops to be "frozen" as
  literals, they would end up referencing an incorrect literal and thus
  miscompile.

value{} ( "name" -- )
  See "Binding moustaches to names" above.

}value ( set, get, m -- )
  Compile a "custom value" as described above.
  "set," is a reference to a "setter compiler" word.
  "get," is a reference to a "getter compiler" word.
  "m" is a reference to a saved moustache.

V1 V2 V3 V4
  Built-in value{}s corresponding to F-4 F-8 F-12 F-16.

MOUSTACHESZ ( -- n )
  Size of a moustache struct.

moustache ( -- a )
  Last moustache to have been parsed.

m< ( -- )
  Parse a moustache from the input stream.

m<, ( -- m )
  Parse a moustache from the input stream and then write it to "here", yielding
  its written address.

val< ( -- n )
  Parse a "<val>" from the input stream.

}) ( -- halop )
  Yield a HAL operand corresponding to the current moustache. This combines the
  "base", "off", "width", "ref" and "applyrcnt" to yield that result.

  For reference, implementation of "@{" is essentially "m< }) @,".

}width) ( halop -- halop )
  Applies current moustache's width to "halop". This is not required if "halop"
  comes from "})", as it's already been applied.

}base) ( -- halop )
  The "base" HAL operand, without anything (offset, ref, etc.) applied to it,
  corresponding to the "base" field of the active moustache. For example, it
  It would return "W)" whether the moustache is "{}" or "{c&+4}".

}addr ( -- a )
  Yields a runtime address corresponding to the current moustache.

}move ( m -- )
  Copy moustache "m" to "moustache" buffer.

}compile ( m -- )
  Compile a "}move" of the moustache "m".

?moustache@ ( a -- n )
  Unless the current moustache is a reference, executes @, w@ or c@ depending on
  moustache's width.

moustache! ( n a -- )
  Executes !, w! or c! depending on moustache's width.

?moustachelit ( -- ?n f )
  Yields whether current moustache has a literal and, if it has, yield it as
  "n".

flags ( -- n )
  Yields the whole 32-bit flags field for the active moustache.

base ( -- n )
  Yields the "base" field of the active moustache.

base! ( n -- )
  Sets the "base" field of the active moustache.

## Flags words

The words:

  store ref keep

all have the signature ( -- f ) and yield the flag of the same name for the
active moustache.

## Field words:

The words:

  off lit width nbelem

all have the signature ( -- a ) and yield the address corresponding to the
field of the same name, for the active moustache.

## Implementations details

A moustache is a 20b struct divided in 5 fields:

+00 Flags
+04 Offset
+08 Literal
+0c Width
+10 NbElem

Flag bits are organized thus:

b2:0 base (0=W 1=R 2=A 3=' 4=F 5=P 6=S)
b5:3 reserved
b6   has literal
b7   store
b8   ref
b9   keep
b10  nosave

Offset contains the compound result of both "+" and "'" modifiers.

The literal field is only used in conjunction with the "has literal" flag.

Width is the width, in bytes of the moustache. "c" sets it to 1, "w" sets it to
2.

NbElem is the number of elements represented by the moustache.

A moustache has a reset value of 0/0/0/4/1.
