Languages & compilers

XPress: A Simple Truth Expression Language

Rules written as strings, compiled once into .NET expression trees, with variables bound at runtime.

On this page · 5 sections

The short version

  • XPress compiles a boolean expression written as a string, for example in a JSON or XML value, into a .NET expression tree.
  • Compile returns a result with a Compiled flag and a Code predicate, Func<XpressRuntimeContext, bool>, which receives the variables at runtime.
  • It supports int32, float, string and boolean operands, null checks, arithmetic, not, the relational operators eq to le, and and and or.
  • Compiling is the expensive step and happens once. The compiled predicate can be cached and reused.
  • It is pure C#, published on NuGet under the MIT license.

Background#

How many times you needed a quick, simple method to create expressions in a Json or XML element value. and you wished there were an easy way to create dynamic expressions at compile time as a literal string to be compiled and evaluated at runtime using the same powerful CLR. Well, I have!

The need for string expressions that can be simply expressed at compile time by engineers or non-engineering business or support team, has been a recurring theme through out my career. Whether its is business rules, business teams needs to modify it and change it frequently at runtime. or operation rules that devops team would like to control at runtime without the need to make a new deployment.

XPress

Goals#

So, I rolled up my sleeves and created XPress. It came handy in many situations and i used it in different product and solution. I had a few goals in mind when I designed XPress:

  • Simple, yet powerful.
  • Contained as possible, as little dependencies as possible.
  • Few to zero configurations.
  • Purely written in C# and .net.
  • Fast, and efficient.
  • Generates an optimized cacheable .net expressions.
  • Support all truth operators (Binary, Unary, Relational, and Conditional).
  • Support basic data types int32, string, boolean, float.
  • Support variable binding at runtime.
  • Ability to check on null-ability.

How it works?#

NuGet NuGet License

powershell
Terminal window
PM> Install-Package XPress

XPress is simple, all you have to do after installing XPress package using nuget manager, is instantiating XpressCompiler, author XPress expressions, compile it, and execute it. here is a simple XPress sample code:

C#
XpressCompiler _compiler = XpressCompiler.Default;
// Create and Compile Expression
var expression = "x gt y*2";
var compilationResult = _compiler.Compile(code);
// Create XpressRuntimeContext object with variable names and values
XpressRuntimeContext runtimeCtx = new XpressRuntimeContext() { { "x", "10" }, { "y", "9" } };
// Call compiled Func with runtime context
var result = compilationResult.Code(runtimeCtx);

As you can see, XPress language doesn’t need much. very little configuration to start and you’re good to go. If you notice I used XpressCompiler.Default a singleton compiler instance can be used quickly to compile expressions. But a compiler instance can be always instantiated through constructor.

C#
XpressCompiler _compiler = new XpressCompiler();
class-diagram

The compiler class offers a single method Compile(string) taking an xpress expression and return a compilation result. The XpressCompilationResult object offers a boolean flag Compiled to indicate the success or failure of the compilation process, and a Log object of type ILogReader which can be used to get status on compilation process and debug the result. A particularly useful pattern after compilation process is to check the HasErrors flag, if true GetErrorMessages() and print it or log it.

C#
if (compilationResult.Log.HasErrors)
{
var errors = compilationResult.Log.GetErrorMessages();
foreach(var error in errors)
{
Console.WriteLine(error);
}
}

Finally, the compilation result object, will have a Code predicate of type Func<XpressRuntimeContext, bool> that is the optimized compiled .net expression tree for your string expression. it accepts XpressRuntimeContext which is simply a strongly typed dictionary of <string,string> to bind expression’s variables to runtime values. use the XpressRuntimeContext object to pass values to your variables. Code predicate just like any other .net Func can be cached and executed multiple time. the result of execution is a boolean.

Language Features#

Variables#

Variables literals can be used anywhere within an expression. The variable name follows same C# variable literals naming constraints. It Must start with a letter, or _, and it may contain Unicode letter characters, decimal digit characters, Unicode connecting characters, Unicode combining characters, or Unicode formatting characters.

C#
var e = "y eq x+2*2-4/2";

Operands#

XPress supports boolean literals of true and false values, numerical operands of int32 and float decimal values, and string operands. notice how the operand values are defined in the next sample code:

C#
var e1 = "true";
var e2 = "false";
var e3 = "9 gt 10";
var e4 = " 'Ahmed' eq 'ahmed'";

a null operands can also be expressed to compare a string with nothing

C#
var e = " 'Ahmed' ne null";

Binary Expressions#

+, -, *, /, % is supported on numerical operands

C#
var e = "x eq (1+2)";

If + or - operators applied to a string operands it will act as String.concat()

C#
var e = "x eq ('ahmed '+'elmalt')";
Note

Binary operators can’t be applied to mixed types of operands.

Unary Expressions#

At the moment only unary logical operators are supported. not can only be applied to boolean operands or expressions.

C#
// boolean operands
var e1 = "not false";
// boolean variables, the value of x must be set to a boolean value at runtime or runtime error
var e2 = "not x";
// boolean expression
var e3 = "not ('a' eq 'b' and 9 gt 10)";

Notice i applied not to variable x in the previous example. which is acceptable by XPress compiler. it will assume that value of x will be boolean at runtime otherwise it will throw a runtime exception.

Relational Expressions#

The following relational expressions are supported:

  • eq Equal
  • ne Not Equal
  • gt Greater Than
  • lt Less Than
  • ge Greater Than or Equal
  • le Less Than or Equal
C#
var e = "1 eq 4";

Conditional Expressions#

The real power of XPress is composition, you can compose powerful expressions using conditional logical and and or

  • or Logical OR
  • and Logical AND
C#
var e = "false or x lt 2";

Operator Precedence#

  • Parentheses: ()
  • Unary Logical Operators: not
  • Binary Multiplicative Operators: *, / , %
  • Binary Additive Operators: +, -
  • Equality Operators: eq, ne
  • Logical Operators: gt, lt, ge, le
  • Conditional Operators: and, or

XPress is very powerful and can be used to compose sophisticated boolean expressions as strings.

C#
var e = "(x ne null and x+1 gt 10) or (y ne null and (y*(5+1)-2) lt 5)";

What about performance?#

XPress is built to be fast and optimized to generated very efficient .net lambda expressions. the most expensive part of the process as you can expect is the compilation of expressions, but this phase needs to occur once, and the result can be cached for the lifetime of the application. on average Xpress compilation phase takes about ~120ms.

Find more information about XPress on project github repository. I will be blogging more in the future about the internals implementation of the language and its compiler.

XPress is distributed under MIT license. What are you waiting, give it a try and let me know what you think!

Happy Coding!

Share this article

Related posts

3 items
  • Oct 30, 2026 24 min read Software craft

    Inside toolbench: the runtime for small interactive web tools

    The internals of toolbench, the framework behind mainLog's tools: what the runner guards against, why a worker exists only to be terminated, how a graph is laid out and routed the same in every browser, how known answers and size budgets keep tools honest, and why every migration is the identity function.

    frameworksarchitecturetesting
  • Oct 29, 2026 25 min read Software craft

    Introducing toolbench: a tiny framework for interactive web tools

    Toolbench is a small framework for interactive tools in web pages. A tool is a pure function and a JSON manifest, and the runtime builds the form, runs the function and draws the answer. What it is, how it fits together, and the choices behind it, shown with tools that run live on mainLog.

    frameworksarchitectureweb-components
  • Oct 26, 2026 20 min read AI

    What an agent should remember

    Agent memory stores mostly decide what to forget by time: a TTL, or deleting what hasn't been used. In a 90-day scripted scenario, that kept a cancelled booking alive for weeks and stored a restaurant's sentence as the user's preference. Two fields fix both: who wrote the memory, and which event would make it false.

    AI & agentic architecturesai-agentsarchitecture
  • Software craft

    Inside toolbench: the runtime for small interactive web tools

    The internals of toolbench, the framework behind mainLog's tools: what the runner guards against, why a worker exists only to be terminated, how a graph is laid out and routed the same in every browser, how known answers and size budgets keep tools honest, and why every migration is the identity function.

    frameworksarchitecture
    Oct 2026
  • Software craft

    Introducing toolbench: a tiny framework for interactive web tools

    Toolbench is a small framework for interactive tools in web pages. A tool is a pure function and a JSON manifest, and the runtime builds the form, runs the function and draws the answer. What it is, how it fits together, and the choices behind it, shown with tools that run live on mainLog.

    frameworksarchitecture
    Oct 2026
  • AI

    What an agent should remember

    Agent memory stores mostly decide what to forget by time: a TTL, or deleting what hasn't been used. In a 90-day scripted scenario, that kept a cancelled booking alive for weeks and stored a restaurant's sentence as the user's preference. Two fields fix both: who wrote the memory, and which event would make it false.

    ai-agentsarchitecture
    Oct 2026

Comments