PATTERN Cited by 1 source
Expression-def triples DSL¶
What it is¶
A boolean-logic DSL built from a single primitive —
[left, op, right] triples — composed via and / or /
not combinators. The universal shape:
Expression :=
| [Field, Op, Value | FieldRef] -- binary expression
| { and: Expression[] }
| { or: Expression[] }
| { not: Expression } -- sometimes included
Op ∈ { "=", "<>", ">", "<", ">=", "<=" } -- often extensible
A Field is typically a "table.column" or entity.attribute
string. A FieldRef distinguishes a reference from a literal — Figma
uses {type: "field", ref: "user.id"} — so ["file.owner_id", "=",
{ref: "user.id"}] means equal to the user's id, vs ["file.status",
"=", "open"] which compares to the scalar string "open".
Why it matters¶
- Minimal core — six binary operators and three combinators is expressive enough for most policy / filter / query workloads.
- JSON-serializable by construction — the entire DSL is plain data (concepts/json-serializable-dsl); any language with a JSON parser can consume it.
- Trivial static analysis — a recursive walk is enough to extract data dependencies, detect logic bugs, or transform the tree.
- Cross-language evaluator parity — Figma reports 2–3 days for a senior engineer to write a new language's evaluator; shared test suites guarantee semantic consistency.
- Composable helpers — wrap common sub-expressions as functions
in the authoring surface (e.g.
isOrgFile(File),teamUserHasPaidStatusOnFile(...)) that returnExpressionDef; this is how Figma scales without losing structural simplicity.
Canonical instances¶
- Figma's permissions DSL —
the
ExpressionDeftype: binary expressions +and+or+not, with{type:"field",ref:"..."}references — canonical instance per the 2026-04-21 article. LiveGraph's originalExpressionDefpredates and inspired this. - Elasticsearch Query DSL —
bool+must/should/must_nottrees over term/range queries. - MongoDB query operators —
$and/$or/$notover field-operator-value documents. - AWS IAM
Conditionblock — structurally similar (operator keys + field-value pairs), though with more embedded semantics.
Design knobs¶
- Binary operators — the six comparison ops are the minimum
useful set; projects add
in,like,exists, regex, set-membership as needed, weighing added expressivity against evaluator complexity + analyzability loss. - Field-reference representation — an explicit wrapper
(
{type:"field", ref:"..."}) is cleaner than inferring by prefix convention; prevents ambiguity when strings are also valid scalars. - Operator extensibility — keeping the set small is a feature; every addition must be implemented in every evaluator.
- Combinator set —
and+oris the minimal boolean basis;notis convenient but can be avoided by transforming (e.g. De Morgan).
Caveats¶
- Arithmetic and function calls don't fit cleanly — can't
express
"file.size > team.quota * 0.9". Either extended with special operators or kept out. - Recursion / loops can't be expressed directly. Most policy/query workloads don't need them; some do (e.g. ReBAC-style "transitively a member of").
- The triples DSL doesn't force the JSON-serializable property — a Lisp-like AST is structurally similar but usually code, not data. Serializability is the follow-on choice (concepts/json-serializable-dsl).
Seen in¶
- sources/2026-04-21-figma-how-we-built-a-custom-permissions-dsl — canonical modern production instance. The article explicitly shows the type definitions and the evaluation function shape.