Exemple #1
0
        Expression ProcessVertexBuffer(StageValue vertexBuffer)
        {
            Expression result;

            if (!VertexBuffers.TryGetValue(vertexBuffer.Value.ToString(), out result))
            {
                var src  = vertexBuffer.Value.Source;
                var type = ILFactory.GetType(src, "Uno.Graphics.VertexBuffer");

                if (vertexBuffer.Value.ReturnType.Equals(type))
                {
                    result = ProcessStage(vertexBuffer, MetaStage.Volatile, MetaStage.Volatile).Value;
                    VertexBuffers.Add(vertexBuffer.Value.ToString(), result);
                    return(result);
                }

                var loc = LocationStack.Last();
                var mp  = GetProperty(loc);

                var name  = CreateFieldName(mp, loc);
                var owner = Path.DrawBlock.Method.DeclaringType;

                var field = new Field(src, owner, name, null, Modifiers.Private | Modifiers.Generated, 0, type);
                owner.Fields.Add(field);

                result = new LoadField(src, new This(src, owner), field);
                VertexBuffers.Add(vertexBuffer.Value.ToString(), result);

                if (vertexBuffer.MinStage > MetaStage.Volatile)
                {
                    Log.Error(src, ErrorCode.E5025, "Vertex buffer cannot be accessed from " + vertexBuffer.MinStage + " stage");
                    return(result);
                }
                else if (vertexBuffer.MinStage == MetaStage.Volatile)
                {
                    InitScope.Statements.Add(
                        new StoreField(src, new This(src, owner), field,
                                       ILFactory.NewObject(src, "Uno.Graphics.VertexBuffer",
                                                           ILFactory.GetExpression(src, "Uno.Graphics.BufferUsage.Dynamic"))));

                    FrameScope.Statements.Add(
                        ILFactory.CallMethod(src, new LoadField(src, new This(src, owner), field), "Update",
                                             vertexBuffer.Value));
                }
                else
                {
                    InitScope.Statements.Add(
                        new StoreField(src, new This(src, owner), field,
                                       ILFactory.NewObject(src, "Uno.Graphics.VertexBuffer",
                                                           vertexBuffer.Value,
                                                           ILFactory.GetExpression(src, "Uno.Graphics.BufferUsage.Immutable"))));
                }

                FreeScope.Statements.Add(
                    ILFactory.CallMethod(src, new LoadField(src, new This(src, owner), field), "Dispose"));
            }

            return(result);
        }
Exemple #2
0
        void ProcessIndexBuffer(Source vaSrc, StageValue indexBuffer, StageValue indexType)
        {
            if (IndexBuffer == null && indexBuffer.Value == null && IndexType == null && indexType.Value == null ||
                indexBuffer.Value != null && IndexBuffer == indexBuffer.Value.ToString() && indexType.Value != null && IndexType == indexType.Value.ToString())
            {
                // OK
                return;
            }

            if (IndexBuffer != null || indexBuffer.Value == null || IndexType != null || indexType.Value == null)
            {
                Log.Error(vaSrc, ErrorCode.E5023, "Index buffer argument must be consistent for all <vertex_attrib>s in " + Path.Quote());
                return;
            }

            var src  = indexBuffer.Value.Source;
            var type = ILFactory.GetType(src, "Uno.Graphics.IndexBuffer");

            IndexBuffer = indexBuffer.Value.ToString();
            IndexType   = indexType.Value.ToString();

            if (indexBuffer.Value.ReturnType.Equals(type))
            {
                DrawState.OptionalIndices = new IndexBinding(
                    ProcessStage(indexType, MetaStage.Volatile, MetaStage.Volatile).Value,
                    ProcessStage(indexBuffer, MetaStage.Volatile, MetaStage.Volatile).Value);

                return;
            }

            var loc = LocationStack.Last();
            var mp  = GetProperty(loc);

            var name  = CreateFieldName(mp, loc);
            var owner = Path.DrawBlock.Method.DeclaringType;

            var field = new Field(src, owner, name,
                                  null, Modifiers.Private | Modifiers.Generated, 0, type);

            owner.Fields.Add(field);

            DrawState.OptionalIndices = new IndexBinding(
                ProcessStage(indexType, MetaStage.Volatile, MetaStage.Volatile).Value,
                new LoadField(src, new This(src, owner), field));

            if (indexBuffer.MinStage > MetaStage.Volatile)
            {
                Log.Error(src, ErrorCode.E5024, "Index buffer cannot be accessed from " + indexBuffer.MinStage + " stage");
                return;
            }

            if (indexBuffer.MinStage == MetaStage.Volatile)
            {
                InitScope.Statements.Add(
                    new StoreField(src, new This(src, owner), field,
                                   ILFactory.NewObject(src, "Uno.Graphics.IndexBuffer",
                                                       ILFactory.GetExpression(src, "Uno.Graphics.BufferUsage.Dynamic"))));

                FrameScope.Statements.Add(
                    ILFactory.CallMethod(src, new LoadField(src, new This(src, owner), field), "Update",
                                         indexBuffer.Value));
            }
            else
            {
                InitScope.Statements.Add(
                    new StoreField(src, new This(src, owner), field, ILFactory.NewObject(src, "Uno.Graphics.IndexBuffer",
                                                                                         indexBuffer.Value,
                                                                                         ILFactory.GetExpression(src, "Uno.Graphics.BufferUsage.Immutable"))));
            }

            FreeScope.Statements.Add(
                ILFactory.CallMethod(src, new LoadField(src, new This(src, owner), field), "Dispose"));
        }
Exemple #3
0
        public Expression CompileVertexAttribImplicit(AstVertexAttribImplicit e)
        {
            var      vertexBuffer   = CompileExpression(e.VertexBuffer);
            DataType vertexDataType = null;

            if (vertexBuffer.ReturnType.IsArray)
            {
                vertexDataType = vertexBuffer.ReturnType.ElementType;
            }
            else if (!vertexBuffer.IsInvalid)
            {
                Log.Error(e.Source, ErrorCode.E2067, vertexBuffer.ReturnType.Quote() + " cannot be used to create vertex buffer because it is not an array type");
                vertexBuffer = Expression.Invalid;
            }

            Expression indexBuffer   = null;
            DataType   indexDataType = null;

            if (e.OptionalIndexBuffer != null)
            {
                indexBuffer = CompileExpression(e.OptionalIndexBuffer);

                if (indexBuffer.ReturnType.IsArray)
                {
                    indexDataType = indexBuffer.ReturnType.ElementType;
                }
                else if (!indexBuffer.IsInvalid)
                {
                    Log.Error(indexBuffer.Source, ErrorCode.E2069, indexBuffer.ReturnType.Quote() + " cannot be used to create index buffer because it is not an array type");
                    indexBuffer = Expression.Invalid;
                }
            }

            Expression vertexStride        = null;
            Expression vertexAttributeType = null;

            if (vertexDataType != null)
            {
                switch (vertexDataType.BuiltinType)
                {
                case BuiltinType.Float:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 4);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.Float", "Uno.Graphics.VertexAttributeType");
                    VerifyNonNormalizedVertexAttribute(vertexBuffer.Source, e.Normalize);
                    break;

                case BuiltinType.Float2:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 8);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.Float2", "Uno.Graphics.VertexAttributeType");
                    VerifyNonNormalizedVertexAttribute(vertexBuffer.Source, e.Normalize);
                    break;

                case BuiltinType.Float3:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 12);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.Float3", "Uno.Graphics.VertexAttributeType");
                    VerifyNonNormalizedVertexAttribute(vertexBuffer.Source, e.Normalize);
                    break;

                case BuiltinType.Float4:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 16);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.Float4", "Uno.Graphics.VertexAttributeType");
                    VerifyNonNormalizedVertexAttribute(vertexBuffer.Source, e.Normalize);
                    break;

                case BuiltinType.Short:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 2);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.Short" + (e.Normalize ? "Normalized" : ""), "Uno.Graphics.VertexAttributeType");
                    vertexDataType      = Essentials.Float;
                    break;

                case BuiltinType.Short2:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 4);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.Short2" + (e.Normalize ? "Normalized" : ""), "Uno.Graphics.VertexAttributeType");
                    vertexDataType      = Essentials.Float2;
                    break;

                case BuiltinType.Short4:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 8);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.Short4" + (e.Normalize ? "Normalized" : ""), "Uno.Graphics.VertexAttributeType");
                    vertexDataType      = Essentials.Float4;
                    break;

                case BuiltinType.UShort:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 2);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.UShort" + (e.Normalize ? "Normalized" : ""), "Uno.Graphics.VertexAttributeType");
                    vertexDataType      = Essentials.Float;
                    break;

                case BuiltinType.UShort2:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 4);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.UShort2" + (e.Normalize ? "Normalized" : ""), "Uno.Graphics.VertexAttributeType");
                    vertexDataType      = Essentials.Float2;
                    break;

                case BuiltinType.UShort4:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 8);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.UShort4" + (e.Normalize ? "Normalized" : ""), "Uno.Graphics.VertexAttributeType");
                    vertexDataType      = Essentials.Float4;
                    break;

                case BuiltinType.SByte4:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 4);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.SByte4" + (e.Normalize ? "Normalized" : ""), "Uno.Graphics.VertexAttributeType");
                    vertexDataType      = Essentials.Float4;
                    break;

                case BuiltinType.Byte4:
                    vertexStride        = new Constant(vertexBuffer.Source, Essentials.Int, 4);
                    vertexAttributeType = ILFactory.GetExpression(vertexBuffer.Source, "Uno.Graphics.VertexAttributeType.Byte4" + (e.Normalize ? "Normalized" : ""), "Uno.Graphics.VertexAttributeType");
                    vertexDataType      = Essentials.Float4;
                    break;

                default:
                    Log.Error(vertexBuffer.Source, ErrorCode.E0000, vertexDataType.Quote() + " is not a valid vertex attribute type");
                    vertexBuffer = Expression.Invalid;
                    break;
                }
            }

            Expression indexType = null;

            if (indexDataType != null)
            {
                switch (indexDataType.BuiltinType)
                {
                case BuiltinType.Byte:
                    indexType = ILFactory.GetExpression(indexBuffer.Source, "Uno.Graphics.IndexType.Byte", "Uno.Graphics.IndexType");
                    break;

                case BuiltinType.UShort:
                    indexType = ILFactory.GetExpression(indexBuffer.Source, "Uno.Graphics.IndexType.UShort", "Uno.Graphics.IndexType");
                    break;

                case BuiltinType.UInt:
                    indexType = ILFactory.GetExpression(indexBuffer.Source, "Uno.Graphics.IndexType.UInt", "Uno.Graphics.IndexType");
                    break;

                default:
                    Log.Error(indexBuffer.Source, ErrorCode.E0000, indexDataType.Quote() + " is not a valid index type");
                    indexBuffer = Expression.Invalid;
                    break;
                }
            }

            if (vertexBuffer.IsInvalid || indexBuffer != null && indexBuffer.IsInvalid)
            {
                return(Expression.Invalid);
            }

            var vertexOffset = new Constant(vertexBuffer.Source, Essentials.Int, 0);

            return(new NewVertexAttrib(e.Source, vertexDataType, vertexAttributeType, vertexBuffer, vertexStride, vertexOffset, indexType, indexBuffer));
        }
        public Statement CompileStatement(AstStatement e)
        {
            switch (e.StatementType)
            {
            default:
                if (e is AstExpression)
                {
                    return(CompileExpression(e as AstExpression));
                }
                break;

            case AstStatementType.VariableDeclaration:
                return(CompileVariableDeclaration(e as AstVariableDeclaration));

            case AstStatementType.FixedArrayDeclaration:
                return(CompileFixedArrayDeclaration(e as AstFixedArrayDeclaration));

            case AstStatementType.Scope:
                return(CompileScope(e as AstScope));

            case AstStatementType.Draw:
                return(Compiler.BlockBuilder.CompileDraw(Function, VariableScopeStack, e as AstDraw));

            case AstStatementType.DrawDispose:
                return(new DrawDispose(e.Source));

            case AstStatementType.Break:
                return(new Break(e.Source));

            case AstStatementType.Continue:
                return(new Continue(e.Source));

            case AstStatementType.Unchecked:
            {
                CheckCastStack.Add(false);

                try
                {
                    return(CompileStatement(((AstModifiedStatement)e).Statement));
                }
                finally
                {
                    CheckCastStack.RemoveLast();
                }
            }

            case AstStatementType.IfElse:
            {
                var s = e as AstIfElse;

                if (s.Condition is AstDefined)
                {
                    var def = s.Condition as AstDefined;

                    return(Environment.Test(def.Source, def.Condition)
                            ? s.OptionalIfBody != null
                                ? CompileStatement(s.OptionalIfBody)
                                : new NoOp(s.Source)
                            : s.OptionalElseBody != null
                                ? CompileStatement(s.OptionalElseBody)
                                : new NoOp(s.Source));
                }

                var r = new IfElse(s.Source, CompileCondition(s.Condition));

                if (s.OptionalIfBody != null)
                {
                    r.OptionalIfBody = CompileStatement(s.OptionalIfBody);
                }
                if (s.OptionalElseBody != null)
                {
                    r.OptionalElseBody = CompileStatement(s.OptionalElseBody);
                }

                return(r);
            }

            case AstStatementType.ExternScope:
            {
                var s = (AstExternScope)e;
                return(new ExternScope(s.Source,
                                       Compiler.CompileAttributes(Namescope, s.Attributes),
                                       s.Body.String,
                                       ExtensionTransform.CreateObject(s.Source, Function, TypeBuilder.Parameterize(Function.DeclaringType)),
                                       s.OptionalArguments != null
                            ? CompileArgumentList(s.OptionalArguments)
                            : ExtensionTransform.CreateArgumentList(s.Source, Function),
                                       GetUsings(s.Source)));
            }

            case AstStatementType.While:
            {
                var s = e as AstLoop;
                var r = new While(s.Source, false, CompileCondition(s.Condition));

                var vscope = new VariableScope();
                VariableScopeStack.Add(vscope);

                if (s.OptionalBody != null)
                {
                    r.OptionalBody = CompileStatement(s.OptionalBody);
                }

                if (s.OptionalBody == null || (!s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) || !(s.OptionalBody is AstScope))))
                {
                    VariableScopeStack.Remove(vscope);
                    CurrentVariableScope.Scopes.Add(vscope);
                }

                return(r);
            }

            case AstStatementType.DoWhile:
            {
                var s      = e as AstLoop;
                var r      = new While(s.Source, true, CompileCondition(s.Condition));
                var vscope = new VariableScope();
                VariableScopeStack.Add(vscope);

                if (s.OptionalBody != null)
                {
                    r.OptionalBody = CompileStatement(s.OptionalBody);
                }

                if (s.OptionalBody == null || (!s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) || !(s.OptionalBody is AstScope))))
                {
                    VariableScopeStack.Remove(vscope);
                    CurrentVariableScope.Scopes.Add(vscope);
                }

                return(r);
            }

            case AstStatementType.For:
            {
                var s      = e as AstFor;
                var r      = new For(s.Source);
                var vscope = new VariableScope();
                VariableScopeStack.Add(vscope);

                if (s.OptionalInitializer != null)
                {
                    r.OptionalInitializer = CompileStatement(s.OptionalInitializer);
                }
                if (s.OptionalCondition != null)
                {
                    r.OptionalCondition = CompileCondition(s.OptionalCondition);
                }
                if (s.OptionalBody != null)
                {
                    r.OptionalBody = CompileStatement(s.OptionalBody);
                }
                if (s.OptionalIncrement != null)
                {
                    r.OptionalIncrement = CompileExpression(s.OptionalIncrement);
                }

                if (s.OptionalBody == null ||
                    (!s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) ||
                                                   !(s.OptionalBody is AstScope))))
                {
                    VariableScopeStack.Remove(vscope);
                    CurrentVariableScope.Scopes.Add(vscope);
                }

                return(r);
            }

            case AstStatementType.Foreach:
            {
                var       s          = e as AstForeach;
                var       scope      = new Scope(s.Source);
                var       collection = CompileExpression(s.Collection);
                Statement result;

                var vscope = new VariableScope();
                VariableScopeStack.Add(vscope);
                VerifyVariableName(s.ElementName.Source, s.ElementName.Symbol);

                if (collection.ReturnType.IsArray ||
                    collection.ReturnType == Essentials.String)
                {
                    var loop = new For(s.Source)
                    {
                        OptionalBody = scope
                    };
                    var collectionVar = new Variable(s.Collection.Source, Function, Namescope.GetUniqueIdentifier("array"), collection.ReturnType);

                    if (collection is LoadLocal)
                    {
                        collectionVar = (collection as LoadLocal).Variable;
                    }
                    else
                    {
                        vscope.Variables.Add(collectionVar.Name, collectionVar);
                    }

                    var indexInitializer  = new Constant(s.Collection.Source, Essentials.Int, 0);
                    var lengthInitializer = CompileImplicitCast(s.Collection.Source, Essentials.Int,
                                                                CompileExpression(
                                                                    new AstMember(
                                                                        new AstIdentifier(s.Collection.Source, collectionVar.Name),
                                                                        new AstIdentifier(s.Collection.Source, "Length"))));

                    var indexVar  = new Variable(s.Collection.Source, Function, Namescope.GetUniqueIdentifier("index"), Essentials.Int);
                    var lengthVar = new Variable(s.Collection.Source, Function, Namescope.GetUniqueIdentifier("length"), Essentials.Int);

                    if (collection is LoadLocal)
                    {
                        indexVar.OptionalValue   = indexInitializer;
                        lengthVar.OptionalValue  = lengthInitializer;
                        loop.OptionalInitializer = new VariableDeclaration(indexVar, lengthVar);
                    }
                    else
                    {
                        loop.OptionalInitializer = new SequenceOp(
                            new StoreLocal(s.Collection.Source, collectionVar, collection),
                            new StoreLocal(s.Collection.Source, indexVar, indexInitializer),
                            new StoreLocal(s.Collection.Source, lengthVar, lengthInitializer));
                    }

                    vscope.Variables.Add(indexVar.Name, indexVar);
                    vscope.Variables.Add(lengthVar.Name, lengthVar);

                    loop.OptionalCondition = CompileCondition(
                        new AstBinary(AstBinaryType.LessThan,
                                      new AstIdentifier(s.Collection.Source, indexVar.Name),
                                      s.Collection.Source,
                                      new AstIdentifier(s.Collection.Source, lengthVar.Name)));

                    loop.OptionalIncrement = new FixOp(s.Collection.Source, FixOpType.IncreaseBefore,
                                                       new LoadLocal(s.Collection.Source, indexVar));

                    var elementType = s.ElementType.ExpressionType == AstExpressionType.Var
                            ? collection.ReturnType.IsArray
                                    ? collection.ReturnType.ElementType
                                    : Essentials.Char
                            : NameResolver.GetType(Namescope, s.ElementType);

                    var elementVar = new Variable(s.ElementName.Source, Function, s.ElementName.Symbol, elementType, VariableType.Iterator,
                                                  CompileImplicitCast(s.ElementName.Source, elementType,
                                                                      CompileExpression(
                                                                          new AstCall(AstCallType.LookUp,
                                                                                      new AstIdentifier(s.ElementName.Source, collectionVar.Name),
                                                                                      new AstIdentifier(s.ElementName.Source, indexVar.Name)))));

                    scope.Statements.Add(new VariableDeclaration(elementVar));
                    vscope.Variables.Add(elementVar.Name, elementVar);
                    result = loop;
                }
                else
                {
                    // TODO: Verify that collection implements IEnumerable<T>

                    var loop = new While(s.Source)
                    {
                        OptionalBody = scope
                    };
                    var enumeratorInitializer = ILFactory.CallMethod(s.Collection.Source, collection.Address, "GetEnumerator");
                    var enumeratorVar         = new Variable(s.Collection.Source, Function, Namescope.GetUniqueIdentifier("enum"), enumeratorInitializer.ReturnType, VariableType.Default, enumeratorInitializer);

                    vscope.Variables.Add(enumeratorVar.Name, enumeratorVar);

                    loop.Condition = CompileImplicitCast(s.Collection.Source, Essentials.Bool,
                                                         ILFactory.CallMethod(s.Collection.Source,
                                                                              new LoadLocal(s.Collection.Source, enumeratorVar).Address,
                                                                              "MoveNext"));

                    var elementInitializer = CompileExpression(new AstMember(
                                                                   new AstIdentifier(s.ElementName.Source, enumeratorVar.Name),
                                                                   new AstIdentifier(s.ElementName.Source, "Current")));

                    var elementType = s.ElementType.ExpressionType == AstExpressionType.Var
                                ? elementInitializer.ReturnType
                                : NameResolver.GetType(Namescope, s.ElementType);
                    var elementVar = new Variable(s.Source, Function, s.ElementName.Symbol, elementType, VariableType.Iterator,
                                                  CompileImplicitCast(s.ElementName.Source, elementType, elementInitializer));

                    var hasDispose = false;
                    foreach (var m in enumeratorVar.ValueType.Methods)
                    {
                        if (m.Name == "Dispose" && m.Parameters.Length == 0)
                        {
                            hasDispose = true;
                            break;
                        }
                    }

                    // Optimization: avoid casting to IDisposable when Dispose() method is found
                    var dispose = hasDispose
                            ? ILFactory.CallMethod(s.Collection.Source,
                                                   new LoadLocal(s.Collection.Source, enumeratorVar).Address,
                                                   "Dispose")
                            : ILFactory.CallMethod(s.Collection.Source,
                                                   new CastOp(s.Collection.Source, Essentials.IDisposable,
                                                              new LoadLocal(s.Collection.Source, enumeratorVar)).Address,
                                                   "Dispose");

                    scope.Statements.Add(new VariableDeclaration(elementVar));
                    vscope.Variables.Add(elementVar.Name, elementVar);
                    result = new Scope(s.Source,
                                       new VariableDeclaration(enumeratorVar),
                                       new TryCatchFinally(s.Source,
                                                           new Scope(s.Source, loop),
                                                           new Scope(s.Source, dispose)));
                }

                if (s.OptionalBody != null)
                {
                    var body = CompileStatement(s.OptionalBody);

                    if (body is Scope)
                    {
                        scope.Statements.AddRange((body as Scope).Statements);
                    }
                    else
                    {
                        scope.Statements.Add(body);
                    }
                }

                if (s.OptionalBody == null ||
                    !s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) ||
                                                  !(s.OptionalBody is AstScope)))
                {
                    VariableScopeStack.Remove(vscope);
                    CurrentVariableScope.Scopes.Add(vscope);
                }

                return(result);
            }

            case AstStatementType.Return:
                return(new Return(e.Source));

            case AstStatementType.ReturnValue:
            {
                var s = e as AstValueStatement;

                var returnValue = CompileExpression(s.Value);

                var returnType = Lambdas.Count == 0
                        ? Function.ReturnType
                        : Lambdas.Peek().DelegateType.ReturnType;

                return(new Return(s.Source, CompileImplicitCast(s.Source, returnType, returnValue)));
            }

            case AstStatementType.TryCatchFinally:
            {
                var   s            = e as AstTryCatchFinally;
                var   tryScope     = CompileScope(s.TryScope);
                var   catchBlocks  = new List <CatchBlock>();
                Scope finallyScope = null;

                foreach (var c in s.CatchBlocks)
                {
                    var exceptionType =
                        c.OptionalType != null?
                        NameResolver.GetType(Namescope, c.OptionalType) :
                            Essentials.Exception;

                    var vscope = new VariableScope();
                    VariableScopeStack.Add(vscope);

                    VerifyVariableName(c.Name.Source, c.Name.Symbol);
                    var exceptionVar = new Variable(c.Name.Source, Function, c.Name.Symbol, exceptionType, VariableType.Exception);
                    vscope.Variables.Add(exceptionVar.Name, exceptionVar);

                    var catchBody = CompileScope(c.Body);

                    if (c.Body == null || !c.Body.IsInvalid && c.Body.IsClosed)
                    {
                        VariableScopeStack.Remove(vscope);
                        CurrentVariableScope.Scopes.Add(vscope);
                    }

                    catchBlocks.Add(new CatchBlock(c.Name.Source, exceptionVar, catchBody));
                }

                if (s.OptionalFinallyScope != null)
                {
                    finallyScope = CompileScope(s.OptionalFinallyScope);
                }

                return(new TryCatchFinally(s.Source, tryScope, finallyScope, catchBlocks.ToArray()));
            }

            case AstStatementType.Lock:
            {
                var s            = e as AstLock;
                var scope        = new Scope(s.Source);
                var tryScope     = new Scope(s.Source);
                var finallyScope = new Scope(s.Source);
                var obj          = CompileExpression(s.Object);

                switch (obj.ExpressionType)
                {
                case ExpressionType.LoadLocal:
                case ExpressionType.LoadArgument:
                case ExpressionType.LoadField:
                case ExpressionType.This:
                case ExpressionType.Base:
                    if (!obj.ReturnType.IsReferenceType)
                    {
                        Log.Error(obj.Source, ErrorCode.E0000, "Only reference types can be used in 'lock'");
                    }
                    break;

                default:
                    Log.Error(obj.Source, ErrorCode.E0000, "Only variables can occur inside 'lock' initializer");
                    break;
                }

                if (s.OptionalBody != null)
                {
                    tryScope.Statements.Add(CompileStatement(s.OptionalBody));
                }

                scope.Statements.Add(ILFactory.CallMethod(obj.Source, Essentials.Monitor, "Enter", obj));
                finallyScope.Statements.Add(ILFactory.CallMethod(obj.Source, Essentials.Monitor, "Exit", obj));
                scope.Statements.Add(new TryCatchFinally(s.Source, tryScope, finallyScope));
                return(scope);
            }

            case AstStatementType.Using:
            {
                var s       = e as AstUsing;
                var scope   = new Scope(s.Source);
                var objects = new List <Expression>();
                var vscope  = new VariableScope();
                VariableScopeStack.Add(vscope);
                var init = CompileStatement(s.Initializer);

                for (int i = 0; i < 1; i++)
                {
                    switch (init.StatementType)
                    {
                    case StatementType.VariableDeclaration:
                    {
                        scope.Statements.Add(init);
                        for (var var = ((VariableDeclaration)init).Variable;
                             var != null;
                             var = var.Next)
                        {
                            objects.Add(new LoadLocal(var.Source, var));
                        }
                        continue;
                    }

                    case StatementType.Expression:
                    {
                        if (AddObjects(objects, (Expression)init))
                        {
                            continue;
                        }
                        break;
                    }
                    }

                    // TODO: Actually some expressions are valid as well in C#. Read spec and implement later
                    Log.Error(init.Source, ErrorCode.E0000, "Only variable declarations, fields and/or local variables can occur inside 'using' initializer");
                }

                var tryScope     = new Scope(s.Source);
                var finallyScope = new Scope(s.Source);

                if (s.OptionalBody != null)
                {
                    tryScope.Statements.Add(CompileStatement(s.OptionalBody));
                }

                foreach (var dispose in Enumerable.Reverse(objects))
                {
                    var idisposable = CompileImplicitCast(dispose.Source, Essentials.IDisposable, dispose);
                    finallyScope.Statements.Add(ILFactory.CallMethod(dispose.Source, idisposable, "Dispose"));
                }

                scope.Statements.Add(new TryCatchFinally(s.Source, tryScope, finallyScope));

                if (s.OptionalBody == null ||
                    (!s.OptionalBody.IsInvalid && ((s.OptionalBody is AstScope && (s.OptionalBody as AstScope).IsClosed) ||
                                                   !(s.OptionalBody is AstScope))))
                {
                    VariableScopeStack.Remove(vscope);
                    CurrentVariableScope.Scopes.Add(vscope);
                }

                return(scope);
            }

            case AstStatementType.ThrowValue:
            {
                var s = e as AstValueStatement;
                return(new Throw(s.Source, CompileExpression(s.Value)));
            }

            case AstStatementType.Throw:
            {
                for (int i = VariableScopeStack.Count - 1; i >= 0; i--)
                {
                    foreach (var v in VariableScopeStack[i].Variables.Values)
                    {
                        if (v.IsException)
                        {
                            return(new Throw(e.Source, new LoadLocal(e.Source, v), true));
                        }
                    }
                }

                return(Error(e.Source, ErrorCode.E0000, "Cannot rethrow outside of catch block"));
            }

            case AstStatementType.Switch:
            {
                var s = e as AstSwitch;
                var c = CompileExpression(s.Condition);

                if (!c.ReturnType.IsIntegralType)
                {
                    c = TryCompileImplicitCast(s.Source, Essentials.Int, c) ??
                        Error(s.Condition.Source, ErrorCode.E3415, "A switch expression must be of enum or integral type");
                }

                var cases = new List <SwitchCase>();

                foreach (var a in s.Cases)
                {
                    var handler         = CompileScope(a.Scope);
                    var values          = new List <Constant>();
                    var includesDefault = false;

                    foreach (var v in a.Values)
                    {
                        if (v == null)
                        {
                            includesDefault = true;
                            continue;
                        }

                        var sym      = CompileImplicitCast(v.Source, c.ReturnType, CompileExpression(v));
                        var constSym = Compiler.ConstantFolder.TryMakeConstant(sym);

                        if (constSym != null)
                        {
                            values.Add(constSym);
                        }
                        else if (sym.IsInvalid)
                        {
                            values.Add(new Constant(sym.Source, DataType.Invalid, -1));
                        }
                        else
                        {
                            Log.Error(v.Source, ErrorCode.E3410, "Case-expression must be constant");
                        }
                    }

                    cases.Add(new SwitchCase(values.ToArray(), includesDefault, handler));
                }

                return(new Switch(s.Source, c, cases.ToArray()));
            }

            case AstStatementType.Assert:
            {
                if (!Environment.Debug)
                {
                    return(new NoOp(e.Source, "Stripped assert"));
                }

                var s     = e as AstValueStatement;
                var value = CompileExpression(s.Value);
                var args  = new List <Expression>
                {
                    value,
                    new Constant(s.Source, Essentials.String, value.ToString()),
                    new Constant(s.Source, Essentials.String, s.Source.File.ToString().Replace('\\', '/')),
                    new Constant(s.Source, Essentials.Int, s.Source.Line),
                };
                var locals = new List <StoreLocal>();

                switch (value.ExpressionType)
                {
                case ExpressionType.CallUnOp:
                {
                    var o = value as CallUnOp;
                    args.Add(CreateAssertIndirection(ref o.Operand, locals, Namescope));
                    break;
                }

                case ExpressionType.CallBinOp:
                {
                    var o = value as CallBinOp;
                    args.Add(CreateAssertIndirection(ref o.Left, locals, Namescope));
                    args.Add(CreateAssertIndirection(ref o.Right, locals, Namescope));
                    break;
                }

                case ExpressionType.BranchOp:
                {
                    var o = value as BranchOp;
                    args.Add(CreateAssertIndirection(ref o.Left, locals, Namescope));
                    args.Add(CreateAssertIndirection(ref o.Right, locals, Namescope));
                    break;
                }

                case ExpressionType.CallMethod:
                {
                    var o = value as CallMethod;
                    for (int i = 0; i < o.Arguments.Length; i++)
                    {
                        args.Add(CreateAssertIndirection(ref o.Arguments[i], locals, Namescope));
                    }
                    break;
                }
                }

                var result = ILFactory.CallMethod(s.Source, "Uno.Diagnostics.Debug", "Assert", args.ToArray());

                while (locals.Count > 0)
                {
                    result = new SequenceOp(locals.RemoveLast(), result);
                }

                return(result);
            }

            case AstStatementType.DebugLog:
            {
                if (!Environment.Debug)
                {
                    return(new NoOp(e.Source, "Stripped debug_log"));
                }
                var s           = (AstValueStatement)e;
                var message     = CompileExpression(s.Value);
                var messageType = ILFactory.GetExpression(s.Source, "Uno.Diagnostics.DebugMessageType.Debug");
                var file        = new Constant(s.Source, Essentials.String, s.Source.File.ToString().Replace('\\', '/'));
                var line        = new Constant(s.Source, Essentials.Int, s.Source.Line);
                return(ILFactory.CallMethod(s.Source, "Uno.Diagnostics.Debug", "Log", message, messageType, file, line));
            }

            case AstStatementType.BuildError:
                return(CreateBuildError(e.Source, true));

            case AstStatementType.BuildWarning:
                return(CreateBuildError(e.Source, false));

            case AstStatementType.BuildErrorMessage:
            {
                var s = (AstValueStatement)e;
                return(CreateBuildError(e.Source, true, s.Value));
            }

            case AstStatementType.BuildWarningMessage:
            {
                var s = (AstValueStatement)e;
                return(CreateBuildError(e.Source, false, s.Value));
            }
            }

            Log.Error(e.Source, ErrorCode.I3411, "Unknown statement type <" + e.StatementType + ">");
            return(Expression.Invalid);
        }