# Structures

The unit at [lib/struct.fs] provides an API to describe structures, that is,
data organized in terms of offsets relative to a base address. For example:

  struct Foo
    field foo
    field bar
  endstruct

describes a structure with two 32-bit fields. "foo" is at offset 0 and "bar" is
at offset 4. If a particular instance of that structure is at address $1234,
this means that the "foo" field of that instance lives at $1234 and the "bar"
field, at $1238.

## Defining fields

Multiple types of fields can go inside a struct definition. The most basic one
is "field", a 32-bit accessor. This word is basically a frontend for "value{}"
in [lib/bm]. The resulting accessor word ("foo" and "bar" in the first example)
obey to moustache semantics.

Every time a field is added, the running offset counter for the struct being
defined goes up and that will be the offset of the next field.

There are other types of fields. For example, there are "fieldw" and "fieldb"
for defining 16-bit and 8-bit fields.

There is also "reference" that will create a field that will yield the address
of the offset.

You might want to bump the running offset by an arbitrary amount. You can use
"skip" for this.

"method" is the equivalent of a value{} targeting the current struct offset
where the default action, instead of being a "@{}", is a "execute{}". There's a
slight difference with execute{} though: PS top is not consumed. You can update
a method pointer with "!{>mymethod}", like you would with a value.

Here's a full example with, below, the equivalent naive Forth code to each
accessor:

  struct Foo
    field first
    reference second 8 skip
    method third
    fieldw fourth
    fieldb fifth
  endstruct

  data first  --> data @
  data second --> data 4 +
  data third  --> data 12 + @ execute
  data fourth --> data 16 + w@
  data fifth  --> data 18 + c@

## Arrays

There is also arrays, which can be created with "array ( sz n -- )" which
represent an array of "n" elements of size of "sz" bytes. Example:

  struct Arrays
    4 10 array foo
    1 42 array bar
  endstruct

"foo" is an array of 10 32-bit numbers and "bar" is an array of 42 bytes. The
accessor field yield the address of the array.

This can be seen as an equivalent to a "reference" field followed by a "skip"
call, but it's not quite that, because the field is a moustache and can be used
with the "[]{}" action [hal/muldiv].

## absstruct

Sometimes, you want to define a struct that isn't a base+offset, but that exists
as a single structure at an absolute address in memory. You can do this with
"absstruct":

  $1234 abstruct Struct
    field foo
    fieldw bar
    reference baz
  endstruct

  Equivalents:
  foo --> $1234 @
  bar --> $1238 w@
  baz --> $123a

## Extending a struct

You can pick up where another struct left off through "extends":

  struct Struct1
    field foo
    field bar
  endstruct

  extends Struct1 struct Struct2
    field baz
  endstruct

  extends Struct1 struct Struct3
    field quux
  endstruct

  Both "baz" and "quux" will have a offset +8.

## API

struct ( "name" -- )
  Begin defining a struct

endstruct ( -- )
  Stop defining a struct

extends ( "name" -- )
  The next structure being defined will be an extension of specified struct.

structsz ( struct -- n )
  Yields the size in bytes of a particular structure.

field ( "name" -- )
  Define a 32-bit field.

fieldw ( "name" -- )
  Define a 16-bit field.

fieldb ( "name" -- )
  Define a 8-bit field.

fields ( "..." -- )
  Parse the rest of line and define a 32-bit field for each word. Equivalent of
  repeatedly calling "field".

method ( "name" -- )
  Define a new method as per [lib/bm]'s "method{}".

reference ( "name" -- )
  Define a field that yields its own address.

array ( sz n "name" -- )
  Define an array of "n" element each being "sz" bytes wide.
