diff --git a/src/DynamicExpresso.Core/ExpressionInterpreter.cs b/src/DynamicExpresso.Core/ExpressionInterpreter.cs
new file mode 100644
index 00000000..8958c63a
--- /dev/null
+++ b/src/DynamicExpresso.Core/ExpressionInterpreter.cs
@@ -0,0 +1,459 @@
+using DynamicExpresso.Parsing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using DynamicExpresso.Exceptions;
+using DynamicExpresso.Reflection;
+using DynamicExpresso.Visitors;
+
+namespace DynamicExpresso
+{
+ ///
+ /// Class used to parse and compile a text expression into an Expression or a Delegate that can be invoked. Expression are written using a subset of C# syntax.
+ /// Only get properties, Parse and Eval methods are thread safe.
+ ///
+ public class ExpressionInterpreter
+ {
+ private readonly ParserSettings _settings;
+ private readonly ISet _visitors = new HashSet();
+
+ #region Constructors
+ ///
+ /// Creates a new ExpressionInterpreter using InterpreterOptions.Default.
+ ///
+ public ExpressionInterpreter()
+ : this(InterpreterOptions.Default)
+ {
+ }
+
+ ///
+ /// Creates a new ExpressionInterpreter using the specified options.
+ ///
+ ///
+ public ExpressionInterpreter(InterpreterOptions options)
+ {
+ var caseInsensitive = options.HasFlag(InterpreterOptions.CaseInsensitive);
+
+ var lateBindObject = options.HasFlag(InterpreterOptions.LateBindObject);
+
+ _settings = new ParserSettings(caseInsensitive, lateBindObject);
+
+ if ((options & InterpreterOptions.SystemKeywords) == InterpreterOptions.SystemKeywords)
+ {
+ SetIdentifiers(LanguageConstants.Literals);
+ }
+
+ if ((options & InterpreterOptions.PrimitiveTypes) == InterpreterOptions.PrimitiveTypes)
+ {
+ Reference(LanguageConstants.PrimitiveTypes);
+ Reference(LanguageConstants.CSharpPrimitiveTypes);
+ }
+
+ if ((options & InterpreterOptions.CommonTypes) == InterpreterOptions.CommonTypes)
+ {
+ Reference(LanguageConstants.CommonTypes);
+ }
+
+ if ((options & InterpreterOptions.LambdaExpressions) == InterpreterOptions.LambdaExpressions)
+ {
+ _settings.LambdaExpressions = true;
+ }
+
+ _visitors.Add(new DisableReflectionVisitor());
+ }
+
+ ///
+ /// Create a new ExpressionInterpreter with the settings copied from another interpreter
+ ///
+ internal ExpressionInterpreter(ParserSettings settings)
+ {
+ _settings = settings;
+ }
+ #endregion
+
+ #region Properties
+ public bool CaseInsensitive
+ {
+ get
+ {
+ return _settings.CaseInsensitive;
+ }
+ }
+
+ ///
+ /// Gets a list of registeres types. Add types by using the Reference method.
+ ///
+ public IEnumerable ReferencedTypes
+ {
+ get
+ {
+ return _settings.KnownTypes
+ .Select(p => p.Value)
+ .ToList();
+ }
+ }
+
+ ///
+ /// Gets a list of known identifiers. Add identifiers using SetVariable, SetFunction or SetExpression methods.
+ ///
+ public IEnumerable Identifiers
+ {
+ get
+ {
+ return _settings.Identifiers
+ .Select(p => p.Value)
+ .ToList();
+ }
+ }
+
+ ///
+ /// Gets the available assignment operators.
+ ///
+ public AssignmentOperators AssignmentOperators
+ {
+ get { return _settings.AssignmentOperators; }
+ }
+ #endregion
+
+ #region Options
+
+ ///
+ /// Allow to set de default numeric type when no suffix is specified (Int by default, Double if real number)
+ ///
+ ///
+ ///
+ public ExpressionInterpreter SetDefaultNumberType(DefaultNumberType defaultNumberType)
+ {
+ _settings.DefaultNumberType = defaultNumberType;
+ return this;
+ }
+
+ ///
+ /// Allows to enable/disable assignment operators.
+ /// For security when expression are generated by the users is more safe to disable assignment operators.
+ ///
+ ///
+ ///
+ public ExpressionInterpreter EnableAssignment(AssignmentOperators assignmentOperators)
+ {
+ _settings.AssignmentOperators = assignmentOperators;
+
+ return this;
+ }
+ #endregion
+
+ #region Visitors
+ public ISet Visitors
+ {
+ get { return _visitors; }
+ }
+
+ ///
+ /// Enable reflection expression (like x.GetType().GetMethod() or typeof(double).Assembly) by removing the DisableReflectionVisitor.
+ ///
+ ///
+ public ExpressionInterpreter EnableReflection()
+ {
+ var visitor = Visitors.FirstOrDefault(p => p is DisableReflectionVisitor);
+ if (visitor != null)
+ Visitors.Remove(visitor);
+
+ return this;
+ }
+ #endregion
+
+ #region Register identifiers
+ ///
+ /// Allow the specified function delegate to be called from a parsed expression.
+ ///
+ ///
+ ///
+ ///
+ public ExpressionInterpreter SetFunction(string name, Delegate value)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ throw new ArgumentNullException(nameof(name));
+
+ if (_settings.Identifiers.TryGetValue(name, out var identifier) && identifier is FunctionIdentifier fIdentifier)
+ {
+ fIdentifier.AddOverload(value);
+ }
+ else
+ {
+ SetIdentifier(new FunctionIdentifier(name, value));
+ }
+
+ return this;
+ }
+
+ ///
+ /// Allow the specified variable to be used in a parsed expression.
+ ///
+ ///
+ ///
+ ///
+ public ExpressionInterpreter SetVariable(string name, object value)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ throw new ArgumentNullException(nameof(name));
+
+ return SetExpression(name, Expression.Constant(value));
+ }
+
+ ///
+ /// Allow the specified variable to be used in a parsed expression.
+ ///
+ ///
+ ///
+ ///
+ public ExpressionInterpreter SetVariable(string name, T value)
+ {
+ return SetVariable(name, value, typeof(T));
+ }
+
+ ///
+ /// Allow the specified variable to be used in a parsed expression.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ExpressionInterpreter SetVariable(string name, object value, Type type)
+ {
+ if (type == null)
+ throw new ArgumentNullException(nameof(type));
+ if (string.IsNullOrWhiteSpace(name))
+ throw new ArgumentNullException(nameof(name));
+
+ return SetExpression(name, Expression.Constant(value, type));
+ }
+
+ ///
+ /// Allow the specified Expression to be used in a parsed expression.
+ /// Basically add the specified expression as a known identifier.
+ ///
+ ///
+ ///
+ ///
+ public ExpressionInterpreter SetExpression(string name, Expression expression)
+ {
+ return SetIdentifier(new Identifier(name, expression));
+ }
+
+ ///
+ /// Allow the specified list of identifiers to be used in a parsed expression.
+ /// Basically add the specified expressions as a known identifier.
+ ///
+ ///
+ ///
+ public ExpressionInterpreter SetIdentifiers(IEnumerable identifiers)
+ {
+ foreach (var i in identifiers)
+ SetIdentifier(i);
+
+ return this;
+ }
+
+ ///
+ /// Allow the specified identifier to be used in a parsed expression.
+ /// Basically add the specified expression as a known identifier.
+ ///
+ ///
+ ///
+ public ExpressionInterpreter SetIdentifier(Identifier identifier)
+ {
+ if (identifier == null)
+ throw new ArgumentNullException(nameof(identifier));
+
+ if (LanguageConstants.ReservedKeywords.Contains(identifier.Name))
+ throw new InvalidOperationException($"{identifier.Name} is a reserved word");
+
+ _settings.Identifiers[identifier.Name] = identifier;
+
+ return this;
+ }
+ #endregion
+
+ #region Register referenced types
+ ///
+ /// Allow the specified type to be used inside an expression. The type will be available using its name.
+ /// If the type contains method extensions methods they will be available inside expressions.
+ ///
+ ///
+ ///
+ public ExpressionInterpreter Reference(Type type)
+ {
+ if (type == null)
+ throw new ArgumentNullException(nameof(type));
+
+ return Reference(type, type.Name);
+ }
+
+ ///
+ /// Allow the specified type to be used inside an expression.
+ /// See Reference(Type, string) method.
+ ///
+ ///
+ ///
+ public ExpressionInterpreter Reference(IEnumerable types)
+ {
+ if (types == null)
+ throw new ArgumentNullException(nameof(types));
+
+ foreach (var t in types)
+ Reference(t);
+
+ return this;
+ }
+
+ ///
+ /// Allow the specified type to be used inside an expression by using a custom alias.
+ /// If the type contains extensions methods they will be available inside expressions.
+ ///
+ ///
+ /// Public name that must be used in the expression.
+ ///
+ public ExpressionInterpreter Reference(Type type, string typeName)
+ {
+ return Reference(new ReferenceType(typeName, type));
+ }
+
+ ///
+ /// Allow the specified type to be used inside an expression by using a custom alias.
+ /// If the type contains extensions methods they will be available inside expressions.
+ ///
+ ///
+ ///
+ public ExpressionInterpreter Reference(ReferenceType type)
+ {
+ if (type == null)
+ throw new ArgumentNullException(nameof(type));
+
+ _settings.KnownTypes[type.Name] = type;
+
+ foreach (var extensionMethod in type.ExtensionMethods)
+ {
+ _settings.ExtensionMethods.Add(extensionMethod);
+ }
+
+ return this;
+ }
+ #endregion
+
+ #region Parse
+
+ ///
+ /// Parse a text expression and convert it into a ParseResult with Delegate type info.
+ ///
+ /// Expression statement
+ ///
+ ///
+ ///
+ public ParseResult Parse(string expressionText, params string[] parametersNames)
+ {
+ var delegateInfo = ReflectionExtensions.GetDelegateInfo(typeof(TDelegate), parametersNames);
+ var parseResult = Parse(
+ expressionText,
+ delegateInfo.ReturnType,
+ delegateInfo.Parameters.Select(x => x.Expression).ToArray());
+
+ return new ParseResult(
+ expression: parseResult.Expression,
+ usedParameters: parseResult.UsedParameters,
+ declaredParameters: parseResult.DeclaredParameters,
+ types: parseResult.Types,
+ identifiers: parseResult.Identifiers);
+ }
+
+ ///
+ /// Parse a text expression.
+ ///
+ /// Expression statement
+ /// Expression input parameters
+ ///
+ ///
+ public ParseResult Parse(string expressionText, params ParameterExpression[] parameters)
+ {
+ return Parse(expressionText, typeof(void), parameters);
+ }
+
+ ///
+ /// Parse a text expression.
+ ///
+ /// Expression statement
+ /// Expected expression return type
+ /// Expression input parameters
+ ///
+ ///
+ public ParseResult Parse(string expressionText, Type expressionReturnType, params ParameterExpression[] parameters)
+ {
+ return Parse(expressionText, expressionReturnType, parameters.AsEnumerable());
+ }
+
+ ///
+ /// Parse a text expression.
+ ///
+ /// Expression statement
+ /// Expected expression return type
+ /// Expression input parameters
+ ///
+ ///
+ public ParseResult Parse(string expressionText, Type expressionReturnType, IEnumerable parameters)
+ {
+ if (parameters == null)
+ parameters = Enumerable.Empty();
+
+ var arguments = new ParserArguments(
+ expressionText,
+ _settings,
+ expressionReturnType,
+ parameters.Select(x => new Parameter(x)));
+
+ var expression = Visitors.Aggregate(Parser.Parse(arguments), (current, visitor) => visitor.Visit(current));
+
+ var lambda = new ParseResult(
+ expression: expression,
+ usedParameters: arguments.UsedParameters.Select(x => x.Expression),
+ declaredParameters: arguments.DeclaredParameters.Select(x => x.Expression),
+ types: arguments.UsedTypes,
+ identifiers: arguments.UsedIdentifiers);
+
+#if TEST_DetectIdentifiers
+ AssertDetectIdentifiers(lambda);
+#endif
+
+ return lambda;
+ }
+
+ #endregion
+
+ #region Detection
+
+ public IdentifiersInfo DetectIdentifiers(string expression)
+ {
+ var detector = new Detector(_settings);
+
+ return detector.DetectIdentifiers(expression);
+ }
+
+ #endregion
+
+ #region Private methods
+
+#if TEST_DetectIdentifiers
+ private void AssertDetectIdentifiers(Lambda lambda)
+ {
+ var info = DetectIdentifiers(lambda.ExpressionText);
+
+ if (info.Identifiers.Count() != lambda.Identifiers.Count())
+ throw new Exception("Detected identifiers doesn't match actual identifiers");
+ if (info.Types.Count() != lambda.Types.Count())
+ throw new Exception("Detected types doesn't match actual types");
+ if (info.UnknownIdentifiers.Count() != lambda.UsedParameters.Count())
+ throw new Exception("Detected unknown identifiers doesn't match actual parameters");
+ }
+#endif
+ #endregion
+ }
+}
diff --git a/src/DynamicExpresso.Core/InterpreterExtensions.cs b/src/DynamicExpresso.Core/InterpreterExtensions.cs
new file mode 100644
index 00000000..e706bd6b
--- /dev/null
+++ b/src/DynamicExpresso.Core/InterpreterExtensions.cs
@@ -0,0 +1,171 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Runtime.ExceptionServices;
+using DynamicExpresso.Exceptions;
+
+namespace DynamicExpresso
+{
+ ///
+ /// Interpreter extensions.
+ ///
+ public static class InterpreterExtensions
+ {
+ ///
+ /// Parse a text expression with expected return type.
+ ///
+ ///
+ /// Expression statement
+ ///
+ ///
+ ///
+ public static ParseResult ParseWithReturnType(
+ this ExpressionInterpreter interpreter,
+ string expressionText,
+ params ParameterExpression[] parameters)
+ {
+ return interpreter.Parse(expressionText, typeof(TReturnType), parameters);
+ }
+
+ ///
+ /// Compiles lambda with declared parameters.
+ ///
+ public static Delegate Compile(this ParseResult parseResult)
+ {
+ var lambdaExpression = Expression.Lambda(parseResult.Expression, parseResult.DeclaredParameters.ToArray());
+
+ return lambdaExpression.Compile();
+ }
+
+ ///
+ /// Compiles lambda with declared parameters.
+ ///
+ public static TDelegate Compile(this ParseResult parseResult)
+ {
+ var lambdaExpression = Expression.Lambda(parseResult.Expression, parseResult.DeclaredParameters.ToArray());
+
+ return lambdaExpression.Compile();
+ }
+
+ ///
+ /// Compiles lambda with declared parameters.
+ ///
+ public static TDelegate Compile(this ParseResult parseResult)
+ {
+ return Compile((ParseResult) parseResult);
+ }
+
+ ///
+ /// Convert parse result to expression.
+ ///
+ public static Expression AsExpression(this ParseResult parseResult)
+ {
+ return Expression.Lambda(parseResult.Expression, parseResult.DeclaredParameters.ToArray());
+ }
+
+ ///
+ /// Convert parse result to expression.
+ ///
+ public static Expression AsExpression(this ParseResult parseResult)
+ {
+ return ((ParseResult) parseResult).AsExpression();
+ }
+
+ ///
+ /// Convert parse result to lambda expression.
+ ///
+ public static LambdaExpression AsLambdaExpression(this ParseResult parseResult, Type delegateType)
+ {
+ return Expression.Lambda(delegateType, parseResult.Expression, parseResult.DeclaredParameters.ToArray());
+ }
+
+ ///
+ /// Evaluate expression.
+ ///
+ public static object Eval(this ExpressionInterpreter interpreter, string expressionText,
+ Func