From 14c4550aff926f53f256e831a7d99bffffd21dfd Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Sat, 31 Oct 2020 22:38:29 -0600 Subject: settle on a tagged union plan (for now) --- language/scanning.rst | 2 +- language/source-file.rst | 2 +- language/type-definition.rst | 52 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 52 insertions(+), 4 deletions(-) (limited to 'language') diff --git a/language/scanning.rst b/language/scanning.rst index ed85ead..c45e6b8 100644 --- a/language/scanning.rst +++ b/language/scanning.rst @@ -15,7 +15,7 @@ Scanning ``char``, ``const``, ``continue``, ``default``, ``do``, ``double``, ``else``, ``enum``, ``extern``, ``float``, ``for``, ``fragile``, ``function``, ``if``, :crowbar:ref:`include `, ``int``, ``long``, ``return``, - ``short``, ``signed``, ``sizeof``, ``struct``, ``switch``, + ``short``, ``signed``, ``sizeof``, ``struct``, ``switch``, ``union``, ``unsigned``, ``void``, or ``while``. identifier diff --git a/language/source-file.rst b/language/source-file.rst index 6522ea8..2fc3ba0 100644 --- a/language/source-file.rst +++ b/language/source-file.rst @@ -2,7 +2,7 @@ Source Files ------------ .. crowbar:element:: HeaderFile <- IncludeStatement* HeaderFileElement+ -.. crowbar:element:: HeaderFileElement <- TypeDefinition / FunctionDeclaration / ConstantDefinition / UninitializedVariableDeclaration +.. crowbar:element:: HeaderFileElement <- TypeDefinition / FunctionDeclaration / ConstantDefinition / VariableDeclaration A Crowbar header file defines an API boundary, either at the surface of a library or between pieces of a library or application. :crowbar:ref:`IncludeStatement`\ s can only appear at the beginning of the header file, and header files cannot define behavior directly. diff --git a/language/type-definition.rst b/language/type-definition.rst index 02616b8..88c4a04 100644 --- a/language/type-definition.rst +++ b/language/type-definition.rst @@ -5,7 +5,7 @@ Defining Types Crowbar has three different kinds of user-defined types. -.. crowbar:element:: StructDefinition <- 'struct' identifier '{' VariableDeclaration+ '}' ';' +.. crowbar:element:: StructDefinition <- 'struct' identifier '{' VariableDeclaration+ '}' A ``struct`` defines a composite type with several members. @@ -13,7 +13,7 @@ Defining Types define struct layout in memory -.. crowbar:element:: EnumDefinition <- 'enum' identifier '{' EnumMember (',' EnumMember)* ','? '}' ';' +.. crowbar:element:: EnumDefinition <- 'enum' identifier '{' EnumMember (',' EnumMember)* ','? '}' EnumMember <- identifier ('=' Expression)? An ``enum`` defines a type which can take one of several specified values. @@ -21,3 +21,51 @@ Defining Types .. 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. + The top-level variable declaration must have a type which is some ``enum``, and its name must be the same as the identifier in the ``switch``. + + For example:: + + enum TokenType { + Identifier, + Constant, + Operator, + Whitespace, + } + + union Token { + enum TokenType type; + + switch (type) { + case Identifier: (const char) * name; + case Constant: int value; + case Operator: char 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, like a struct, is a simple bag of fields. + However, unlike a struct, only the most recently assigned field is valid at any given time. + 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 -- cgit v1.2.3