parsing – C# Logical and Math expression parser


I needed a simple parser that could do both logical and math operations expressed in a string, as well as being able to use variables stored in json.

None of what I found online seemed to do all of the above, so I came up with my own. Below is the source code for my ExpressionParser as well as my JExpressionParser, in case your variables are stored in a JSON.

Hopefully this post will help someone, as well as allow others to improve my code.

Here is the base parser:

using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

public class ExpressionParser
{
    public virtual IDictionary<string, object> Variables { get; }
    protected ExpressionParser() { }
    protected virtual DataTable GetComputer()
    {
        var computer = new DataTable();
        if (Variables != null)
        {
            computer.Columns.AddRange(Variables.Select(v => new DataColumn(v.Key) { DataType = v.Value.GetType() }).ToArray());
            computer.Rows.Add(Variables.Values.ToArray());
        }
        return computer;
    }
    public ExpressionParser(IDictionary<string, object> variables = null)
    {
        Variables = variables ?? new Dictionary<string, object>();
    }
    public object Compute(string expression)
    {
        StringBuilder sb = new StringBuilder(expression);
        foreach (var key in Variables.Keys)
            sb.Replace(key, $"Sum({key})");
        sb.Replace("==", "=");
        using (var computer = GetComputer())
            return computer.Compute(sb.ToString(), null);
    }
}

And here is one that works with json objects:

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;

public class JExpressionParser : ExpressionParser
{
    public JObject JVariables { get; set; }
    public override IDictionary<string, object> Variables => 
        JVariables.Properties().ToDictionary(p => p.Name, p => p.Value.ToObject(conversions(p.Value.Type)));
    static readonly Dictionary<JTokenType, Type> conversions = new Dictionary<JTokenType, Type>()
    {
        (JTokenType.Integer) = typeof(int),
        (JTokenType.Float) = typeof(float),
        (JTokenType.Boolean) = typeof(bool),
    };
    public JExpressionParser(JObject jVariables = null)
    {
        JVariables = jVariables ?? new JObject();
    }
}

Usage:

var variables = new Dictionary<string, object>() { ("budget") = 1000, ("cost") = 965 };
var parser = new ExpressionParser(variables);
Console.WriteLine("We have $" + parser.Compute("budget - cost") + " of budget left.");