Skip to content

jaysonragasa/Interpreter

 
 

Repository files navigation

Interpreter

Overview

The Interpreter is an expression interpreter written in pure C#. It parses any mathematical or logical expression and returns a result. The return result depends on the return type of the last function / operation. An expression can contain variables that can be supplied before the expression is executed and the result returned.

Video Tutorial

The video overview and tutorial is available here: http://youtu.be/D9UGHPQpKP4

Examples:

  1. Passing a variable to the expression. The example below parses the expression and creates the expression tree via Engine.Parse(). The variables are then supplied to the expression and the expression executed via Execute().
var expression = new Engine().Parse("SUM(A) * 2 - B");
expression.Variables["A"].Value = new Array(new decimal[] { 1, 2, 3, 4 });
expression.Variables["B"].Value = new Number(10);
decimal result = expression.Execute<Number>();
  1. Using an IF function:
decimal result = new Engine().Parse("IF(1 < 2, 10, 20)").Execute<Number>();
  1. Custom functions can provide support for accessing data from a database:
    class GetMyDataFunction : Function
    {
    	public override string Name 
    	{
    		get 
    		{
    			return "GETMYDATA"; 
    		}
    	}

    	public override Literal Execute(IConstruct[] arguments)
    	{
    		base.EnsureArgumentCountIs(arguments, 2);
	
    		var tableName = base.GetTransformedArgument<Text>(arguments, 0);
	    	var fieldName = base.GetTransformedArgument<Text>(arguments, 1);

    		// Retrieve data using tableName and fieldName and return Array<Number>.
    		// This return value can then be used by any functions that accept Array<Number> as an argument such as SUM().
    		// return new Array(new decimal[] { 1, 2, 3, 4 });
    	}
    }
    
    var engine = new Engine();
    engine.Register(new GetMyDataFunction());	
    decimal result = Engine.Parse("SUM(GETMYDATA('MyTable', 'MyField'))").Execute<Number>();
  1. Custom functions that manipulate values:
    class NegateNumber : Function
    {
        public override string Name 
        {
            get 
            {
	            return "NEGATE"; 
            }
        }

        public override Literal Execute(IConstruct[] arguments)
        {
            base.EnsureArgumentCountIs(arguments, 1);

    		decimal inputValue = base.GetTransformedArgument<Number>(arguments, argumentIndex: 0);

            return new Number(-inputValue);
        }
    }
    
    var engine = new Engine();
    engine.Register(new NegateNumber());
    decimal result = Engine.Parse("NEGATE(1)").Execute<Number>();
  1. Working with numbers:
var expression = new Engine().Parse("Sum(Array(1, 2, 3, 4, 5)) / 2");
decimal result = expression.Execute<Number>();
  1. Working with text:
var expression = new Engine().Parse("'$ ' + Format(Amount, '0.00')");
expression.Variables["Amount"].Value = (Number)1;
string result = expression.Execute<Text>();
var engine = new Engine();
var xp = engine.Parse("ToUpper(Substring('hello world', 0, 5) + ' jayson')");
string result = xp.Execute<Text>();
  1. Working with dates:
var expression = new Engine().Parse("Today() > #2000-1-1#");
bool result = expression.Execute<Boolean>();
  1. Working with logical operators and parentheses:
var expression = new Engine().Parse("1 < 2 AND (2 > 3 OR 3 < 4)");
bool result = expression.Execute<Boolean>();
  1. Executing multiple expressions:
 var engine = new Engine();

 var expression1 = engine.Parse("A + 2");
 expression1.Variables["A"].Value = (Number)1;

 var expression2 = engine.Parse("Expression1 + 3");
 expression2.Variables["Expression1"].Value = expression1;

 decimal result = expression2.Execute<Number>();
  1. Using in Xamarin with inline code with Converter.

    Condition example

public class Convert_Interpret : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string result = string.Empty;

        if (!string.IsNullOrEmpty((string)value))
        {
            var e = ((App)Application.Current).Interpret;
            var xp = e.Parse((string)parameter);
            xp.Variables["A"].Value = new Text((string)value);
            result = xp.Execute<Text>();
        }

        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

Supported Functions

  • SUM(array)
  • AVG(array)
  • IF(condition, trueResult, falseResult)
  • Array(item1, item2, ...)
  • Format(value [, format]) -- Formats a number or date/time
  • Len(text) -- returns the length of a string
  • Custom functions can be created by extending Function and registered it via Engine.Register(Function)
  • Substring('string', index, length) -- ex: Substring('Hello World', 0, 7) This will return Hello W
  • ToUpper('string') -- ex: ToUpper(Substring('Hello World', 0, 7)) this will return HELLO W
  • ToTitleCase(value) - Returns a Title format string.

Supported data types (can be extended)

  • Number/decimal
    • Example: 1.0
  • Boolean
    • Supports constants 'true' and 'false'
    • Example: true <> false
  • Array
    • Can contain all data types
    • Data types can be mixed in the same array
    • Example: Array(1, 2, 3, 4)
  • Text
    • Delimited by " or ' characters
    • Exampe: 'ABC'
  • Date/Time
    • Surrounded by '#' characters
    • Example: #2000-01-30 12:30:03#

Supported functions (can be extended)

  • If(condition, trueResult, falseResult)
    • Example: If(1 > 2, 10, 20)
  • Max(array)
    • Example: Max(Array(1, 2, 3))
  • Min(array)
    • Example: Min(Array(1, 2, 3))
  • Sum(array):
    • Example: Sum(Array(1, 2, 3))
  • Today:
    • Returns the date component (no time component) for today.
    • Example: Today() + 1 -- returns the date for tomorrow
  • Len(text)
    • Returns the length of a string
    • Example: Len('abc') -- returns 3
  • ToUpper(value)
    • Example: ToUpper('jayson') -- returns JAYSON
  • Substring(value, firstIndex, string_length)
    • Example: Substring('hello jayson', 6, 6) -- returns Jayson
  • ToTitleCase(value)
    • Returns a title format of a string
    • Example: ToTitleCase('hello jayson') -- returns Hello Jayon

Supported Operations (can be extended)

    • - addition  (numbers, date/time + number, string concatenation)
      
    • - subtraction (numbers, date/time - number)
      
  • / - divide
    • - multiply
      
  • = - equal
  • <> - not equal to
  • < - less than
  • - greater than
    
  • = - greater than or equal to

  • <= - less than or equal to
  • OR - logical or
  • AND - logical and

Supported Platforms

Supported platforms are Windows and MonoTouch/Mono.

License

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Unit Tests

The unit test project is available in a separate repository on Github here. It is also a good resource for examples on how to utilise the library. To run the unit tests project in conjunction with the library it must be located in the same directory as the library.

For example:

/Interpreter /Interpreter.UnitTests

About

Simple language interpreter written in pure C#.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 100.0%