# Compiler signatures

The unit at [comp/sig.fs] is a small extension over [lib/type] that defines a
Signature type and provides convenience words to attach signatures to Forth
words, the goal being to allow compilers to interface with those words.

Once a word has been annotated with a signature, it can be called from any
language that support all the types used in that signature.

## Usage

Here's how we can annotate the word "max ( a b -- n )":

  DWord 1 DWord DWord 2 annotate max

## Signature documentation

Many words throughout Dusk are annotated through this unit. When they are, the
documentation of such word will show the signature right under the Forth
signature, in this fashion:

  foobar ( a b -- c )
  uint foobar(uint b, uint a);
    Do something foobar-like.

These signatures use the C syntax, but this doesn't mean that these signatures
can only be used in C. They can be used in any language.

## Common signatures

In addition to supplying the mechanism to tag words with signatures, it also
tags some core words:

void abort();
void quit();
void noop();
void emit(uchar c);
void rtype(char* a, uint u);
void stype(char* s);
void `. (uint n);
void `.x (uint n);
void `.x2 (uint n);
void `.x1 (uint n);
void cfill (uint n, uint u, void *a);
void wfill (uint n, uint u, void *a);
void fill (uint n, uint u, void *a);
void cmove (uint u, void *dst, void *src);
void wmove (uint u, void *dst, void *src);
void move (uint u, void *dst, void *src);

uint `le@ (void* a);
uint `wle@ (void* a);
void `le! (void* a, uint n);
void `wle! (void* a, uint n);
uint `be@ (void* a);
uint `wbe@ (void* a);
void `be! (void* a, uint n);
void `wbe! (void* a, uint n);

Additionally, some units that are used during Dusk bootstrapping are annotated
in the comp/sig unit rather than in those units in order to avoid having to pull
comp/sig in the bootstrap stream. Those units are:

* [io/drive]
* [io/stream]
* [fs/core]
* [drv/timer]

## API

### Signature category

The Signature category has this structure:

+00 Category
+04 Number of input elements
+08 Number of output elements
+0c Flags
... array of pointers to types for each input, then output elements.

Flags have this bit structure:

b31:1 unused
b0    Has variable arguments

The input and output fields are ordered from the shallowest (PS top) to the
deepest. For example, if we have a Forth signature "( a b -- c d )", "b" is the
first element of the "in" array and "d" is the first element of the "out" array.

Some signature don't make sense because of the PS restriction that all arguments
are 32-bits in size. For example, an Array can't go there. You'll want a Pointer
to an Array. comp/sig doesn't validate this stuff.

"typesz" of a Signature yields 0. "type)" is a noop. Unlike Untyped, we don't
raise an error to keep the flexibility to attach a Signature (rather than a
Pointer to Signature) to a function pointer.

### Words

signaturetype ( ... n ... n -- type )
  Take two counted lists from PS where each is a list of types. The shallowest
  list is the Input signature and the deepest list is the Output. The shallowest
  item of each list represents the shallowest item of the signature.

  For example, the signature "( a b -- c d )" would go thus:

    typeC typeD 2 typeA typeB 2 signaturetype

sigcounts ( type -- inputcount outputcount )
  Yields the IN/OUT counts for specified signature.

siginputs ( type -- a )
  Yields the address of the first input type of the signature.

sigoutputs ( type -- a )
  Yields the address of the first output type of the signature.

varargs? ( type -- f )
  Yields whether the signature has the "varargs" flag set.

varargs! ( type -- )
fixedargs! ( type -- )
  Set/Unset "varargs flag".

annotate ( ... n ... n "name" -- )
  Create a signature through "signaturetype", then look for "name" in sysdict.
  Then, in [lib/tagl], add tag the found execution token with "SIGT" and the
  created signature as a value.

annotate@ ( ... n ... n "name" -- sig )
  Same as annotate, but yield the annotated signature.

annotate< ( ... n ... n -- )
  Like annotate, but apply the same signature to all the names written on the
  rest of line.

findannotated ( name -- ?sig xt-or-0 )
  Find name in sysdict and, if the entry is tagged with "SIGT", yield the found
  xt along with the annotated signature. Otherwise, xt=0 and sig is absent.
