/// <summary>
        /// Parses specified C# expression and returns <see cref="Expression{TDelegate}"/> which could be compiled with <see cref="ExpressionExtensions.CompileAot{TResult}"/> and executed.
        /// </summary>
        /// <param name="expression">A valid c# expression. Not null, not empty string.</param>
        /// <param name="typeResolver">Type resolver for C# expression. Or <seealso cref="Binder.DefaultTypeResolver"/> if not specified.</param>
        /// <returns>A parsed and bound syntax tree.</returns>
        public static Expression <Action> ParseAction(string expression, ITypeResolver typeResolver = null)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            AotCompilation.RegisterAction();

            var tokens           = Tokenizer.Tokenize(expression);
            var parseTree        = Parser.Parse(tokens);
            var expressionTree   = parseTree.ToSyntaxTree(cSharpExpression: expression);
            var expressionBinder = new Binder(new ParameterExpression[0], resultType: typeof(void), typeResolver: typeResolver);

            return((Expression <Action>)expressionBinder.Bind(expressionTree));
        }
        /// <summary>
        /// Compiles specified expression into <see cref="Action"/> delegate using AOT aware expression compiler.
        /// </summary>
        /// <param name="expression">An expression syntax tree. Not null.</param>
        /// <param name="forceAot">True to always use AOT compiler event if environment is JIT and supports dynamic code.</param>
        /// <returns>A compiled expression.</returns>
        public static Action CompileAot(this Expression <Action> expression, bool forceAot = false)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            AotCompilation.RegisterAction();

            if (AotCompilation.IsAotRuntime || forceAot)
            {
                return(AotCompiler.PrepareAction(expression.Body));
            }
            else
            {
                return(expression.Compile());
            }
        }
        /// <summary>
        ///  Compiles specified expression into <see cref="Func{TArg1, TArg2, TResult}"/> delegate using AOT aware expression compiler.
        /// </summary>
        /// <typeparam name="TArg1">First argument type.</typeparam>
        /// <typeparam name="TArg2">Second argument type.</typeparam>
        /// <typeparam name="TResult">Result type.</typeparam>
        /// <param name="expression">An expression syntax tree. Not null.</param>
        /// <param name="forceAot">True to always use AOT compiler event if environment is JIT and supports dynamic code.</param>
        /// <returns>A compiled expression.</returns>
        public static Func <TArg1, TArg2, TResult> CompileAot <TArg1, TArg2, TResult>(this Expression <Func <TArg1, TArg2, TResult> > expression, bool forceAot = false)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            AotCompilation.RegisterFunc <TArg1, TArg2, TResult>();

            if (AotCompilation.IsAotRuntime || forceAot)
            {
                return(AotCompiler.PrepareFunc <TArg1, TArg2, TResult>(expression.Body, expression.Parameters));
            }
            else
            {
                return(expression.Compile());
            }
        }
        /// <summary>
        /// Parses specified C# expression and returns <see cref="Expression{TDelegate}"/> which could be compiled with <see cref="ExpressionExtensions.CompileAot{TResult}"/> and executed.
        /// </summary>
        /// <typeparam name="Arg1T">First argument type.</typeparam>
        /// <param name="expression">A valid c# expression. Not null, not empty string.</param>
        /// <param name="arg1Name">First argument name or <see cref="ARG1_DEFAULT_NAME"/> if not specified.</param>
        /// <param name="typeResolver">Type resolver for C# expression. Or <seealso cref="Binder.DefaultTypeResolver"/> if not specified.</param>
        /// <returns>A parsed and bound syntax tree.</returns>
        public static Expression <Action <Arg1T> > ParseAction <Arg1T>(string expression, string arg1Name = ARG1_DEFAULT_NAME, ITypeResolver typeResolver = null)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            AotCompilation.RegisterAction <Arg1T>();

            var tokens            = Tokenizer.Tokenize(expression);
            var parseTree         = Parser.Parse(tokens);
            var expressionTree    = parseTree.ToSyntaxTree(cSharpExpression: expression);
            var expressionBuilder = new Binder(new[]
            {
                Expression.Parameter(typeof(Arg1T), arg1Name ?? ARG1_DEFAULT_NAME)
            }, resultType: typeof(void), typeResolver: typeResolver);

            return((Expression <Action <Arg1T> >)expressionBuilder.Bind(expressionTree));
        }
        /// <summary>
        /// Parses specified C# expression and returns <see cref="Expression{TDelegate}"/> which could be compiled with <see cref="ExpressionExtensions.CompileAot{TResult}"/> and executed.
        /// </summary>
        /// <typeparam name="Arg1T">First argument type.</typeparam>
        /// <typeparam name="Arg2T">Second argument type.</typeparam>
        /// <typeparam name="Arg3T">Third argument type.</typeparam>
        /// <typeparam name="ResultT">Result type.</typeparam>
        /// <param name="expression">A valid c# expression. Not null, not empty string.</param>
        /// <param name="arg1Name">First argument name or <see cref="ARG1_DEFAULT_NAME"/> if not specified.</param>
        /// <param name="arg2Name">Second argument name or <see cref="ARG2_DEFAULT_NAME"/> if not specified.</param>
        /// <param name="arg3Name">Third argument name or <see cref="ARG3_DEFAULT_NAME"/> if not specified.</param>
        /// <param name="typeResolver">Type resolver for C# expression. Or <seealso cref="Binder.DefaultTypeResolver"/> if not specified.</param>
        /// <returns>A parsed and bound syntax tree.</returns>
        public static Expression <Func <Arg1T, Arg2T, Arg3T, ResultT> > ParseFunc <Arg1T, Arg2T, Arg3T, ResultT>(string expression, string arg1Name = ARG1_DEFAULT_NAME, string arg2Name = ARG2_DEFAULT_NAME, string arg3Name = ARG3_DEFAULT_NAME, ITypeResolver typeResolver = null)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            AotCompilation.RegisterFunc <Arg1T, Arg2T, Arg3T, ResultT>();

            var tokens           = Tokenizer.Tokenize(expression);
            var parseTree        = Parser.Parse(tokens);
            var expressionTree   = parseTree.ToSyntaxTree();
            var expressionBinder = new Binder(new[]
            {
                Expression.Parameter(typeof(Arg1T), arg1Name ?? ARG1_DEFAULT_NAME),
                Expression.Parameter(typeof(Arg2T), arg2Name ?? ARG2_DEFAULT_NAME),
                Expression.Parameter(typeof(Arg3T), arg3Name ?? ARG3_DEFAULT_NAME),
            }, resultType: typeof(ResultT), typeResolver: typeResolver);

            return((Expression <Func <Arg1T, Arg2T, Arg3T, ResultT> >)expressionBinder.Bind(expressionTree));
        }