5 Design
This section describes the implementation of CamlTemplate; you don't need to read it
unless you are interested in developing CamlTemplate itself.
CamlTemplate is a fairly straightforward implementation of the Interpreter1 pattern. It uses ocamllex and ocamlyacc to parse
template source code, generating an abstract syntax tree consisting of objects; these
objects do the work of interpreting the template.
5.1 The Abstract Syntax Tree
There are two kinds of objects in the abstract syntax tree, represented by the class type
statement and the virtual class expression. Statements produce output;
expressions have values. A template consists essentially of a list of statements (each of
which may contain one or more lists of statements, e.g. to represent the body of a loop,
or the branches of a conditional); when merged, the template iterates over its statements,
calling each statement's interpret method in turn.
5.2 The Parser and Lexer
The parser is very straightforward, and probably needs no explanation if you are familiar
with ocamlyacc. The lexer, on the other hand, is rather complicated, mainly because of
the absence of delimiters around literal text in a template language; this requires us to
assume that we are reading literal text until we get to something that looks like template
language syntax.
The CamlTemplate lexer therefore maintains some state to indicate which sort of
environment is being tokenised. The variable cur_mode keeps track of whether the
lexer is currently in literal text, an expansion or a statement. For the most part,
instead of using specialised rules, the lexer uses a single rule containing all the
patterns that are meaningful in tokens; once it has matched a pattern, it decides what to
do depending on its current mode.
5.3 Scopes
Scopes in CamlTemplate are roughly patterned after those in JavaScript. There are two
writable scopes, template scope and macro scope; the template model is an additional
read-only scope. Assignment and lookup of values in scopes are encapsulated in the scope class in ctScope.ml.
5.4 Thread Support
Since parser and lexer both maintain some global state, and since template caches are
modifiable, they are all protected by a global mutex (in ctCache.ml) when
thread support is linked in.