Skip to content

Getting Started

Install

dotnet add package Celly

Evaluate an expression

using Celly;

var program = CelEnv.Default.Compile("1 + 2 * 3 == 7");
var result = program.Eval();   // BoolValue.True

Compile parses the expression and plans it into a reusable CelProgram. Programs are immutable and safe to evaluate concurrently from many threads.

Bind variables

Variables come from an activation — a bag of named values supplied at evaluation time. The easiest form is a dictionary; plain .NET types are adapted automatically:

var program = CelEnv.Default.Compile("age >= 18 && name.startsWith('A')");

var result = program.Eval(new Dictionary<string, object?>
{
    ["age"] = 21L,          // long   -> int
    ["name"] = "Alice",     // string -> string
});
// BoolValue.True
.NET type CEL type
bool bool
int, long, short, sbyte int (64-bit signed)
uint, ulong, ushort, byte uint (64-bit unsigned)
double, float double
string string
byte[] bytes
IDictionary map
IEnumerable list
null null

Use the type checker

By default Compile only parses. Declaring variable types lets the checker reject bad expressions before they ever run:

using Celly.Checking;
using Celly.Types;

var env = CelEnv.Create(new CelEnvSettings
{
    Declarations =
    [
        new VariableDecl("age", CelType.Int),
        new VariableDecl("name", CelType.String),
    ],
});

var parsed = env.Parse("age + name");        // parses fine...
var check = env.Check(parsed.Ast!);          // ...but doesn't type-check
// check.Issues[0]: found no matching overload for '_+_' applied to '(int, string)'

Inspect results

Every evaluation returns a CelValue. Pattern match to consume it:

using Celly.Values;

var value = program.Eval(bindings);
var verdict = value switch
{
    BoolValue b => b.Value,
    ErrorValue e => throw new InvalidOperationException(e.Message),
    _ => throw new InvalidOperationException($"expected bool, got {value.Type}"),
};

Errors are values

CEL evaluation never throws for expression-level failures (division by zero, missing keys, overflow). Those come back as ErrorValue — see Errors & Absorption for why that design matters.

Enable extensions

The standard environment covers the CEL spec. Optionals, format, math helpers, and the rest are opt-in libraries:

using Celly.Extensions;

var env = CelEnv.Create(new CelEnvSettings
{
    Libraries = [OptionalsLibrary.Instance, StringsLibrary.Instance, MathLibrary.Instance],
});

env.Compile("optional.of(5).orValue(0) == math.greatest(1, 5, 3)").Eval();  // true

See Extension Libraries for the full catalog.