File: Rules\Parser\Symbol.cs
Project: ndp\cdf\src\WF\Activities\System.Workflow.Activities.csproj (System.Workflow.Activities)
// ---------------------------------------------------------------------------
// Copyright (C) 2006 Microsoft Corporation All Rights Reserved
// ---------------------------------------------------------------------------
 
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text;
 
 
namespace System.Workflow.Activities.Rules
{
    internal abstract class Symbol
    {
        internal abstract string Name { get; }
        internal abstract CodeExpression ParseRootIdentifier(Parser parser, ParserContext parserContext, bool assignIsEquality);
        internal abstract void RecordSymbol(ArrayList list);
    }
 
    // Represents a field, property, or method within "this".  (Not a nested type.)
    internal class MemberSymbol : Symbol
    {
        private MemberInfo member;
 
        internal MemberSymbol(MemberInfo member)
        {
            this.member = member;
        }
 
        internal override string Name
        {
            get { return member.Name; }
        }
 
        internal override CodeExpression ParseRootIdentifier(Parser parser, ParserContext parserContext, bool assignIsEquality)
        {
            return parser.ParseUnadornedMemberIdentifier(parserContext, this, assignIsEquality);
        }
 
        internal override void RecordSymbol(ArrayList list)
        {
            list.Add(member);
        }
    }
 
    internal class NamespaceSymbol : Symbol
    {
        private string name;
        internal readonly NamespaceSymbol Parent;
        internal Dictionary<string, Symbol> NestedSymbols;
        internal readonly int Level;
 
        internal NamespaceSymbol(string name, NamespaceSymbol parent)
        {
            this.name = name;
            this.Parent = parent;
            this.Level = (parent == null) ? 0 : parent.Level + 1;
        }
 
        // For unnamed namespaces.  There is only one of these.
        internal NamespaceSymbol()
        {
        }
 
        internal override string Name
        {
            get { return name; }
        }
 
        internal NamespaceSymbol AddNamespace(string nsName)
        {
            if (NestedSymbols == null)
                NestedSymbols = new Dictionary<string, Symbol>();
 
            Symbol ns = null;
            if (!NestedSymbols.TryGetValue(nsName, out ns))
            {
                ns = new NamespaceSymbol(nsName, this);
                NestedSymbols.Add(nsName, ns);
            }
 
            return ns as NamespaceSymbol;
        }
 
        internal void AddType(Type type)
        {
            TypeSymbol typeSym = new TypeSymbol(type);
            string typeName = typeSym.Name;
 
            if (NestedSymbols == null)
                NestedSymbols = new Dictionary<string, Symbol>();
 
            Symbol existingSymbol = null;
            if (NestedSymbols.TryGetValue(typeName, out existingSymbol))
            {
                OverloadedTypeSymbol overloadSym = existingSymbol as OverloadedTypeSymbol;
                if (overloadSym == null)
                {
                    TypeSymbol typeSymbol = existingSymbol as TypeSymbol;
                    System.Diagnostics.Debug.Assert(typeSymbol != null);
                    overloadSym = new OverloadedTypeSymbol(typeName, typeSym, typeSymbol);
                    NestedSymbols[typeName] = overloadSym;
                }
                else
                {
                    overloadSym.AddLocalType(typeSym);
                }
            }
            else
            {
                NestedSymbols.Add(typeName, typeSym);
            }
        }
 
        internal Symbol FindMember(string memberName)
        {
            Symbol nestedSym = null;
            NestedSymbols.TryGetValue(memberName, out nestedSym);
            return nestedSym;
        }
 
        internal ArrayList GetMembers()
        {
            ArrayList members = new ArrayList(NestedSymbols.Count);
            foreach (Symbol sym in NestedSymbols.Values)
                sym.RecordSymbol(members);
 
            return members;
        }
 
        internal string GetQualifiedName()
        {
            StringBuilder sb = new StringBuilder();
 
            Stack<string> names = new Stack<string>();
 
            names.Push(Name);
            for (NamespaceSymbol currentParent = Parent; currentParent != null; currentParent = currentParent.Parent)
                names.Push(currentParent.Name);
 
            sb.Append(names.Pop());
            while (names.Count > 0)
            {
                sb.Append('.');
                sb.Append(names.Pop());
            }
 
            return sb.ToString();
        }
 
        internal override CodeExpression ParseRootIdentifier(Parser parser, ParserContext parserContext, bool assignIsEquality)
        {
            return parser.ParseRootNamespaceIdentifier(parserContext, this, assignIsEquality);
        }
 
        internal override void RecordSymbol(ArrayList list)
        {
            // Just add the name (string) to the member list.
            list.Add(Name);
        }
    }
 
    internal abstract class TypeSymbolBase : Symbol
    {
        internal abstract OverloadedTypeSymbol OverloadType(TypeSymbolBase typeSymBase);
    }
 
    internal class TypeSymbol : TypeSymbolBase
    {
        internal readonly Type Type;
        internal readonly int GenericArgCount;
        private string name;
 
        internal TypeSymbol(Type type)
        {
            this.Type = type;
            this.name = type.Name;
 
            if (type.IsGenericType)
            {
                int tickIx = type.Name.LastIndexOf('`');
                if (tickIx > 0)
                {
                    string count = type.Name.Substring(tickIx + 1);
                    GenericArgCount = Int32.Parse(count, CultureInfo.InvariantCulture);
                    name = type.Name.Substring(0, tickIx);
                }
            }
        }
 
        internal override string Name
        {
            get { return name; }
        }
 
        internal override OverloadedTypeSymbol OverloadType(TypeSymbolBase newTypeSymBase)
        {
            OverloadedTypeSymbol newTypeOverload = newTypeSymBase as OverloadedTypeSymbol;
            if (newTypeOverload != null)
            {
                // We've encountered an overloaded type symbol over a previous simple
                // type symbol.
                return newTypeOverload.OverloadType(this);
            }
            else
            {
                // We've encountered two simple types... just create an overload for them if
                // possible.
                TypeSymbol newTypeSym = newTypeSymBase as TypeSymbol;
                if (newTypeSym != null && this.CanOverload(newTypeSym))
                    return new OverloadedTypeSymbol(name, this, newTypeSym);
            }
 
            return null;
        }
 
        internal bool CanOverload(TypeSymbol typeSym)
        {
            return typeSym.GenericArgCount != this.GenericArgCount;
        }
 
        internal override CodeExpression ParseRootIdentifier(Parser parser, ParserContext parserContext, bool assignIsEquality)
        {
            // The root name is a type (might be generic or not).
            return parser.ParseRootTypeIdentifier(parserContext, this, assignIsEquality);
        }
 
        internal override void RecordSymbol(ArrayList list)
        {
            // Add the System.Type to the member list.
            list.Add(Type);
        }
    }
 
    internal class OverloadedTypeSymbol : TypeSymbolBase
    {
        internal List<TypeSymbol> TypeSymbols = new List<TypeSymbol>();
        private string name;
 
        internal OverloadedTypeSymbol(string name, TypeSymbol typeSym1, TypeSymbol typeSym2)
        {
            this.name = name;
            AddLocalType(typeSym1);
            AddLocalType(typeSym2);
        }
 
        private OverloadedTypeSymbol(string name, List<TypeSymbol> typeSymbols)
        {
            this.name = name;
            this.TypeSymbols = typeSymbols;
        }
 
        internal override string Name
        {
            get { return name; }
        }
 
        // Add a local overload (within the same namespace).
        internal void AddLocalType(TypeSymbol typeSym)
        {
            // Since it's a local overload, we don't have to check whether it's ambiguous.
            TypeSymbols.Add(typeSym);
        }
 
        internal override OverloadedTypeSymbol OverloadType(TypeSymbolBase newTypeSymBase)
        {
            List<TypeSymbol> newOverloads = new List<TypeSymbol>();
            TypeSymbol typeSym = null;
 
            OverloadedTypeSymbol newTypeOverload = newTypeSymBase as OverloadedTypeSymbol;
            if (newTypeOverload != null)
            {
                newOverloads.AddRange(newTypeOverload.TypeSymbols);
            }
            else
            {
                // We've encountered a simple type... just create an overload for them if
                // possible.
                typeSym = newTypeSymBase as TypeSymbol;
                if (typeSym != null)
                    newOverloads.Add(typeSym);
            }
 
            // If every item in this overloaded type symbol is overloadable with the new one,
            // add to the new list all our items.
            foreach (TypeSymbol thisTypeSym in this.TypeSymbols)
            {
                foreach (TypeSymbol newTypeSym in newOverloads)
                {
                    if (!newTypeSym.CanOverload(thisTypeSym))
                        return null; // Can't overload
                }
 
                newOverloads.Add(thisTypeSym);
            }
 
            return new OverloadedTypeSymbol(name, newOverloads);
        }
 
        internal override CodeExpression ParseRootIdentifier(Parser parser, ParserContext parserContext, bool assignIsEquality)
        {
            return parser.ParseRootOverloadedTypeIdentifier(parserContext, this.TypeSymbols, assignIsEquality);
        }
 
        internal override void RecordSymbol(ArrayList list)
        {
            foreach (TypeSymbol overloadedType in TypeSymbols)
                list.Add(overloadedType.Type);
        }
    }
}