tinytemplate/instruction.rs
1/// TinyTemplate implements a simple bytecode interpreter for its template engine. Instructions
2/// for this interpreter are represented by the Instruction enum and typically contain various
3/// parameters such as the path to context values or name strings.
4///
5/// In TinyTemplate, the template string itself is assumed to be statically available (or at least
6/// longer-lived than the TinyTemplate instance) so paths and instructions simply borrow string
7/// slices from the template text. These string slices can then be appended directly to the output
8/// string.
9
10/// Sequence of named steps used for looking up values in the context
11pub(crate) type Path<'template> = Vec<&'template str>;
12
13/// Path, but as a slice.
14pub(crate) type PathSlice<'a, 'template> = &'a [&'template str];
15
16/// Enum representing the bytecode instructions.
17#[derive(Eq, PartialEq, Debug, Clone)]
18pub(crate) enum Instruction<'template> {
19 /// Emit a literal string into the output buffer
20 Literal(&'template str),
21
22 /// Look up the value for the given path and render it into the output buffer using the default
23 /// formatter
24 Value(Path<'template>),
25
26 /// Look up the value for the given path and pass it to the formatter with the given name
27 FormattedValue(Path<'template>, &'template str),
28
29 /// Look up the value at the given path and jump to the given instruction index if that value
30 /// is truthy (if the boolean is true) or falsy (if the boolean is false)
31 Branch(Path<'template>, bool, usize),
32
33 /// Push a named context on the stack, shadowing only that name.
34 PushNamedContext(Path<'template>, &'template str),
35
36 /// Push an iteration context on the stack, shadowing the given name with the current value from
37 /// the vec pointed to by the path. The current value will be updated by the Iterate instruction.
38 /// This is always generated before an Iterate instruction which actually starts the iterator.
39 PushIterationContext(Path<'template>, &'template str),
40
41 /// Pop a context off the stack
42 PopContext,
43
44 /// Advance the topmost iterator on the context stack by one and update that context. If the
45 /// iterator is empty, jump to the given instruction.
46 Iterate(usize),
47
48 /// Unconditionally jump to the given instruction. Used to skip else blocks and repeat loops.
49 Goto(usize),
50
51 /// Look up the named template and render it into the output buffer with the value pointed to
52 /// by the path as its context.
53 Call(&'template str, Path<'template>),
54}
55
56/// Convert a path back into a dotted string.
57pub(crate) fn path_to_str(path: PathSlice) -> String {
58 let mut path_str = "".to_string();
59 for (i, step) in path.iter().enumerate() {
60 if i > 0 {
61 path_str.push('.');
62 }
63 path_str.push_str(step);
64 }
65 path_str
66}