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) --- _ext/crowbar_domain.py | 1 - _ext/crowbar_lexer.py | 2 +- index.rst | 1 - language/scanning.rst | 2 +- language/source-file.rst | 2 +- language/type-definition.rst | 52 ++++++++++++++++++++++++++++++++++++++++++-- tagged-unions.md | 3 --- vs-c.rst | 2 +- 8 files changed, 54 insertions(+), 11 deletions(-) delete mode 100644 tagged-unions.md diff --git a/_ext/crowbar_domain.py b/_ext/crowbar_domain.py index db1330e..619487d 100644 --- a/_ext/crowbar_domain.py +++ b/_ext/crowbar_domain.py @@ -125,7 +125,6 @@ class CrowbarDomain(Domain): return make_refnode(builder, fromdocname, todocname, targ, contnode, targ) else: - print('Awww, found nothing') return None def add_keyword(self, signature): diff --git a/_ext/crowbar_lexer.py b/_ext/crowbar_lexer.py index 6f0ec5e..2dd20ec 100644 --- a/_ext/crowbar_lexer.py +++ b/_ext/crowbar_lexer.py @@ -268,7 +268,7 @@ class CrowbarLexer(RegexLexer): tokens = { 'root': [ (r'bool|char|double|float|function|int|long|short|signed|unsigned|void', Keyword.Type), - (r'const|enum|extern|struct', Keyword.Declaration), + (r'const|enum|extern|struct|union', Keyword.Declaration), (r'include', Keyword.Namespace), (r'break|case|continue|default|do|else|for|fragile|if|return|switch|while', Keyword), (r"[\p{L}\p{Pc}\p{Sk}\p{Mn}][\p{L}\p{Pc}\p{Sk}\p{Mn}\p{N}]*", Name), diff --git a/index.rst b/index.rst index 8b310af..92e9a4d 100644 --- a/index.rst +++ b/index.rst @@ -52,7 +52,6 @@ Chapters :numbered: vs-c - tagged-unions types safety errors 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 diff --git a/tagged-unions.md b/tagged-unions.md deleted file mode 100644 index 256eebd..0000000 --- a/tagged-unions.md +++ /dev/null @@ -1,3 +0,0 @@ -# Tagged Unions - -TODO diff --git a/vs-c.rst b/vs-c.rst index 346f6f0..8317155 100644 --- a/vs-c.rst +++ b/vs-c.rst @@ -52,7 +52,7 @@ Adjustments Some C features are footguns by default, so Crowbar ensures that they are only used correctly. * Unions are not robust by default. - Crowbar only supports unions when they are :doc:`tagged-unions` (or declared and used with the ``fragile`` keyword). + Crowbar offers two types of union declarations: a :crowbar:ref:`tagged union ` (the default) and a :crowbar:ref:`fragile union ` for interoperability purposes. C's syntax isn't perfect, but it's usually pretty good. However, sometimes it just sucks, and in those cases Crowbar makes changes. -- cgit v1.2.3