Overview
Atlassian Sourcetree is a free Git and Mercurial client for Windows.
Atlassian Sourcetree is a free Git and Mercurial client for Mac.
TLC
Tiny Lua-equipped C-preprocessor is a small integrated C/C++ preprocessor that acts as a compile-time scripting interface for code generation.
TLC works closely alongside the Lua scripting language and is written in Java.
TLC can also be extended to implement specific Java functionality as well.
Inclusion
There are various ways to script pre-processing. Initially TLC will include inline, side-by-side, and imported pre-processor scripts.
Inline
Inline scripts are Lua scripts included directly in the C++ source file. While arguably messy, these scripts are editable directly within the code.
Inline Lua is just performed using the Lua directive. If defining functions, for example, the closure will return nothing and will essentially eliminate the call from the output source (see the below note under Lua Directive).
Side-by-Side
Side-by-Side inclusion occurs when a
.c or
.cpp file has an adjacent
.c.lua or
.cpp.lua file, respectively. The Lua script is automatically imported into the state before the C++ source is preprocessed.
Imported
Lastly, scripts can be imported using the
@import directive (see below). Import scripts can be found given inclusion directories passed along the command line.
Tricky Business
The import system is just a translation of built-in Lua keywords. Include directories passed along the command line are simply added to the module path (yes,
? is still valid), and
@import simply
require's the script.
Directives
There are two directive formats that are associated with TLC and activate two different portions of the project.
Function Directive
All function directives refer to a specific Java functionality.
Some examples:
@import "myScript" // Invokes the registered Java handler to import a script @define var val // Invokes the registered Java handler to create a variable
The two directives above will invoke specific Java (not Lua) classes to handle the code.
Lua Directive
The Lua directive refers to specific Lua functionality and executes arbitrary Lua code. It works similarly to a macro, but instead is replaced by the return value of the closure.
There are two forms of the Lua directive; return form and closure form. The return form,
$value, prepends
return to the beginning of the statement. The closure form,
${statement}, simply executes Lua and doesn't necessarily have to return values.
$value is functionally equivalent to
${return value}.
NOTE: If 0 values are returned from a closure, the directive is simply deleted from the output source. If more than one value is returned, the rest are discarded and only the first is used as a replacement.
NOTE: The return form allows for tricky use of meta-methods as it calls
tostringon all values. Developers can use this to their advantage by writing meta-method replacements for tables to do some neat stuff without having to use
${return someCode()}.
See More Tricky Business for an example
For instance, if we have the Lua function:
function appendif(test, append, inp) if test == true then return inp .. append else return inp end end
And then the equivalent C++ code
#include <iostream> // Debug mode? @set debug true void output_d() { std::cout << "Debug mode is ON"; } void output() { std::cout << "Debug mode is OFF"; } int main() { ${return appendif(debug, "_d", "output")}(); // Evaluates to output_d(); return 0; }
The above would effectively output
Debug mode is ON:
It also recognizes Lua tables; the following would also be acceptable:
-- Lua tbl = {} function tbl.appendif(...) -- ...
// C++: ${return tbl.appendif(debug, "_d", "output")}();
More Tricky Business
The note above mentions that
tostring is called on all replacement-type directives. This can lead to some interesting uses of meta-methods; the following is an example.
Lua:
mt = {} mt.__tostring = function() return "\"Woooo!\"" end woostring = {} setmetatable(woostring, mt)
C/C++:
#include <iostream> int main() { // Even though woostring() is a table, its // __tostring() meta-method allows it to // be used with TLC's replacement-type Lua directive. printf("The programmer says \"%s\"", $woostring); return 0; }
Processing
Processing the files is defined very clearly and how you would (hope) to expect it to.
Order and Scope
Processing is handled in a linear fashion, and variables do not persist between files. Yes, TLC (as of this writing) does not acknowledge
#include directives.
Evaluation of Invocation/Replacement Directives
All directives working with Lua (i.e. Replacement Directives and Invocation Directives) are evaluated as lua instead of parsed by Java. Invocation directives simply evaluate the code, whereas replacement directives evaluate and return the code.
For replacement directives, any code that cannot be successfully parsed with a
return pre-pended onto the raw string will need to be placed into a function using one of the placement methods listed above.
Caveats
The golden rule of TLC is that it should be run before the C preprocessor is ever invoked.
License / Disclaimer
This code is provided 'as-is' with no warranty whatsoever. Use it at your own risk.
TLC cannot be distributed or sold (including bundled with any software) neither in source or binary form. All other reproductions, communications, modifications, enhancements, hacks or uses of the code are permitted with credit back to the (this) original GitHub repository. If you do something cool with it, I ask that you show me/submit a pull request (please!). All limitations (or lackthereof) are only applicable to the fullest extent as the referenced supporting 3rd party libraries allow, respectively.
The views expressed in snarky (or anything synonymous) comments cannot be used against the original Author(s).