314 lines
10 KiB
C#
314 lines
10 KiB
C#
|
// ---------------------------------------------------------------------------
|
||
|
// 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);
|
||
|
}
|
||
|
}
|
||
|
}
|