# 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       @ le@ be@ ! le! be! @! @A
  Arithmetics  + - swap- * / lshift rshift and or xor = <> < > <= >=
  Special      execute

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.

"le@" "le!" "be@" and "be!" actions work like "@" and "!" but compile their
accesses in an endian-specific manner.

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

## 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
  Flags       ! & k
  Named       ><name>

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

The "<name>" part of Named is read with "word" and then looked up with
"scryfind#", expecting a tagged address [doc/usage/tag] with one of the
supported tags. See "Named targets" below.

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]. For example, "{F-4}" is the equivalent of the "V1" local
variable [usage/to]. "{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).

### Type

A moustache's default type [lib/type] is DWord (native 32-bit access). You can
make a moustache's type into Byte or Word with "c" or "w". It works pretty much
exactly like "8b)" and "16b)" in the HAL. If the moustache has a "c", the access
is 8-bit, if it has a "w", it's 16-bit.

### 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 construct a moustache from another word such as a
struct field or a value. See "Named targets" below.

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

## Named targets

Instead of describing a moustache from scratch, you can also use what we call a
"named target". A named target is a scryable Forth word yielding a tagged value
of one of the supported types. This named value represent a location that is
"moustache actionable". The supported named targets are:

* values [doc/usage/to]
* field fieldw fieldb array reference [lib/struct]

Using a named target works like describing a moustache from scratch. For
example, if you have a value "foo", doing "@{>foo}" is like using the "'" target
with the address of the cell where "foo" store its value.

If you have a "struct MyStruct fields foo bar", doing "@{>bar}" is the exact
equivalent of "@{+4}".

## API

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

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

){ ( -- halop ) *I*
  Yields the HAL operand corresponding to the specified moustache. Works both
  in interpret and compile mode.

  For example, "){+4}" is the equivalent of "W) 4 +)", but you'll mostly want to
  use this for field values, for example "){>myfield} +,".

## Implementations details

A moustache is a 16b struct divided in 4 fields:

+00 Flags
+04 Offset
+08 Literal
+0c Type

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.

Type is a pointer to a [lib/type] struct.

A moustache has a reset value of 0/0/0/DWord.
