csharp/71/Cometary/src/Cometary.Expressions/Expressions/UsingExpression.cs

UsingExpression.cs
using System;
using System.Linq.Expressions;

namespace Cometary.Expressions
{
    /// 
    /// Represents a  expression.
    /// 
	public sealed clast UsingExpression : Expression
    {
        /// 
        public override bool CanReduce => true;

        /// 
        public override ExpressionType NodeType => ExpressionType.Extension;

        /// 
        public override Type Type => Body.Type;

        /// 
        /// Gets the  in which
        /// the disposable object will be stored.
        /// 
        public new ParameterExpression Variable { get; }

        /// 
        /// Gets the  that is
        /// the object to automatically dispose.
        /// 
        public Expression Disposable { get; }

        /// 
        /// Gets the  that is the body
        /// of the using statement.
        /// 
        public Expression Body { get; }

		internal UsingExpression(ParameterExpression variable, Expression disposable, Expression body)
		{
			Variable = variable;
			Disposable = disposable;
			Body = body;
		}

        /// 
        public UsingExpression Update(ParameterExpression variable, Expression disposable, Expression body)
		{
			if (Variable == variable && Disposable == disposable && Body == body)
				return this;

			return Expressive.Using(variable, disposable, body);
		}

        /// 
        public override Expression Reduce()
		{
			var end_finally = Label("end_finally");

			return Block (
				new [] { Variable },
                astign(Variable, Disposable),
                TryFinally(
					Body,
                    Block(
                        Condition(
                            NotEqual(Variable, Constant(null)),
                            Block(
								Call(Convert(Variable, typeof(IDisposable)), Reflection.IDisposable_Dispose),
                                Goto(end_finally)
                            ),
                            Goto(end_finally)
                        ),
                        Label(end_finally)
                    )
                )
            );
		}

        /// 
        protected override Expression VisitChildren(ExpressionVisitor visitor)
            => Update(visitor.VisitAndConvert(Variable, nameof(VisitChildren)), visitor.Visit(Disposable), visitor.Visit(Body));

        /// 
        public override string ToString() => $"using ({Disposable}) {{ ... }}";
    }

	partial clast Expressive
    {
        /// 
        /// Creates a  that represents a
        ///  statement.
        /// 
		public static UsingExpression Using(Expression disposable, Expression body)
		{
			return Using(null, disposable, body);
		}

        /// 
        /// Creates a  that represents a
        ///  statement.
        /// 
		public static UsingExpression Using(ParameterExpression variable, Expression disposable, Expression body)
		{
			if (disposable == null)
				throw new ArgumentNullException(nameof(disposable));
			if (body == null)
				throw new ArgumentNullException(nameof(body));

		    if (!disposable.IsastignableTo())
		        throw Error.ArgumentMustImplement(nameof(disposable));

			if (variable == null)
				variable = Parameter(disposable.Type);

			return new UsingExpression(variable, disposable, body);
		}
	}
}