File: Microsoft\Build\Tasks\Xaml\XamlStackWriter.cs
Project: ndp\cdf\src\NetFx40\XamlBuildTask\XamlBuildTask.csproj (XamlBuildTask)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace Microsoft.Build.Tasks.Xaml
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Xaml;
    using System.Runtime;
    using XamlBuildTask;
 
    internal enum XamlStackFrameType
    {
        None,
        Object,
        GetObject,
        Member
    }
 
    internal struct XamlStackFrame
    {
        private static object s_setSentinel = new object();
 
        private object _data;
        private object _isSet;
 
        public XamlStackFrameType FrameType { get; private set; }
 
        public XamlType Type
        {
            get { return FrameType == XamlStackFrameType.Object ? (XamlType)_data : null; }
        }
 
        public XamlMember Member
        {
            get { return FrameType == XamlStackFrameType.Member ? (XamlMember)_data : null; }
        }
 
        public bool IsSet()
        {
            return _isSet != null;
        }
 
        public bool IsSet(XamlMember member)
        {
            HashSet<XamlMember> setMembers = _isSet as HashSet<XamlMember>;
            return (setMembers == null) ? false : setMembers.Contains(member);
        }
 
        internal void Set()
        {
            if (FrameType != XamlStackFrameType.Member)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UnexpectedXaml));
            }
            _isSet = s_setSentinel;
        }
 
        internal void Set(XamlMember member)
        {
            if (FrameType != XamlStackFrameType.Object && FrameType != XamlStackFrameType.GetObject)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UnexpectedXaml));
            }
            HashSet<XamlMember> setMembers = _isSet as HashSet<XamlMember>;
            if (setMembers == null)
            {
                setMembers = new HashSet<XamlMember>();
                _isSet = setMembers;
            }
            if (!setMembers.Contains(member))
            {
                setMembers.Add(member);
            }
        }
 
        internal static XamlStackFrame ForObject(XamlType type)
        {
            XamlStackFrame result = new XamlStackFrame();
            result._data = type;
            result.FrameType = XamlStackFrameType.Object;
            return result;
        }
 
        internal static XamlStackFrame ForGetObject()
        {
            XamlStackFrame result = new XamlStackFrame();
            result.FrameType = XamlStackFrameType.GetObject;
            return result;
        }
 
        internal static XamlStackFrame ForMember(XamlMember member)
        {
            XamlStackFrame result = new XamlStackFrame();
            result._data = member;
            result.FrameType = XamlStackFrameType.Member;
            return result;
        }
    }
 
 
    internal class XamlStackWriter : XamlWriter
    {
        List<XamlStackFrame> _stack = new List<XamlStackFrame>();
 
        // the stack writer does not care about schema context
        public override XamlSchemaContext SchemaContext { get { return null; } }
 
        public int Depth { get { return _stack.Count; } }
 
        public XamlStackFrame TopFrame
        {
            get
            {
                Fx.Assert(_stack.Count != 0, "Stack cannot be empty");
                return _stack[_stack.Count - 1];
            }
        }
 
        public XamlStackFrame FrameAtDepth(int ndx)
        {
            return _stack[ndx - 1];
        }
 
 
        public override void WriteEndMember()
        {
            if (TopFrame.FrameType != XamlStackFrameType.Member)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UnexpectedXaml));
            }
            PopStack();
        }
 
        public override void WriteEndObject()
        {
            if (TopFrame.FrameType != XamlStackFrameType.Object &&
                TopFrame.FrameType != XamlStackFrameType.GetObject)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UnexpectedXaml));
            }
            PopStack();
        }
 
        public override void WriteGetObject()
        {
            SetTopFrame();
            _stack.Add(XamlStackFrame.ForGetObject());
        }
 
        public override void WriteNamespace(NamespaceDeclaration namespaceDeclaration)
        {
            throw FxTrace.Exception.AsError(new NotImplementedException());
        }
 
        public override void WriteStartMember(XamlMember property)
        {
            if (property == null)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UnexpectedXamlValueNull("property")));
            }
            SetTopFrame(property);
            _stack.Add(XamlStackFrame.ForMember(property));
        }
 
        public override void WriteStartObject(XamlType type)
        {
            if (type == null)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UnexpectedXamlValueNull("type")));
            }
            SetTopFrame();
            _stack.Add(XamlStackFrame.ForObject(type));
        }
 
        public override void WriteValue(object value)
        {
            SetTopFrame();
        }
 
        private void PopStack()
        {
            _stack.RemoveAt(_stack.Count - 1);
        }
 
        private void SetTopFrame()
        {
            if (Depth > 0 && TopFrame.FrameType == XamlStackFrameType.Member)
            {
                TopFrame.Set();
            }
        }
 
        private void SetTopFrame(XamlMember member)
        {
            if (Depth > 0 &&
                (TopFrame.FrameType == XamlStackFrameType.GetObject ||
                 TopFrame.FrameType == XamlStackFrameType.Object))
            {
                TopFrame.Set(member);
            }
        }
    }
}