Skip to content

FDL Reference Manual

Paul Manias edited this page May 7, 2024 · 1 revision

FDL - the Fluid Definition Language - is an Interface Definition Language designed specifically for Parasol. It is accompanied with a series of tools - idl-c, idl-compile and idl-doc, which parse .fdl 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 FDL Tools manual.


File Structure

FDL files must be given a .fdl extension and are expected to start with --$FLUID:Include on their first line. FDL 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 FDL 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('<a>', '<b>', ...)

Use c_include() to specify C/C++ headers that must be included when generating C/C++ header output.

cpp_include()

cpp_include('<a>', '<b>', ...)

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('<X11/Xlib.h>', '<X11/extensions/XShm.h>')
end)

Generates the following C header:

#ifdef __xwindows__
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#endif

restrict()

restrict(Function)

Use restrict() to prevent the FDL parser from outputting anything contained within Function.

Consider a situation where an FDL file has a dependency on other FDL files. Using restrict() as a wrapper will prevent the included definitions from appearing in the generated output, as in this example:

restrict(function()
   loadFile(glPath .. 'common.fdl')
   loadFile(glPath .. 'common-graphics.fdl')
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:

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:

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 sub-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:

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 FDL method declared in the source code of the class. The parser will use this information when building viable function calls for the methods.