Cedarbridge User Manual 1.2.0
The cedarbridge language is a language designed for specifying message protocols
with a focus on minimalism and a clean mathematical foundation. The language has the
following notable
features:
The cedarbridge package is available from the following sources:
Regardless of the distribution method, the cedarbridge package
will contain a command named cedarbridge that acts as the main
entrypoint to all the package's functionality. The cedarbridge
command expects an environment variable named CEDARBRIDGE_HOME
to be defined that points to the installation directory. See the documentation for
the
installation methods below for details.
The cedarbridge command requires that a Java 17+ compatible
JVM be accessible via /usr/bin/env java.
Verify the integrity of the distribution zip file:
Unzip the zip file, and set CEDARBRIDGE_HOME appropriately:
This section of the manual attempts to provide a basic introduction to the
cedarbridge
language.
The syntax of the
cedarbridge language is based on
S-expressions, with each
cedarbridge
source file consisting of a series of statements structured as S-expressions.
A cedarbridge file should start with a
language statement
indicating which version of the cedarbridge language the file is targeting. Should any
backwards-incompatible changes be made to the language in the future, any files that
explicitly declared which
version of the language they are targeting would continue to be compiled correctly
without errors. A file that
does not contain a language statement will be compiled using whatever is the latest
version of the language the compiler supports. The following example specifies that
the file is intended for
cedarbridge
major version 1, minor version 0:
The language allows for using parentheses or square brackets to enclose expressions
as long as the use is
balanced. For example, all of these expressions are valid:
However, these expressions are not valid and will cause a parse error:
The
cedarbridge language contains a basic
package
system. All declared message types and protocols must be declared inside packages.
A package has a unique name
conventionally in lowercase
reverse domain notation. A
package statement begins the definition of a
package, and the definition continues to the next
package statement or end-of-file,
whichever occurs first. The following statement begins defining a package
com.example:
Packages may import other packages using
import statements:
An import statement (import x z) exposes all of
the types present in package x via the short name
z. For example, if a type T is declared in
x, the type can be referred to using the qualified name
z:T:
The cedarbridge language allows for defining message types based on algebraic sums and
products. Product types are referred to as record types (similar to
structs
in the C language), and sum types are referred to as
variant
types (similar to algebraic data types in Haskell or the ML family of languages).
Types may be parameterized by
other types (referred to as
generics
or parametric polymorphism in other languages). A record type consists of a series of
uniquely-named fields, and the order of fields is significant. The following statement
declares a simple
Color
record type consisting of red,
green, and blue fields:
The cedarbridge language supports conventional variant types.
The classic example for a variant type is the
option
type where values of type option may either be
None
or Some s for some value s. The following statement
declares the classic parameterized Option type, with the None
case having zero fields, and the
Some
case having exactly one field which is given the name
value:
In the
cedarbridge language, there are no backwards-compatible changes
possible for types: Adding, removing, or reordering record fields is a backwards-incompatible
change.
Reordering the cases of a variant type, or changing the fields of cases are backwards-incompatible
changes.
Rather than resort to the horrendously fragile and excessively permissive model used
by other message
protocol languages such as
protobuf,
the
cedarbridge language exposes a strict and principled
versioning mechanism that allows for unambiguous reasoning about any given
version of a protocol; if you know the version of the protocol you are speaking, you
know the exact
shape of any and all messages that appear in that protocol without the possibility
of any extra or missing fields.
A
protocol declares a set of
versions, with each
version declaring the set of
types
present in each version of the protocol. The following example defines a simple protocol
Foo with three versions:
Note that Command0 and Command1 appear
in the first two versions of the protocol, but version 3 of the protocol drops support
for
Command0. The Response type appears in
all versions of the protocol. This allows for a disciplined approach to versioning;
if a newer version of a
protocol requires "changing" a message, the approach taken is to simply declare a
new protocol version that
contains a new message type (and, almost certainly, removes the old message type).
The cedarbridge package provides a command-line interface for performing tasks such as
type-checking definitions, generating code, generating documentation, etc. The base
cedarbridge command is broken into a number of subcommands which are documented
over the following sections.
All subcommands accept a --verbose parameter that may be set to one of
trace, debug, info,
warn, or error. This parameter sets the lower bound for
the severity of messages that will be logged. For example, at debug verbosity, only
messages of severity debug and above will be logged. Setting the verbosity to
trace
level effectively causes everything to be logged, and will produce large volumes of
debugging output.
The
cedarbridge command-line tool uses
jcommander
to parse command-line arguments, and therefore supports placing command-line arguments
into a file,
one argument per line, and then referencing that file with
@. For example:
All subcommands, unless otherwise specified, yield an exit code of 0 on success, and
a non-zero exit code on failure.
check - Check the validity of cedarbridge definitions
The check command checks the validity of cedarbridge definitions.
compile - Compile cedarbridge sources
The compile command compiles cedarbridge sources.
document - Generate documentation for cedarbridge sources
The document command generates documentation for cedarbridge sources.
list-code-generators - List the available code generators
The list-code-generators command lists the available code generators.
list-documentation-generators - List the available documentation generators
The list-documentation-generators command lists the available documentation generators.
version - Display the cedarbridge version
The version command displays the current version of the command-line tool.
Documentation for the compiler's API is provided in the included
JavaDoc.