Twing Internals

Twing is very extensible and you can easily hack it. Keep in mind that you should probably try to create an extension before hacking the core, as most features and enhancements can be handled with extensions. This chapter is especially useful for people who want to understand how Twing works under the hood.

How does Twing work?

The rendering of a Twig template can be summarized into three key steps:

  • First, the lexer tokenizes the template source code into syntactic tokens (the token stream);
  • Then, the parser converts the token stream into a tree of nodes (the Abstract Syntax Tree);
  • Lastly, the AST is executed to render the template.

Tokenization

The lexer tokenizes a template source code into a token stream. Each token is an instance of twig-lexer’s Token and the stream is an instance of TwingTokenStream.

You can convert a source code into a token stream by calling the tokenize() method of an environment:

const tokenStream = environment.tokenize(createSource(identifier, source));

Parsing

The parser converts the token stream into an AST (Abstract Syntax Tree), or a node tree (an instance of TwingTemplateNode).

You can convert a token stream into a node tree by calling the parse() method of an environment:

const ast = environment.parse(stream);

Execution

The last step consists ar executing the AST, passing it an execution context (an instance of TwingExecutionContext), and pipe the result to a writable stream

You can execute the AST by calling the execute() method of the AST node:

const outputBuffer = createOutputBuffer();

// outputBuffer.outputStream is a readable stream so it can be piped into any writable stream
outputBuffer.outputStream.pipe(process.stdout);

const output = ast.execute({
    context: {
        hello: 'world'
    },
    outputBuffer
});