4 using System.Collections.Concurrent;
5 using System.Collections.Generic;
6 using System.Reflection;
7 using SiliconStudio.Shaders.Ast;
10 namespace SiliconStudio.Shaders.Visitor
17 private delegate
object NodeVisitFunction(
VisitorBase visitor,
object node);
19 private readonly
static Dictionary<Type, Dictionary<Type, NodeVisitFunction>> AllVisitors =
new Dictionary<Type, Dictionary<Type, NodeVisitFunction>>();
20 private readonly
static Dictionary<Type, List<Type>> MapDefaultTypeToInheritance =
new Dictionary<Type, List<Type>>();
21 private readonly Dictionary<Type, NodeVisitFunction> methodVisitors;
22 private readonly Dictionary<Type, List<Type>> mapTypeToInheritance =
new Dictionary<Type, List<Type>>();
24 #region Constructors and Destructors
34 Dictionary<Type, NodeVisitFunction> concurrentVisitors;
35 var thisType = GetType();
36 if (!AllVisitors.TryGetValue(thisType, out concurrentVisitors))
38 concurrentVisitors = Initialize(
this);
39 AllVisitors.Add(thisType, concurrentVisitors);
41 methodVisitors =
new Dictionary<Type, NodeVisitFunction>(concurrentVisitors);
42 mapTypeToInheritance =
new Dictionary<Type, List<Type>>(MapDefaultTypeToInheritance);
47 NodeStack =
new List<Node>();
53 #region Public Properties
61 public List<Node> NodeStack {
get; set; }
65 #region Public Methods
73 protected void VisitDynamicList<T>(
IList<T> list, Func<T, bool> filter = null) where T :
Node
75 for (
int i = 0; i < list.Count; i++)
80 if (filter != null && filter(item))
continue;
82 var newNode = VisitDynamic(list[i]);
89 else if (!ReferenceEquals(newNode, item))
105 protected virtual Node VisitDynamic<T>(T node,
bool visitRealType =
true) where T :
Node
112 bool nodeStackAdded =
false;
114 if (NodeStack != null)
116 if (NodeStack.Count > 0 && ReferenceEquals(NodeStack[NodeStack.Count - 1], node))
117 throw new InvalidOperationException(
string.Format(
"Cannot visit recursively a node [{0}] already being visited", node));
120 nodeStackAdded =
true;
124 bool doVisit = PreVisitNode(node);
127 var result = (
Node)node;
130 NodeVisitFunction process = null;
131 var typeToVisit = visitRealType ? node.GetType() : typeof(T);
133 if (!methodVisitors.TryGetValue(typeToVisit, out process))
135 foreach (var ancestor
in Ancestors(typeToVisit))
137 if (methodVisitors.TryGetValue(ancestor, out process))
140 if (typeToVisit != ancestor)
141 methodVisitors[typeToVisit] = process;
148 throw new InvalidOperationException(
string.Format(
"Unable to find a suitable visitor method for this type [{0}]", typeToVisit.FullName));
150 result = (
Node)process(
this, node);
154 PostVisitNode(node, doVisit);
156 if (NodeStack != null && nodeStackAdded)
158 NodeStack.RemoveAt(NodeStack.Count - 1);
171 return Ancestors(mapTypeToInheritance, type);
183 if (registeredTypes.TryGetValue(type, out inheritance))
187 inheritance.AddRange(type.GetInterfaces());
188 var baseType = type.BaseType;
189 while (baseType != null)
191 inheritance.Add(baseType);
192 baseType = baseType.BaseType;
194 registeredTypes[type] = inheritance;
200 MapDefaultTypeToInheritance[type] = inheritance;
205 private static Dictionary<Type, NodeVisitFunction> Initialize(VisitorBase visitor)
207 var methodVisitors =
new Dictionary<Type, NodeVisitFunction>();
208 var methods = visitor.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
210 foreach (var method
in methods)
212 var attributes = method.GetCustomAttributes(typeof(VisitAttribute),
true);
213 if (attributes.Length > 0)
216 var
function = BuildMethodVisitor(method, out parameterType);
217 methodVisitors[parameterType] =
function;
220 Ancestors(MapDefaultTypeToInheritance, parameterType);
223 return methodVisitors;
226 private static NodeVisitFunction BuildMethodVisitor(MethodInfo method, out Type parameterType)
228 var declaringtype = method.DeclaringType;
230 if (declaringtype == null)
231 throw new InvalidOperationException(
string.Format(
"No declaring type for method [{0}]", method.Name));
234 if (method.GetParameters().Length != 1)
235 throw new InvalidOperationException(
236 string.Format(
"Invalid number of parameters [{0}] for visit method [{1}] for type [{2}]. One parameter is expected", method.GetParameters().Length, method.Name, declaringtype.FullName));
238 parameterType = method.GetParameters()[0].ParameterType;
239 if (!parameterType.IsInterface && !typeof(
Node).IsAssignableFrom(parameterType))
240 throw new InvalidOperationException(
241 string.Format(
"Invalid type parameter [{0}] for visit method [{1}] for type [{2}]. Parameter must inherit from Node", parameterType, method.Name, declaringtype.FullName));
243 var thisParameter = LinqExpression.Parameter(typeof(VisitorBase),
"this");
244 var nodeParameter = LinqExpression.Parameter(typeof(
object),
"node");
245 var thisCastVariable = LinqExpression.Variable(declaringtype,
"thisCast");
247 var statements =
new List<LinqExpression>
249 LinqExpression.Assign(thisCastVariable, LinqExpression.Convert(thisParameter, declaringtype))
252 var callVisitMethod = LinqExpression.Call(thisCastVariable, method, LinqExpression.Convert(nodeParameter, parameterType));
254 if (typeof(
void) == method.ReturnType)
256 statements.Add(callVisitMethod);
257 statements.Add(nodeParameter);
261 statements.Add(callVisitMethod);
264 var block = LinqExpression.Block(
new[] { thisCastVariable }, statements);
266 var lambda = LinqExpression.Lambda<NodeVisitFunction>(block, thisParameter, nodeParameter);
267 return lambda.Compile();
294 [AttributeUsage(AttributeTargets.Method, Inherited =
true, AllowMultiple =
false)]
Tag a visitable method with this attribute.
virtual void PostVisitNode(Node node, bool nodeVisited)
Called after visiting the node.
virtual bool PreVisitNode(Node node)
Called before visiting the node.
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.
VisitorBase(bool useNodeStack=false)
Initializes a new instance of the VisitorBase class.
System.Linq.Expressions.Expression LinqExpression