Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ParadoxSemanticAnalysis.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.Collections.Generic;
4 using System.Linq;
5 
6 using SiliconStudio.Paradox.Shaders.Parser.Ast;
7 using SiliconStudio.Paradox.Shaders.Parser.Mixins;
8 using SiliconStudio.Paradox.Shaders.Parser.Utility;
9 using SiliconStudio.Shaders.Ast;
10 using SiliconStudio.Shaders.Ast.Hlsl;
11 using SiliconStudio.Shaders.Parser;
12 using SiliconStudio.Shaders.Visitor;
13 
15 
16 namespace SiliconStudio.Paradox.Shaders.Parser.Analysis
17 {
18  internal class ParadoxSemanticAnalysis : ParadoxTypeAnalysis
19  {
20  #region Static members
21 
22  /// <summary>
23  /// List of useful language keywords
24  /// </summary>
25  private static readonly string[] ParadoxKeywords = { "base", "streams", "this" };
26 
27  /// <summary>
28  /// List of all the stream types
29  /// </summary>
30  private static readonly string[] StreamTypes = { "Streams", "Input", "Input2", "Output", "Constants" };
31 
32  /// <summary>
33  /// A fake variable of custom type stream
34  /// </summary>
35  public static Variable StreamsVariable = new Variable(ParadoxType.Streams, "streams");
36 
37  #endregion
38 
39  #region Private members
40 
41  /// <summary>
42  /// The structure that will store all the information
43  /// </summary>
44  private ParadoxParsingInfo parsingInfo;
45 
46  /// <summary>
47  /// List of all the mixins inside the module
48  /// </summary>
49  private readonly HashSet<ModuleMixin> moduleMixins = new HashSet<ModuleMixin>();
50 
51  /// <summary>
52  /// The module that is the context of the analysis
53  /// </summary>
54  private readonly ModuleMixin analyzedModuleMixin = null;
55 
56  /// <summary>
57  /// The method currently visited
58  /// </summary>
59  private MethodDeclaration currentVisitedMethod = null;
60 
61  /// <summary>
62  /// a flag stating if the visitor visits a sampler
63  /// </summary>
64  private bool inSampler = false;
65 
66  /// <summary>
67  /// Status of the assignment
68  /// </summary>
69  private AssignmentOperatorStatus currentAssignmentOperatorStatus = AssignmentOperatorStatus.Read;
70 
71  /// <summary>
72  /// A flag for expanding foreach statements
73  /// </summary>
74  private bool expandForEachStatements;
75 
76  #endregion
77 
78  #region Constructor and helpers
79 
80  /// <summary>
81  /// Initializes a new instance of the <see cref="ParadoxSemanticAnalysis"/> class.
82  /// </summary>
83  /// <param name="result">The result</param>
84  /// <param name="analyzedMixin">the context in which the analysis is set</param>
85  /// <param name="moduleMixinsInCompilationGroup">the list of all the modules that are not in the inheritance hierarchy of the context</param>
86  public ParadoxSemanticAnalysis(ParsingResult result, ModuleMixin analyzedMixin, List<ModuleMixin> moduleMixinsInCompilationGroup)
87  : base(result)
88  {
89  SetupHlslAnalyzer();
90 
91  analyzedModuleMixin = analyzedMixin;
92 
93  ScopeStack.First().AddDeclaration(StreamsVariable);
94 
95  var currentScope = new ScopeDeclaration(analyzedMixin.Shader);
96  ScopeStack.Push(currentScope);
97 
98  currentScope.AddDeclarations(analyzedMixin.VirtualTable.Typedefs);
99  currentScope.AddDeclarations(analyzedMixin.VirtualTable.StructureTypes);
100  currentScope.AddDeclarations(analyzedMixin.VirtualTable.Variables.Select(x => x.Variable));
101  currentScope.AddDeclarations(analyzedMixin.VirtualTable.Methods.Select(x => x.Method));
102  currentScope.AddDeclarations(analyzedMixin.InheritanceList.Select(x => x.Shader));
103 
104  // add the mixins in the compilation group
105  var sd = new ScopeDeclaration();
106  ScopeStack.Push(sd);
107  foreach (var mixin in moduleMixinsInCompilationGroup)
108  {
109  moduleMixins.Add(mixin);
110  sd.AddDeclaration(mixin.Shader);
111  }
112  }
113 
114  #endregion
115 
116  #region Public static methods
117 
118  /// <summary>
119  /// Run the analysis
120  /// </summary>
121  /// <param name="mixinToAnalyze">the current context (virtual table) from mixin inheritance</param>
122  /// <param name="compilationContext">List of all the mixin in the compilation context</param>
123  /// <returns>true if the shader is correct, false otherwise</returns>
124  public static ParadoxParsingInfo RunAnalysis(ModuleMixin mixinToAnalyze, List<ModuleMixin> compilationContext, bool transformForEach = false)
125  {
126  var shader = new Shader();
127  shader.Declarations.Add(mixinToAnalyze.Shader);
128  var toParse = new ParsingResult { Shader = shader };
129  var analysis = new ParadoxSemanticAnalysis(toParse, mixinToAnalyze, compilationContext) { parsingInfo = new ParadoxParsingInfo() };
130  analysis.expandForEachStatements = transformForEach;
131  analysis.Run();
132 
133  // look at the static classes
134  analysis.parsingInfo.StaticClasses.UnionWith(analysis.parsingInfo.StaticReferences.VariablesReferences.Select(x => x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin));
135  analysis.parsingInfo.StaticClasses.UnionWith(analysis.parsingInfo.StaticReferences.MethodsReferences.Select(x => x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin));
136  analysis.parsingInfo.StaticClasses.Remove(mixinToAnalyze);
137  analysis.parsingInfo.ErrorsWarnings = analysis.ParsingResult;
138 
139  return analysis.parsingInfo;
140  }
141 
142  #endregion
143 
144  #region Private and protected methods
145 
146  /// <summary>
147  /// Visits the specified shader type name.
148  /// </summary>
149  /// <param name="shaderTypeName">Name of the type.</param>
150  [Visit]
151  protected TypeBase Visit(ShaderTypeName shaderTypeName)
152  {
153  // just here to prevent a problem when a mixin class is called Texture (that creates an hlsl typename instead)
154  // grammar was changed accordingly
155  Visit((Node)shaderTypeName);
156  return shaderTypeName;
157  }
158 
159  /// <summary>
160  /// Store the method in the correct list
161  /// </summary>
162  /// <param name="methodDeclaration"></param>
163  private void StoreMethod(MethodDeclaration methodDeclaration)
164  {
165  if (!parsingInfo.ClassReferences.MethodsReferences.ContainsKey(methodDeclaration))
166  parsingInfo.ClassReferences.MethodsReferences.Add(methodDeclaration, new HashSet<MethodInvocationExpression>());
167  }
168 
169  /// <summary>
170  /// Checks that the method does not have mixin as parameter or return type
171  /// </summary>
172  /// <param name="methodDeclaration">the method.</param>
173  private void CheckParamatersAndReturnType(MethodDeclaration methodDeclaration)
174  {
175  foreach (var parameter in methodDeclaration.Parameters)
176  {
177  if (parameter.Type.TypeInference.Declaration is ShaderClassType)
178  Error(ParadoxMessageCode.ErrorShaderClassTypeParameter, methodDeclaration.Span, methodDeclaration, parameter, analyzedModuleMixin.MixinName);
179  }
180 
181  if (methodDeclaration.ReturnType.TypeInference.Declaration is ShaderClassType)
182  Error(ParadoxMessageCode.ErrorShaderClassReturnType, methodDeclaration.Span, methodDeclaration, analyzedModuleMixin.MixinName);
183  }
184 
185  /// <summary>
186  /// Analyse the method declaration and store it in the correct list
187  /// </summary>
188  /// <param name="methodDeclaration">The MethodDeclaration</param>
189  [Visit]
190  protected void Visit(MethodDeclaration methodDeclaration)
191  {
192  currentVisitedMethod = methodDeclaration;
193 
194  if (!methodDeclaration.Qualifiers.Contains(ParadoxStorageQualifier.Abstract))
195  Error(ParadoxMessageCode.ErrorMissingAbstract, methodDeclaration.Span, methodDeclaration, analyzedModuleMixin.MixinName);
196  if (methodDeclaration.Qualifiers.Contains(ParadoxStorageQualifier.Override))
197  Error(ParadoxMessageCode.ErrorUnnecessaryOverride, methodDeclaration.Span, methodDeclaration, analyzedModuleMixin.MixinName);
198 
199  Visit((Node)methodDeclaration);
200  PostMethodDeclarationVisit(methodDeclaration);
201  }
202 
203  /// <summary>
204  /// Analyse the method definition and store it in the correct lists (based on storage and stream usage)
205  /// </summary>
206  /// <param name="methodDefinition">the MethodDefinition</param>
207  /// <returns>the input method definition</returns>
208  [Visit]
209  protected override MethodDefinition Visit(MethodDefinition methodDefinition)
210  {
211  currentVisitedMethod = methodDefinition;
212 
213  if (methodDefinition.Qualifiers.Contains(ParadoxStorageQualifier.Abstract))
214  Error(ParadoxMessageCode.ErrorUnnecessaryAbstract, methodDefinition.Span, methodDefinition, analyzedModuleMixin.MixinName);
215 
216  var ret = base.Visit(methodDefinition);
217 
218  PostMethodDeclarationVisit(methodDefinition);
219 
220  return ret;
221  }
222 
223  /// <summary>
224  /// Performs operations applicable for MethodDefinition & MethodDeclaration nodes
225  /// </summary>
226  /// <param name="methodDeclaration">the method declaration or definition</param>
227  private void PostMethodDeclarationVisit(MethodDeclaration methodDeclaration)
228  {
229  currentVisitedMethod = null;
230  StoreMethod(methodDeclaration);
231  CheckParamatersAndReturnType(methodDeclaration);
232  }
233 
234  /// <summary>
235  /// Visits the specified variable
236  /// </summary>
237  /// <param name="variable">The variable</param>
238  [Visit]
239  protected void Visit(Variable variable)
240  {
241  if (inSampler)
242  return;
243 
244  if (variable.Type is StateType)
245  inSampler = true;
246 
247  // type inference for variable
248  if (ParentNode is ForEachStatement)
249  {
250  var forEachStatement = ParentNode as ForEachStatement;
251  if (variable == forEachStatement.Variable)
252  {
253  var finalType = forEachStatement.Collection.TypeInference.TargetType;
254  if (finalType is ArrayType)
255  finalType = (finalType as ArrayType).Type;
256  variable.Type = finalType;
257  if ((forEachStatement.Collection.TypeInference.Declaration as Variable).Qualifiers.Contains(ParadoxStorageQualifier.Extern))
258  variable.Qualifiers |= ParadoxStorageQualifier.Extern;
259  }
260  }
261 
262  Visit((Node)variable);
263 
264  inSampler = false;
265 
266  if (currentVisitedMethod == null)
267  {
268  if (variable.InitialValue is VariableReferenceExpression)
269  {
270  var vre = variable.InitialValue as VariableReferenceExpression;
271  if (vre.Name.Text == "stage")
272  {
273  if (variable.Qualifiers.Contains(StorageQualifier.Extern) && variable.Type.TypeInference.Declaration is ClassType)
274  parsingInfo.StageInitializedVariables.Add(variable);
275  else
276  Error(ParadoxMessageCode.ErrorStageInitNotClassType, variable.Span, variable, analyzedModuleMixin.MixinName);
277  }
278  }
279 
280  if (variable.Qualifiers.Contains(StorageQualifier.Extern))
281  {
282  var varType = variable.Type;
283  if (varType is ArrayType)
284  varType = (varType as ArrayType).Type;
285 
286  if (!(varType.TypeInference.Declaration is ClassType))
287  Error(ParadoxMessageCode.ErrorExternNotClassType, variable.Span, variable, analyzedModuleMixin.MixinName);
288  }
289 
290  // should not happen because extern keyword is set in the ShaderCompilationContext
291  if (!variable.Qualifiers.Contains(StorageQualifier.Extern) && variable.Type.TypeInference.Declaration is ClassType)
292  Error(ParadoxMessageCode.ErrorMissingExtern, variable.Span, variable, analyzedModuleMixin.MixinName);
293  }
294 
295  // check var type
296  if (variable.Type is VarType)
297  {
298  if (variable.InitialValue == null)
299  Error(ParadoxMessageCode.ErrorVarNoInitialValue, variable.Span, variable, analyzedModuleMixin.MixinName);
300  else if (variable.InitialValue.TypeInference.TargetType == null)
301  Error(ParadoxMessageCode.ErrorVarNoTypeFound, variable.Span, variable, analyzedModuleMixin.MixinName);
302  else
303  variable.Type = variable.InitialValue.TypeInference.TargetType.ResolveType();
304  }
305 
306  if (variable.ContainsTag(ParadoxTags.ShaderScope))
307  {
308  if (!parsingInfo.ClassReferences.VariablesReferences.ContainsKey(variable))
309  parsingInfo.ClassReferences.VariablesReferences.Add(variable, new HashSet<ExpressionNodeCouple>());
310  }
311 
312  if (currentVisitedMethod != null && !(ParentNode is ForEachStatement))
313  {
314  if (FindFinalType(variable.Type) is ShaderClassType)
315  Error(ParadoxMessageCode.ErrorShaderVariable, variable.Span, variable, analyzedModuleMixin.MixinName);
316  }
317  }
318 
319  /// <summary>
320  /// Find the base type in case of array
321  /// </summary>
322  /// <param name="typeBase">the type to explore</param>
323  /// <returns>the base type</returns>
324  private static TypeBase FindFinalType(TypeBase typeBase)
325  {
326  if (typeBase is ArrayType)
327  return FindFinalType((typeBase as ArrayType).Type);
328  return typeBase.ResolveType();
329  }
330 
331  /// <summary>
332  /// store the Typedef
333  /// </summary>
334  /// <param name="typedef">the Typedef</param>
335  [Visit]
336  private void Visit(Typedef typedef)
337  {
338  Visit((Node)typedef);
339 
340  if (currentVisitedMethod != null)
341  Error(ParadoxMessageCode.ErrorTypedefInMethod, typedef.Span, typedef, currentVisitedMethod, analyzedModuleMixin.MixinName);
342 
343  parsingInfo.Typedefs.Add(typedef);
344  }
345 
346  /// <summary>
347  /// Visit a technique, store an error
348  /// </summary>
349  /// <param name="technique">the technique</param>
350  [Visit]
351  public override void Visit(Technique technique)
352  {
353  Error(ParadoxMessageCode.ErrorTechniqueFound, technique.Span, technique, analyzedModuleMixin.MixinName); // TODO: remove because parsing may fail before
354  }
355 
356  /// <summary>
357  /// Visits the specified member reference.
358  /// </summary>
359  /// <param name="memberReference">The member reference.</param>
360  protected override void CommonVisit(MemberReferenceExpression memberReference)
361  {
362  var targetDecl = memberReference.Target.TypeInference.Declaration;
363  var variableTargetDecl = targetDecl as Variable;
364 
365  if (memberReference.Target is IndexerExpression)
366  variableTargetDecl = (memberReference.Target as IndexerExpression).Target.TypeInference.Declaration as Variable;
367 
368  if (variableTargetDecl != null && memberReference.TypeInference.Declaration == null && variableTargetDecl.Qualifiers.Contains(StorageQualifier.Extern)) // from composition
369  {
370  var varType = variableTargetDecl.Type;
371  if (varType is ArrayType)
372  varType = (varType as ArrayType).Type;
373 
374  var matchingDecls = FindDeclarationsFromObject(varType, memberReference.Member.Text).ToList();
375  var varDecl = matchingDecls.OfType<Variable>().FirstOrDefault();
376  var methodDecl = matchingDecls.OfType<MethodDeclaration>().FirstOrDefault();
377  var shaderDecl = matchingDecls.OfType<ShaderClassType>().FirstOrDefault();
378 
379  if (varDecl != null)
380  {
381  memberReference.TypeInference.Declaration = varDecl;
382  memberReference.TypeInference.TargetType = varDecl.Type.ResolveType();
383 
384  if (!(ParentNode is MemberReferenceExpression) || varType is VectorType) // do not store the intermediate references, only the last one - except for vector types
385  {
386  if (IsStageInitMember(memberReference))
387  memberReference.SetTag(ParadoxTags.StageInitRef, null);
388  else
389  memberReference.SetTag(ParadoxTags.ExternRef, null);
390  }
391  }
392  else if (shaderDecl != null)
393  {
394  memberReference.TypeInference.Declaration = shaderDecl;
395  memberReference.TypeInference.TargetType = shaderDecl.ResolveType();
396  }
397  else if (methodDecl == null)
398  {
399  Error(ParadoxMessageCode.ErrorExternMemberNotFound, memberReference.Span, memberReference, variableTargetDecl.Type, analyzedModuleMixin.MixinName);
400  }
401  }
402  else if (targetDecl is ShaderClassType)
403  FindMemberTypeReference(targetDecl as ShaderClassType, memberReference);
404  else
405  base.CommonVisit(memberReference);
406 
407  if (IsStreamMember(memberReference))
408  {
409  if (!(memberReference.Target.TypeInference.TargetType is VectorType
410  || memberReference.Target.TypeInference.TargetType != null && memberReference.Target.TypeInference.TargetType.TypeInference.TargetType is VectorType)) // do not look deeper in vector types
411  CheckStreamMemberReference(memberReference);
412 
413  if (memberReference.TypeInference.Declaration is Variable)
414  {
415  var refAsVariable = memberReference.TypeInference.Declaration as Variable;
416  if (!refAsVariable.Qualifiers.Contains(ParadoxStorageQualifier.Stream) && !refAsVariable.Qualifiers.Contains(ParadoxStorageQualifier.PatchStream))
417  Error(ParadoxMessageCode.ErrorExtraStreamsPrefix, memberReference.Span, memberReference, refAsVariable, analyzedModuleMixin.MixinName);
418  }
419  }
420  else if (IsInputOutputMember(memberReference))
421  {
422  CheckStreamMemberReference(memberReference);
423  }
424  else if (memberReference.TypeInference.Declaration is Variable)
425  {
426  var variableDecl = (Variable)memberReference.TypeInference.Declaration;
427  if (variableDecl.Qualifiers.Contains(ParadoxStorageQualifier.Stream) || variableDecl.Qualifiers.Contains(ParadoxStorageQualifier.PatchStream))
428  Error(ParadoxMessageCode.ErrorMissingStreamsStruct, memberReference.Span, memberReference, analyzedModuleMixin.MixinName);
429  }
430 
431  if (memberReference.TypeInference.Declaration is Variable) // TODO: check if it is a variable whose scope is inside the hierarchy
432  {
433  var isExtern = HasExternQualifier(memberReference);
434  var shouldStoreExpression = !(ParentNode is MemberReferenceExpression) ^ (memberReference.TypeInference.TargetType is VectorType || memberReference.TypeInference.TargetType is MatrixType);
435  if (shouldStoreExpression && isExtern)
436  memberReference.SetTag(ParadoxTags.ExternRef, null);
437 
438  if (!isExtern && memberReference.Target.TypeInference.Declaration is ShaderClassType && !ReferenceEquals(analyzedModuleMixin.Shader, memberReference.Target.TypeInference.Declaration) && analyzedModuleMixin.InheritanceList.All(x => !ReferenceEquals(x.Shader, memberReference.Target.TypeInference.Declaration)))
439  memberReference.SetTag(ParadoxTags.StaticRef, null);
440 
441  var varDecl = (Variable)memberReference.TypeInference.Declaration;
442  if (currentVisitedMethod != null && currentVisitedMethod.Qualifiers.Contains(StorageQualifier.Static) && varDecl != null && varDecl.GetTag(ParadoxTags.BaseDeclarationMixin) != null)
443  Error(ParadoxMessageCode.ErrorNonStaticReferenceInStaticMethod, memberReference.Span, currentVisitedMethod, varDecl, analyzedModuleMixin.MixinName);
444  }
445 
446  // Add to variable references list
447  AddToVariablesReference(memberReference);
448  }
449 
450  /// <summary>
451  /// Analyze the stream and store the datas
452  /// </summary>
453  /// <param name="memberReference">the MemberReferenceExpression</param>
454  private void CheckStreamMemberReference(MemberReferenceExpression memberReference)
455  {
456  // search the reference variable that should be stream
457  var decl = memberReference.TypeInference.Declaration ?? FindDeclarations(memberReference.Member.Text).FirstOrDefault();
458  var variableDecl = decl as Variable;
459  var mixinDecl = decl as ShaderClassType;
460 
461  if (variableDecl != null)
462  {
463  memberReference.TypeInference.Declaration = variableDecl;
464  memberReference.TypeInference.TargetType = variableDecl.Type.ResolveType();
465  }
466  else if (mixinDecl != null)
467  {
468  memberReference.TypeInference.Declaration = mixinDecl;
469  memberReference.TypeInference.TargetType = mixinDecl.ResolveType();
470  }
471  else
472  {
473  Error(ParadoxMessageCode.ErrorStreamNotFound, memberReference.Span, memberReference.Member.Text, analyzedModuleMixin.MixinName);
474  }
475  }
476 
477  /// <summary>
478  /// Finds the member type reference.
479  /// </summary>
480  /// <param name="shaderDecl">Type of the shader</param>
481  /// <param name="memberReference">The member reference.</param>
482  protected void FindMemberTypeReference(ShaderClassType shaderDecl, MemberReferenceExpression memberReference)
483  {
484  var mixin = moduleMixins.FirstOrDefault(x => x.Shader == shaderDecl);
485  if (mixin != null)
486  {
487  var shader = mixin.InheritanceList.FirstOrDefault(x => x.MixinName == memberReference.Member.Text);
488  if (shader != null)
489  {
490  memberReference.TypeInference.Declaration = shader.Shader;
491  memberReference.TypeInference.TargetType = shader.Shader;
492  return;
493  }
494 
495  var variableDecl = mixin.VirtualTable.Variables.FirstOrDefault(x => x.Variable.Name.Text == memberReference.Member.Text);
496  if (variableDecl != null)
497  {
498  var isStream = IsStreamMember(memberReference);
499  if (!isStream || variableDecl.Variable.Qualifiers.Contains(ParadoxStorageQualifier.Stream))
500  {
501  memberReference.TypeInference.Declaration = variableDecl.Variable;
502  memberReference.TypeInference.TargetType = variableDecl.Variable.Type.ResolveType();
503  return;
504  }
505  }
506 
507  if (ParentNode is MethodInvocationExpression)
508  {
509  var invocationExpression = ParentNode as MethodInvocationExpression;
510  if (ReferenceEquals(invocationExpression.Target, memberReference))
511  {
512  var methodDecl = mixin.VirtualTable.Methods.Select(x => x.Method).FirstOrDefault(x => x.IsSameSignature(invocationExpression));
513  if (methodDecl != null)
514  {
515  memberReference.TypeInference.Declaration = methodDecl;
516  invocationExpression.TypeInference.TargetType = methodDecl.ReturnType.ResolveType();
517  return;
518  }
519  }
520  }
521  }
522  }
523 
524  /// <summary>
525  /// Finds the declaration inside the compositions and calls the base method too
526  /// </summary>
527  /// <param name="typeBase">the type of the object</param>
528  /// <param name="memberName">the name of its member</param>
529  /// <returns>a collection of all possible members</returns>
530  protected override IEnumerable<IDeclaration> FindDeclarationsFromObject(TypeBase typeBase, string memberName)
531  {
532  // look if it is a composition
533  // the typebase is unique for each extern so there is no need to look for the right class
534  //var mixin = compositionsVirtualTables.FirstOrDefault(x => ReferenceEquals(x.Key.ResolveType(), typeBase.ResolveType())).Value;
535 
536  var mixin = moduleMixins.FirstOrDefault(x => x.MixinName == typeBase.Name.Text);
537 
538  if (mixin != null)
539  {
540  foreach (var member in mixin.VirtualTable.Variables.Where(x => x.Variable.Name.Text == memberName))
541  yield return member.Variable;
542 
543  foreach (var member in mixin.VirtualTable.Methods.Where(x => x.Method.Name.Text == memberName))
544  yield return member.Method;
545 
546  if (mixin.MixinName == memberName)
547  yield return mixin.Shader;
548 
549  foreach (var dep in mixin.InheritanceList.Where(x => x.MixinName == memberName).Select(x => x.Shader))
550  yield return dep;
551  }
552  else
553  {
554  foreach (var item in base.FindDeclarationsFromObject(typeBase.ResolveType(), memberName))
555  yield return item;
556  }
557  }
558 
559 
560  /// <summary>
561  /// Finds a list of declaration by its name.
562  /// </summary>
563  /// <param name="name">The name.</param>
564  /// <returns>A list of declaration</returns>
565  protected override IEnumerable<IDeclaration> FindDeclarations(string name)
566  {
567  var res = base.FindDeclarations(name);
568 
569  if (res.OfType<Variable>().Any(x => analyzedModuleMixin.PotentialConflictingVariables.Contains(x)))
570  Error(ParadoxMessageCode.ErrorVariableNameAmbiguity, new SourceSpan(), name, analyzedModuleMixin.MixinName);
571  if (res.OfType<MethodDeclaration>().Any(x => analyzedModuleMixin.PotentialConflictingMethods.Contains(x)))
572  Error(ParadoxMessageCode.ErrorMethodNameAmbiguity, new SourceSpan(), name, analyzedModuleMixin.MixinName);
573 
574  return res;
575  }
576 
577  /// <summary>
578  /// Calls the base method but modify the stream usage beforehand
579  /// </summary>
580  /// <param name="expression">the method expression</param>
581  [Visit]
582  protected override void Visit(MethodInvocationExpression expression)
583  {
584  expression.SetTag(ParadoxTags.CurrentShader, analyzedModuleMixin);
585 
586  base.Visit(expression);
587 
588  if (expression.TypeInference.TargetType == null && expression.Target.TypeInference.Declaration == null)
589  Error(ParadoxMessageCode.ErrorMissingMethod, expression.Span, expression, analyzedModuleMixin.MixinName);
590  else if (!Equals(expression.TypeInference.Declaration, expression.Target.TypeInference.Declaration))
591  expression.TypeInference.Declaration = expression.Target.TypeInference.Declaration;
592 
593  var methodDecl = expression.Target.TypeInference.Declaration as MethodDeclaration;
594 
595  if (methodDecl != null)
596  {
597  expression.Target.TypeInference.TargetType = (expression.Target.TypeInference.Declaration as MethodDeclaration).ReturnType.ResolveType();
598  expression.TypeInference.TargetType = expression.Target.TypeInference.TargetType.ResolveType();
599 
600  if (currentVisitedMethod.Qualifiers.Contains(StorageQualifier.Static)
601  && !methodDecl.Qualifiers.Contains(StorageQualifier.Static)
602  && methodDecl.GetTag(ParadoxTags.BaseDeclarationMixin) != null)
603  {
604  Error(ParadoxMessageCode.ErrorNonStaticCallInStaticMethod, expression.Span, currentVisitedMethod, methodDecl, analyzedModuleMixin.MixinName);
605  }
606  }
607 
608  // add to the reference list
609  AddToMethodsReferences(expression);
610 
611  if (methodDecl != null)
612  expression.Target.SetTag(ParadoxTags.VirtualTableReference, methodDecl.GetTag(ParadoxTags.VirtualTableReference));
613  }
614 
615  /// <summary>
616  /// Analyse the MethodInvocationExpression, link to the base calls, remove "this" from virtual calls, store in the correct list for later analysis
617  /// </summary>
618  /// <param name="expression">the method expression</param>
619  /// <param name="methodName">the method name</param>
620  /// <param name="declarations">the special declarations</param>
621  protected override void ProcessMethodInvocation(MethodInvocationExpression expression, string methodName, List<IDeclaration> declarations)
622  {
623  bool callBaseProcessMethodInvocation = true;
624  bool isNotBaseCall = true;
625 
626  // check if it is a base/this invocation
627  var memberReferenceExpression = expression.Target as MemberReferenceExpression;
628  if (memberReferenceExpression != null)
629  {
630  var variableReferenceExpression = memberReferenceExpression.Target as VariableReferenceExpression;
631  if (variableReferenceExpression != null)
632  {
633  switch (variableReferenceExpression.Name.Text)
634  {
635  case "base":
636  {
637  parsingInfo.BaseMethodCalls.Add(expression);
638  isNotBaseCall = false;
639  callBaseProcessMethodInvocation = false;
640 
641  // get a base method declaration
642  MethodDeclaration baseMethod = null;
643  foreach (var mixin in analyzedModuleMixin.InheritanceList)
644  {
645  baseMethod = mixin.LocalVirtualTable.Methods.Select(x => x.Method).FirstOrDefault(x => x.IsSameSignature(expression));
646  if (baseMethod != null)
647  break;
648  }
649  if (baseMethod == null)
650  baseMethod = analyzedModuleMixin.LocalVirtualTable.Methods.Select(x => x.Method).FirstOrDefault(x => x.IsSameSignature(expression));
651 
652  if (baseMethod != null)
653  {
654  expression.TypeInference.TargetType = baseMethod.ReturnType.ResolveType();
655  expression.Target.TypeInference.Declaration = baseMethod;
656  }
657  else
658  Error(ParadoxMessageCode.ErrorImpossibleBaseCall, memberReferenceExpression.Span, expression, analyzedModuleMixin.MixinName);
659  break;
660  }
661  case "this":
662  {
663  // remove "this" keyword
664  var vre = new VariableReferenceExpression(memberReferenceExpression.Member);
665  expression.Target = vre;
666 
667  callBaseProcessMethodInvocation = false;
668 
669  // get top method declaration
670  var topMethod = analyzedModuleMixin.VirtualTable.Methods.Select(x => x.Method).FirstOrDefault(x => x.IsSameSignature(expression));
671  if (topMethod != null)
672  {
673  expression.TypeInference.TargetType = topMethod.ReturnType.ResolveType();
674  expression.Target.TypeInference.Declaration = topMethod;
675 
676  if (!(topMethod is MethodDefinition))
677  Warning(ParadoxMessageCode.WarningDeclarationCall, memberReferenceExpression.Span, expression, topMethod, analyzedModuleMixin.MixinName);
678  }
679  else
680  Error(ParadoxMessageCode.ErrorImpossibleVirtualCall, memberReferenceExpression.Span, expression, analyzedModuleMixin.MixinName, analyzedModuleMixin.MixinName);
681 
682  memberReferenceExpression = null;
683 
684  break;
685  }
686  }
687 
688  }
689 
690  if (expression.Target is MemberReferenceExpression)
691  {
692  var typeCall = (expression.Target as MemberReferenceExpression).Target.TypeInference.TargetType;
693  if (typeCall is ShaderClassType)
694  declarations.AddRange(FindDeclarationsFromObject(typeCall, memberReferenceExpression.Member));
695  }
696  }
697 
698  // call base
699  if (callBaseProcessMethodInvocation)
700  base.ProcessMethodInvocation(expression, methodName, declarations);
701 
702  var methodDecl = expression.Target.TypeInference.Declaration as MethodDeclaration;
703  var isBuiltIn = true;
704 
705  if (methodDecl != null)
706  {
707  // check if it is a recursive call
708  if (ReferenceEquals(currentVisitedMethod, expression.Target.TypeInference.Declaration)) // How to handle "this" keyword?
709  Error(ParadoxMessageCode.ErrorCyclicMethod, currentVisitedMethod.Span, currentVisitedMethod, analyzedModuleMixin.MixinName);
710 
711  // check if it is a build-in method
712  isBuiltIn = !methodDecl.ContainsTag(ParadoxTags.ShaderScope);
713 
714  if (memberReferenceExpression != null)
715  {
716  var varDecl = memberReferenceExpression.Target.TypeInference.Declaration as Variable;
717  if (memberReferenceExpression.Target is IndexerExpression)
718  varDecl = (memberReferenceExpression.Target as IndexerExpression).Target.TypeInference.Declaration as Variable;
719 
720  if (varDecl != null && varDecl.Qualifiers.Contains(StorageQualifier.Extern))
721  {
722  if (IsStageInitMember(memberReferenceExpression))
723  expression.SetTag(ParadoxTags.StageInitRef, null);
724  else
725  expression.SetTag(ParadoxTags.ExternRef, null);
726  }
727 
728  var shaderDecl = memberReferenceExpression.Target.TypeInference.Declaration as ShaderClassType;
729  if (shaderDecl != null && shaderDecl != analyzedModuleMixin.Shader && analyzedModuleMixin.InheritanceList.All(x => x.Shader != shaderDecl))
730  expression.SetTag(ParadoxTags.StaticRef, null);
731  }
732 
733  if (!isBuiltIn)
734  {
735  // store if not a base call
736  if (isNotBaseCall && !expression.ContainsTag(ParadoxTags.ExternRef) && !expression.ContainsTag(ParadoxTags.StageInitRef) && !expression.ContainsTag(ParadoxTags.StaticRef))
737  parsingInfo.ThisMethodCalls.Add(expression);
738 
739  if (methodDecl.Qualifiers.Contains(ParadoxStorageQualifier.Stage))
740  parsingInfo.StageMethodCalls.Add(expression);
741  }
742  }
743 
744  if (!(isBuiltIn || methodDecl == null || expression.Target.TypeInference.Declaration is MethodDefinition || methodDecl.Qualifiers.Contains(ParadoxStorageQualifier.Stage)))
745  Warning(ParadoxMessageCode.WarningDeclarationCall, expression.Span, expression, expression.Target.TypeInference.Declaration, analyzedModuleMixin.MixinName);
746  }
747 
748  /// <summary>
749  /// Tests the arguments of the method - check streams type here
750  /// </summary>
751  /// <param name="argTypeBase">the argument typebase</param>
752  /// <param name="expectedTypeBase">the expected typebase</param>
753  /// <param name="argType">the argument type</param>
754  /// <param name="expectedType">the expected type</param>
755  /// <param name="score">the score of the overload</param>
756  /// <returns>true if the overload is correct, false otherwise</returns>
757  protected override bool TestMethodInvocationArgument(TypeBase argTypeBase, TypeBase expectedTypeBase, TypeBase argType, TypeBase expectedType, ref int score)
758  {
759  if (argTypeBase == ParadoxType.Streams && expectedTypeBase == ParadoxType.Output) // streams and output are the same
760  return true;
761  if (argTypeBase is ParadoxType && expectedType is ParadoxType)
762  return argTypeBase == expectedType;
763 
764  return base.TestMethodInvocationArgument(argTypeBase, expectedTypeBase, argType, expectedType, ref score);
765  }
766 
767  /// <summary>
768  /// Analyse the AssignmentExpression to correctly infer the potential stream usage
769  /// </summary>
770  /// <param name="assignmentExpression">the AssignmentExpression</param>
771  [Visit]
772  protected override void Visit(AssignmentExpression assignmentExpression)
773  {
774  if (currentAssignmentOperatorStatus != AssignmentOperatorStatus.Read)
775  Error(ParadoxMessageCode.ErrorNestedAssignment, assignmentExpression.Span, assignmentExpression, analyzedModuleMixin.MixinName);
776 
777  assignmentExpression.Value = (Expression)VisitDynamic(assignmentExpression.Value);
778  currentAssignmentOperatorStatus = (assignmentExpression.Operator != AssignmentOperator.Default) ? AssignmentOperatorStatus.ReadWrite : AssignmentOperatorStatus.Write;
779 
780  assignmentExpression.Target = (Expression)VisitDynamic(assignmentExpression.Target);
781 
782  currentAssignmentOperatorStatus = AssignmentOperatorStatus.Read;
783  }
784 
785  /// <summary>
786  /// Checks that the name does not bear many meanings
787  /// </summary>
788  /// <param name="variableReferenceExpression">the variable reference expression to check to check</param>
789  private void CheckNameConflict(VariableReferenceExpression variableReferenceExpression)
790  {
791  var name = variableReferenceExpression.Name.Text;
792  // NOTE: a VariableReferenceExpression means that we are in the context of the currently analyzed mixin
793  // we need to check that a variable does not appear twice
794  var varCount = analyzedModuleMixin.VirtualTable.Variables.Count(x => x.Variable.Name.Text == name);
795 
796  if (varCount > 1)
797  Error(ParadoxMessageCode.ErrorVariableNameAmbiguity, variableReferenceExpression.Span, variableReferenceExpression, analyzedModuleMixin.MixinName);
798  }
799 
800  /// <summary>
801  /// Analyse the VariableReferenceExpression, detects streams, propagate type inference, get stored in the correct list for later analysis
802  /// </summary>
803  /// <param name="variableReferenceExpression">the VariableReferenceExpression</param>
804  [Visit]
805  protected override void Visit(VariableReferenceExpression variableReferenceExpression)
806  {
807  // HACK: force types on base, this and stream keyword to eliminate errors in the log and use the standard type inference
808  var name = variableReferenceExpression.Name.Text;
809  if (name == "base")
810  {
811  variableReferenceExpression.TypeInference.Declaration = analyzedModuleMixin.Shader;
812  variableReferenceExpression.TypeInference.TargetType = analyzedModuleMixin.Shader;
813  return;
814  }
815  if (name == "this")
816  {
817  variableReferenceExpression.TypeInference.Declaration = analyzedModuleMixin.Shader;
818  variableReferenceExpression.TypeInference.TargetType = analyzedModuleMixin.Shader;
819  return;
820  }
821  if (name == "stage")
822  {
823  if (!(ParentNode is Variable && (ParentNode as Variable).InitialValue == variableReferenceExpression))
824  Error(ParadoxMessageCode.ErrorStageOutsideVariable, ParentNode.Span, ParentNode, analyzedModuleMixin.MixinName);
825 
826  return;
827  }
828  if (name == "streams")
829  {
830  variableReferenceExpression.TypeInference.Declaration = StreamsVariable;
831  variableReferenceExpression.TypeInference.TargetType = StreamsVariable.Type;
832  }
833 
834  // check if the variable is double-defined
835  if (!ParadoxKeywords.Contains(variableReferenceExpression.Name.Text))
836  CheckNameConflict(variableReferenceExpression);
837 
838  base.Visit(variableReferenceExpression);
839 
840  var varDecl = variableReferenceExpression.TypeInference.Declaration as Variable;
841 
842  if (varDecl != null)
843  {
844  // because the parent classes do not do this all the time
845  if (variableReferenceExpression.TypeInference.TargetType == null)
846  variableReferenceExpression.TypeInference.TargetType = (variableReferenceExpression.TypeInference.Declaration as Variable).Type.ResolveType();
847 
848  if (varDecl.ContainsTag(ParadoxTags.ShaderScope))
849  {
850  // stream variable should be called within the streams scope
851  if (varDecl.Qualifiers.Contains(ParadoxStorageQualifier.Stream) || varDecl.Qualifiers.Contains(ParadoxStorageQualifier.PatchStream))
852  Error(ParadoxMessageCode.ErrorMissingStreamsStruct, variableReferenceExpression.Span, variableReferenceExpression, analyzedModuleMixin.MixinName);
853  }
854  }
855 
856  var isMethodName = defaultDeclarations.Any(x => x.Name.Text == variableReferenceExpression.Name.Text);
857 
858  if (!ParadoxKeywords.Contains(variableReferenceExpression.Name.Text) && variableReferenceExpression.TypeInference.Declaration == null && !inSampler && !isMethodName)
859  Error(ParadoxMessageCode.ErrorMissingVariable, variableReferenceExpression.Span, variableReferenceExpression, analyzedModuleMixin.MixinName);
860 
861  // update function static status
862  if (!inSampler && !isMethodName && variableReferenceExpression.TypeInference.Declaration == null)
863  Error(ParadoxMessageCode.ErrorNoTypeInference, variableReferenceExpression.Span, variableReferenceExpression, analyzedModuleMixin.MixinName);
864 
865  if (currentVisitedMethod != null && currentVisitedMethod.Qualifiers.Contains(StorageQualifier.Static) && varDecl != null && varDecl.GetTag(ParadoxTags.BaseDeclarationMixin) != null)
866  Error(ParadoxMessageCode.ErrorNonStaticReferenceInStaticMethod, variableReferenceExpression.Span, currentVisitedMethod, varDecl, analyzedModuleMixin.MixinName);
867 
868  // Add to the variables references list
869  AddToVariablesReference(variableReferenceExpression);
870  }
871 
872  /// <summary>
873  /// Find the type of the expression
874  /// </summary>
875  /// <param name="indexerExpression">the indexer expression</param>
876  protected override void ProcessIndexerExpression(IndexerExpression indexerExpression)
877  {
878  var targetType = indexerExpression.Target.TypeInference.TargetType;
879 
880  if (targetType is ClassType && (targetType.Name.Text == "InputPatch" || targetType.Name.Text == "OutputPatch" || targetType.Name.Text == "PointStream" || targetType.Name.Text == "StructuredBuffer" || targetType.Name.Text == "RWStructuredBuffer"))
881  indexerExpression.TypeInference.TargetType = (targetType as ClassType).GenericArguments[0].ResolveType();
882  else
883  base.ProcessIndexerExpression(indexerExpression);
884 
885  if (!(indexerExpression.Index is LiteralExpression) && indexerExpression.Target.TypeInference.Declaration is Variable)
886  {
887  var varDecl = indexerExpression.Target.TypeInference.Declaration as Variable;
888  if (varDecl.Qualifiers.Contains(ParadoxStorageQualifier.Extern))
889  Error(ParadoxMessageCode.ErrorIndexerNotLiteral, indexerExpression.Span, indexerExpression, analyzedModuleMixin.MixinName);
890  }
891  }
892 
893 
894  /// <summary>
895  /// Visit an interface to send an error
896  /// </summary>
897  /// <param name="interfaceType">the interface.</param>
898  [Visit]
899  private void Visit(InterfaceType interfaceType)
900  {
901  Error(ParadoxMessageCode.ErrorInterfaceFound, interfaceType.Span, interfaceType, analyzedModuleMixin.MixinName);
902  }
903 
904  /// <summary>
905  /// Visit a structure and store its definition
906  /// </summary>
907  /// <param name="structType">the structure definition</param>
908  [Visit]
909  private void Visit(StructType structType)
910  {
911  Visit((Node)structType);
912 
913  if (structType.ContainsTag(ParadoxTags.ShaderScope))
914  parsingInfo.StructureDefinitions.Add(structType);
915  }
916 
917  /// <summary>
918  /// Visit a generic type and test that it has no shader class type
919  /// </summary>
920  /// <param name="genericType">the generic type</param>
921  [Visit]
922  protected override void Visit(GenericType genericType)
923  {
924  base.Visit(genericType);
925 
926  foreach (var param in genericType.Parameters.OfType<TypeName>())
927  {
928  if (param.TypeInference.TargetType is ShaderClassType)
929  Error(ParadoxMessageCode.ErrorMixinAsGeneric, param.Span, param, genericType, analyzedModuleMixin.MixinName);
930  }
931  }
932 
933  /// <summary>
934  /// Adds the expression to the reference list of the variable
935  /// </summary>
936  /// <param name="expression">the Expression</param>
937  private void AddToVariablesReference(Expression expression)
938  {
939  var variable = expression.TypeInference.Declaration as Variable;
940  if (variable != null && variable.ContainsTag(ParadoxTags.ShaderScope))
941  {
942  if (expression.ContainsTag(ParadoxTags.StaticRef) || variable.Qualifiers.Contains(StorageQualifier.Static))
943  parsingInfo.StaticReferences.InsertVariable(variable, new ExpressionNodeCouple(expression, ParentNode));
944  else if (expression.ContainsTag(ParadoxTags.ExternRef))
945  parsingInfo.ExternReferences.InsertVariable(variable, new ExpressionNodeCouple(expression, ParentNode));
946  else if (expression.ContainsTag(ParadoxTags.StageInitRef))
947  parsingInfo.StageInitReferences.InsertVariable(variable, new ExpressionNodeCouple(expression, ParentNode));
948  else
949  parsingInfo.ClassReferences.InsertVariable(variable, new ExpressionNodeCouple(expression, ParentNode));
950  }
951  }
952 
953  /// <summary>
954  /// Adds the method reference to the list of methods references
955  /// </summary>
956  /// <param name="expression">the method reference expression</param>
957  private void AddToMethodsReferences(MethodInvocationExpression expression)
958  {
959  var methodDecl = expression.Target.TypeInference.Declaration as MethodDeclaration;
960  if (methodDecl != null && methodDecl.ContainsTag(ParadoxTags.ShaderScope))
961  {
962  if (expression.ContainsTag(ParadoxTags.StaticRef) || methodDecl.Qualifiers.Contains(StorageQualifier.Static))
963  parsingInfo.StaticReferences.InsertMethod(methodDecl, expression);
964  else if (expression.ContainsTag(ParadoxTags.ExternRef))
965  parsingInfo.ExternReferences.InsertMethod(methodDecl, expression);
966  else if (expression.ContainsTag(ParadoxTags.StageInitRef))
967  parsingInfo.StageInitReferences.InsertMethod(methodDecl, expression);
968  else
969  parsingInfo.ClassReferences.InsertMethod(methodDecl, expression);
970  }
971  }
972 
973  /// <summary>
974  /// Visits the ForEachStatement Node and collects information from it.
975  /// </summary>
976  /// <param name="forEachStatement">The ForEachStatement</param>
977  [Visit]
978  private Node Visit(ForEachStatement forEachStatement)
979  {
980  if (expandForEachStatements)
981  {
982  // run analysis on collection
983  Visit(forEachStatement.Collection);
984 
985  var inference = forEachStatement.Collection.TypeInference.Declaration as Variable;
986  if (!(inference != null && inference.Type is ArrayType))
987  return forEachStatement;
988 
989  if ((inference.Type as ArrayType).Dimensions.Count > 1)
990  {
991  Error(ParadoxMessageCode.ErrorMultiDimArray, forEachStatement.Span, inference, forEachStatement, analyzedModuleMixin.MixinName);
992  return forEachStatement;
993  }
994 
995  var dim = (int)((inference.Type as ArrayType).Dimensions.FirstOrDefault() as LiteralExpression).Value;
996 
997  var result = new StatementList();
998  for (int i = 0; i < dim; ++i)
999  {
1000  var cloned = forEachStatement.DeepClone();
1001  var replace = new ParadoxReplaceExtern(cloned.Variable, new IndexerExpression(cloned.Collection, new LiteralExpression(i)));
1002  replace.Run(cloned.Body);
1003  result.Add(cloned.Body);
1004  }
1005 
1006  Visit((Node)result);
1007  return result;
1008  }
1009  else
1010  {
1011  Visit((Node)forEachStatement);
1012  parsingInfo.ForEachStatements.Add(new StatementNodeCouple(forEachStatement, ParentNode));
1013  return forEachStatement;
1014  }
1015  }
1016 
1017  /// <summary>
1018  /// Gets the type of the binary implicit conversion.
1019  /// </summary>
1020  /// <param name="span">The span.</param>
1021  /// <param name="left">The left.</param>
1022  /// <param name="right">The right.</param>
1023  /// <param name="isBinaryOperator">if set to <c>true</c> [is binary operator].</param>
1024  /// <returns>
1025  /// The implicit conversion between between to two types
1026  /// </returns>
1027  protected override TypeBase GetBinaryImplicitConversionType(SourceSpan span, TypeBase left, TypeBase right, bool isBinaryOperator)
1028  {
1029  if (left.ResolveType() is ParadoxType || right.ResolveType() is ParadoxType)
1030  return ParadoxType.Streams;
1031 
1032  return base.GetBinaryImplicitConversionType(span, left, right, isBinaryOperator);
1033  }
1034 
1035  /// <summary>
1036  /// Gets the type of the binary implicit conversion.
1037  /// </summary>
1038  /// <param name="span">The span.</param>
1039  /// <param name="left">The left.</param>
1040  /// <param name="right">The right.</param>
1041  /// <returns>The implicit conversion between between to two types</returns>
1042  protected override TypeBase GetMultiplyImplicitConversionType(SourceSpan span, TypeBase left, TypeBase right)
1043  {
1044  if (left.ResolveType() is ParadoxType || right.ResolveType() is ParadoxType)
1045  return ParadoxType.Streams;
1046 
1047  return base.GetMultiplyImplicitConversionType(span, left, right);
1048  }
1049 
1050  /// <summary>
1051  /// Gets the type of the binary implicit conversion.
1052  /// </summary>
1053  /// <param name="span">The span.</param>
1054  /// <param name="left">The left.</param>
1055  /// <param name="right">The right.</param>
1056  /// <returns>The implicit conversion between between to two types</returns>
1057  protected override TypeBase GetDivideImplicitConversionType(SourceSpan span, TypeBase left, TypeBase right)
1058  {
1059  if (left.ResolveType() is ParadoxType || right.ResolveType() is ParadoxType)
1060  return ParadoxType.Streams;
1061 
1062  return base.GetDivideImplicitConversionType(span, left, right);
1063  }
1064 
1065  /// <summary>
1066  /// Test if the expression is from a stage nitialized one
1067  /// </summary>
1068  /// <param name="expression">the expression</param>
1069  /// <returns>true if it is the case, false otherwise</returns>
1070  private bool IsStageInitMember(Expression expression)
1071  {
1072  if (expression != null)
1073  return parsingInfo.StageInitializedVariables.Contains(expression.TypeInference.Declaration) || (expression is MemberReferenceExpression && IsStageInitMember((expression as MemberReferenceExpression).Target));
1074 
1075  return false;
1076  }
1077 
1078  #endregion
1079 
1080  #region Private static helper functions
1081 
1082 
1083  /// <summary>
1084  /// Look for extern qualifier in expression typeinference
1085  /// </summary>
1086  /// <param name="expression">the expression</param>
1087  /// <returns>true if there is a reference to an extern variable</returns>
1088  private static bool HasExternQualifier(Expression expression)
1089  {
1090  var varDecl = expression.TypeInference.Declaration as Variable;
1091  if (varDecl != null && varDecl.Qualifiers.Contains(StorageQualifier.Extern))
1092  return !(varDecl.InitialValue is VariableReferenceExpression) || (varDecl.InitialValue as VariableReferenceExpression).Name.Text != "stage";
1093 
1094  if (expression is MemberReferenceExpression)
1095  return HasExternQualifier((expression as MemberReferenceExpression).Target);
1096  return false;
1097  }
1098 
1099  /// <summary>
1100  /// Checks if expression is a stream
1101  /// </summary>
1102  /// <param name="expression">the Expression</param>
1103  /// <param name="deepSearch">flag for looking deep into the MemberReferenceExpression the keyword "streams"</param>
1104  /// <returns>true if it is a stream, false otherwise</returns>
1105  private static bool IsStreamMember(MemberReferenceExpression expression)
1106  {
1107  if (expression != null)
1108  {
1109  if (expression.Target.TypeInference.TargetType != null && StreamTypes.Contains(expression.Target.TypeInference.TargetType.Name.Text))
1110  return true;
1111 
1112  // iterate until the base "class" is found and compare it to "streams"
1113  var target = expression.Target;
1114  while (target is MemberReferenceExpression)
1115  target = (target as MemberReferenceExpression).Target;
1116 
1117  var variableReferenceExpression = target as VariableReferenceExpression;
1118  return variableReferenceExpression != null && (variableReferenceExpression.Name.Text == "streams" || variableReferenceExpression.TypeInference.TargetType is ParadoxType);
1119  }
1120  return false;
1121  }
1122 
1123  /// <summary>
1124  /// Tests if a MemberReferenceExpression is a reference to a stream from an Input/Output type
1125  /// </summary>
1126  /// <param name="expression">the expression to analyze</param>
1127  /// <returns>true if it is a member of an Input/Output type</returns>
1128  private static bool IsInputOutputMember(MemberReferenceExpression expression)
1129  {
1130  var targetType = expression.Target.TypeInference.TargetType;
1131  if (targetType != null)
1132  {
1133  var targetTypeName = targetType.Name.Text;
1134  return (targetTypeName == "Input" || targetTypeName == "Input2" || targetTypeName == "Output"); // Streams & Constants too ?
1135  }
1136 
1137  return false;
1138  }
1139 
1140  #endregion
1141  }
1142 }
Base class for all vector types
Definition: VectorType.cs:10
static readonly Ast.StorageQualifier Static
Static modifier.
TypeBase TargetType
Gets or sets the type.
TypeBase Type
Gets or sets the type.
Definition: Variable.cs:61
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Abstract
Override keyword (override).
A typeless reference.
Definition: TypeName.cs:10
TypeInference TypeInference
Gets or sets the resolved reference.
Definition: TypeBase.cs:69
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Stream
Stream keyword (stream).
Variable()
Initializes a new instance of the Variable class.
Definition: Variable.cs:18
SourceSpan Span
Gets or sets the source span.
Definition: Node.cs:37
string Text
Gets or sets the name.
Definition: Identifier.cs:77
Expression Collection
Gets or sets the condition.
bool ContainsTag(object tagKey)
Determines whether the specified instance contains this tag.
Definition: Node.cs:105
Expression Index
Gets or sets the index.
A Scope declaration provides a way to retrieve all scope declaration (variable, methods...etc.) and attached nodes.
virtual TypeBase ResolveType()
Resolves the type.
Definition: TypeBase.cs:101
Expression Target
Gets or sets the target receving the assigment.
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Override
Override keyword (override).
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
Expression Value
Gets or sets the value of the assigment..
void SetTag(object tagKey, object tagValue)
Sets a tag value associated to this node.
Definition: Node.cs:116
TypeBase ReturnType
Gets or sets the type of the return.
A variable declaration.
Definition: Variable.cs:11
A member reference in the form {this}.{Name}
List< Node > Parameters
Gets or sets the parameters.
Definition: GenericType.cs:82
Base type for all types.
Definition: TypeBase.cs:11
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Stage
Stage keyword (stage).
Base class for all generic types.
Definition: GenericType.cs:14
Toplevel container of a shader parsing result.
Definition: Shader.cs:12
bool Contains(CompositeEnum enumValue)
Determines whether [contains] [the specified enum value].
List< Parameter > Parameters
Gets or sets the parameters.
SiliconStudio.Shaders.Ast.Hlsl.StorageQualifier StorageQualifier
Qualifier Qualifiers
Gets or sets the storage class.
Identifier Name
Gets or sets the type name.
Definition: TypeBase.cs:77
static readonly Ast.StorageQualifier Extern
Extern modifier.