blob: 40da052d8ab0688eeb7f1819cd458cdf0743fff3 [file] [log] [blame] [view]
# Emboss Language Reference
## Top Level Structure
An `.emb` file contains four sections: a documentation block, imports, an
attribute block, containing attributes which apply to the whole module, followed
by a list of type definitions:
```
# Documentation block (optional)
-- This is an example of an .emb file, with every section.
# Imports (optional)
import "other.emb" as other
import "project/more.emb" as project_more
# Attribute block (optional)
[$default byte_order: "LittleEndian"]
[(cpp) namespace: "foo::bar::baz"]
[(java) namespace: "com.example.foo.bar.baz"]
# Type definitions
enum Foo:
ONE = 1
TEN = 10
PURPLE = 12
struct Bar:
0 [+4] Foo purple
4 [+4] UInt payload_size (s)
8 [+s] UInt:8[] payload
```
The documentation and/or attribute blocks may be omitted if they are not
necessary.
### Comments
Comments start with `#` and extend to the end of the line:
```
struct Foo: # This is a comment
# This is a comment
0 [+1] UInt field # This is a comment
```
Comments are ignored. They should not be confused with
[*documentation*](#documentation), which is intended to be used by some back
ends.
## Documentation
Documentation blocks may be attached to modules, types, fields, or enum values.
They are different from comments in that they will be used by the
(not-yet-ready) documentation generator back-end.
Documentation blocks take the form of any number of lines starting with `-- `:
```
-- This is a module documentation block. Text in this block will be attached to
-- the module as documentation.
--
-- This is a new paragraph in the same module documentation block.
--
-- Module-level documentation should describe the purpose of the module, and may
-- point out the most salient features of the module.
struct Message:
-- This is a documentation block attached to the Message structure. It should
-- describe the purpose of Message, and how it should be used.
0 [+4] UInt header_length
-- This is documentation for the header_length field. Again, it should
-- describe this specific field.
4 [+4] MessageType message_type -- Short docs can go on the same line.
```
Documentation should be written in CommonMark format, ignoring the leading
`-- `.
## Imports
An `import` line tells Emboss to read another `.emb` file and make its types
available to the current file under the given name. For example, given the
import line:
```
import "other.emb" as helper
```
then the type `Type` from `other.emb` may be referenced as `helper.Type`.
The `--import-dir` command-line flag tells Emboss which directories to search
for imported files; it may be specified multiple times. If no `--import-dir` is
specified, Emboss will search the current working directory.
## Attributes
Attributes are an extensible way of adding arbitrary information to a module,
type, field, or enum value. Currently, only whitelisted attributes are allowed
by the Emboss compiler, but this may change in the future.
Attributes take a form like:
```
[name: value] # name has value for the current entity.
[$default name: value] # Default name to value for all sub-entities.
[(backend) name: value] # Attribute for a specific back end.
```
### `byte_order`
The `byte_order` attribute is used to specify the byte order of `bits` fields
and of field with an atomic type, such as `UInt`.
`byte_order` takes a string value, which must be either `"BigEndian"`,
`"LittleEndian"`, or `"Null"`:
```
[$default byte_order: "LittleEndian"]
struct Foo:
[$default byte_order: "Null"]
0 [+4] UInt bar
[byte_order: "BigEndian"]
4 [+4] bits:
[byte_order: "LittleEndian"]
0 [+23] UInt baz
23 [+9] UInt qux
8 [+1] UInt froble
```
A `$default` byte order may be set on a module or structure.
The `"BigEndian"` and `"LittleEndian"` byte orders set the byte order to big or
little endian, respectively. That is, for little endian:
```
byte 0 byte 1 byte 2 byte 3
+--------+--------+--------+--------+
|76543210|76543210|76543210|76543210|
+--------+--------+--------+--------+
^ ^ ^ ^ ^ ^ ^ ^
07 00 15 08 23 16 31 24
^^^^^^^^^^^^^^^ bit ^^^^^^^^^^^^^^^
```
And for big endian:
```
byte 0 byte 1 byte 2 byte 3
+--------+--------+--------+--------+
|76543210|76543210|76543210|76543210|
+--------+--------+--------+--------+
^ ^ ^ ^ ^ ^ ^ ^
31 24 23 16 15 08 07 00
^^^^^^^^^^^^^^^ bit ^^^^^^^^^^^^^^^
```
The `"Null"` byte order is used if no `byte_order` attribute is specified.
`"Null"` indicates that the byte order is unknown; it is an error if a
byte-order-dependent field that is not exactly 8 bits has the `"Null"` byte
order.
### `requires`
The `requires` attribute may be placed on an atomic field (e.g., type `UInt`,
`Int`, `Flag`, etc.) to specify a predicate that values of that field must
satisfy, or on a `struct` or `bits` to specify relationships between fields that
must be satisfied.
```
struct Foo:
[requires: bar < qux]
0 [+4] UInt bar
[requires: this <= 999_999_999]
4 [+4] UInt qux
[requires: 100 <= this <= 1_000_000_000]
let bar_plus_qux = bar + qux
[requires: this >= 199]
```
For `[requires]` on a field, other fields may not be referenced, and the value
of the current field must be referred to as `this`.
For `[requires]` on a `struct` or `bits`, any atomic field in the structure may
be referenced.
### `(cpp) namespace`
The `namespace` attribute is used by the C++ back end to determine which
namespace to place the generated code in:
```
[(cpp) namespace: "foo::bar::baz"]
```
A leading `::` is allowed, but not required; the previous example could also be
written as:
```
[(cpp) namespace: "::foo::bar::baz"]
```
Internally, Emboss will translate either of these into a nested `namespace foo {
namespace bar { namespace baz { ... } } }` wrapping the generated C++ code for
this module.
The `namespace` attribute may only be used at the module level; all structures
and enums within a module will be placed in the same namespace.
### `(cpp) enum_case`
The `enum_case` attribute can be specified for the C++ backend to specify
in which case the enum values should be emitted to generated source. It does
not change the text representation, which always uses the original emboss
definition name as the canonical name.
Currently, the supported cases are`SHOUTY_CASE` and `kCamelCase`.
A `$default` enum case can be set on a module, struct, bits, or enum and
applies to all enum values within that module, struct, bits, or enum
definition.
For example, to use `kCamelCase` by default for all enum values in a module:
```
[$default enum_case: "kCamelCase"]
```
This will change enum names like `UPPER_CHANNEL_RANGE_LIMIT` to
`kUpperChannelRangeLimit` in the C++ source for all enum values in the module.
Multiple case names can be specified, which is especially useful when
transitioning between two cases:
```
[enum_case: "SHOUTY_CASE, kCamelCase"]
```
### `text_output`
The `text_output` attribute may be attached to a `struct` or `bits` field to
control whether or not the field is included when emitting the text format
version of the structure. For example:
```
struct SuppressedField:
0 [+1] UInt a
1 [+1] UInt b
[text_output: "Skip"]
```
The text format output (as from `emboss::WriteToString()` in C++) would be of
the form:
```
{ a: 1 }
```
instead of the default:
```
{ a: 1, b: 2 }
```
For completeness, `[text_output: "Emit"]` may be used to explicitly specify that
a field should be included in text output.
### `external` specifier attributes
The `addressable_unit_size`, `type_requires`, `fixed_size_in_bits`, and
`is_integer` attributes are used on `external` types to tell the compiler what
it needs to know about the `external` types. They are currently
unstable, and should only be used internally.
## Type Definitions
Emboss allows you to define structs, unions, bits, and enums, and uses externals
to define "basic types." Types may be defined in any order, and may freely
reference other types in the same module or any imported modules (including the
implicitly-imported prelude).
### `struct`
A `struct` defines a view of a sequence of bytes. Each field of a `struct` is a
view of some particular subsequence of the `struct`'s bytes, whose
interpretation is determined by the field's type.
For example:
```
struct FramedMessage:
-- A FramedMessage wraps a Message with magic bytes, lengths, and CRC.
[$default byte_order: "LittleEndian"]
0 [+4] UInt magic_value
4 [+4] UInt header_length (h)
8 [+4] UInt message_length (m)
h [+m] Message message
h+m [+4] UInt crc32
[byte_order: "BigEndian"]
```
The first line introduces the `struct` and gives it a name. This name may be
used in field definitions to specify that the field has a structured type, and
is used in the generated code. For example, to read the `message_length` from a
sequence of bytes in C++, you would construct a `FramedMessageView` over the
bytes:
```c++
// vector<uint8_t> bytes;
auto framed_message_view = FramedMessageView(&bytes[0], bytes.size());
uint32_t message_length = framed_message_view.message_length().Read();
```
(Note that the `FramedMessageView` does not take ownership of the bytes: it only
provides a view of them.)
Each field starts with a byte range (`0 [+4]`) that indicates *where* the field
sits in the struct. For example, the `magic_value` field covers the first four
bytes of the struct.
Field locations *do not have to be constants*. In the example above, the
`message` field starts at the end of the header (as determined by the
`header_length` field) and covers `message_length` bytes.
After the field's location is the field's *type*. The type determines how the
field's bytes are interpreted: the `header_length` field will be interpreted as
an unsigned integer (`UInt`), while the `message` field is interpreted as a
`Message` -- another `struct` type defined elsewhere.
After the type is the field's *name*: this is a name used in the generated code
to access that field, as in `framed_message_view.message_length()`. The name
may be followed by an optional *abbreviation*, like the `(h)` after
`header_length`. The abbreviation can be used elsewhere in the `struct`, but is
not available in the generated code: `framed_message_view.h()` wouldn't compile.
Finally, fields may have attributes and documentation, just like any other
Emboss construct.
#### `$next`
The keyword `$next` may be used in the offset expression of a physical field:
```
struct Foo:
0 [+4] UInt x
$next [+2] UInt y
$next [+1] UInt z
$next [+4] UInt q
```
`$next` translates to a built-in constant meaning "the end of the previous
physical field." In the example above, `y` will start at offset 4 (0 + 4), `z`
starts at offset 6 (4 + 2), and `q` at 7 (6 + 1).
`$next` may be used in `bits` as well as `struct`s:
```
bits Bar:
0 [+4] UInt x
$next [+2] UInt y
$next [+1] UInt z
$next [+4] UInt q
```
You may use `$next` like a regular variable. For example, if you want to leave
a two-byte gap between `z` and `q` (so that `q` starts at offset 9):
```
struct Foo:
0 [+4] UInt x
$next [+2] UInt y
$next [+1] UInt z
$next+2 [+4] UInt q
```
`$next` is particularly useful if your datasheet defines structures as lists of
fields without offsets, or if you are translating from a C or C++ packed
`struct`.
#### Parameters
`struct`s and `bits` can take runtime parameters:
```
struct Foo(x: Int:8, y: Int:8):
0 [+x] UInt:8[] xs
x [+y] UInt:8[] ys
enum Version:
VERSION_1 = 10
VERSION_2 = 20
struct Bar(version: Version):
0 [+1] UInt payload
if payload == 1 && version == Version.VERSION_1:
1 [+10] OldPayload1 old_payload_1
if payload == 1 && version == Version.VERSION_2:
1 [+12] NewPayload1 new_payload_1
```
Each parameter must have the form *name`:` type*. Currently, the *type* can
be:
* <code>UInt:*n*</code>, where *`n`* is a number from 1 to 64, inclusive.
* <code>Int:*n*</code>, where *`n`* is a number from 1 to 64, inclusive.
* The name of an Emboss `enum` type.
`UInt`- and `Int`-typed parameters are integers with the corresponding range:
for example, an `Int:4` parameter can have any integer value from -8 to +7.
`enum`-typed parameters can take any value in the `enum`'s native range. Note
that Emboss `enum`s are *open*, so unnamed values are allowed.
Parameterized structures can be included in other structures by passing their
parameters:
```
struct Baz:
0 [+1] Version version
1 [+1] UInt:8 size
2 [+size] Bar(version) bar
```
#### Virtual "Fields"
It is possible to define a non-physical "field" whose value is an expression:
```
struct Foo:
0 [+4] UInt bar
let two_bar = 2 * bar
```
These virtual "fields" may be used like any other field in most circumstances:
```
struct Bar:
0 [+4] Foo foo
if foo.two_bar < 100:
foo.two_bar [+4] UInt uint_at_offset_two_bar
```
Virtual fields may be integers, booleans, or an enum:
```
enum Size:
SMALL = 1
LARGE = 2
struct Qux:
0 [+4] UInt x
let x_is_big = x > 100
let x_size = x_is_big ? Size.LARGE : Size.SMALL
```
When a virtual field has a constant value, you may refer to it using its type:
```
struct Foo:
let foo_offset = 0x120
0 [+4] UInt foo
struct Bar:
Foo.foo_offset [+4] Foo foo
```
This does not work for non-constant virtual fields:
```
struct Foo:
0 [+4] UInt foo
let foo_offset = foo + 10
struct Bar:
Foo.foo_offset [+4] Foo foo # Won't compile.
```
Note that, in some cases, you *must* use Type.field, and not field.field:
```
struct Foo:
0 [+4] UInt foo
let foo_offset = 10
struct Bar:
# Won't compile: foo.foo_offset depends on foo, which depends on
# foo.foo_offset.
foo.foo_offset [+4] Foo foo
# Will compile: Foo.foo_offset is a static constant.
Foo.foo_offset [+4] Foo foo
```
This limitation may be lifted in the future, but it has no practical effect.
##### Aliases
Virtual fields of the form `let x = y` or `let x = y.z.q` are allowed even when
`y` or `q` are composite fields. Virtuals of this form are considered to be
*aliases* of the referred field; in generated code, they may be written as well
as read, and writing through them is equivalent to writing to the aliased field.
##### Simple Transforms
Virtual fields of the forms `let x1 = y + 1`, `let x2 = 2 + y`, `let x3 = y -
3`, and `let x4 = 4 - y`, where `y` is a writeable field, will be writeable in
the generated code. When writing through these fields, the transformed field
will be set to an appropriate value. For example, writing `5` to `x1` will
actually write `4` to `y`, and writing `6` to `x4` will write `-2` to `y`. This
can be used to model fields whose raw values should be adjusted by some constant
value, e.g.:
```
struct PosixDate:
0 [+1] Int raw_year
-- Number of years since 1900.
let year = raw_year + 1900
-- Gregorian year number.
1 [+1] Int zero_based_month
-- Month number, from 0-11. Good for looking up a month name in a table.
let month = zero_based_month + 1
-- Month number, from 1-12. Good for printing directly.
2 [+1] Int day
-- Day number, one-based.
```
#### Subtypes
A `struct` definition may contain other type definitions:
```
struct Foo:
struct Bar:
0 [+2] UInt baz
2 [+2] UInt qux
0 [+4] Bar bar
4 [+4] Bar bar2
```
#### Conditional fields
A `struct` field may have fields which are only present under some
circumstances. For example:
```
struct FramedMessage:
0 [+4] enum message_id:
TYPE1 = 1
TYPE2 = 2
if message_id == MessageId.TYPE1:
4 [+16] Type1Message type_1_message
if message_id == MessageId.TYPE2:
4 [+8] Type2Message type_2_message
```
The `type_1_message` field will only be available if `message_id` is `TYPE1`,
and similarly the `type_2_message` field will only be available if `message_id`
is `TYPE2`. If `message_id` is some other value, then neither field will be
available.
#### Inline `struct`
It is possible to define a `struct` inline in a `struct` field. For example:
```
struct Message:
[$default byte_order: "BigEndian"]
0 [+4] UInt message_length
4 [+4] struct payload:
0 [+1] UInt incoming
2 [+2] UInt scale_factor
```
This is equivalent to:
```
struct Message:
[$default byte_order: "BigEndian"]
struct Payload:
0 [+1] UInt incoming
2 [+2] UInt scale_factor
0 [+4] UInt message_length
4 [+4] Payload payload
```
This can be useful as a way to group related fields together.
#### Automatically-Generated Fields
A `struct` will have `$size_in_bytes`, `$max_size_in_bytes`, and
`$min_size_in_bytes` virtual field automatically generated. These virtual field
can be referenced inside the Emboss language just like any other virtual field:
```
struct Inner:
0 [+4] UInt field_a
4 [+4] UInt field_b
struct Outer:
0 [+1] UInt message_type
if message_type == 4:
4 [+Inner.$size_in_bytes] Inner payload
```
##### `$size_in_bytes` {#size-in-bytes}
An Emboss `struct` has an *intrinsic* size, which is the size required to hold
every field in the `struct`, regardless of how many bytes are in the buffer that
backs the `struct`. For example:
```
struct FixedSize:
0 [+4] UInt long_field
4 [+2] UInt short_field
```
In this case, `FixedSize.$size_in_bytes` will always be `6`, even if a
`FixedSize` is placed in a larger field:
```
struct Envelope:
# padded_payload.$size_in_bytes == FixedSize.$size_in_bytes == 6
0 [+8] FixedSize padded_payload
```
The intrinsic size of a `struct` might not be constant:
```
struct DynamicallySizedField:
0 [+1] UInt length
1 [+length] UInt:8[] payload
# $size_in_bytes == 1 + length
struct DynamicallyPlacedField:
0 [+1] UInt offset
offset [+1] UInt payload
# $size_in_bytes == offset + 1
struct OptionalField:
0 [+1] UInt version
if version > 3:
1 [+1] UInt optional_field
# $size_in_bytes == (version > 3 ? 2 : 1)
```
If the intrinsic size is dynamic, it can still be read dynamically from a field:
```
struct Envelope2:
0 [+1] UInt payload_size
1 [+payload_size] DynamicallySizedField payload
let padding_bytes = payload_size - payload.$size_in_bytes
```
##### `$max_size_in_bytes` {#max-size-in-bytes}
The `$max_size_in_bytes` virtual field is a constant value that is at least as
large as the largest possible value for `$size_in_bytes`. In most cases, it
will exactly equal the largest possible message size, but it is possible to
outsmart Emboss's bounds checker.
```
struct DynamicallySizedStruct:
0 [+1] UInt length
1 [+length] UInt:8[] payload
struct PaddedContainer:
0 [+DynamicallySizedStruct.$max_size_in_bytes] DynamicallySizedStruct s
# s will be 256 bytes long.
```
##### `$min_size_in_bytes` {#min-size-in-bytes}
The `$min_size_in_bytes` virtual field is a constant value that is no larger
than the smallest possible value for `$size_in_bytes`. In most cases, it will
exactly equal the smallest possible message size, but it is possible to
outsmart Emboss's bounds checker.
```
struct DynamicallySizedStruct:
0 [+1] UInt length
1 [+length] UInt:8[] payload
struct PaddedContainer:
0 [+DynamicallySizedStruct.$min_size_in_bytes] DynamicallySizedStruct s
# s will be 1 byte long.
```
### `enum`
An `enum` defines a set of named integers.
```
enum Color:
BLACK = 0
RED = 1
GREEN = 2
YELLOW = 3
BLUE = 4
MAGENTA = 5
CYAN = 6
WHITE = 7
struct PaletteEntry:
0 [+1] UInt id
1 [+1] Color color
```
Enum values are always read the same way as `Int` or `UInt` -- that is, as an
unsigned integer or as a 2's-complement signed integer, depending on whether the
`enum` contains any negative values or not.
Enum values do not have to be contiguous, and may repeat:
```
enum Baud:
B300 = 300
B600 = 600
B1200 = 1200
STANDARD = 1200
```
All values in a single `enum` must either be between -9223372036854775808
(-2^63) and 9223372036854775807 (2^(63)-1), inclusive, or between 0 and
18446744073709551615 (2^(64)-1), inclusive.
It is valid to have an `enum` field that is too small to contain some values in
the `enum`:
```
enum LittleAndBig:
LITTLE = 1
BIG = 0x1_0000_0000
struct LittleOnly:
0 [+1] LittleAndBig:8 little_only # Too small to hold LittleAndBig.BIG
```
Emboss `enum`s are *open*: they may take values that are not defined in the
`.emb`, as long as those values are in range. The `is_signed` and
`maximum_bits` attributes, below, may be used to control the allowed range of
values.
#### `is_signed` Attribute
The attribute `is_signed` may be used to explicitly specify whether an `enum`
is signed or unsigned. Normally, an `enum` is signed if there is at least one
negative value, and unsigned otherwise, but this behavior can be overridden:
```
enum ExplicitlySigned:
[is_signed: true]
POSITIVE = 10
```
#### `maximum_bits` Attribute
The attribute `maximum_bits` may be used to specify the *maximum* width of an
`enum`: fields of `enum` type may be smaller than `maximum_bits`, but never
larger:
```
enum ExplicitlySized:
[maximum_bits: 32]
MAX_VALUE = 0xffff_ffff
struct Foo:
0 [+4] ExplicitlySized four_bytes # 32-bit is fine
#4 [+8] ExplicitlySized eight_bytes # 64-bit field would be an error
```
If not specified, `maximum_bits` defaults to `64`.
This also allows back end code generators to use smaller types for `enum`s, in
some cases.
#### Inline `enum`
It is possible to provide an enum definition directly in a field definition in a
`struct` or `bits`:
```
struct TurnSpecification:
0 [+1] UInt degrees
1 [+1] enum direction:
LEFT = 0
RIGHT = 1
```
This example creates a nested `enum` `TurnSpecification.Direction`, exactly as
if it were written:
```
struct TurnSpecification:
enum Direction:
LEFT = 0
RIGHT = 1
0 [+1] UInt degrees
1 [+1] Direction direction
```
This can be useful when a particular `enum` is short and only used in one place.
Note that `maximum_bits` and `is_signed` cannot be used on an inline `enum`.
If you need to use either of these attributes, make a separate `enum`.
### `bits`
A `bits` defines a view of an ordered sequence of bits. Each field is a view of
some particular subsequence of the `bits`'s bits, whose interpretation is
determined by the field's type.
The structure of a `bits` definition is very similar to a `struct`, except that
a `struct` provides a structured view of bytes, where a `bits` provides a
structured view of bits. Fields in a `bits` must have bit-oriented types (such
as other `bits`, `UInt`, `Bcd`, `Flag`). Byte-oriented types, such as
`struct`s, may not be embedded in a `bits`.
For example:
```
bits ControlRegister:
-- The `ControlRegister` holds basic control values.
4 [+12] UInt horizontal_start_offset
-- The number of pixel clock ticks to wait after the start of a line
-- before starting to draw pixel data.
3 [+1] Flag horizontal_overscan_disable
-- If set, the electron gun will be disabled during the overscan period,
-- otherwise the overscan color will be used.
0 [+3] UInt horizontal_overscan_color
-- The palette index of the overscan color to use.
struct RegisterPage:
-- The registers of the BGA (Bogus Graphics Array) card.
0 [+2] ControlRegister control_register
[byte_order: "LittleEndian"]
```
The first line introduces the `bits` and gives it a name. This name may be
used in field definitions to specify that the field has a structured type, and
is used in the generated code.
For example, to write a `horizontal_overscan_color` of 7 to a pair of bytes in
C++, you would use:
```c++
// vector<uint8_t> bytes;
auto register_page_view = RegisterPageWriter(&bytes[0], bytes.size());
register_page_view.control_register().horizontal_overscan_color().Write(7);
```
Similar to `struct`, each field starts with a *bit* range (`4 [+12]`) that
indicates which bits it covers. For example, the `horizontal_overscan_disable`
field only covers bit 3. Bit 0 always corresponds to the lowest-order bit the
bitfield; that is, if a `UInt` covers the same bits as the `bits` construct,
then bit 0 in the `bits` will be the same as the `UInt` mod 2. This is often,
but not always, how bits are numbered in protocol specifications.
After the field's location is the field's *type*. The type determines how the
field's bits are interpreted: typical choices are `UInt` (for unsigned
integers), `Flag` (for boolean flags), and `enum`s. Other `bits` may also be
used, as well as any `external` types declared with `[addressable_unit_size:
1]`.
Fields may have attributes and documentation, just like any other Emboss
construct.
In generated code, reading or writing any field of a `bits` construct will cause
the entire field to be read or written -- something to keep in mind when reading
or writing a memory-mapped register space.
#### Automatically-Generated Fields
A `bits` will have `$size_in_bits`, `$max_size_in_bits`, and `$min_size_in_bits`
virtual fields automatically generated. These virtual fields can be referenced
inside the Emboss language just like any other virtual field:
```
bits Inner:
0 [+4] UInt field_a
4 [+4] UInt field_b
struct Outer:
0 [+1] UInt message_type
if message_type == 4:
4 [+Inner.$size_in_bits] Inner payload
```
##### `$size_in_bits` {#size-in-bits}
Like a `struct`, an Emboss `bits` has an *intrinsic* size, which is the size
required to hold every field in the `bits`, regardless of how many bits are
in the buffer that backs the `bits`. For example:
```
bits FixedSize:
0 [+3] UInt long_field
3 [+1] Flag short_field
```
In this case, `FixedSize.$size_in_bits` will always be `4`, even if a
`FixedSize` is placed in a larger field:
```
struct Envelope:
# padded_payload.$size_in_bits == FixedSize.$size_in_bits == 4
0 [+8] FixedSize padded_payload
```
Unlike `struct`s, the size of `bits` must known at compile time; there are no
dynamic `$size_in_bits` fields.
##### `$max_size_in_bits` {#max-size-in-bits}
Since `bits` must be fixed size, the `$max_size_in_bits` field has the same
value as `$size_in_bits`. It is provided for consistency with
`$max_size_in_bytes`.
##### `$min_size_in_bits` {#min-size-in-bits}
Since `bits` must be fixed size, the `$min_size_in_bits` field has the same
value as `$size_in_bits`. It is provided for consistency with
`$min_size_in_bytes`.
#### Anonymous `bits`
It is possible to use an anonymous `bits` definition directly in a `struct`;
for example:
```
struct Message:
[$default byte_order: "BigEndian"]
0 [+4] UInt message_length
4 [+4] bits:
0 [+1] Flag incoming
1 [+1] Flag last_fragment
2 [+4] UInt scale_factor
31 [+1] Flag error
```
In this case, the fields of the `bits` will be treated as though they are fields
of the outer struct.
#### Inline `bits`
Like `enum`s, it is also possible to define a named `bits` inline in a `struct`
or `bits`. For example:
```
struct Message:
[$default byte_order: "BigEndian"]
0 [+4] UInt message_length
4 [+4] bits payload:
0 [+1] Flag incoming
1 [+1] Flag last_fragment
2 [+4] UInt scale_factor
31 [+1] Flag error
```
This is equivalent to:
```
struct Message:
[$default byte_order: "BigEndian"]
bits Payload:
0 [+1] Flag incoming
1 [+1] Flag last_fragment
2 [+4] UInt scale_factor
31 [+1] Flag error
0 [+4] UInt message_length
4 [+4] Payload payload
```
This can be useful as a way to group related fields together.
### `external`
An `external` type is used when a type cannot be defined in Emboss itself;
instead, external code must be provided to manipulate the type.
Emboss's built-in types, such as `UInt`, `Bcd`, and `Flag`, are defined this way
in a special file called the *prelude*. For example, `UInt` is defined as:
```
external UInt:
-- UInt is an automatically-sized unsigned integer.
[type_requires: $is_statically_sized && 1 <= $static_size_in_bits <= 64]
[is_integer: true]
[addressable_unit_size: 1]
```
`external` types are an unstable feature. Contact `emboss-dev` if you would
like to add your own `external`s.
## Builtin Types and the Prelude
Emboss has a built-in module called the *Prelude*, which contains types that are
automatically usable from any module. In particular, types like `Int` and
`UInt` are defined in the Prelude.
The Prelude is (more or less) a standard Emboss file, called `prelude.emb`, that
is embedded in the Emboss compiler.
<!-- TODO(bolms): When the documentation generator backend is built, generate
the Prelude documentation from prelude.emb. -->
### `UInt`
A `UInt` is an unsigned integer. `UInt` can be anywhere from 1 to 64 bits in
size, and may be used both in `struct`s and in `bits`. `UInt` fields may be
referenced in integer expressions.
### `Int`
An `Int` is a signed two's-complement integer. `Int` can be anywhere from 1 to
64 bits in size, and may be used both in `struct`s and in `bits`. `Int` fields
may be referenced in integer expressions.
### `Bcd`
(Note: `Bcd` is subject to change.)
A `Bcd` is an unsigned binary-coded decimal integer. `Bcd` can be anywhere from
1 to 64 bits in size, and may be used both in `struct`s and in `bits`. `Bcd`
fields may be referenced in integer expressions.
When a `Bcd`'s size is not a multiple of 4 bits, the high-order "digit" is
treated as if it were zero-extended to a multiple of 4 bits. For example, a
7-bit `Bcd` value can store any number from 0 to 79.
### `Flag`
A `Flag` is a 1-bit boolean value. A stored value of `0` means `false`, and a
stored value of `1` means `true`.
### `Float`
A `Float` is a floating-point value in an IEEE 754 binaryNN format, where NN is
the bit width.
Only 32- and 64-bit `Float`s are supported. There are no current plans to
support 16- or 128-bit `Float`s, nor the nonstandard x86 80-bit `Float`s.
IEEE 754 does not specify which NaN bit patterns are signalling NaNs and which
are quiet NaNs, and thus Emboss also does not specify which NaNs are which.
This means that a quiet NaN written through an Emboss view one system could be
read out as a signalling NaN through an Emboss view on a different system. If
this is a concern, the application must explicitly check for NaN before doing
arithmetic on any floating-point value read from a `Float` field.
## General Syntax
### Names
All names in Emboss must be ASCII, for compatibility with languages such as C
and C++ that do not support Unicode identifiers.
Type names in Emboss are always `CamelCase`. They must start with a capital
letter, contain at least one lower-case letter, and contain only letters and
digits. They are required to match the regex
`[A-Z][a-zA-Z0-9]*[a-z][a-zA-Z0-9]*`
Imported module names and field names are always `snake_case`. They must start
with a lower-case letter, and may only contain lower-case letters, numbers, and
underscore. They must match the regex `[a-z][a-z_0-9]*`.
Enum value names are always `SHOUTY_CASE`. They must start with a capital
letter, may only contain capital letters, numbers, and underscore, and must be
at least two characters long. They must match the regex
`[A-Z][A-Z_0-9]*[A-Z_][A-Z_0-9]*`.
Additionally, names that are used as keywords in common programming languages
are disallowed. A complete list can be found in the [Grammar
Reference](grammar.md).
### Expressions
#### Primary expressions
Emboss primary expressions are field names (like `field` or `field.subfield`),
numeric constants (like `9` or `0x1_0000_0000`), enum value names (like
`Enum.VALUE`), and the boolean constants `true` and `false`.
Subfields may be specified using `.`; e.g., `foo.bar` references the `bar`
subfield of the `foo` field. Emboss parses `.` before any expressions: unlike
many languages, something like `(foo).bar` is a syntax error in Emboss.
Enum values generally must be qualified by their type; e.g., `Color.RED` rather
than just `RED`. Enums defined in other modules must use the imported module
name, as in `styles.Color.RED`.
#### Operators and Functions
Note: Emboss currently has a relatively limited set of operators because
operators have been implemented as needed. If you could use an operator that is
not on the list, email `emboss-dev@`, and we'll see about adding it.
Emboss operators have the following precedence (tightest binding to loosest
binding):
1. `()` `$max()` `$present()` `$upper_bound()` `$lower_bound()`
2. unary `+` and `-` ([see note 1](#precedence-note-unary-plus-minus))
3. `*`
4. `+` `-`
5. `<` `>` `==` `!=` `>=` `<=` ([see note 2](#precedence-note-comparisons))
6. `&&` `||` ([see note 3](#precedence-note-and-or))
7. `?:` ([see note 4](#precedence-note-choice))
###### Note 1 {#precedence-note-unary-plus-minus}
Only one unary `+` or `-` may be applied to an expression without parentheses.
These expressions are valid:
```
-5
+6
-(-x)
```
These are not:
```
- -5
-+5
+ +5
+-5
```
###### Note 2 {#precedence-note-comparisons}
The relational operators may be chained like so:
```
10 <= x < 50 # 10 <= x && x < 50
10 <= x == y < 50 # 10 <= x && x == y && y < 50
100 > y >= 2 # 100 > y && y >= 2
x == y == 15 # x == y && y == 15
```
These are not:
```
10 < x > 50
10 < x == y >= z
x == y >= z <= 50
```
If one specifically wants to compare the result of a comparison, parentheses
must be used:
```
(x > 15) == (y > 15)
(x > 15) == true
```
The `!=` operator may not be chained.
A chain may contain either `<`, `<=`, and/or `==`, or `>`, `>=`, and/or `==`.
Greater-than comparisons may not be mixed with less-than comparisons.
###### Note 3 {#precedence-note-and-or}
The boolean logical operators have the same precedence, but may not be mixed
without parentheses. The following are allowed:
```
x && y && z
x || y || z
(x || y) && z
x || (y && z)
```
The following are not allowed:
```
x || y && z
x && y || z
```
###### Note 4 {#precedence-note-choice}
The choice operator `?:` may not be chained without parentheses. These are OK:
```
q ? x : (r ? y : z)
q ? (r ? x : y) : z
```
This is not:
```
q ? x : r ? y : z # Is this `(q?x:r)?y:z` or `q?x:(r?y:z)`?
q ? r ? x : y : z # Technically unambiguous, but visually confusing
```
##### `()`
Parentheses are used to override precedence. The subexpression inside the
parentheses will be evaluated as a unit:
```
3 * 4 + 5 == 17
3 * (4 + 5) == 27
```
The value inside the parentheses can have any type; the value of the resulting
expression will have the same type.
##### `$present()`
The `$present()` function takes a field as an argument, and returns `true` if
the field is present in its structure.
```
struct PresentExample:
0 [+1] UInt x
if false:
1 [+1] UInt y
if x > 10:
2 [+1] UInt z
if $present(x): # Always true
0 [+1] Int x2
if $present(y): # Always false
1 [+1] Int y2
if $present(z): # Equivalent to `if x > 10`
2 [+1] Int z2
```
`$present()` takes exactly one argument.
The argument to `$present()` must be a reference to a field. It can be a nested
reference, like `$present(x.y.z.q.r)`. The type of the field does not matter.
`$present()` returns a boolean.
##### `$max()`
The `$max()` function returns the maximum value out of its arguments:
```
$max(1) == 1
$max(-10, -5) == -5
$max(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 10
```
`$max()` requires at least one argument. There is no explicit limit on the
number of arguments, but at some point the Emboss compiler will run out of
memory.
All arguments to `$max()` must be integers, and it returns an integer.
##### `$upper_bound()`
The `$upper_bound()` function returns a value that is at least as high as the
maximum possible value of its argument:
```
$upper_bound(1) == 1
$upper_bound(-10) == -10
$upper_bound(foo) == 255 # If foo is UInt:8
$upper_bound($max(foo, 500)) == 500 # If foo is UInt:8
```
Generally, `$upper_bound()` will return a tight bound, but it is possible to
outsmart Emboss's bounds checker.
`$upper_bound()` takes a single integer argument, and returns a single integer
argument.
##### `$lower_bound()`
The `$lower_bound()` function returns a value that is no greater than the
minimum possible value of its argument:
```
$lower_bound(1) == 1
$lower_bound(-10) == -10
$lower_bound(foo) == -127 # If foo is Int:8
$lower_bound($min(foo, -500)) == -500 # If foo is Int:8
```
Generally, `$lower_bound()` will return a tight bound, but it is possible to
outsmart Emboss's bounds checker.
`$lower_bound()` takes a single integer argument, and returns a single integer
argument.
##### Unary `+` and `-`
The unary `+` operator returns its argument unchanged.
The unary `-` operator subtracts its argument from 0:
```
3 * -4 == 0 - 12
-(3 * 4) == -12
```
Unary `+` and `-` require an integer argument, and return an integer result.
##### `*`
`*` is the multiplication operator:
```
3 * 4 == 12
10 * 10 == 100
```
The `*` operator requires two integer arguments, and returns an integer.
##### `+` and `-`
`+` and `-` are the addition and subtraction operators, respectively:
```
3 + 4 == 7
3 - 4 == -1
```
The `+` and `-` operators require two integer arguments, and return an integer
result.
##### `==` and `!=`
The `==` operator returns `true` if its arguments are equal, and `false` if not.
The `!=` operator returns `false` if its arguments are equal, and `true` if not.
Both operators take two boolean arguments, two integer arguments, or two
arguments of the same enum type, and return a boolean result.
##### `<`, `<=`, `>`, and `>=`
The `<` operator returns `true` if its first argument is numerically less than
its second argument.
The `>` operator returns `true` if its first argument is numerically greater
than its second argument.
The `<=` operator returns `true` if its first argument is numerically less than
or equal to its second argument.
The `>=` operator returns `true` if its first argument is numerically greater
than or equal to its second argument.
All of these operators take two integer arguments, and return a boolean value.
##### `&&` and `||`
The `&&` operator returns `false` if either of its arguments are `false`, even
if the other argument cannot be computed. `&&` returns `true` if both arguments
are `true`.
The `||` operator returns `true` if either of its arguments are `true`, even if
the other argument cannot be computed. `||` returns `false` if both arguments
are `false`.
The `&&` and `||` operators require two boolean arguments, and return a boolean
result.
##### `?:`
The `?:` operator, used like <code>*condition* ? *if\_true* :
*if\_false*</code>, returns *`if_true`* if *`condition`* is `true`, otherwise
*`if_false`*.
Other than having stricter type requirements for its arguments, it behaves like
the C, C++, Java, JavaScript, C#, etc. conditional operator `?:` (sometimes
called the "ternary operator").
The `?:` operator's *`condition`* argument must be a boolean, and the
*`if_true`* and *`if_false`* arguments must have the same type. It returns the
same type as *`if_true`* and *`if_false`*.
### Numeric Constant Formats
Numeric constants in Emboss may be written in decimal, hexadecimal, or binary
format:
```
12 # The decimal value of 6 + 6.
012 # The same value; NOT interpreted as octal.
0xc # The same value, written in hexadecimal.
0xC # Hex digits may be written in capital letters.
# Note that the 'x' must be lower-case: 0XC is not allowed.
0b1100 # The same value, in binary.
```
Decimal numbers may use `_` as a thousands separator:
```
1_000_000 # 1e6
123_456_789
```
Hexadecimal and binary numbers may use `_` as a separator every 4 or 8 digits:
```
0x1234_5678_9abc_def0
0x12345678_9abcdef0
0b1010_0101_1010_0101
0b10100101_10100101
```
If separators are used, they *must* be thousands separators (for decimal
numbers) or 4- or 8-digit separators (for binary or hexadecimal numbers); `_`
may *not* be placed arbitrarily. Binary and hexadecimal numbers must be
consistent about whether they use 4- or 8-digit separators; they cannot be
mixed in the same constant:
```
1000_000 # Not allowed: missing the separator after 1.
1_000_00 # Not allowed: separators must be followed by a multiple
# of 3 digits.
0x1234_567 # Not allowed: separators must be followed by a multiple
# of 4 or 8 digits.
0x1234_5678_9abcdef0 # Not allowed: cannot mix 4- and 8-digit separators.
```