# Types

The unit at [lib/type.fs] provides a universal type system. The main goal of
this unit is for different programming languages to talk to each other, but the
type system can be used independently.

What are types for? For answering these questions:

1. What kind of value do I have here? integer, pointer, array or struct...
   something else?
2. If it's an integer, is it 8, 16 or 32-bit in width? signed?
3. If it's a pointer, what type does it point to?
4. If it's an array, what is it an array of? How big?
5. etc..

## The Type structure

What we call a Type is a structure with a Category as its first field followed
by a structure that is specific to that category.

A Category is an opaque structure that contains its name and base handling
routines. Its address is its ID. To check whether a type if of a particular
category, we compare addresses.

New categories can be added with ":category". For example, [comp/oberon] has
this concept of sets that is unique to it. These sets have their own category.
Other languages having no notion of Oberon sets will choke when they encounter
one of these categories, but this allows Oberon to operate within global types
semantics while having its own specificities.

There are builtin categories:

Untyped
Integer
Pointer
Array
Signature

Structures are defined in [lib/struct].

## Type entries

When you create type entries in the sysdict, you can use "addtype" instead of
"create" or "const". It will make the entry tagged [doc/usage/tag] with "TYPE".

Then, what you can do is to use "findtype" which takes uses "findtagged" to give
you a universal type repository.

## All types have a size

All types have a size, yielded by "typesz". This number represents the number
of bytes that a single element of that type needs for storage. This size is
*not* aligned. There are moment when you'll want to apply alignment to that
size.

## All types are printable

All types can be printed through ".type ( type -- )". When you define a new
category, you have to supply it with a "printer word". This makes types very
introspectible.

## Untyped category

This category is for unknown types. It has a 0 size.

## Integer category

Types of this category represent a straight integer number.

+00 Category
+04 Width 1=8b 2=16b 4=32b anything else is invalid
+08 Signed?

## Pointer category

Types of this category represent a value that points to an address where
there's another value of the specified type.

+00 Category
+04 Type being pointed to

## Array category

Types of this category represent an address where there's a specific number of
elements of a specific type.

+00 Category
+04 Type of the elements
+08 Count

There is no convention for representing an array of an unknown Count. It's
better to do like in C and represent such values as "pointer to XXX", with the
understanding that more "XXX" are following or preceding the address we point
to.

## Example usage

  0 4 integertype addtype uint
  1 1 integertype addtype char
  uint pointertype addtype uint*

  uint* reftype typesz . \ prints 4

## API

### Builtin types

Void   Untyped
DWord  Integer(4)
Word   Integer(2)
Byte   Integer(1)
String Pointer(Integer(1))
AnyPtr Pointer(Void)

### Words

:category ( "name" ... -- )
  Create a new category along with its "typesz" then ".type" routines.
  Semantics are like ":", but you do it twice! Example:

  :category @ ; Integer @+ . @ if 'S' emit then ;

  To save ourselves a tedious and repetitive "4+" in those routines, the
  signature of those handlers isn't "( type -- ... )", but "( type+4 -- ... )",
  that is, we skip the Category field.

typesz ( -- n )
  Yields the size in bytes needed to store an element of that type.

.type ( type -- )
  Print a human-readable representation of type.

addtype ( type "name" -- )
  Same as "const", but tags the entry with "TYPE"

findtype ( name -- type-or-0 )
  Uses "findtagged" to perform a dict lookup in sysdict specifically for entries
  with the "TYPE" tag.

category ( type -- category
  Yield the category of a type.

Integer ( -- category )
Pointer ( -- category )
Array ( -- category )
  Yields the category struct of the builtin types.

integertype ( signed? width -- type )
pointertype ( type -- type )
arraytype ( count type -- type )
  Create a new type of the specified category with the specified fields.

intsigned? ( inttype -- f )
  Yields whether inttype is signed.

reftype ( type -- type )
  Works for both Pointer and Array (and when you create a new category, if
  there's a reference Type in it, us the same offset so that you can reuse
  "reftype"). Yields the type it refers to.

arraycount ( arraytype -- count )
  Yields the count of a type of an Array category

typealign ( a type -- a )
  Align "a" to an address that properly stores "type", that is, align to 2 for
  typesz=2, don't align for typesz=1 and otherwise, align to 4.
