ridl
(pronounced riddle) is an Interface Description Language
compiler. Of sorts. Compared with other tools that call themselves IDL
compilers ridl
stands out. Firstly because it does not use an
interface definition language. And secondly because it doesn't
actually compile anything. ridl is an an IDL compiler. With no
IDL. That it doesn't compile.
Instead of defining an IDL ridl
uses an existing language, Go, and
re-interprets its constant and type declarations to be definitions of
interfaces (which, of course, they already are). ridl
parses Go
code, using standard Go packages, builds a data structure to represent
the constants and types the code defines, and then uses Go's standard
template package to execute user-supplied templates with this data
structure as the so-called template context. The result permits the
Go declarations to transformed to whatever is produced by the
templates.
ridl comes with example templates to convert Go declarations to C++. These will be developed to allow for network messaging, using different transports, with Go interface types defining sets of messages.
Using Go as the definition language means ridl is restricted to what Go's type specifications can express. That means there are no unions, also called variant records, sum types or enums in some languages. There is no direct support for interface versioning and no support for the direct expression of enumerated values a la C/C++.
Unions and versioning are left to end-users however ridl does recognize the idiomatic Go way of defining C-style enumerated types and generates a data model that allows templates to "undo" the Go-style representation.
The RIDL (Go) source code is distributed under the GPLv2 license. Refer to the file, LICENSE, for details. Code generated by RIDL is NOT covered by any license.
RIDL template files are distributed under the MIT license and may be freely used for any purpose. The template files distributed with RIDL are primarily intended to serve as tests and examples and user-created templates derived from these are NOT covered by the RIDL copyright.
The real intent is that RIDL template files would be distributed without license if that were permitted in all locations.
A ridl interface description is a Go package containing only constant and type
declarations, i.e. there are no functions. By convention these are named with
a .ridl
extension but the file is a .go
file and can be processed by
standard Go tools.
Like Go, or more correctly because of it, ridl
has a module system
based upon packages. Each interface belongs to a package and an
interface must declare its pacakge as its first statement (ridl is
go).
Packages may be used in template expansion. The C++ template uses the Go package to name a C++ namespace.
Basic usage is,
ridl
options [ _filename... ]
If no input files are named on the command line ridl
reads all files
with the extension .ridl
in the current directory. If one, or more,
files are named on the command line only those files are processed.
- -t template
Use template to generate output. More than one template may be used in which case - -o filename
Write output to filename. The filename-
represents the standard output. - -D directory
Read template files from directory. - -typemap filename
Read type map definitions from filename. See *Type Maps below. - -write-typemap
Output the JSON-encoded type map to stdout and exit. - -version
Output ridl version and exit. - -debug
Enable debug output.
ridl
, or more correctly the supplied C++ template file, interprets a
Go interface
type as the definition of a set of messages. Each
method represents a distinct message with the interface where a
method's name identifies the message within the interface. Any
arguments to the method define the message payload, the data
communicated to the receiver along with the message identity. If the
method has results they define the payload of a result message
(who's identity is derived from the method name).
Arrays, slice and map types may be used. They are easily mapped to some appropriate construct in most target languages.
Go's error
type is permitted and is mapped to whatever
representation of errors is used with the target language.
The error type's interface is limited, only permitting extracting the error as a string, so ridl defines errors as string.
Function, channel and pointer types are not permitted.
Function declarations are by default errors. A permissive mode could be used to parse Go files and ignore constructs not permitted in ridl files.
- PackageName
The name of the (Go) ridl package being processed. - RidlVersion
The version of ridl being used. - Directory
The name of the directory being processed. - Filenames
The names of the .ridl files being processed. - BuildTime
The (system) time when template generation started. - Username
The name of the user running ridl. - Hostname
The name of the host on which ridl is being run.
- Decls
All declarations - constants, types and interfaces. - Imports
The names of any imported packages - Typedefs
The basic types defined by the ridl files. - ArrayTypes
The array and slice (variable size arrays). - MapTypes
The defined map types. - StructTypes
The defined struct types. - Interfaces
The interfaces. - Constants
All constants. - Enums
Constants that are enum like. - NotEnums
Constants that are not enum like.
Each template may define an output spec which is used to generate the name of the output file created when that template is used. An output spec is defined via special comment forms embedded in the template, so called ridl comments.
Ridl comments are //
style line comments that:
- begin at the start of the line (i.e. the first column)
- have a first, space-separated, token of "ridl:"
The ridl output
comment is used to define the so-called output specification.
A text/template
template used to generate the name of the output
file created by a template.
The specification is evaluated with a context defining a number of variables:
- Template
The name of the template being processed. - Package
The name of the package being processed. - Directory
The directory being processed. - Time
Time of processing. - Username
Name of the user running ridl. - Hostname
Name of the host on which ridl is being run.
Returns a string with the C++ type corresponding to the given Go type when a value of that type is used an argument to a function.
Returns the base filename for a given pathname without any extension.
Returns a string with the C++ type corresponding to the given Go type.
Determines if a Go type is a slice, i.e. if the Go type name
starts with the sequence []
.
Returns the lower case version of a string.
Returns the sum of two integers.
Returns the element type of an array or slice type.
Returns the C++ type to be used as a function result.
TBD.
Converts any leading capital letter in a string to lower case.
The cpptype
template function maps a Go type to an equivalent C++
type. Standard Go types are mapped as per the following table,
Go Type | C++ Type |
---|---|
byte | std::byte |
error | std::runtime_error |
string | std::string |
float32 | float |
float64 | double |
rune | uint32_t |
bool | bool |
int | int |
uint | unsigned int |
float | float32 |
int8 | int8_t |
uint8 | uint8_t |
int16 | int16_t |
uint16 | uint16_t |
int32 | int32_t |
uint32 | uint32_t |
int64 | int64_t |
uint64 | int64_t |
uintptr | ptrdiff_t |
complex32 | std::complex |
complex64 | std::complex |
Note, the int
and float
Go types represent the types of the so-called
untyped constants.
Users may override the default mapping or define extra mappings via a type map file, a JSON encoded structure that defines the mapping from a Go type to a C++ type.
A type map contains a, JSON, array of mappings where each mapping is a dictionary the the keys
go-type
the type's name as used in Gocpp-type
the corresponding C++ type namepass-by-ref
a flag indicating if values of the type should be passed by reference
[
{
"go-type": "Timepoint",
"cpp-type": "std::chrono::steady_clock::timepoint",
"pass-by-ref": false
},
{
"go-type": "StringMap",
"cpp-type": "std::map<std::string, std::string>",
"pass-by-ref": true
}
]
The -write-typemap
flag can be used to output the default, JSON-encoded,
type map which may be used to tailor the desired type map.