aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2020-10-31 22:38:29 -0600
committerMelody Horn <melody@boringcactus.com>2020-10-31 22:38:29 -0600
commit14c4550aff926f53f256e831a7d99bffffd21dfd (patch)
tree09be545f8edd4923b4b771845fe8b9a3db614430
parent5af481d62df80d8be3f5835042d30372ef9cbe04 (diff)
downloadspec-14c4550aff926f53f256e831a7d99bffffd21dfd.tar.gz
spec-14c4550aff926f53f256e831a7d99bffffd21dfd.zip
settle on a tagged union plan (for now)
-rw-r--r--_ext/crowbar_domain.py1
-rw-r--r--_ext/crowbar_lexer.py2
-rw-r--r--index.rst1
-rw-r--r--language/scanning.rst2
-rw-r--r--language/source-file.rst2
-rw-r--r--language/type-definition.rst52
-rw-r--r--tagged-unions.md3
-rw-r--r--vs-c.rst2
8 files changed, 54 insertions, 11 deletions
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 <IncludeStatement>`, ``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 <RobustUnionDefinition>` (the default) and a :crowbar:ref:`fragile union <FragileUnionDefinition>` 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.