This utility is used to generate boilerplate code for CoppeliaSim Lua callbacks. It reads an XML file containing a description of the callbacks, script functions, and enums, and it produces documentation, C++ source and header files, and other stuff:
graph LR;
IN["Callbacks specification (XML)"]-->F[simStubsGen];
F-->OUT1[HTML API documentation];
F-->OUT2[C++ stubs for Lua callbacks];
F-->OUT3[More...];
Additionally, it can parse special comments in the lua files to generate similar documentation for pure Lua functions. See below.
- Python interpreter (3.8 or greater)
- xsltproc (available via
apt
/brew
/choco
) - (optional) Python package 'xmlschema' (
python3 -m pip install xmlschema
)
For CMake, use the coppeliasim_generate_stubs
CMake macro, e.g.:
coppeliasim_generate_stubs(
${CMAKE_CURRENT_BINARY_DIR}/generated
XML_FILE ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.xml
LUA_FILE ${CMAKE_CURRENT_SOURCE_DIR}/simOMPL.lua)
The XML_FILE
parameter is mandatory.
The LUA_FILE
is optional; passing a LUA_FILE
parameter will also parse the lua comments for generating documentation and calltips.
The tool can also be invoked standalone (invoke generate.py --help
for a description of command line options).
The callbacks.xml
files has this structure:
<plugin name="PluginName" author="[email protected]">
<description>An example plugin</description>
<!--
put <command>, <script-function>, <enum> or <struct> elements here
-->
</plugin>
Each <command>
or <script-function>
element serves both as a declaration and documentation for a Lua command/callback of the plugin. It can contain a description of the command itself, and several input and output parameters, with annotated type and documentation.
See below for how to specify parameters.
Example:
<command name="test">
<description>Perform some computation with the given parameters.</description>
<params>
<param name="a" type="int">
<description>An integer argument</description>
</param>
<param name="b" type="string">
<description>An string argument</description>
</param>
<param name="c" type="table" item-type="float">
<description>A vector of floats</description>
</param>
</params>
<return>
<param name="x" type="float">
<description>A float return value</description>
</param>
<param name="y" type="string">
<description>A string return value</description>
</param>
</return>
</command>
The name
attribute is mandatory.
The tool will generate C++ code:
- a
test_in
data structure for the input arguments - a
test_out
data structure for the output arguments
In C++ code, the corresponding callback must be implemented:
void test(SScriptCallBack *p, const char *cmd, test_in *in, test_out *out)
{
...
}
If name
is not a valid C identifier (e.g. some reserved keyword, such as "union"), an additional c-name
attribute can be specified with the name for the C symbols.
Similarly, the names of the _in
and _out
data structures can be changed with the c-in-name
and c-out-name
attributes of <command>
.
The <struct>
element will generate a C++ struct, and documentation for the data structure. It can contain a description of the data structure itself, and several parameters, with annotated type and documentation.
See below for how to specify parameters.
Example:
<struct name="mystruct">
<description>Extra options for the curve creation function <command-ref name="addCurve"/>.</description>
<param name="a" type="int" default="1">
<description>an integer field</description>
</param>
<param name="b" type="bool" default="true">
<description>a boolean field</description>
</param>
</struct>
See below for how to specify parameters.
Then in C++ it can be used like this:
mystruct x;
x.a = 3;
x.b = false;
or passed as parameter to commands.
The <enum>
element will generate a C++ enum, and documentation for that. It can contain several <item>
elements.
The element <item>
must have a name
attribute, and an optional value
attribute to explicitly specify a value. If such value is not given, it will be determined by adding the <item>
position (0-based) to base
.
Example:
<enum name="myenum" item-prefix="foo_" base="32000">
<item name="alpha" />
<item name="beta" />
<item name="gamma" />
</enum>
It will generate an enum named myenum
with items sim_plugname_foo_alpha
, sim_plugname_foo_beta
, sim_plugname_foo_gamma
.
The enum items will be available also in Lua as simPluginName.myenum.alpha
, simPluginName.myenum.beta
, simPluginName.myenum.gamma
.
The <param>
element can have the following attributes:
name
: (mandatory) the name of the field. Cannot start with an underscore, and must be a valid C and a valid Lua identifier.type
: (mandatory) the type of the field (int
,float
,double
,bool
,string
,table
, or the name of a struct).nullable
: iftrue
, the fields accepts also a nil value; the C++ type will be wrapped into astd::optional
(only valid forint
,float
,double
,bool
,string
).default
: the default value of the field (no more fields without default value should follow); in case of tables specify a list of values as{1, 2, 3}
; in case of strings, the string value must be enclosed by"
s, but the"
must be escaped as"
, i.e.:default=""some value""
, or single quotes must be used in the XML attribute, i.e.default='"some value"'
.skip
: iftrue
, the value will be left on the stack; no other fields not marked asskip
should follow.
If type
is table
the following attributes are valid:
item-type
: indicates the tape of an item in the table (int
,float
,bool
,string
).size
: size of the table; can be either a fixed size (e.g.:3
), or a range (e.g.:0..1
), where the upper bound can be*
to indicate unbounded, e.g.1..*
.
The <description>
elements can contain basic HTML markup elements, such as <br>
, <sub>
, <sup>
, <em>
, <strong>
, <ul>
, <ol>
, <li>
, <code>
, and any special cross-referencing elements described below.
The <description>
element of the various items can reference other items in the document, via the tags:
<command-ref>
: reference to a command<script-function-ref>
: reference to a script function<enum-ref>
: reference to an enum<struct-ref>
: reference to a struct
The name
attribute is mandatory.
Example:
<description>This command computes a value based on the result of <command-ref name="foo" /></description>
The above elements can be contained also in a <see-also>
node child of the <command>
or <script-function>
elements. Those will render in the apposite "see also" section of the documentation.
Example:
<command name="addCurve">
<description>Adds a curve to a plot widget.</description>
<see-also>
<enum-ref name="curve_type" />
<enum-ref name="curve_style" />
<struct-ref name="curve_options" />
</see-also>
<params>
<param name="handle" type="int">
<description>ui handle</description>
</param>
<param name="id" type="int">
<description>widget id</description>
</param>
<param name="type" type="int">
<description>type of the curve. see <enum-ref name="curve_type"/>.</description>
</param>
</params>
<return>
</return>
</command>
Elements <command>
, <script-function>
can also have categories.
Commands in the same category will automatically have the "see also" section populated with cross-reference to other items in the same category.
A <category>
element with the indirect
attribute equal to true
will cause that command to reference other commands in that category, but not vice-versa.
Example:
<command name="addCurveTimePoints">
<description>Adds time points to the specified curve of the plot widget.</description>
<categories>
<category name="plot" />
<category name="widgets" indirect="true" />
</categories>
...
</command>
As plugins can provide additional functions via lua files, special comments can be added to lua files to generate a similar documentation (html reference, calltips, etc...).
Comments should start at the very beginning of a line, and are in the form:
--@key value...
Function name and description: (must be the first line of a block)
--@fun <function-name> [description]
Function arguments and return values:
--@arg <type-specification> <parameter-name> [description]
--@ret <type-specification> <parameter-name> [description]
where <type-specification>
can be a string with the type (int
, float
, bool
, string
, table
, table.int
, table.string
, etc...) or an extended type specification in the form {key1=value1,key2=value2}
where the key names are the same as the XML attributes of <param>
(described above) whose -
character is replaced by _
.
Categories:
A list of categories, separated by comma (spaces are ignored)
--@cats <category> [, <category>] ...
Example:
--@fun getPathStateCount get the number of states in the given path
--@arg int taskHandle the handle of the task
--@arg table.float path the path, as returned by simOMPL.getPath
--@ret int count the number of states in the path
--@cats path, state
function simOMPL.getPathStateCount(taskHandle,path)
...
end
Another example, using extended type specification:
--@fun drawPath draw a solution path for the specified motion planning task (as lines)
--@arg int taskHandle the handle of the task
--@arg table.float path the path, as returned by simOMPL.getPath
--@arg float lineSize size of the line (in pixels)
--@arg {type=table,item_type=float,size=3} color color of the lines
--@arg int extraAttributes extra attributes to pass to sim.addDrawingObject
--@ret table.int dwos a table of handles of new drawing objects
--@cats path, drawing
function simOMPL.drawPath(taskHandle,path,lineSize,color,extraAttributes)
...
end
See simExtSkel for an example of a CoppeliaSim plugin using this framework.