Reference¶
The process of building a template into a function has the following steps:
- The template is broken down into blocks (such as literal text and
code execution) that are treated differently. This is handled by
the block parser
. - The resultant sequence of blocks is passed to the
Parser
to be turned into a parse tree. - The parse tree is processed by
code generation
to make Python bytecode.
Compiler¶
The compiler module contains the public interface to the library.
Code generation¶
This module contains the building blocks of the final template function, in the form of bytecode generators.
There are a series of classes in here that are used as nodes in the
code generation tree, and each one implements a make_bytecode()
method.
-
class
margate.code_generation.
Sequence
[source]¶ A sequence of nodes that occur in a parse tree. Elements in the sequence can themselves be sequences (thus forming a tree).
-
class
margate.code_generation.
IfBlock
(condition)[source]¶ The IfBlock generates code for a conditional expression.
This currently only includes literal True and False as expressions, and doesn’t support an else branch.
Block parser¶
The block parser splits a template into the blocks that make it up. There are three different sorts of data in a template that get handled in different ways:
- Literal text, which just gets embedded in the output (but may be skipped or repeated by executing code around it).
- Executable code
- Embedded variable expressions that get expanded into text output.
It’s implemented as a state machine, where the template starts out in
literal text and transitions to a different state depending on whether
it encounters {{
, }}
, {%
or %}
.
-
class
margate.block_parser.
LiteralState
(text)[source]¶ The literal state is the state the block parser is in when it is processing anything that will be included in the template output as a literal. The template starts out in literal state and transitions back into it every time a block is closed.
Parser¶
The parser converts the template language into a usable structured form.
There are two layers to the parsing: breaking the template down into
blocks (which is done by the block_parser
module),
and parsing the expressions that appear in the execution blocks within
the template.
The parser in this module uses a combination of ad hoc parsing,
funcparserlib and
ast.parse. The
top-level rules in the language (if
, for
, endif
etc.) are
handled ad hoc since they are not recursive. However, the expression
that is given as an argument to if
is an arbitrary expression and
parsed
-
class
margate.parser.
Parser
(template_locator=None)[source]¶ The Parser is responsible for turning a template in “tokenised” form into a tree structure from which it is straightforward to generate bytecode.
The input is in the form of a flat list of atomic elements of the template, where literal text (of any length) is a single element, and a
{% %}
or{{ }}
expression is a single element.Figuring out nesting of starting and ending of loops happens within the parser.
-
margate.parser.
parse_expression
(expression)[source]¶ Parse an expression that appears in an execution node, i.e. a block delimited by
{% %}
.This can be a compound expression like a
for
statement with several sub-expressions, or it can just be a single statement such asendif
.Parameters: expression (list) – Tokenised expression.