I’ve been working recently on a new project, Jello, which I intend to be an easy to use expression/rule evaluator, and has just hit a useable-though-lacking-in-features state.
I wanted Jello to be really simple to use, and think I achieved that. Before I began writing Jello I tried a number of different approaches, including using embeddable languages such as Boo or IronPython, parser generators such as Irony, and expression evaluators such as NCalc. I found that for my needs, to evaluate simple expressions, the embeddable languages were just overkill; parser generators worked well, but I had to write a lot of boilerplate each time to specify the core of the language; and the expression evaluators didn’t offer the flexibility I wanted; and so decided to roll my own. The result is a compact, simple and easy to use and (will be) highly configurable.
Typical use cases could be:
- Decision/underwriting rules (I’ve used this in a document generator to allow users to specify criteria to determine if a part of a document is included or not. I’ve also implemented similar behaviour in the past (before writing Jello) for scripting rules to determine whether a buyer accepts a particular lead or not)
- Evaluating simple expressions, such as calculating the max value for a field based on some criteria
- Essentially, any time that you need your users to be able to have a high degree of flexibility when specifying rules/calculations, Jello is your friend
Currently it has a very simple syntax consisting of basic equality/logical operators (&&, || and ==) and arithmetic (+, -, * and /), and supports basic data types: booleans, strings, dates and numbers (only decimal types to keep it simple – after all, Jello is intended for the users of your system). Date formats are not fixed allowing you to specify the format that best suits your needs – the default is to use the StandardDateParser which ships with Jello and uses the .net
DateTime.TryParse(dateString, out date) method internally, but you can create a class which inherits from the IDateParser interface and parse dates however you’d like. Using the StandardDateParser you can also specify an IFormatProvider and DateTimeStyles if you’d like.
You can also use variables which take their values from a data source that is passed into the parse result when executing. Data sources are classes that inherit from a simple interface, IDataSource, which specifies only a single method:
bool TryGet(string key, out object value). The only datasource currently shipped with Jello is a CompositeDataSource, which simply allows you to aggregate multiple data sources, though I intend to add a basic dictionary datasource shortly so that you won’t always have to create your own classes.
As I said before, the syntax is currently fixed, but my hope for Jello is that it will become flexible enough that it can be fit to most uses. The date parser is the first example of this to be added, since there are so many nuances with dates that I didn’t want to force users to use one specific date format, but I plan to add configurable operator overloading, functions and macros so that Jello can be bent to any will.
- Add operator overloading / functions
- Support user-defined datatypes
- Add macros to allow substituting operators (ie. using ‘and’ instead of ‘&&’)
- Extend grammar to make it more than just expression evaluation; allowing for specifying/amending variables, if/else statements, loops and return statements.