Skip to content

Commit 36385c4

Browse files
committed
design: Add variable expansion design document
1 parent c054680 commit 36385c4

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

docs/core/design/var_expand.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
layout: doc
3+
title: Variable expansion design
4+
dovecotlinks:
5+
var_expand: variable expansion design
6+
---
7+
8+
# Variable expansion design
9+
10+
Dovecot comes with powerful variable expansion system, which allows constructing reusable text templates.
11+
This has been upgraded since v2.3 to a more flexible systemt .
12+
13+
## Syntax
14+
15+
```
16+
<var> ::= <expression-list>
17+
<expression-list> ::= <expression-list> <expression>
18+
<expression> ::= <VALUE>, "{" <filter-list> "}", "%"
19+
<filter-list> ::= <filter-list> "|" <filter>, <filter>
20+
<filter> ::= <func> <math-list>
21+
<math-list> ::= <math>
22+
<math> ::= <operator> <number>, <operator> <NAME>
23+
<number> ::= "-" <NUMBER>, <NUMBER>
24+
<operator> ::= "+", "-", "*", "/"
25+
<func> ::= <NAME> <arguments>
26+
<arguments> ::= "(" <argument-list> ")"
27+
<argument-list> ::= <argument-list> "," <argument>
28+
<argument> ::= <VALUE>, <NAME>, <number>, <key> "=" <number>, <key> "=" <NAME>, <key> "=" <VALUE>
29+
30+
NAME = string
31+
VALUE = "string" or 'string'
32+
NUMBER = [0-9]+
33+
```
34+
35+
## Design
36+
37+
Internally, everything is stored in a binary-safe string container. There is no other data type internally.
38+
This buffer can be set and unset, and the content can be tagged by filters to be binary or string.
39+
40+
The system uses programs to perform the actual expansion. The given input is always first parsed into a list of programs.
41+
Input that consists from multiple expansions separated by non-expansion strings is split into multiple programs.
42+
Once program is compiled, it can be executed multiple times with different parameters.
43+
44+
Program parameters consists from variable table(s), provider(s) and escape function. A program can be executed with different parameters.
45+
46+
## Parameters
47+
48+
Parameters are provided via `struct var_expand_params`. Variable mappings are provided via `struct var_expand_table` array, which is `VAR_EXPAND_TABLE_END` terminated list of
49+
key-value mappings. Key's value can also be provided by a function.
50+
51+
Providers are used to handle scoped variables, such as passdb, ldap etc. There are also global providers which are always available.
52+
53+
Providers can be provide with `struct var_expand_provider` array which contains prefix and provider function, and is `VAR_EXPAND_TABLE_END` terminated.
54+
55+
It is also possible to provide escape function, which is applied to each %{pipeline} output.
56+
57+
Key functions and providers use the same context.
58+
59+
Key-value tables and providers can also be provided as arrays of arrays, which must be NULL terminated.
60+
Contexts for these must be provided in an array that is `VAR_EXPAND_CONTEXTS_END` terminated.
61+
62+
When these arrays are used, first match wins.
63+
64+
## Filters
65+
66+
Filters are functions that accept input from left side and emit output to right side. They can accept positional and named parameters.
67+
Some filters can start expressions, namely ones that do not require any input.
68+
69+
## Variables
70+
71+
Variables are always considered to be strings. NULL value is considered same as empty value. Variable names are unique, and if table contains
72+
multiple variables with same name, the first is always used.
73+
74+
Variable can exist as parameter to filters or as the first token in expression.
75+
76+
## Output handling
77+
78+
If a program ends up with binary tagged output, the output is automatically hex-encoded.
79+
If there is no key in table or provider, error will occur.
80+
This error can be negated with `default(value)` filter, which clears error.

0 commit comments

Comments
 (0)