Browse files

sample and documentation updates, bug fixes

imported from personal svn:
* added cpp reflection sample
* added nest indentation sample
* added $< line slurp
* added utils module
* rst documentation updates
  • Loading branch information...
kevinic committed Apr 11, 2013
1 parent e6748ed commit 1112a5cac5cb0a9d9d6d339b16bcb1f3f17bfbb5
@@ -9,3 +9,6 @@ Python API
.. automodule:: texthon.parser
.. _utility_module:
.. automodule:: texthon.utils
@@ -56,22 +56,25 @@ contains sample templates. They are:
* `hello <>`_ - a minimal example
* `basic <>`_ - shows basic directive use and template module loads
* `html <>`_ - shows the use of template mixins and parser parameters
* `nest <>`_ - using the :ref:`utility class <utility_classes>` to control indentation
* `cpp <>`_ - templates that generate c++ structs and type information
.. highlight:: none
.. productionlist::
directive: dir_prefix dir_command dir_statement
dir_command: "`* <comment_directive>`" | "!" | "{" | "}" | dir_keyword
dir_keyword: "load" | "import" | "attribute" | "template" | "end"
directive: <dir_prefix> dir_statement
dir_statement: `comment` | exec_stmt | keyword_stmt
exec_stmt: `single_exec` | `compound_begin` | `compound_end`
keyword_stmt: `load_stmt` | `import_stmt` | `attribute_stmt` | `template_stmt` | `end_stmt`
Directives are Texthon control commands and do not affect the output text
directly. A directive is issued on its own line, beginning with the directive
prefix token. The rest of the documentation assumes '#' is the prefix.
Prepend '\' to escape the token. Escapes are only processed at the beginning
Prepend '\\' to escape the token. Escapes are only processed at the beginning
of the line.
Directives operate either in the module scope or the function scope. Only
@@ -99,9 +102,10 @@ lines.
Module and function scope::
Module and function scope:
#* <comment>
.. productionlist::
comment: "*" <comment>
Comments are ignored at the module scope, and emitted as Python #
comments at the function scope to aid debugging.
@@ -115,9 +119,10 @@ Example::
Module scope::
Module scope:
#import <module> as <alias>
.. productionlist::
import_stmt: "import" <module> "as" <alias>
Import a Python module under <alias>. The alias is required. Once imported,
the alias will be available for all definitions in the module.
@@ -132,9 +137,10 @@ Example::
Module scope::
Module scope:
#load <path> as <alias> [(attributes)]
.. productionlist::
load_stmt: "load" <path> "as" <alias> ["(" <attributes> ")"]
Load another template module in the file specified by <alias>. <path> is
resolved relative to the directory of the current file and the list of
@@ -153,17 +159,18 @@ following attributes are available:
#load "lib/file.tmpl" as lib
#load "lib/file.tmpl.html" as html_lib (directive_token = <!--)
#load "lib/file.tmpl.html" as html_lib (directive_token = "<!--")
#load "lib/file.tmpl" as lib (abs)
.. _attribute_directive:
Module scope::
Module scope:
#attribute <name> <expression>
.. productionlist::
attribute_stmt: "attribute" <name> "=" <expression>
Declare a module level variable <name> and assign the result of <expression>.
@@ -185,10 +192,11 @@ Example::
Template Function
Module scope::
Module scope:
#template <name>[(parameters)]
#end template
.. productionlist::
template_stmt: "template" <name> ["(" <parameters> ")"]
end_stmt: "end" "template"
Define a template function within the current module. Anything between
``#template`` and ``#end template`` are evaluated in function scope.
@@ -213,9 +221,10 @@ Example::
Single Statement
Function scope::
Function scope:
#! <python_statement>
.. productionlist::
single_exec: "!" <python_statement>
The entire <python_statement> is copied over to the generated template function
code (with indentation stripped). Write the statement as if it were inside a
@@ -236,10 +245,11 @@ For builtin variables available to the execution statement, refer
Compound Statement
Function scope::
Function scope:
#{ <python_compound_statement>
.. productionlist::
compound_begin: "{" <python_statement>
compound_end: "}"
Compound statements are useful for Python control logic such as ``if``,
``for``, and ``while``. Text lines and other execution statements between
@@ -315,32 +325,52 @@ For complex substituion, surround a Python expression with brackets.
<python_expression> will be evaluated using Python ``eval``, and the result
is used for the substitution.
'\' can be used within the expression to escape the ending bracket '}',
'\\' can be used within the expression to escape the ending bracket '}',
the sum of the values is ${a + b}
lookup result: ${values[key]}
Slurp Placeholder
Slurp Placeholders
Two special place holders, ``$<`` and ``$>`` , are used to discard parts of the
text line; they are useful for whitespace control.
Anything in the text line before ``$<`` is discarded.
A special place holder, ``$<``, is used to slurp whatever text that comes
between it and the next line. It's useful for eating up extraneous newlines.
text line 0
$<text line 1
$<text line 2
will generate the following output::
For instance::
text line 0
text line 1
text line 2
This allows you some flexibility in indenting the source template lines, making
them more readable.
Anything in the text line after ``$>`` is discarded.
this is the end of the file
#end template
will generate a newline after "file" since it's considered part of the
textline, whereas::
this is the end of the file$<
this is the end of the file$>
#end template
will ensure that no newline occurrs at the end of the output.
@@ -353,7 +383,7 @@ Template Execution
When a template function executes, it has a set of variables defined on entry.
Here they are in definition order:
* :ref:`python import <import_directive>` aliases
* :ref:`python import <import_directive>` aliases, including the :ref:`_utils <utility_classes>` autoimport
* :ref:`template load <load_directive>` aliases
* module :ref:`attributes <attribute_directive>`
* other :ref:`template function <template_directive>` names within the same module
@@ -405,3 +435,16 @@ available in any of the three modules.
See the :ref:`html sample <test_samples>` for example usage.
.. _utility_classes:
Utility Classes
Texthon provides some utility classes/functions to aid template formatting.
They are automatically imported under the ``_utils`` module alias.
See the `nest <>`_
sample for templates that rely on the ``Indent`` class to dynamically
control whitespace.
:ref:`More details <utility_module>`.
@@ -70,29 +70,27 @@ If only it wouldn't bug me about that stupid Namemapper extension all the time.
Here's a snippet showing sample template text, along with the code
that evaluates it::
Here's a simple template file, ``hello.tmpl.txt`` ::
import texthon
template = """
#template main(who, count)
$who says:
#{for i in range(0, count):
hello world!
#end template
engine = texthon.Engine()
engine.load_text(template, "@root")
using the script ``texthon`` with the following parameters::
print(engine.modules["@root"].main("someone", 2))
texthon hello.tmpl.txt -P who=someone -P count=2
which prints the following output::
the following output is generated::
someone says:
hello world!
hello world!
For an example that's closer to a real-world scenario, `these templates <>`_
demonstrate the use of Texthon to write C++ object reflection code: a task that
would normally require tedious copy-and-pasting and/or C++ template/macro black
No changes.
@@ -0,0 +1,55 @@
#include "rtt.h"
#include <stdio.h>
using namespace game;
void print_r(unsigned int level, char const* name, rtt::typeinfo_base const* type, void* ptr)
for(unsigned int i = 0; i < level; ++i)
printf(" ");
case rtt::type_traits<float>::id:
printf("%s: %f\n", name, *type->cast<float>(ptr));
case rtt::type_traits<int>::id:
printf("%s: %i\n", name, *type->cast<int>(ptr));
printf("%s:\n", name);
for(unsigned int field = 0; field < type->field_count(); ++field)
print_r(level + 1, type->field_name(field), type->field_type(field), type->get_field(ptr, field));
template <class T> void print(T& obj)
print_r(0, "obj", rtt::get_type(&obj), &obj);
int main(int, char**)
transform trans = {
{0, 0, 1, 0},
{0, 1, 0, 0},
{1, 0, 0, 0},
{0, 0, 0, 1},
object obj; = 100;
obj.xform = trans;
return 0;
@@ -0,0 +1,11 @@
def norm(types):
typeId = 0
for type in types:
type["id"] = typeId
if "extern" not in type:
type["extern"] = False
if "members" not in type:
type["members"] = []
typeId += 1
@@ -0,0 +1,31 @@
namespace texthon {
struct type_lib
int get_typeid(int* t)
return 0;
struct type_info
unsigned int field_count;
void* get_field(void* ptr, unsigned int field);
type_info const* get_field_type(void* ptr, unsigned int field);
virtual void on_visit(void* p)
T* actual = static_cast<T>(p);
template <class T> T* lib::try_cast(type_info const& type, void* ptr)
id =<T>;
Oops, something went wrong.

0 comments on commit 1112a5c

Please sign in to comment.