中文 | English
It's designed to be used in ACL (Access Control List) systems, where you need to check if a user has access to a resource.
- Literals: string, int, float, bool, nil, list, and map
- Nested lists/maps, plus trailing commas
- Comments:
//and nested/* ... */ - Context lookup with
@path, including quoted field names, integer indexes, negative indexes, computed path segments, and nested@access - Postfix access on any primary expression with
.field/.index - Operators:
!, unary-,+ - * / %,== != < > <= >=,in,&&,||,??, and?: insupports substring, list membership/subset, and map key lookup- Missing access resolves to
nil - Bare identifiers are string values outside
@, and field names inside@ - Default arithmetic keeps exact integer division when possible and promotes to float when needed
- Optional advanced arithmetic extends
+/-to strings, lists, and maps
(@record.published || @record.owner == @req.user.id) // Normal case
|| // Or operator
(@req.user.role == 'admin' || @req.user.id in @record.granted) // Special caseLet's break it down:
@req.user.role == 'admin': Check if the user has the role ofadmin.@req.user.id in @record.granted: Check if the user's id is in thegrantedlist of the record.@record.published: Check if the record is published.@record.owner == @req.user.id: Check if the record's owner is the user.
The above example is a simple ACL system that checks if the user has access to a record.
More language details can be found in LANG.md.
- JSON is supported in the default build
- YAML and TOML are available as optional input backends
- When a backend is compiled in, the CLI can force it with
--json,--yaml, or--toml
- Reads the context from
stdinand the expression from argv --check/-cexits with code0for truthy results and1for falsy results--astprints the parsed AST instead of evaluating it--version/-Vprints the version--help/-hprints usage
- Parse with
Expr::try_fromor cachedExpr::parse_cached_arc - Evaluate with
Expr::eval - Inspect required context names with
requested_ctx - Check whether an expression is context-independent with
is_ctx_independent
- WASM via
wasm-bindgen(docs) - C shared library (docs)
- Python module via PyO3 (docs)
- The library also supports
no_std(withalloc) whenstdis disabled
// Parse expr
let expr = "@req.user.name in 'foobar' && @files.0.published == true";
let expr = Expr::try_from(expr)?;
// Construct context
let ctx_names = expr.requested_ctx(); // ["req", "files"]
// You can construct the context indeed, but we use json! for simplicity
let ctx = json!({
"req": {
"user": "foo"
},
"files": [
{
"name": "file1",
"published": true
}
]
});
// Eval
let result = expr.eval(ctx.into())?; // Val::Bool(true)
match result {
Val::Bool(b) => {
assert!(b);
}
_ => {
panic!("unexpected result");
}
}echo '{"req": {"user": {"role": "admin"}}}' | cargo run -- '@req.user.role == "admin"'
# Check mode (exit code 0/1)
echo '{"x": 1}' | cargo run -- --check '@x == 1' && echo ok
# Dump AST
echo '{}' | cargo run -- --ast '1 + 2'make wasm # WASM package → pkg/
make ffi # C shared lib → target/release/libqcl.so
make python # Python module → installed into active venvSee docs/ for detailed binding documentation.
Apache-2.0 lollipopkit
