| # FIDL 2.0: Language Specification |
| |
| Status: DRAFT |
| |
| Author: jeffbrown@google.com |
| |
| This document is a specification of the Fuchsia Interface Definition Language |
| (FIDL) v2.0 syntax. Once ratified, it will be transformed into a Markdown file |
| stored in the source tree. |
| |
| See [FIDL 2.0: Overview](index.md) for more information about FIDL's overall |
| purpose, goals, and requirements, as well as links to related documents. |
| |
| **WORK IN PROGRESS** |
| |
| [TOC] |
| |
| ## Syntax |
| |
| The Fuchsia Interface Definition Language provides a syntax for declaring named |
| constants, enums, structs, unions, and interfaces. These declarations are |
| collected into packages for distribution. |
| |
| FIDL declarations are stored in plain text UTF-8 files. Each file consists of a |
| sequence of semicolon delimited declarations. The order of declarations within a |
| FIDL file or among FIDL files within a package is irrelevant. FIDL does not |
| require (or support) forward declarations of any kind. |
| |
| Topics for discussion: |
| |
| * Previously we defined FIDL files as standalone units loosely organized into |
| modules which caused problems for languages such as Dart and Rust which |
| prefer to work with more granular units, hence the idea of formalizing the |
| concept of FIDL packages. Is this the right approach? |
| |
| ### Tokens |
| |
| #### Comments |
| |
| FIDL supports C-style single-line and multiline comments. They may contain UTF-8 |
| content (which is of course ignored). |
| |
| ``` |
| // this is a single-line comment |
| /* this is a multi- |
| * line comment */ |
| ``` |
| |
| #### Document Comments |
| |
| TODO: we should think about how we will generate online documentation from FIDL |
| files. Perhaps the compiler can emit document contents together with the |
| declarations in a machine-readable FIDL IR format that could be consumed by |
| other tools. |
| |
| #### Reserved Words |
| |
| The following keywords are reserved in FIDL. |
| |
| **as, bool, const, float32, float64, handle,** |
| |
| |
| **int8, int16, int32, int64, interface, package, string, struct,** |
| |
| |
| **uint8, uint16, uint32, uint64, union, using, vector** |
| |
| To use these words as identifiers, they must be escaped by prepending an "@". |
| For example "interface" is a reserved word but "@interface" is an identifier |
| whose name is "interface". |
| |
| #### Identifiers |
| |
| FIDL identifiers must match the regex "@?[a-zA-Z_][0-9a-zA-Z]*". The "@" prefix, |
| if present, serves to distinguish identifiers from reserved words in the FIDL |
| language. The "@" prefix itself is ignored for the purposes of naming the |
| identifier. This allows reserved words in the FIDL language to nevertheless be |
| used as identifiers (when escaped with "@"). |
| |
| Identifiers are case-sensitive. |
| |
| ``` |
| // a package named "foo" |
| package foo; |
| |
| // a struct named "Foo" |
| struct Foo { }; |
| |
| // a struct named "struct" |
| struct @struct { }; |
| ``` |
| |
| #### Qualified Identifiers |
| |
| FIDL always looks for unqualified symbols within the scope of the current |
| package. To reference symbols in other packages, they must be qualified by |
| prefixing the identifier with the package name or alias. |
| |
| Names may also require qualification when they refer to symbols which have been |
| declared within the scope of a **struct**, **union**, or **interface**. |
| |
| **objects.fidl:** |
| |
| ``` |
| package objects; |
| using textures as tex; |
| |
| interface Frob { |
| // "Thing" refers to "Thing" in the "objects" package |
| // "tex.Color" refers to "Color" in the "textures" package |
| Paint(Thing thing, tex.Color color); |
| }; |
| |
| struct Thing { |
| string name; |
| }; |
| ``` |
| |
| **textures.fidl:** |
| |
| ``` |
| package textures; |
| |
| struct Color { |
| uint32 rgba; |
| }; |
| ``` |
| |
| Topics for discussion: |
| |
| * Should we provide shortcuts for referencing types in other packages? Should |
| we support importing symbols into the package's own scope? |
| |
| #### Literals |
| |
| FIDL supports the following literal types using C-like syntax: bools, signed |
| integers, unsigned integers, floats, strings. |
| |
| ``` |
| const bool kBool = true; |
| const int32 kInt = -333; |
| const uint32 kUInt = 42; |
| const uint64 kDiamond = 0x183c7effff7e3c18; |
| const string kString = "a string"; |
| const float32 kFloat = 1.0; |
| ``` |
| |
| Topics for discussion: |
| |
| * Provide more formal definition. |
| * Describe special constants like float.NAN and uint32.MAX. |
| |
| #### Declaration Separator |
| |
| FIDL uses the semi-colon **';'** to separate adjacent declarations within the |
| file, much like C. Although it is somewhat of a nuisance, it makes the grammar |
| more regular (constant, member, and type declarations look the same) which |
| simplifies parsing. |
| |
| NB: I am sure there are other viewpoints on this… Ideally the grammar should be |
| LL(1) but whoever ultimately writes the new compiler can weigh in on what's |
| simple to parse or not. |
| |
| ### Packages |
| |
| Packages are named containers of FIDL declarations. |
| |
| Each package has a name consisting of a dot-delimited identifier. Package names |
| appear in [Qualified Identifiers](#qualified-identifiers). |
| |
| Packages may declare that they use other packages with a "using" declaration. |
| This allows the package to refer to symbols defined in other packages upon which |
| they depend. Symbols which are imported this way may be accessed either by |
| qualifying them with the package name as in _"mozart.geometry.Rect"_ or by |
| qualifying them with the package alias as in _"geo.Rect"_. |
| |
| ``` |
| package mozart.composition; |
| using mozart.geometry as geo; |
| using mozart.buffers; |
| |
| interface Compositor { … }; |
| ``` |
| |
| In the source tree, each package consists of a directory with some number of |
| ***.fidl** files. The name of the directory is irrelevant to the FIDL compiler |
| but by convention it should resemble the package name itself. A directory should |
| not contain FIDL files for more than one package. |
| |
| The scope of "package" and "using" declarations is limited to a single file. |
| Each individual file within a FIDL package must restate the "package" |
| declaration together with any "using" declarations needed by that file. |
| |
| When the FIDL compiler encounters a package name such as "mozart.geometry", |
| searches the package path to find the directory which contains that package's |
| FIDL files, then loads the files. The compiler emits an error ifs any referenced |
| package cannot be found. |
| |
| The build system generally takes care of providing the FIDL compiler with a |
| suitable package path argument derived from the build dependencies for the |
| target. eg. _"--package mozart.geometry=apps/mozart/services/geometry --package |
| mozart.buffers=apps/mozart/services/buffers"_ |
| |
| The package's name may be used by certain language bindings to provide scoping |
| for symbols emitted by the code generator. |
| |
| For example, the C++ bindings generator places declarations for the FIDL library |
| "mozart.composition" within the C++ namespace "mozart::composition". Similarly, |
| for languages such as Dart and Rust which have their own module system, each |
| FIDL package is compiled as a module for that language. |
| |
| Topics for discussion: |
| |
| * Are there any attributes we would like to define at the package level? eg. |
| C++ namespace or other code generator hints |
| * Should the individual FIDL files which make up a package be collated (merged |
| into one combined file archive) or is the one-to-one mapping of package to |
| directory good enough? |
| * Do FIDL packages need any auxiliary metadata represented separately from the |
| FIDL files themselves? |
| |
| ### Types and Type Declarations |
| |
| #### Primitives |
| |
| * Simple value types. |
| * Not nullable. |
| |
| The following primitive types are supported: |
| |
| Boolean **<code>bool</code></strong> |
| |
| |
| Signed integer **<code>int8 int16 int32 int64</code></strong> |
| |
| |
| Unsigned integer **<code>uint8 uint16 uint32 uint64</code></strong> |
| |
| |
| IEEE 754 Floating-point **<code>float32 float64</code></strong> |
| |
| Numbers are suffixed with their size in bits, **<code>bool</code></strong> is 1 |
| byte. |
| |
| ##### Use |
| |
| ``` |
| // A record which contains fields of a few primitive types. |
| struct Sprite { |
| float32 x; |
| float32 y; |
| uint32 index; |
| uint32 color; |
| bool visible; |
| }; |
| ``` |
| |
| #### Enums |
| |
| * Proper enumerated types; bit fields are not valid enums. |
| * Discrete subset of named values chosen from an underlying integer primitive |
| type. |
| * Not nullable. |
| |
| ##### Declaration |
| |
| The ordinal index is **required** for each enum element. The underlying type of |
| an enum must be one of: **int8, uint8, int16, uint16, int32, uint32, int64, |
| uint64**. If omitted, the underlying type is assumed to be **uint32**. |
| |
| Enums may be scoped within: **package, struct, union, interface**. |
| |
| ``` |
| // An enum declared at package scope. |
| enum Beverage : uint8 { |
| WATER = 0, |
| COFFEE = 1, |
| TEA = 2, |
| WHISKEY = 3, |
| }; |
| |
| // An enum declared at package scope. |
| // Underlying type is assumed to be uint32. |
| enum Vessel { |
| CUP = 0, |
| BOWL = 1, |
| TUREEN = 2, |
| JUG = 3, |
| }; |
| |
| // An enum declared within an interface scope. |
| interface VendingMachine { |
| enum PaymentMethod { |
| CASH = 0, |
| CREDIT = 1, |
| HONOR_SYSTEM = 2, |
| }; |
| }; |
| ``` |
| |
| ##### Use |
| |
| Enum types are denoted by their identifier, which may be qualified if needed. |
| |
| ``` |
| // A record which contains two enum fields. |
| struct Order { |
| Beverage beverage; |
| Vessel vessel; |
| }; |
| ``` |
| |
| #### Arrays |
| |
| * Fixed-length sequences of homogeneous elements. |
| * Elements can be of any type including: primitives, enums, arrays, strings, |
| vectors, handles, structs, unions. |
| * Not nullable themselves; may contain nullable types. |
| |
| ##### Use |
| |
| Arrays are denoted **<code>T[n]</code></strong> where <em>T</em> can be any FIDL |
| type (including an array) and <em>n</em> is a constant expression which |
| specified the number of elements in the array. |
| |
| ``` |
| // A record which contains some arrays. |
| struct Record { |
| // array of exactly 16 floating point numbers |
| float32[16] matrix; |
| |
| // array of exactly 10 arrays of 4 strings each |
| string[4][10] form; |
| }; |
| ``` |
| |
| #### Strings |
| |
| * Variable-length sequence of UTF-8 encoded characters representing text. |
| * Nullable; null strings and empty strings are distinct. |
| * Can specify a maximum size, eg. **<code>string:40</code></strong> for a |
| maximum 40 byte string. |
| |
| ##### Use |
| |
| Strings are denoted as follows: |
| |
| * **<code>string</code></strong> : non-nullable string (validation error |
| occurs if null is encountered) |
| * <strong><code>string?</code></strong> : nullable string |
| * <strong><code>string:N, string:N?</code></strong> : string with maximum |
| length of <em>N</em> bytes |
| |
| ``` |
| // A record which contains some strings. |
| struct Record { |
| // title string, maximum of 40 bytes long |
| string:40 title; |
| |
| // description string, may be null, no upper bound on size |
| string? description; |
| }; |
| |
| ``` |
| |
| #### Vectors |
| |
| * Variable-length sequence of homogeneous elements. |
| * Nullable; null vectors and empty vectors are distinct. |
| * Can specify a maximum size, eg. **<code>vector<T>:40</code></strong> for a |
| maximum 40 element vector. |
| * There is no special case for vectors of bools. Each bool element takes one |
| byte as usual. |
| |
| ##### Use |
| |
| Vectors are denoted as follows: |
| |
| * **<code>vector<T></code></strong> : non-nullable vector of element type |
| <em>T</em> (validation error occurs if null is encountered) |
| * <strong><code>vector<T>?</code></strong> : nullable vector of element type |
| <em>T</em> |
| * <strong><code>vector<T>:N, vector<T>:N?</code></strong> : vector with |
| maximum length of <em>N</em> elements |
| |
| <em>T</em> can be any FIDL type. |
| |
| ``` |
| // A record which contains some vectors. |
| struct Record { |
| // a vector of up to 10 integers |
| vector<int32>:10 params; |
| |
| // a vector of bytes, no upper bound on size |
| vector<uint8> blob; |
| |
| // a nullable vector of up to 24 strings |
| vector<string>:24? nullable_vector_of_strings; |
| |
| // a vector of nullable strings |
| vector<string?> vector_of_nullable_strings; |
| |
| // a vector of vectors of arrays of floating point numbers |
| vector<vector<float32[16]>> complex; |
| }; |
| ``` |
| |
| #### Handles |
| |
| * Transfers a Zircon capability by handle value. |
| * Stored as a 32-bit unsigned integer. |
| * Nullable by encoding as a zero-valued handle. |
| |
| ##### Use |
| |
| Handles are denoted: |
| |
| * **<code>handle</code></strong> : non-nullable Zircon handle of |
| unspecified type |
| * <strong><code>handle?</code></strong> : nullable Zircon handle of |
| unspecified type |
| * <strong><code>handle<H></code></strong> : non-nullable Zircon handle |
| of type <em>H</em> |
| * <strong><code>handle<H>?</code></strong> : nullable Zircon handle of |
| type <em>H</em> |
| |
| <em>H</em> can be one of[^1]: **<code>channel, event, eventpair, fifo, job, |
| process, port, resource, socket, thread, vmo</code></strong> |
| |
| ``` |
| // A record which contains some handles. |
| struct Record { |
| // a handle of unspecified type |
| handle h; |
| |
| // an optional channel |
| handle<channel>? c; |
| }; |
| ``` |
| |
| #### Structs |
| |
| * Record type consisting of a sequence of typed fields. |
| * Declaration is not intended to be modified once deployed; use interface |
| extension instead. |
| * Reference may be nullable. |
| |
| ##### Declaration |
| |
| ``` |
| struct Point { float32 x, y; }; |
| struct Color { float32 r, g, b; }; |
| ``` |
| |
| ##### Use |
| |
| Structs are denoted by their declared name (eg. **Circle**) and nullability: |
| |
| * **<code>Circle</code></strong> : non-nullable Circle |
| * <strong><code>Circle?</code></strong> : nullable Circle |
| |
| ``` |
| struct Circle { |
| bool filled; |
| Point center; // Point will be stored in-line |
| float32 radius; |
| Color? color; // Color will be stored out-of-line |
| bool dashed; |
| }; |
| |
| ``` |
| |
| #### Unions |
| |
| * Tagged option type consisting of tag field and variadic contents. |
| * Declaration is not intended to be modified once deployed; use interface |
| extension instead. |
| * Reference may be nullable. |
| |
| ##### Declaration |
| |
| ``` |
| union Pattern { |
| Color color; |
| Texture texture; |
| }; |
| struct Color { float32 r, g, b; }; |
| struct Texture { string name; }; |
| ``` |
| |
| ##### Use |
| |
| Union are denoted by their declared name (eg. **Pattern**) and nullability: |
| |
| * **<code>Pattern</code></strong> : non-nullable Shape |
| * <strong><code>Pattern?</code></strong> : nullable Shape |
| |
| ``` |
| struct Paint { |
| Pattern fg; |
| Pattern? bg; |
| }; |
| |
| ``` |
| |
| #### Interfaces |
| |
| * Describe methods which can be invoked by sending messages over a channel. |
| * Methods are identified by their ordinal index. Ordinals must be stated |
| explicitly to reduce the chance that developers might break interfaces by |
| reordering methods and to help with interface extension and derivation. |
| * Method ordinals are unsigned values in the range **0x00000000** to |
| **0x7fffffff**. |
| * The FIDL wire format internally represents ordinals as 32-bit values but |
| reserves the range **0x80000000** to **0xffffffff** for protocol control |
| messages, so these values cannot be associated with methods. |
| * Each method declaration states its arguments and results. |
| * If no results are declared, then the method is one-way: no response will |
| be generated by the server. |
| * If results are declared (even if empty), then the method is two-way: |
| each invocation of the method generates a response from the server. |
| * When a client or server of an interface is about to close its side of the |
| channel, it may elect to send an **epitaph** message to its peer to indicate |
| the disposition of the connection. If sent, the epitaph must be the last |
| message delivered through the channel. An epitaph message includes: |
| * 32-bit generic status: one of the **ZX_status_t** constants |
| * 32-bit protocol-specific code: meaning is left up to the interface in |
| question |
| * a string: a human-readable message explaining the disposition |
| * **Interface extension: **New methods can be added to existing interfaces as |
| long as they do not collide with existing methods. |
| * **Interface derivation: **New interfaces can be derived from any number of |
| existing interfaces as long as none of their methods use the same ordinals. |
| (This is purely a FIDL language feature, does not affect the wire format.) |
| |
| ##### Declaration |
| |
| ``` |
| interface Calculator { |
| 1: Add(int32 a, int32 b) -> (int32 sum); |
| 2: Divide(int32 dividend, int32 divisor) |
| -> (int32 quotient, int32 remainder); |
| 3: Clear(); |
| }; |
| |
| interface RealCalculator : Calculator { |
| 1001: AddFloats(float32 a, float32 b) -> (float32 sum); |
| }; |
| |
| interface Science { |
| 2001: Hypothesize(); |
| 2002: Investigate(); |
| 2003: Explode(); |
| 2004: Reproduce(); |
| }; |
| |
| interface ScientificCalculator : RealCalculator, Science { |
| 3001: Sin(float32 x) -> (float32 result); |
| }; |
| ``` |
| |
| TODO: Bikeshed away… |
| |
| * **'->'** is actually just like the new C++ function syntax, so at least it's |
| somewhat consistent, but could use a keyword instead |
| * would be nice if enums and interfaces specified values/ordinals the same way |
| * might need a way to reserve ordinal ranges, or perhaps we could do so |
| implicitly by using interface numbering instead: assign a number to each |
| interface (default 0), construct actual method ordinal given (iface_number |
| << 16 | method_number) |
| * interface Foo@5 { Add@2(int32 a, int32 b) -> (int32 result); }; |
| |
| ##### Use |
| |
| Interfaces are denoted by their name, directionality of the channel, and |
| optionality: |
| |
| * **<code>Interface</code></strong> : non-nullable FIDL interface (client |
| endpoint of channel) |
| * <strong><code>Interface?</code></strong> : nullable FIDL interface (client |
| endpoint of channel) |
| * <strong><code>Interface&</code></strong> : non-nullable FIDL interface |
| request (server endpoint of channel) |
| * <strong><code>Interface&?</code></strong> : nullable FIDL interface request |
| (server endpoint of channel) |
| |
| ``` |
| // A record which contains interface-bound channels. |
| struct Record { |
| // client endpoint of a channel bound to the Calculator interface |
| Calculator c; |
| |
| // server endpoint of a channel bound to the Science interface |
| Science& s; |
| |
| // optional client endpoint of a channel bound to the |
| // RealCalculator interface |
| RealCalculator? r; |
| }; |
| |
| ``` |
| |
| ### Constant Declarations |
| |
| Constant declarations introduce a name within their scope. The constant's type |
| must be either a primitive or an enum. |
| |
| Constants may be scoped within: **package, struct, union, interface**. |
| |
| ``` |
| // a constant declared at package scope |
| const int32 kFavoriteNumber = 42; |
| |
| // a constant declared within an interface scope |
| interface VendingMachine { |
| const Beverage kFavoriteBeverage = WHISKEY; |
| }; |
| ``` |
| |
| ### Constant Expressions |
| |
| TODO: decide whether we want to support any kind of arithmetic, especially for |
| interface ordinals and enum values, maybe defer? |
| |
| ## Grammar |
| |
| [Grammar is here](grammar.md). |
| |
| ## Examples |
| |
| See also [FIDL 2.0: I/O Sketch](io-sketch.md). |
| |
| <!-- Footnotes themselves at the bottom. --> |
| |
| ## Notes |
| |
| [^1]: New handle types can easily be added to the language without affecting the |
| wire format since all handles are transferred the same way. |