We have 2 APIs, the C++ and the C API. Both are explained in this page.
C++ API
The C++ API is part of the Generator.hpp header. Most
functionality is contained under the UTTE::Generator class,
which is used to parse a document.
Loading a document
To load a document, initialise the UTTE::Generator class
using the default constructor, then call the loadFromFile
or loadFromString functions like this:
UTTE::Generator generator{};
generator.loadFromFile("test.tmpl");The loadFromFile and loadFromString
functions both have the same signature. They receive a string which will
be the file location or the buffer to be used.
Both of these functions return an InitialisationResult
struct, which looks like this:
enum InitialisationResult
{
UTTE_INITIALISATION_RESULT_SUCCESS = 0,
UTTE_INITIALISATION_RESULT_INVALID_UTF8 = 1,
UTTE_INITIALISATION_RESULT_INVALID_FILE = 2,
};It is used to check if there were any errors when trying to initialise the generator.
Parsing a document
Once a document is loaded, you can parse it with the
parse member function. It returns a struct of type
ParseResult, which looks like this:
struct ParseResult
{
ParseResultStatus status;
const std::string* result;
Variable _internalBuffer;
};The resulting string is the result member, which is a
pointer to an std::string.
The status member is of type
ParseResultStatus, which looks like this:
enum ParseResultStatus
{
UTTE_PARSE_STATUS_SUCCESS = 0,
UTTE_PARSE_STATUS_OUT_OF_BOUNDS = 1,
UTTE_PARSE_STATUS_EXPECTED_TERMINATION = 2,
UTTE_PARSE_STATUS_INVALID_VALUE = 3,
UTTE_PARSE_STATUS_INVALID_TYPE = 4,
};It can be used to do error checking.
Finally, the _internalBuffer variable contains rubbish
intermediate internal data. You should not use it.
Adding additional variables and functions
You can add additional variables and functions by calling the
pushVariable and pushFunction members,
respectively.
Variables
The pushVariable function takes a constant reference to
a Variable struct and a name for the variable. The
Variable struct looks like this:
struct Variable
{
std::string value;
VariableTypeHint type = UTTE_VARIABLE_TYPE_HINT_NORMAL;
ParseResultStatus status = UTTE_PARSE_STATUS_SUCCESS;
bool _internalBoolComment = false;
};Its members are the following:
value- The value of the variableVariableTypeHint- A hint to the type of the variablestatus- The status of a variable when returning from a function. Used to tell the parser to shut down on error_internalBoolComment- Whether to treat the variable like a comment. Do not use
Tip
When returning an error from a function, use the
UTTE_ERROR(x) macro. It only takes a single argument, which
is the ParseResultStatus enum.
The VariableTypeHint enum looks like this:
enum VariableTypeHint
{
UTTE_VARIABLE_TYPE_HINT_NORMAL = 0,
UTTE_VARIABLE_TYPE_HINT_ARRAY = 1,
UTTE_VARIABLE_TYPE_HINT_MAP = 2,
UTTE_VARIABLE_TYPE_HINT_FUNCTION = 3,
};A variable set to UTTE_VARIABLE_TYPE_HINT_NORMAL is a
simple string.
The pushVariable function also returns a reference to a
Function struct, which was pushed to the function registry,
as variables are treated as functions.
The Function struct looks like this:
struct Function
{
std::string name;
std::function<Func> function = [](std::vector<Variable>&, UTTE::Generator*) -> Variable{ return {}; };
};The name member is the name of the function, while the
function member is the actual function pointer to be
called. It is of type std::function<Func>, where
Func is a type definition of
Variable(std::vector<Variable>&, UTTE::Generator*).
Tip
If you want to change the value of a variable from a custom function,
use the UTTE_VARIABLE_SET_NEW_VAL macro like this:
UTTE_VARIABLE_SET_NEW_VAL(key, a, a.first, UTTE_VARIABLE_TYPE_HINT_NORMAL);In this example, the arguments are like this:
key- TheFunction&returned bypushVariablea- A struct to pass to the internal lambda through the capture, in this case anstd::paira.first- The new value of the variableUTTE_VARIABLE_TYPE_HINT_NORMAL- The new type of the variable
Functions
Functions can be added by calling the pushFunction
function. It takes a constant reference to a Function
struct and returns a reference to itself, but in the function
registry.
Updating arbitrary variables and functions
Generally, it's preferable to keep references to the values returned
by pushVariable and pushFunction, but
sometimes it's not possible. The setVariable and
setFunction members of Generator can be used
to update a function or variable from a name.
They both return void and their first argument is the name of the
function or variable as a string. The second argument is a
const Variable& or a
const std::function<Func>&, for
setVariable and setFunction respectively.
Creating arrays and maps
To push array and map variables to the generator, use the
makeArray and makeMap static member functions
of the Generator class. They take a
const std::vector<std::string>& and
const std::map<std::string, std::string>&
respectively and both return a Variable struct that can be
used directly with pushVariable
Returning arrays and maps from custom functions
When in a custom function, it may be convenient to return an array or map. This, however, requires you to store the given map or array beyond the lifetime of the given function. Instead of making you create your own custom registry to store these variables, the parser can create and store them for you automatically.
The UTTE::Generator::requestArrayWithGC and
UTTE::Generator::requestMapWithGC functions return a
reference to an array and map, respectively. The underlying variables
have the same lifetime as the generator.
Getting the internal functions registry
Some special functions may need more control over what functions are
part of the registry. For systems that want tighter security, this may
even mean removing components of the standard library. To get full
access to the functions registry call
UTTE::Generator::getFunctionsRegistry.
It returns a reference to an array of
UTTE::Function.
C API
The C API has a lot of overlap with the C++ one, therefore, make sure to read through the entire C++ API part of the page, before continuing to read about the C API. This guide will only cover parts of the API that are different from the C++ one.
Most functions that are part of the C API are the same as the one in
the C++ API, except that the :: operator is replaced by a
_, making the C++ function
UTTE::Generator::loadFromFile into the C function
UTTE_CGenerator_loadFromFile.
Creating the generator
In the C API, the generator is created by calling the
UTTE_CGenerator_Allocate function. It returns a pointer of
type UTTE_CGenerator. Since C generators are allocated on
the heap, this handle needs to be freed using the
UTTE_CGeneratorFree function.
All functions that are related to the generator take a
UTTE_CGenerator* as their first argument.
The UTTE_CParseResult
struct
The C alternative to the UTTE::ParseResult struct is
UTTE_CParseReult. It is returned by
UTTE_Generator_parse and looks like this:
struct UTTE_CParseResult
{
UTTE_ParseResultStatus status;
const char* result;
};The only significant difference is the replacement of
utte_string with const char* for the
result member
Pushing variables and functions
Variables
To push a variable, call UTTE_CGenerator_pushVariable.
It takes a pointer to the generator, as well as a pointer to a
UTTE_CVariable struct and a name as a
const char*.
The UTTE_CVariable struct is the alternative of the C++
UTTE::Variable struct, and looks like this:
struct UTTE_CVariable
{
const char* value;
UTTE_VariableTypeHint type;
bool bDeallocate;
UTTE_ParseResultStatus status;
};The difference is that value is now a
const char* and that a new member called
bDeallocate is added. If the value member is
heap-allocated, you can set bDeallocate to automatically
free it after use when calling the following functions:
UTTE_CGenerator_pushVariableUTTE_CGenerator_tryFreeCVariable
The pushVariable functions a
UTTE_CFunctionHandle*, which is a handle to a
UTTE::Function in the functions' registry. The following
functions take it:
UTTE_CGenerator_modify- Given a Function handle and aUTTE_CFunctionstruct as arguments, will change the underlying function to the data of theUTTE_CFunctionargument. If thenamefield of theUTTE_CFunctionstruct is set to an empty string, the name of the function will not be changedUTTE_CGenerator_getName- Given a Function handle, returns the name of the function
The UTTE_CFunction struct is the C alternative of the
UTTE::Function struct and looks like this:
struct UTTE_CFunction
{
const char* name;
UTTE_CFunctionCallback function;
bool bDeallocate;
};If name is set to a heap-allocated value, setting
bDeallocate to true will free it in the
following functions:
UTTE_CGenerator_modifyUTTE_CGenerator_pushFunction
The function field is of type
UTTE_CFunctionCallback, which has the following signature:
UTTE_CVariable()(UTTE_CVariable*, size_t size, UTTE_CGenerator*).
Functions
Functions are pushed using the
UTTE_CGenerator_pushFunction function. The second argument
needs to be a pointer to a UTTE_CFunction struct. It
returns a UTTE_CFunctionHandle*, like
pushVariable.
Setting variables and functions
The UTTE_CGenerator_setVariable and
UTTE_CGenerator_setFunction functions allow the user to
iterate the internal generator registry for a function using a name. If
found, its data is replaced by the given UTTE_CVariable*
and UTTE_CFunctionCallback arguments, respectively.
Both functions return true if a function is found and
false if not.
UTTE_CGenerator_setVariable will deallocate the
value field of the UTTE_CVariable struct if
the bDeallocate boolean is set to true.
Generating arrays
To generate an array, call the UTTE_CGenerator_makeArray
function. It takes a char** for the array and a
size_t for its size.
It returns a UTTE_CVariable struct with a heap-allocated
value. The bDeallocate member is set to
true, so passing it to
UTTE_CGenerator_pushVariable will free the memory
automatically. Alternatively, use
UTTE_CGenerator_tryFreeCVariable to free it manually.
Generating maps
To generate a map, call the UTTE_CGenerator_makeMap
function. It takes a UTTE_CPair* for the array and a
size_t for its size.
The UTTE_CPair struct stores a key and a value and looks
like this:
struct UTTE_CPair
{
char* key;
char* val;
};It returns a UTTE_CVariable struct with a heap-allocated
value. The bDeallocate member is set to
true, so passing it to
UTTE_CGenerator_pushVariable will free the memory
automatically. Alternatively, use
UTTE_CGenerator_tryFreeCVariable to free it manually.