TDL - the Tiri Definition Language - is an Interface Definition Language designed specifically for Kōtuku. It is accompanied with a series of tools - `idl-c`, `idl-compile` and `idl-doc`, which parse `.tdl` files to produce language headers and user documentation. This document describes the definition language itself. Instruction on how to use the tools is provided in the TDL Tools manual. --- ## File Structure TDL files must be given a `.tdl` extension and are expected to start with `--$TIRI:Include` on their first line. TDL is a function-oriented document format, meaning the document itself makes calls to the parser so that it has control over the entire process. The first function that is called from the TDL file must be one of the following: ### module() `module({ Options... }, Function)` Use `module()` to declare the interface of a named module. The following key-values can be provided as `Options`: |Key|Description| |:-|:-| |name|The name of the module.| |copyright|Copyright information declaring the owner(s) of the module, recommended to be kept under 120 characters.| The `Function` is a callback that will define the module interface using functions declared in the next section. ### header() `header({ Options... }, Function)` Use `header()` to create a language header file that declares constant types and values. Unlike `module()`, a header is not permitted to export functional interfaces. The following key-values can be provided as `Options`: |Key|Description| |:-|:-| |path|A simplified path for the header file. For example, a value of `system/fields` would evaluate to `include/system/fields.h` when generated as a C++ header.| |copyright|Copyright information declaring the owner(s) of the header, recommended to be kept under 120 characters.| The `Function` is a callback that will define the header content, using the functions declared in the next section. --- ## Utility Functions ### c_include() `c_include('', '', ...)` Use `c_include()` to specify C/C++ headers that must be included when generating C/C++ header output. ### cpp_include() `cpp_include('', '', ...)` Use `cpp_include()` to specify C++ headers that must be included when generating C++ header output. ### c_insert() `c_insert(String)` Use `c_insert()` to output C/C++ content when generating C/C++ headers. ### platform() `platform(PlatformFilter, Function)` Use `platform()` when the content described in `Function` is for a specific target platform. Valid `PlatformFilter` values are `windows`, `linux`, `x11` and `osx`. As an example, the following: ``` platform('X11', function() c_include('', '') end) ``` Generates the following C header: ``` #ifdef __xwindows__ #include #include #endif ``` ### restrict() `restrict(Function)` Use `restrict()` to prevent the TDL parser from outputting anything contained within `Function`. Consider a situation where an TDL file has a dependency on other TDL files. Using `restrict()` as a wrapper will prevent the included definitions from appearing in the generated output, as in this example: ```lua restrict(function() loadFile(glPath .. 'common.tdl') loadFile(glPath .. 'common-graphics.tdl') end) ``` ### priority() `priority(Function)` Use `priority()` to ensure that the content wrapped by `Function` is inserted at the top of the generated header file. ### privateNames() `privateNames(Values...)` Use `privateNames()` to name a series of types that are considered private and not to appear in generated documentation. This does not affect header generation. ## Primary Functions ### hash() `hash(Prefix, Format, Values...)` Use `hash()` to convert a series of string `Values` to their 32-bit hash equivalent, as output by the `StrHash()` function. Each value will be named as `Prefix_Value` and the generated hash will be formatted in-line with the provided `Format`. For example: ```lua hash('SVF', '0x%s', 'APPEND-PATH', 'AZIMUTH') ``` Generates the following C output: ``` #define SVF_APPEND_PATH 0x64cbc017 #define SVF_AZIMUTH 0x52cfd287 ``` ### flags() `flags(Prefix, { Options }, Values..., { Manual })` Use `flags()` to specify a group of bit-flags suitable for application to an integer of unspecified size. A unique name must be given to `Prefix` that will categorise the group of flags. Available `Options` are: |Name|Description| |:-|:-| |restrict|Do not output the listed flags to the language header file.| |module|Output the listed flags only if `flags()` has been called from the named module.| |comment|A short description that will be added to documentation for the collection.| |bits|The maximum number of bits recommended for hosting the flags.| The `Values` is a list of strings that define the name of each flag with an appropriate short description, formatted as `NAME: Description`. If `NAME` contains multiple words, developers are strongly encouraged to use underscores to separate them. Sometimes a flag may have one or more synonyms, in which case the separator bar may be used to specify them, i.e. `NAME|ALT_NAME:Description`. If more control over flag configuration is required, this can be achieved by ending the value list with a table of `Manual` settings. If a flag needs to be created that is a superset of other flags, a key-value like the following can be created: `NAME = 'OTHER_FLAG_A|OTHER_FLAG_B|...'` If a flag has a specific value to be associated with it, this can be achieved as follows: `NAME = '0x00000000: Description'` ### enum() `enum(Prefix, { Options }, Values..., { Manual })` Use `enum()` to list a collection of named numeric constants that enumerate from zero. Available `Options` are: |Name|Description| |:-|:-| |restrict|Do not output the listed values to the language header file.| |module|Output the listed values only if `enum()` has been called from the named module.| |comment|A short description that will be added to documentation for the collection.| |start|Start the count from this value, otherwise default to 0.| |type|The integer type that represents the collection, typically `int`, `short` or `char`. Highly recommended for enabling strong typing.| The `Values` is a list of strings that define the name of each value with an appropriate short description, formatted as `NAME: Description`. If `NAME` contains multiple words, developers are strongly encouraged to use underscores to separate them. If more control over flag configuration is required, this can be achieved by ending the value list with a table of `Manual` settings. If a flag has a specific value to be associated with it, this can be achieved as follows: `NAME = '0x00000000: Description'` ### const() `const(Prefix, { Options }, { Values... })` Use `const()` to list a collection of named numeric constants with values that are manually provided. Available `Options` are: |Name|Description| |:-|:-| |restrict|Do not output the listed values to the language header file.| |module|Output the listed values only if `const()` has been called from the named module.| |comment|A short description that will be added to documentation for the collection.| |type|The integer type that represents the collection, typically `int`, `short` or `char`. Highly recommended for enabling strong typing.| The `Values` are provided as a key-value table. To specify a value without a comment, use the format: `NAME = Value` To attach a comment to the value: `NAME = 'Value: Description'` ### functionNames() `functionNames(Prefix, Values...)` If a module exports one or more functions, they need to be named so that an export header can be generated. A `Prefix` must also be specified that will act as a namespace for the functions. Example: ``` functionNames('vec', 'DrawPath', 'GenerateEllipse', 'GeneratePath', 'GenerateRectangle') ``` ### struct() `struct(Name, { Options }, [[ Spec ]], [[ Append ]])` Use `struct()` to declare a named structure consisting of field types. Available `Options` are: |Name|Description| |:-|:-| |restrict|Restricts the output to a specific language. E.g. `restrict='c'` will generate C header output only.| |module|Output the struct only if `struct()` has been called from the named module.| |comment|A short description that will be added to documentation for the collection.| |version|Associates a version number (whole numbers only) with the struct.| |type|For C/C++ only, adds a named `typedef` in conjunction with the struct name.| The Spec is a multi-line string of named types that define the struct. The template for each line is as follows, where `# Comment` is optional: `Type Name # Comment` Example: ```lua struct('VectorPoint', { comment='Structure for the VectorPolygon PointsArray field.' }, [[ double X # The X coordinate of this point. double Y # The Y coordinate of this point. bit(uchar) XScaled # TRUE if the X value is scaled to its viewport (between 0 and 1.0). bit(uchar) YScaled # TRUE if the Y value is scaled to its viewport (between 0 and 1.0). ]]) ``` For information on type definitions, please refer to the Document Formatting manual. Structs that are output to C/C++ can be augmented with additional information specified in `Append`. The information that you provide here will be inserted in its raw form without interpretation from the parser. ### class() `class(Name, { Options }, [[ Spec ]], [[ Private ]], [[ Append ]])` Use `class()` to declare a named structure consisting of field types. Available `Options` are: |Name|Description| |:-|:-| |restrict|Restricts the output to a specific language. E.g. `restrict='c'` will generate C header output only.| |module|Output the class only if `class()` has been called from the named module.| |comment|A short description that will be added to documentation for the collection.| |version|Associates a version number (`Version.Revision`) with the struct.| |type|For C/C++ only, adds a named `typedef` in conjunction with the struct name.| |base|If the spec is for a derived class, refer to the name of its base class here.| |src|A table of paths that refer to the C++ source file(s) representing the class.| |references|An optional table referring to flags, enums and constants that are used by the class. Only required if said references are not already declared in the Spec section.| |output|Specifying a path to an output file will generate C definitions for class methods & actions declared by the class.| The Spec is a multi-line string of named types that define the class. The template for each line is as follows, where `# Comment` is optional: `Type Name # Comment` Example: ```lua class('File', { version=1.2, src='../classes/class_file.cpp', output='../classes/class_file_def.c' }, [[ large Position # The current read/write byte position in a file. int(FL) Flags # File flags and options. int Static # Set to TRUE if a file object should be static. oid Target # Specifies a surface ID to target for user feedback and dialog boxes. ptr(char) Buffer # Points to the internal data buffer if the file content is held in memory. ]]) ``` For information on type definitions, please refer to the Document Formatting manual. Classes that are output to C/C++ can declare internal content for their struct in `Private`. This information will not appear in documentation, nor will it be available to clients using the class. The information that you provide here will be inserted in its raw form without interpretation from the parser. Customised content for C++ clients can be added to the class with `Append`. This feature is typically used for adding C++ specific methods and templates that can aid development, but bear in mind such additions will not be portable to other languages. ### methods() `methods(Class, Prefix, { Methods })` Use `methods()` to declare the public methods of a `Class`. A unique `Prefix` must be assigned to give the methods a namespace. The `Methods` table consists of `id` and `name` keys to declare the methods. The following example illustrates: ``` methods('vectorscene', 'Sc', { { id=1, name='AddDef' }, { id=2, name='SearchByID' }, { id=3, name='FindDef' }, { id=4, name='Debug' } }) ``` Each method must have a corresponding TDL method declared in the source code of the class. The parser will use this information when building viable function calls for the methods.