# C types

This unit is mostly about implementing C's type parsing logic. Because
[lib/type]'s names are the same as C type names, only a handful of extra types
have to be created.

The API of this unit can be logically divided into two main parts. The "low"
part has "parsetype ( -- ?type f )" and "decl ( type -- type name )". These
words consume the input stream for a type to fetch or define. The "high" part
words at ASTs [comp/c/ast] and provides "asttype ( ast -- type )".

The "parsetype" part fetches or defines the type, "decl" goes on and defines a
declaration to go with that type. For example, if you have this stream:

  int *foo;

"parsetype" will stop right after the "int" token and yield it, a Integer(4S)
type. "decl" will consume "*" and "foo" to yield Pointer(Integer(4S)) as the
type and "foo" as the name. Anonymous declarations yield NULLSTR [lib/str] as
the name.

Structure declarations recursively parse subtypes and yield a [lib/struct].
Alignment discipline is enforced and all structure sizes are aligned to 4 bytes.

Unions are parsed like structs, but with all fields having a 0 offset and its
size being the size of the largest member of the struct.

Array declarations yield the Array type.

## Function signatures

Function signatures yield [comp/sig] types. When parsing a function declaration
followed by a body, that is, the "int foo()" form rather than the "int (*foo)()"
one, argument symbols are added to [comp/sym] for each argument.

## The flexuint/flexint type

There's are types called "flexuint" and "flexint" which are the same as a
uint/int, but are yielded by constant, values, literals, pointer subtractions
and boolean operators. The idea is that flex types are compatible with all other
types. Also, it's a "weak" type, so when an expression has to merge two types
into one, the flex type disappears.

This means, for example, that if "foo" is a char, "foo + 42" does the expected
thing, that is, consider 42 a char.

Note that a pointer to void, "void*" is also considered a flexible type to any
other Pointer.

## Type equality and merging

Determining whether two types are equal depends on the point of view, which is
why type equality is not universal (and thus not part of [lib/type]).

In comp/c, it's the job of "type= ( other type -- f )" along with many
supporting helper words.

The logic for merging two types together goes as follow:

1. Is one of the types a flexible type? If yes, result is the "other" one.
2. Are the two types considered equal? If no, abort with error.
3. Result is the left type.

## AST analysis

The "asttype ( ast -- type )" word drills down into the specified AST in order
to figure out the type of an expression. It applies all appropriate type
transformation logic and errors out when it encounters a type inconsistency.

## Private words

inserttype ( basetype bottomtype toptype -- )
  Provided that both "toptype" and "bottomtype" are ref types that end up
  referencing "basetype" at some point and provided that they don't reference
  each other (each are "forks" of "basetype"), insert "bottomtype" in
  "toptype"'s hierarchy at the exact point where "basetype" lies.

  For example, if bottomtype is int, toptype is *int and bottomtype is [int,42],
  we end up with toptype being *[int,42].
