~boringcactus/crowbar-spec

ref: 2a5e244c74c7f23d46dd4b636a5590e81119dcd7 crowbar-spec/language/type-definition.rst -rw-r--r-- 3.8 KiB
2a5e244c — Melody Horn fix irc notifications 1 year, 7 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
Defining Types
--------------

.. crowbar:element:: TypeDefinition <- StructDefinition / EnumDefinition / UnionDefinition

    Crowbar has three different kinds of user-defined types.

    Compile-time Behavior:

    When a type is defined, the compiler must then allow that type to be used.

    Runtime Behavior:

    The definition of a type has no runtime behavior.

.. crowbar:element:: StructDefinition <- NormalStructDefinition / OpaqueStructDefinition
                     NormalStructDefinition <- 'struct' identifier '{' VariableDeclaration+ '}'

    A ``struct`` defines a composite type with several members.

    .. todo::

        define struct layout in memory

.. crowbar:element:: OpaqueStructDefinition <- 'opaque' 'struct' identifier ';'

    An *opaque struct* is a struct whose name is part of an API boundary but whose contents are not.
    Its size is left unspecified, and it can only be used as the target of a pointer.

.. crowbar:element:: EnumDefinition <- 'enum' identifier '{' EnumMember (',' EnumMember)* ','? '}'
                     EnumMember <- identifier ('=' Expression)?

    An ``enum`` defines a type which can take one of several specified values.

    .. todo::

        define enum value assignment, type-related behavior

.. crowbar:element:: UnionDefinition <- RobustUnionDefinition / FragileUnionDefinition

    Unions as implemented in C are not robust by default, and care must be taken to ensure that they are only used robustly.
    However, for the purpose of interoperability with C, Crowbar unions may be defined as robust or as fragile.

.. crowbar:element:: RobustUnionDefinition <- 'union' identifier '{' VariableDeclaration UnionBody '}'
                     UnionBody <- 'switch' '(' identifier ')' '{' UnionBodySet+ '}'
                     UnionBodySet <- CaseSpecifier+ (VariableDeclaration / ';')

    A robust union, or simply union, in Crowbar is what is known more broadly as a tagged union.
    It's a way to package some data alongside an ``enum`` but have the type of data depend on the value of the ``enum``.
    Since the enum value indicates which data is present, the enum value is also known as a *tag*.
    The top-level variable declaration creates the tag.
    The tag must have a type which is some ``enum``.
    The ``switch`` parameter must be the name of the tag, and the cases will declare the data associated with a given value of the tag.
    This allows for storing extra data alongside enum values while using minimal additional space in memory.
    (All the fields under the ``switch`` overlap as stored in memory, so it's important to use the tag to specify which field is available.)

    For example::

        enum TokenType {
            Identifier,
            Constant,
            Operator,
            Whitespace,
        }

        union Token {
            enum TokenType type;

            switch (type) {
                case Identifier: (const byte) * name;
                case Constant: intmax value;
                case Operator: (const byte) * op;
                case Whitespace: ;
            }
        }

    defines a ``union Token`` type, where the ``type`` field controls which of the other fields in the union is valid.

    .. todo::

        go into more depth about how tagged unions work

.. crowbar:element:: FragileUnionDefinition <- 'fragile' 'union' identifier '{' VariableDeclaration+ '}'

    A fragile union also allows for storing one of several different types of data.
    However, there is no internal indication of which type of data is actually being stored in the union.
    As such, in non-trivial cases no compiler can predict which field is or is not valid, and any statement which reads a field of a fragile union must itself be a :crowbar:ref:`FragileStatement`.

    .. todo::

        explain memory layout of fragile unions