Type generators

TempLuator supports quite a few basic types. It would be rather tedious to manually define separate function for every single type (nothing special here, just a matter of copy/paste though), especially considering that the user may want to define his/her own types. Therefore, the concept of type generators was born.

A type generator is a function that generates another parametrized functions, which may be assigned to named variables (and when you call one of these variables, actually the corresponding function gets called). This is possible because most type functions are very, very similar to each other. The main difference between separate types is the name of the type. Therefore, all type generators expect the name of the type being generated as a mandatory parameter. Also, each type cosumes its own number of bytes from the input file and has its own way of printing the value of the type. Since there are not many variations of this, all type generators are built around a corresponding data processing function. In order to make the whole process as flexible as possible, a supplementary correcting function may be passed to each type generator. Well, sounds terrible but in fact usage of type generators is much simplier than you may imagine.

/* data processing functions */
_i8(Type, Name, Comment, NumberOfItems)
_ui8(Type, Name, Comment, NumberOfItems)
_i16(Type, Name, Comment, NumberOfItems)
_ui16(Type, Name, Comment, NumberOfItems)
_i32(Type, Name, Comment, NumberOfItems)
_ui32(Type, Name, Comment, NumberOfItems)
_i64(Type, Name, Comment, NumberOfItems)
_ui64(Type, Name, Comment, NumberOfItems)
_string(Type, Name, Comment, NumberOfItems, NoZero)

 
/* type generators */
type_i8(Type, Fn)
type_ui8(Type, Fn)
type_i16(Type, Fn)
type_ui16(Type, Fn)
type_i32(Type, Fn)
type_ui32(Type, Fn)
type_i64(Type, Fn)
type_ui64(Type, Fn)
type_string(Type, Fn)

Data processing functions

These functions do the bulk of the actual processing of data: they print type, name of the instance, comment (if any), and organize arrays if required. Name of each functions of this set consists of three parts: 1) leading underscore 2) "i" for functions that process signed integer data and "ui" for functions that process unsigned integer data 3) bitness of data - 8, 16, 32, or 64.

Here is an example of _ui8() function definition:

function _ui8(typ, nam, comment, num)
if num then inlinearray(typ, nam, comment, num, PrintUI8, 1)
else
StartType(typ, nam)
PrintUI8(ReadBytes(1))
EndType(comment)
end
end

The rest of the functions of this set is very similar to the definition above with the obvious exception that each function has its own file reading parameter (which defines the bitness of the data) and data printinig routine.

The _string() function is a bit different in that it consumes an additional parameter which tells if the string it defines is terminated with zero or not. It is easy to guess that this function is used for special string types like char__() etc.

Type generators

These are actual type generators. All of them expect two parameters. The first one is mandatory and defines the name of the type. This parameter must evaluate to string. The second one is optional. It defines a special correcting function that will be called during execution of the generated type just before the actual data processing.

Naming of the functions of this set is simple and, as usually, consist of three parts: 1) "type_" 2) "i" for signed integer types or "ui" for unsigned integer types 3) bitness of the type (8, 16, 32, 64).

Usage of these functions is very simple:

-- define my own type
MyOwnType = type_ui8("MYTYPE")
 
-- use this type as usual
MyOwnType("MyType", "Wow! This is my own type. Patent pending")
MyOwnType("MyTypeArray", nil, 4)

and the output is

MYTYPE MyType         = 13;                   // Wow! This is my own type. Patent pending
MYTYPE MyTypeArray[4] = { 10, 45, 45, 32 };

Easy, isn't it? Here is an example of a type generator definition:

function type_ui8(typ, fn)
return function(nam, comment, num)
if fn then
local _nam, _com, _num = fn(nam, comment, num)
nam = nam or _nam; comment = comment or _com; num = num or _num
end
_ui8(typ, nam, comment, num)
end
end

Here you can see the intention of the correcting functions for type generators: they let correct name, comment, and number of items before actual data processing takes place. Such function (if given during the type definition) when the type is executed receives the current name, comment, and number of array items, may change them if necessary and retrun the new, changed name, comment, and number of items, which then are passed to data processor. Obviously, this function may perform any processing in addition to changing the parameters. Here are a couple of actual type definitions from the AVI template:

ChunkID = type_ui32("DWORD", function() Str() return "ID" end)
FOURCC = type_ui32("FOURCC", function() Str() end) -- wow! we can use nameless type instances! ChunkID ChunkID() ChunkID(nil, "wow!") ChunkID "This will be ignored anyway"

The first definition let us use the ChunkID type without the name of the current instance and all instance names are set to "ID" by the correcting function. The second definition does not change anything but sets the current output mode to Str().