Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ParadoxStreamAnalyzer.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 
6 using SiliconStudio.Paradox.Shaders.Parser.Analysis;
7 using SiliconStudio.Paradox.Shaders.Parser.Ast;
8 using SiliconStudio.Paradox.Shaders.Parser.Utility;
9 using SiliconStudio.Shaders.Ast;
10 using SiliconStudio.Shaders.Ast.Hlsl;
11 using SiliconStudio.Shaders.Utility;
12 using SiliconStudio.Shaders.Visitor;
13 
14 namespace SiliconStudio.Paradox.Shaders.Parser.Mixins
15 {
16  internal class ParadoxStreamAnalyzer : ShaderVisitor
17  {
18  #region Private members
19 
20  /// <summary>
21  /// Current stream usage
22  /// </summary>
23  private StreamUsage currentStreamUsage = StreamUsage.Read;
24 
25  /// <summary>
26  /// List of stream usage
27  /// </summary>
28  private List<StreamUsageInfo> currentStreamUsageList = null;
29 
30  /// <summary>
31  /// List of already added methods.
32  /// </summary>
33  private List<MethodDeclaration> alreadyAddedMethodsList = null;
34 
35  /// <summary>
36  /// Status of the assignment
37  /// </summary>
38  private AssignmentOperatorStatus currentAssignmentOperatorStatus = AssignmentOperatorStatus.Read;
39 
40  /// <summary>
41  /// Log of all the warnings and errors
42  /// </summary>
43  private LoggerResult errorWarningLog;
44 
45  /// <summary>
46  /// Name of the shader
47  /// </summary>
48  private string shaderName = "Mix";
49 
50  #endregion
51 
52  #region Public members
53 
54  /// <summary>
55  /// List of assignations in the form of "streams = ...;"
56  /// </summary>
57  public HashSet<AssignmentExpression> StreamAssignations = new HashSet<AssignmentExpression>();
58 
59  /// <summary>
60  /// List of assignations in the form of "... = streams;"
61  /// </summary>
62  public HashSet<AssignmentExpression> AssignationsToStream = new HashSet<AssignmentExpression>();
63 
64  /// <summary>
65  /// streams usage by method
66  /// </summary>
67  public Dictionary<MethodDeclaration, List<StreamUsageInfo>> StreamsUsageByMethodDefinition = new Dictionary<MethodDeclaration, List<StreamUsageInfo>>();
68 
69  /// <summary>
70  /// A list containing all the "streams" Variable references
71  /// </summary>
72  public HashSet<MethodInvocationExpression> AppendMethodCalls = new HashSet<MethodInvocationExpression>();
73 
74  #endregion
75 
76  #region Constructor
77 
78  public ParadoxStreamAnalyzer(LoggerResult errorLog)
79  : base(false, true)
80  {
81  errorWarningLog = errorLog ?? new LoggerResult();
82  }
83 
84  #endregion
85 
86  public void Run(ShaderClassType shaderClassType)
87  {
88  shaderName = shaderClassType.Name.Text;
89  Visit(shaderClassType);
90  }
91 
92  #region Private methods
93 
94  /// <summary>
95  /// Analyse the method definition and store it in the correct lists (based on storage and stream usage)
96  /// </summary>
97  /// <param name="methodDefinition">the MethodDefinition</param>
98  [Visit]
99  protected void Visit(MethodDefinition methodDefinition)
100  {
101  currentStreamUsageList = new List<StreamUsageInfo>();
102  alreadyAddedMethodsList = new List<MethodDeclaration>();
103 
104  Visit((Node)methodDefinition);
105 
106  if (currentStreamUsageList.Count > 0)
107  StreamsUsageByMethodDefinition.Add(methodDefinition, currentStreamUsageList);
108  }
109 
110  /// <summary>
111  /// Calls the base method but modify the stream usage beforehand
112  /// </summary>
113  /// <param name="expression">the method expression</param>
114  [Visit]
115  protected void Visit(MethodInvocationExpression expression)
116  {
117  Visit((Node)expression);
118 
119  var methodDecl = expression.Target.TypeInference.Declaration as MethodDeclaration;
120 
121  if (methodDecl != null)
122  {
123  // Stream analysis
124  if (methodDecl.ContainsTag(ParadoxTags.ShaderScope)) // this will prevent built-in function to appear in the list
125  {
126  // test if the method was previously added
127  if (!alreadyAddedMethodsList.Contains(methodDecl))
128  {
129  currentStreamUsageList.Add(new StreamUsageInfo { CallType = StreamCallType.Method, MethodDeclaration = methodDecl, Expression = expression });
130  alreadyAddedMethodsList.Add(methodDecl);
131  }
132  }
133  for (int i = 0; i < expression.Arguments.Count; ++i)
134  {
135  var arg = expression.Arguments[i] as MemberReferenceExpression; // TODO:
136 
137  if (arg != null && IsStreamMember(arg))
138  {
139  var isOut = methodDecl.Parameters[i].Qualifiers.Contains(SiliconStudio.Shaders.Ast.ParameterQualifier.Out);
140 
141  //if (methodDecl.Parameters[i].Qualifiers.Contains(Ast.ParameterQualifier.InOut))
142  // Error(MessageCode.ErrorInOutStream, expression.Span, arg, methodDecl, contextModuleMixin.MixinName);
143 
144  var usage = methodDecl.Parameters[i].Qualifiers.Contains(SiliconStudio.Shaders.Ast.ParameterQualifier.Out) ? StreamUsage.Write : StreamUsage.Read;
145  AddStreamUsage(arg.TypeInference.Declaration as Variable, arg, usage);
146  }
147  }
148  }
149 
150  // TODO: <shaderclasstype>.Append should be avoided
151  if (expression.Target is MemberReferenceExpression && (expression.Target as MemberReferenceExpression).Target.TypeInference.TargetType is ClassType && (expression.Target as MemberReferenceExpression).Member.Text == "Append")
152  AppendMethodCalls.Add(expression);
153  }
154 
155  private static bool IsStreamMember(MemberReferenceExpression expression)
156  {
157  if (expression.TypeInference.Declaration is Variable)
158  {
159  return (expression.TypeInference.Declaration as Variable).Qualifiers.Contains(ParadoxStorageQualifier.Stream);
160  }
161  return false;
162  }
163 
164  /// <summary>
165  /// Analyse the VariableReferenceExpression, detects streams, propagate type inference, get stored in the correct list for later analysis
166  /// </summary>
167  /// <param name="variableReferenceExpression">the VariableReferenceExpression</param>
168  [Visit]
169  protected void Visit(VariableReferenceExpression variableReferenceExpression)
170  {
171  Visit((Node)variableReferenceExpression);
172  // HACK: force types on base, this and stream keyword to eliminate errors in the log an use the standard type inference
173  var name = variableReferenceExpression.Name.Text;
174  if (name == "streams")
175  {
176  if (!(ParentNode is MemberReferenceExpression)) // streams is alone
177  currentStreamUsageList.Add(new StreamUsageInfo { CallType = StreamCallType.Direct, Variable = ParadoxSemanticAnalysis.StreamsVariable, Expression = variableReferenceExpression, Usage = currentStreamUsage });
178  }
179  }
180 
181  [Visit]
182  protected void Visit(MemberReferenceExpression memberReferenceExpression)
183  {
184  Visit((Node)memberReferenceExpression);
185 
186  // check if it is a stream
187  if (IsStreamMember(memberReferenceExpression))
188  AddStreamUsage(memberReferenceExpression.TypeInference.Declaration as Variable, memberReferenceExpression, currentStreamUsage);
189  }
190 
191  [Visit]
192  protected void Visit(BinaryExpression expression)
193  {
194  var prevStreamUsage = currentStreamUsage;
195  currentStreamUsage = StreamUsage.Read;
196  Visit((Node)expression);
197  currentStreamUsage = prevStreamUsage;
198  }
199 
200  [Visit]
201  protected void Visit(UnaryExpression expression)
202  {
203  var prevStreamUsage = currentStreamUsage;
204  currentStreamUsage = StreamUsage.Read;
205  Visit((Node)expression);
206  currentStreamUsage = prevStreamUsage;
207  }
208 
209  /// <summary>
210  /// Analyse the AssignmentExpression to correctly infer the potential stream usage
211  /// </summary>
212  /// <param name="assignmentExpression">the AssignmentExpression</param>
213  [Visit]
214  private void Visit(AssignmentExpression assignmentExpression)
215  {
216  if (currentAssignmentOperatorStatus != AssignmentOperatorStatus.Read)
217  errorWarningLog.Error(ParadoxMessageCode.ErrorNestedAssignment, assignmentExpression.Span, assignmentExpression, shaderName);
218 
219  var prevStreamUsage = currentStreamUsage;
220  currentStreamUsage = StreamUsage.Read;
221  assignmentExpression.Value = (Expression)VisitDynamic(assignmentExpression.Value);
222  currentAssignmentOperatorStatus = (assignmentExpression.Operator != AssignmentOperator.Default) ? AssignmentOperatorStatus.ReadWrite : AssignmentOperatorStatus.Write;
223 
224  currentStreamUsage = StreamUsage.Write;
225  assignmentExpression.Target = (Expression)VisitDynamic(assignmentExpression.Target);
226 
227  currentAssignmentOperatorStatus = AssignmentOperatorStatus.Read;
228  currentStreamUsage = prevStreamUsage;
229 
230  if (assignmentExpression.Operator == AssignmentOperator.Default)
231  {
232  if (assignmentExpression.Target is VariableReferenceExpression && (assignmentExpression.Target as VariableReferenceExpression).Name.Text == "streams") // "streams = ...;"
233  StreamAssignations.Add(assignmentExpression);
234  else if (assignmentExpression.Value is VariableReferenceExpression && (assignmentExpression.Value as VariableReferenceExpression).Name.Text == "streams") // "... = streams;"
235  AssignationsToStream.Add(assignmentExpression);
236  }
237  }
238 
239  /// <summary>
240  /// Adds a stream usage to the current method
241  /// </summary>
242  /// <param name="variable">the stream Variable</param>
243  /// <param name="expression">the calling expression</param>
244  /// <param name="usage">the encountered usage</param>
245  private void AddStreamUsage(Variable variable, SiliconStudio.Shaders.Ast.Expression expression, StreamUsage usage)
246  {
247  currentStreamUsageList.Add(new StreamUsageInfo { CallType = StreamCallType.Member, Variable = variable, Expression = expression, Usage = usage });
248  }
249 
250  #endregion
251  }
252 
253  [Flags]
254  public enum StreamUsage
255  {
256  Unknown = 0,
257  Read = 1,
258  Write = 2
259  }
260 
261  public enum StreamCallType
262  {
263  Unknown = 0,
264  Member = 1,
265  Method = 2,
266  Direct = 3
267  }
268 
269  public class StreamUsageInfo
270  {
271  public StreamUsage Usage = StreamUsage.Unknown;
272  public StreamCallType CallType = StreamCallType.Unknown;
273  public Variable Variable = null;
274  public MethodDeclaration MethodDeclaration = null;
276  }
277 }
Describes a binary expression.
SiliconStudio.Core.Diagnostics.LoggerResult LoggerResult
string Text
Gets or sets the name.
Definition: Identifier.cs:77
A class to collect parsing/expression messages.
Definition: LoggerResult.cs:13
AssignmentOperator
Assignment operator used in assignment expression (a = b) or statements (a = b;)
A method definition with a body of statements.
Abstract node.
Definition: Node.cs:15
IDeclaration Declaration
Gets or sets the declaration.
TypeInference TypeInference
Gets or sets the type reference.
Definition: Expression.cs:28
Flags
Enumeration of the new Assimp's flags.
A variable declaration.
Definition: Variable.cs:11
A member reference in the form {this}.{Name}
document false