private XenkoStreamCreator(ShaderClassType shaderClassType, ModuleMixin mixin, List<ModuleMixin> mixins, LoggerResult errorLog) { shader = shaderClassType; mainModuleMixin = mixin; mixinInheritance = mixins; errorWarningLog = errorLog ?? new LoggerResult(); }
/// <summary> /// Get the base MethodDeclaration from its call and the mixin where the call is performed /// </summary> /// <param name="expression">the calling expression</param> /// <param name="mixin">the mixin where the call is performed</param> /// <returns>the base MethodDeclaration</returns> public MethodDeclaration GetBaseMethodFromExpression(Expression expression, ModuleMixin mixin) { var info = (VTableReference)expression.GetTag(XenkoTags.VirtualTableReference); var thisMethod = VirtualTable.GetMethod(info.Shader, info.Slot); if (thisMethod == null) { return(null); } var startIndex = mixin == this ? InheritanceList.Count : InheritanceList.IndexOf(mixin); for (int i = startIndex - 1; i >= 0; --i) { var dep = InheritanceList[i]; var array = VirtualTable.VirtualTableGroup[dep.MixinName]; for (int j = 0; j < array.Length; ++j) { var method = array[j]; if (method == thisMethod) { return(dep.VirtualTable.VirtualTableGroup[dep.MixinName][j]); } } } return(null); }
/// <summary> /// Initializes a new instance of the <see cref="XenkoSemanticAnalysis"/> class. /// </summary> /// <param name="result">The result</param> /// <param name="analyzedMixin">the context in which the analysis is set</param> /// <param name="moduleMixinsInCompilationGroup">the list of all the modules that are not in the inheritance hierarchy of the context</param> public XenkoSemanticAnalysis(ParsingResult result, ModuleMixin analyzedMixin, List<ModuleMixin> moduleMixinsInCompilationGroup) : base(result) { analyzedModuleMixin = analyzedMixin; ScopeStack.First().AddDeclaration(StreamsType.ThisStreams); var currentScope = new ScopeDeclaration(analyzedMixin.Shader); ScopeStack.Push(currentScope); currentScope.AddDeclarations(analyzedMixin.VirtualTable.Typedefs); currentScope.AddDeclarations(analyzedMixin.VirtualTable.StructureTypes); currentScope.AddDeclarations(analyzedMixin.VirtualTable.Variables.Select(x => x.Variable)); currentScope.AddDeclarations(analyzedMixin.VirtualTable.Methods.Select(x => x.Method)); currentScope.AddDeclarations(analyzedMixin.InheritanceList.Select(x => x.Shader)); // add the mixins in the compilation group var sd = new ScopeDeclaration(); ScopeStack.Push(sd); foreach (var mixin in moduleMixinsInCompilationGroup) { moduleMixins.Add(mixin); sd.AddDeclaration(mixin.Shader); } }
/// <summary> /// Check if the class is stage /// </summary> /// <param name="mixin">the ModuleMixin to check</param> private void CheckStageClass(ModuleMixin mixin) { mixin.StageOnlyClass = mixin.VirtualTable.Variables.All(x => x.Variable.Qualifiers.Contains(XenkoStorageQualifier.Stage) && !x.Variable.Qualifiers.Contains(XenkoStorageQualifier.Compose)) && // composition variable can be stage but the classes behind may not be. mixin.VirtualTable.Methods.All(x => x.Method.Qualifiers.Contains(XenkoStorageQualifier.Stage) && !x.Method.Qualifiers.Contains(XenkoStorageQualifier.Clone)); }
/// <summary> /// Constructor /// </summary> /// <param name="moduleMixin">the final shader information</param> /// <param name="log">The log.</param> /// <param name="context">all the mixins in the context</param> /// <param name="compositionsPerVariable">The compositions per variable.</param> /// <param name="cloneContext">The clone context.</param> /// <exception cref="System.ArgumentNullException"> /// moduleMixin /// or /// log /// or /// context /// </exception> public XenkoShaderMixer(ModuleMixin moduleMixin, LoggerResult log, Dictionary<string, ModuleMixin> context, CompositionDictionary compositionsPerVariable, CloneContext cloneContext = null) { if (moduleMixin == null) throw new ArgumentNullException("moduleMixin"); if (log == null) throw new ArgumentNullException("log"); if (context == null) throw new ArgumentNullException("context"); this.log = log; mixContext = context; mainModuleMixin = moduleMixin; defaultCloneContext = cloneContext; if (compositionsPerVariable != null) CompositionsPerVariable = compositionsPerVariable; else CompositionsPerVariable = new CompositionDictionary(); var mixinsToAnalyze = new Stack<ModuleMixin>(CompositionsPerVariable.Values.SelectMany(x => x)); mixinsToAnalyze.Push(mainModuleMixin); while (mixinsToAnalyze.Count > 0) AddDefaultCompositions(mixinsToAnalyze); }
/// <summary> /// Check that the stage function calls are possible and that the stage declared variable have a correct type /// </summary> /// <param name="externMixin">the mixin to look into</param> /// <param name="contextMixin">the root mixin</param> private void CheckReferencesFromExternMixin(ModuleMixin externMixin, ModuleMixin contextMixin) { // test that the root mixin has the correct type foreach (var variable in externMixin.ParsingInfo.StageInitializedVariables) { if (variable.Type.Name.Text != contextMixin.MixinName && contextMixin.InheritanceList.All(x => x.MixinName == variable.Type.Name.Text)) // since it is the same AST, compare the object? { ErrorWarningLog.Error(XenkoMessageCode.ErrorExternStageVariableNotFound, variable.Span, variable, externMixin.MixinName); } } foreach (var stageCall in externMixin.ParsingInfo.StageMethodCalls) { var decl = contextMixin.FindTopThisFunction(stageCall).FirstOrDefault(); if (decl == null) { ErrorWarningLog.Error(XenkoMessageCode.ErrorExternStageFunctionNotFound, stageCall.Span, stageCall, externMixin.MixinName, contextMixin.MixinName); } } // recursive calls foreach (var mixin in externMixin.InheritanceList) { CheckReferencesFromExternMixin(mixin, contextMixin); foreach (var externModule in mixin.VariableDependencies) { CheckReferencesFromExternMixin(externModule.Value, contextMixin); } } foreach (var externModule in externMixin.VariableDependencies) { CheckReferencesFromExternMixin(externModule.Value, contextMixin); } }
private void FindShader(Expression expression, ref ModuleMixin mixin) { if (expression is MemberReferenceExpression) { var memberExpression = expression as MemberReferenceExpression; var target = memberExpression.Target; if (target.TypeInference.Declaration is Variable) FindVariable(target, ref mixin); var mixinName = (expression.TypeInference.Declaration as ShaderClassType).Name.Text; mixin = mixin.MixinName == mixinName ? mixin : mixin.InheritanceList.FirstOrDefault(x => x.MixinName == mixinName); } else if (expression is IndexerExpression) { var indexerExpression = expression as IndexerExpression; var target = indexerExpression.Target; Variable result = null; if (target.TypeInference.Declaration is Variable) result = FindVariable(target, ref mixin); var index = (int)(indexerExpression.Index as LiteralExpression).Value; if (result is Variable && (result as Variable).Qualifiers.Contains(XenkoStorageQualifier.Extern)) mixin = CompositionsPerVariable[result as Variable][index]; } }
private MethodDeclaration FindMethod(Expression expression, ref ModuleMixin mixin) { if (expression is MemberReferenceExpression) { var memberExpression = expression as MemberReferenceExpression; var target = memberExpression.Target; if (target.TypeInference.Declaration is Variable) FindVariable(target, ref mixin); else if (target.TypeInference.Declaration is ShaderClassType || target.TypeInference.TargetType is ShaderClassType) FindShader(target, ref mixin); } var topMixin = GetTopMixin(mixin); if (topMixin == null) { log.Error(XenkoMessageCode.ErrorTopMixinNotFound, expression.Span, expression); return null; } var foundMethod = topMixin.GetMethodFromExpression(expression); if (foundMethod == null) { log.Error(XenkoMessageCode.ErrorCallNotFound, expression.Span, expression); return null; } if (foundMethod.Qualifiers.Contains(XenkoStorageQualifier.Abstract)) { log.Error(XenkoMessageCode.ErrorCallToAbstractMethod, expression.Span, expression, foundMethod); return null; } return foundMethod; }
private Variable FindVariableInMixin(string varName, ModuleMixin mixin) { if (varName == "streams") return null; var foundVar = mixin.VirtualTable.Variables.FirstOrDefault(x => x.Variable.Name.Text == varName); if (foundVar != null) return foundVar.Variable; log.Error(XenkoMessageCode.ErrorVariableNotFound, new SourceSpan(), varName, mixin.MixinName); return null; }
/// <summary> /// Redo type inference for stage init variables /// </summary> /// <param name="moduleMixin">the module mixin to analyze</param> private void ProcessStageInitReferences(ModuleMixin moduleMixin) { foreach (var variable in moduleMixin.StageInitReferences.VariablesReferences) { var varMixinName = ((ModuleMixin)variable.Key.GetTag(XenkoTags.ShaderScope)).MixinName; var mixin = MixinInheritance.FirstOrDefault(x => x.MixinName == varMixinName); if (mixin == null) { log.Error(XenkoMessageCode.ErrorStageMixinNotFound, new SourceSpan(), varMixinName, moduleMixin.MixinName); return; } var trueVar = mixin.ClassReferences.VariablesReferences.FirstOrDefault(x => x.Key.Name.Text == variable.Key.Name.Text).Key; if (trueVar == null) { var sourceShader = ((ModuleMixin)variable.Key.GetTag(XenkoTags.ShaderScope)).MixinName; log.Error(XenkoMessageCode.ErrorStageMixinVariableNotFound, new SourceSpan(), varMixinName, sourceShader, moduleMixin.MixinName); return; } foreach (var varRef in variable.Value) { varRef.Expression.TypeInference.Declaration = trueVar; varRef.Expression.TypeInference.TargetType = trueVar.Type.ResolveType(); } mainModuleMixin.ClassReferences.VariablesReferences[trueVar].UnionWith(variable.Value); } foreach (var method in moduleMixin.StageInitReferences.MethodsReferences) { var varMixinName = ((ModuleMixin)method.Key.GetTag(XenkoTags.ShaderScope)).MixinName; var mixin = MixinInheritance.FirstOrDefault(x => x.MixinName == varMixinName); if (mixin == null) { log.Error(XenkoMessageCode.ErrorStageMixinNotFound, new SourceSpan(), varMixinName, moduleMixin.MixinName); return; } var trueVar = GetTopMixin(mixin).GetMethodFromDeclaration(method.Key); if (trueVar == null) { log.Error(XenkoMessageCode.ErrorStageMixinMethodNotFound, new SourceSpan(), varMixinName, method, moduleMixin.MixinName); return; } foreach (var varRef in method.Value) { varRef.Target.TypeInference.Declaration = trueVar; varRef.Target.SetTag(XenkoTags.VirtualTableReference, trueVar.GetTag(XenkoTags.VirtualTableReference)); } mainModuleMixin.ClassReferences.MethodsReferences[trueVar].UnionWith(method.Value); } }
/// <summary> /// Rebranch the type inference for the stage variable reference in the extern /// </summary> /// <param name="externMix"></param> private void InferStageVariables(ModuleMixin externMix) { var stageDict = externMix.ClassReferences.VariablesReferences.Where(x => x.Key.Qualifiers.Contains(XenkoStorageQualifier.Stage)).ToDictionary(x => x.Key, x => x.Value); foreach (var variable in stageDict) { var shaderName = (variable.Key.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName; var foundDeclaration = mainModuleMixin.ClassReferences.VariablesReferences.FirstOrDefault(x => x.Key.Name.Text == variable.Key.Name.Text && (x.Key.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName == shaderName).Key; if (foundDeclaration == null)// get by semantics if necessary { var semantic = variable.Key.Qualifiers.Values.OfType<Semantic>().FirstOrDefault(); if (semantic != null) { foundDeclaration = mainModuleMixin.ClassReferences.VariablesReferences.FirstOrDefault( x => { var varSemantic = x.Key.Qualifiers.Values.OfType<Semantic>().FirstOrDefault(); if (varSemantic != null && semantic.Name.Text == varSemantic.Name.Text) return true; return false; }).Key; } } if (foundDeclaration != null) { mainModuleMixin.ClassReferences.VariablesReferences[foundDeclaration].UnionWith(variable.Value); foreach (var varRef in variable.Value) { varRef.Expression.TypeInference.Declaration = foundDeclaration; varRef.Expression.TypeInference.TargetType = foundDeclaration.Type; } } else { log.Error(XenkoMessageCode.ErrorMissingStageVariable, variable.Key.Span, variable, externMix.MixinName); return; } } foreach (var key in stageDict.Keys) externMix.ClassReferences.VariablesReferences.Remove(key); }
/// <summary> /// Find the mixin in which the parameter is a dependency /// </summary> /// <param name="mixin">the mixin</param> /// <returns>the mixin that depends on the parameter</returns> private ModuleMixin GetTopMixin(ModuleMixin mixin) { var topMixin = mainModuleMixin == mixin || mainModuleMixin.InheritanceList.Any(x => x == mixin) ? mainModuleMixin : null; if (topMixin == null) { foreach (var externMixes in CompositionsPerVariable.Values) { foreach (var externMix in externMixes) { topMixin = externMix == mixin || externMix.InheritanceList.Any(x => x == mixin) ? externMix : null; if (topMixin != null) break; } if (topMixin != null) break; } } return topMixin; }
/// <summary> /// bubble up the static references in the mixin dependency tree /// </summary> /// <param name="topMixin">the top mixin</param> /// <param name="staticMixin">the mixin to look into</param> private void GetStaticReferences(ModuleMixin topMixin, ModuleMixin staticMixin) { foreach (var staticDep in staticMixin.ParsingInfo.StaticClasses) GetStaticReferences(topMixin, staticDep); foreach (var staticDep in staticMixin.InheritanceList) GetStaticReferences(topMixin, staticDep); topMixin.StaticReferences.Merge(staticMixin.ParsingInfo.StaticReferences); }
/// <summary> /// Merge reference from mixin dependencies /// </summary> /// <param name="mixin"></param> private void CreateReferencesStructures(ModuleMixin mixin) { GetStaticReferences(mixin, mixin); // merge class reference mixin.ClassReferences.Merge(mixin.ParsingInfo.ClassReferences); foreach (var dep in mixin.InheritanceList) mixin.ClassReferences.Merge(dep.ParsingInfo.ClassReferences); // merge static references mixin.StaticReferences.Merge(mixin.ParsingInfo.StaticReferences); foreach (var dep in mixin.InheritanceList) mixin.StaticReferences.Merge(dep.ParsingInfo.StaticReferences); // merge extern references mixin.ExternReferences.Merge(mixin.ParsingInfo.ExternReferences); foreach (var dep in mixin.InheritanceList) mixin.ExternReferences.Merge(dep.ParsingInfo.ExternReferences); // merge stage init references mixin.StageInitReferences.Merge(mixin.ParsingInfo.StageInitReferences); foreach (var dep in mixin.InheritanceList) mixin.StageInitReferences.Merge(dep.ParsingInfo.StageInitReferences); }
/// <summary> /// Replaces the ForEachStatements in the mixin by ForStatements /// </summary> /// <param name="mixin">the mixin</param> private static void ExpandForEachStatements(ModuleMixin mixin) { foreach (var statementNodeCouple in mixin.ParsingInfo.ForEachStatements.Where(x => !(x.Statement as ForEachStatement).Variable.Qualifiers.Contains(XenkoStorageQualifier.Extern))) { var newStatement = ExpandForEachStatement(statementNodeCouple.Statement as ForEachStatement); if (newStatement != null) { var replace = new XenkoReplaceVisitor(statementNodeCouple.Statement, newStatement); replace.Run(statementNodeCouple.Node); } } mixin.InheritanceList.ForEach(ExpandForEachStatements); }
/// <summary> /// Check that the stage function calls are possible and that the stage declared variable have a correct type /// </summary> /// <param name="externMixin">the mixin to look into</param> /// <param name="contextMixin">the root mixin</param> private void CheckReferencesFromExternMixin(ModuleMixin externMixin, ModuleMixin contextMixin) { // test that the root mixin has the correct type foreach (var variable in externMixin.ParsingInfo.StageInitializedVariables) { if (variable.Type.Name.Text != contextMixin.MixinName && contextMixin.InheritanceList.All(x => x.MixinName == variable.Type.Name.Text)) // since it is the same AST, compare the object? ErrorWarningLog.Error(XenkoMessageCode.ErrorExternStageVariableNotFound, variable.Span, variable, externMixin.MixinName); } foreach (var stageCall in externMixin.ParsingInfo.StageMethodCalls) { var decl = contextMixin.FindTopThisFunction(stageCall).FirstOrDefault(); if (decl == null) ErrorWarningLog.Error(XenkoMessageCode.ErrorExternStageFunctionNotFound, stageCall.Span, stageCall, externMixin.MixinName, contextMixin.MixinName); } // recursive calls foreach (var mixin in externMixin.InheritanceList) { CheckReferencesFromExternMixin(mixin, contextMixin); foreach (var externModule in mixin.VariableDependencies) CheckReferencesFromExternMixin(externModule.Value, contextMixin); } foreach (var externModule in externMixin.VariableDependencies) CheckReferencesFromExternMixin(externModule.Value, contextMixin); }
/// <summary> /// Check if the class is stage /// </summary> /// <param name="mixin">the ModuleMixin to check</param> private void CheckStageClass(ModuleMixin mixin) { mixin.StageOnlyClass = mixin.VirtualTable.Variables.All(x => x.Variable.Qualifiers.Contains(XenkoStorageQualifier.Stage) && !x.Variable.Qualifiers.Contains(XenkoStorageQualifier.Compose)) // composition variable can be stage but the classes behind may not be. && mixin.VirtualTable.Methods.All(x => x.Method.Qualifiers.Contains(XenkoStorageQualifier.Stage) && !x.Method.Qualifiers.Contains(XenkoStorageQualifier.Clone)); }
/// <summary> /// Adds le methods in the list to the inheritance list /// </summary> /// <param name="extMethodList">the list of methods</param> /// <param name="mixin">the mixin in which the methods are defined</param> public void InsertStageMethods(List<MethodDeclaration> extMethodList, ModuleMixin mixin) { foreach (var extMethod in extMethodList) { if (extMethod is MethodDefinition) { var isClone = extMethod.Qualifiers.Values.Contains(XenkoStorageQualifier.Clone); var newEntry = true; // find a corresponding method var vtReference = mixin.VirtualTable.GetBaseDeclaration(extMethod); foreach (var stageMethodList in StageMethodInheritance) { if (!newEntry) break; if (stageMethodList == null || stageMethodList.Count == 0) continue; var firstOccurence = stageMethodList.First(); var occurenceMixin = firstOccurence.GetTag(XenkoTags.ShaderScope) as ModuleMixin; var listVTReference = occurenceMixin.VirtualTable.GetBaseDeclaration(firstOccurence); if (vtReference.Slot != listVTReference.Slot || vtReference.Shader != listVTReference.Shader) continue; newEntry = false; var extMixin = extMethod.GetTag(XenkoTags.ShaderScope) as ModuleMixin; if (isClone || extMixin.OccurenceId == 1) stageMethodList.Add(extMethod); } if (newEntry) { var list = new List<MethodDeclaration>(); list.Add(extMethod); StageMethodInheritance.Add(list); } var externClassRef = GetTopMixin(mixin).ClassReferences; if (externClassRef != null && !mainModuleMixin.ClassReferences.MethodsReferences.ContainsKey(extMethod)) { externClassRef.RegenKeys(); mainModuleMixin.ClassReferences.MethodsReferences.Add(extMethod, externClassRef.MethodsReferences[extMethod]); externClassRef.MethodsReferences.Remove(extMethod); } } } }
/// <summary> /// Rename the links of the variables /// </summary> /// <param name="mixin">the current mixin</param> /// <param name="context">the string to append</param> /// <param name="visitedMixins">list of already visited mixin</param> private void LinkVariables(ModuleMixin mixin, string context, List<ModuleMixin> visitedMixins) { if (visitedMixins.Contains(mixin)) return; visitedMixins.Add(mixin); foreach (var variable in mixin.LocalVirtualTable.Variables.Select(x => x.Variable)) { if (variable.Qualifiers.Contains(XenkoStorageQualifier.Extern)) { List<ModuleMixin> mixins; if (CompositionsPerVariable.TryGetValue(variable, out mixins)) { if (variable.Type is ArrayType) { for (var i = 0; i < mixins.Count; ++i) { var baselink = "." + variable.Name.Text + "[" + i + "]" + context; LinkVariables(mixins[i], baselink, visitedMixins); } } else { var baselink = "." + variable.Name.Text + context; LinkVariables(mixins[0], baselink, visitedMixins); } } } if (!(variable.Qualifiers.Values.Contains(XenkoStorageQualifier.Stream) || variable.Qualifiers.Values.Contains(XenkoStorageQualifier.PatchStream) || variable.Qualifiers.Values.Contains(XenkoStorageQualifier.Extern))) { var attribute = variable.Attributes.OfType<AttributeDeclaration>().FirstOrDefault(x => x.Name == "Link"); if (attribute == null) { // Try to get class name before generics //string baseClassName; //if (!genericTypeDefinitions.TryGetValue(baseClass, out baseClassName)) // baseClassName = baseClass.Name; // TODO: class name before renaming if generics string linkName; // Use Map attribute (if it exists) var mapAttribute = variable.Attributes.OfType<AttributeDeclaration>().FirstOrDefault(x => x.Name == "Map"); if (mapAttribute != null) { linkName = (string)mapAttribute.Parameters[0].Value; // Remove "Keys" from class name (or maybe we should just include it in key name to avoid issues?) linkName = linkName.Replace("Keys.", "."); } else { linkName = mixin.MixinGenericName + "." + variable.Name.Text; } attribute = new AttributeDeclaration { Name = new Identifier("Link"), Parameters = new List<Literal> { new Literal(linkName) } }; variable.Attributes.Add(attribute); } // Append location to key in case it is a local variable if (!variable.Qualifiers.Values.Contains(XenkoStorageQualifier.Stage)) { attribute.Parameters[0].SubLiterals = null; // set to null to avoid conflict with the member Value attribute.Parameters[0].Value = (string)attribute.Parameters[0].Value + context; } } } foreach (var variable in mixin.StaticReferences.VariablesReferences.Select(x => x.Key)) { var attribute = variable.Attributes.OfType<AttributeDeclaration>().FirstOrDefault(x => x.Name == "Link"); if (attribute == null) { var baseClassName = (variable.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinGenericName; attribute = new AttributeDeclaration { Name = new Identifier("Link"), Parameters = new List<Literal> { new Literal(baseClassName + "." + variable.Name.Text) } }; variable.Attributes.Add(attribute); } } mixin.InheritanceList.ForEach(x => LinkVariables(x, context, visitedMixins)); }
/// <summary> /// Remove the method from the correctdictionary /// </summary> /// <param name="expression"></param> private void RemoveFromMethodsReferences(MethodInvocationExpression expression, ModuleMixin mixin) { foreach (var refList in mixin.ClassReferences.MethodsReferences) refList.Value.RemoveWhere(x => x == expression); foreach (var refList in mainModuleMixin.ClassReferences.MethodsReferences) refList.Value.RemoveWhere(x => x == expression); }
/// <summary> /// Run the analysis /// </summary> /// <param name="mixinToAnalyze">the current context (virtual table) from mixin inheritance</param> /// <param name="compilationContext">List of all the mixin in the compilation context</param> /// <returns>true if the shader is correct, false otherwise</returns> public static XenkoParsingInfo RunAnalysis(ModuleMixin mixinToAnalyze, List<ModuleMixin> compilationContext, bool transformForEach = false) { var shader = new Shader(); shader.Declarations.Add(mixinToAnalyze.Shader); var toParse = new ParsingResult { Shader = shader }; var analysis = new XenkoSemanticAnalysis(toParse, mixinToAnalyze, compilationContext) { parsingInfo = new XenkoParsingInfo() }; analysis.expandForEachStatements = transformForEach; analysis.Run(); // look at the static classes analysis.parsingInfo.StaticClasses.UnionWith(analysis.parsingInfo.StaticReferences.VariablesReferences.Select(x => x.Key.GetTag(XenkoTags.ShaderScope) as ModuleMixin)); analysis.parsingInfo.StaticClasses.UnionWith(analysis.parsingInfo.StaticReferences.MethodsReferences.Select(x => x.Key.GetTag(XenkoTags.ShaderScope) as ModuleMixin)); analysis.parsingInfo.StaticClasses.Remove(mixinToAnalyze); analysis.parsingInfo.ErrorsWarnings = analysis.ParsingResult; return analysis.parsingInfo; }
/// <summary> /// Solves both base and direct method calls /// </summary> /// <param name="mixin"></param> private void PatchAllMethodInferences(ModuleMixin mixin) { mixin.InheritanceList.ForEach(PatchAllMethodInferences); CompositionsPerVariable.Where(x => mixin.LocalVirtualTable.Variables.Any(y => y.Variable == x.Key)).ToList().ForEach(externMixes => externMixes.Value.ForEach(PatchAllMethodInferences)); var topMixin = GetTopMixin(mixin); foreach (var baseCall in mixin.ParsingInfo.BaseMethodCalls) { MethodDeclaration decl = null; if ((baseCall.Target.TypeInference.Declaration as MethodDeclaration).Qualifiers.Contains(XenkoStorageQualifier.Stage)) decl = GetBaseStageMethod(baseCall); else decl = topMixin.GetBaseMethodFromExpression(baseCall.Target, mixin); if (decl != null) { RemoveFromMethodsReferences(baseCall, topMixin); baseCall.TypeInference.TargetType = decl.ReturnType; baseCall.Target.TypeInference.Declaration = decl; AddToMethodsReferences(baseCall); } else log.Error(XenkoMessageCode.ErrorImpossibleBaseCall, baseCall.Span, baseCall, mixin.MixinName); } // resolve this calls foreach (var thisCall in mixin.ParsingInfo.ThisMethodCalls) { MethodDeclaration decl = null; if ((thisCall.Target.TypeInference.Declaration as MethodDeclaration).Qualifiers.Contains(XenkoStorageQualifier.Stage)) decl = GetThisStageMethod(thisCall); else if (thisCall.ContainsTag(XenkoTags.StaticRef)) decl = FindStaticMethod(thisCall); else decl = topMixin.GetMethodFromExpression(thisCall.Target); if (decl != null) { RemoveFromMethodsReferences(thisCall, topMixin); thisCall.TypeInference.TargetType = decl.ReturnType; thisCall.Target.TypeInference.Declaration = decl; if (!thisCall.ContainsTag(XenkoTags.StaticRef)) AddToMethodsReferences(thisCall); } else log.Error(XenkoMessageCode.ErrorImpossibleVirtualCall, thisCall.Span, thisCall, mixin.MixinName, mainModuleMixin.MixinName); } }
/// <summary> /// Get the streams usage for this entrypoint /// </summary> /// <param name="moduleMixin">the current module mixin</param> /// <param name="entryPoint">the entrypoint method</param> /// <returns>a StreamStageUsage containing the streams usages</returns> private StreamStageUsage StreamAnalysisPerShader(ModuleMixin moduleMixin, MethodDeclaration entryPoint, XkShaderStage shaderStage) { var visitedMethods = new List<MethodDeclaration>(); var streamStageUsage = new StreamStageUsage { ShaderStage = shaderStage }; FindStreamsUsage(entryPoint, streamStageUsage.InStreamList, streamStageUsage.OutStreamList, visitedMethods); visitedMethods.Clear(); return streamStageUsage; }
/// <summary> /// Inference for extern calls /// </summary> /// <param name="mixin"></param> private void ProcessExternReferences(ModuleMixin mixin) { mixin.InheritanceList.ForEach(ProcessExternReferences); CompositionsPerVariable.Where(x => mixin.LocalVirtualTable.Variables.Any(y => y.Variable == x.Key)).ToList().ForEach(externMixes => externMixes.Value.ForEach(ProcessExternReferences)); foreach (var externReferences in mixin.ExternReferences.VariablesReferences) { foreach (var expression in externReferences.Value) { var searchMixin = mixin; var foundDefinition = FindVariable(expression.Expression, ref searchMixin); if (foundDefinition != null) // should be always true { if (foundDefinition.Qualifiers.Contains(XenkoStorageQualifier.Stage)) { var sameVar = mixin.ClassReferences.VariablesReferences.FirstOrDefault( x => x.Key.Name.Text == foundDefinition.Name.Text && (x.Key.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName == (foundDefinition.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName).Key; if (sameVar == null) { mixin.ClassReferences.VariablesReferences.Add(foundDefinition, new HashSet<ExpressionNodeCouple>()); sameVar = foundDefinition; } mixin.ClassReferences.VariablesReferences[sameVar].Add(expression); expression.Expression.TypeInference.Declaration = sameVar; expression.Expression.TypeInference.TargetType = sameVar.Type.ResolveType(); } else { if (!mixin.ClassReferences.VariablesReferences.ContainsKey(foundDefinition)) mixin.ClassReferences.VariablesReferences.Add(foundDefinition, new HashSet<ExpressionNodeCouple>()); mixin.ClassReferences.VariablesReferences[foundDefinition].Add(expression); expression.Expression.TypeInference.Declaration = foundDefinition; expression.Expression.TypeInference.TargetType = foundDefinition.Type.ResolveType(); } } else log.Error(XenkoMessageCode.ErrorExternReferenceNotFound, expression.Expression.Span, expression, mixin.MixinName); } } mixin.ExternReferences.VariablesReferences.Clear(); foreach (var externReferences in mixin.ExternReferences.MethodsReferences) { foreach (var methodInvoc in externReferences.Value) { var searchMixin = mixin; var foundDefinition = FindMethod(methodInvoc.Target, ref searchMixin); if (foundDefinition != null) // should be always true { if (!mixin.ClassReferences.MethodsReferences.ContainsKey(foundDefinition)) mixin.ClassReferences.MethodsReferences.Add(foundDefinition, new HashSet<MethodInvocationExpression>()); mixin.ClassReferences.MethodsReferences[foundDefinition].Add(methodInvoc); methodInvoc.Target.TypeInference.Declaration = foundDefinition; } else log.Error(XenkoMessageCode.ErrorExternReferenceNotFound, methodInvoc.Span, methodInvoc, mixin.MixinName); } } mixin.ExternReferences.MethodsReferences.Clear(); }
/// <summary> /// Find the correct variable inference /// </summary> /// <param name="expression"></param> /// <param name="mixin"></param> /// <returns></returns> private Variable FindVariable(Expression expression, ref ModuleMixin mixin) { Variable result = null; var index = 0; if (expression is VariableReferenceExpression) { result = FindVariableInMixin((expression as VariableReferenceExpression).Name.Text, mixin); } else if (expression is MemberReferenceExpression) { var memberExpression = expression as MemberReferenceExpression; var target = memberExpression.Target; if (target.TypeInference.Declaration is Variable) FindVariable(target, ref mixin); else if (target.TypeInference.Declaration is ShaderClassType || target.TypeInference.TargetType is ShaderClassType) FindShader(target, ref mixin); result = FindVariableInMixin(memberExpression.Member.Text, mixin); } else if (expression is IndexerExpression) { var indexerExpression = expression as IndexerExpression; var target = indexerExpression.Target; if (target.TypeInference.Declaration is Variable) result = FindVariable(target, ref mixin); index = (int)(indexerExpression.Index as LiteralExpression).Value; } if (result is Variable && (result as Variable).Qualifiers.Contains(XenkoStorageQualifier.Extern) && !((result as Variable).Type is ArrayType)) mixin = CompositionsPerVariable[result as Variable][index]; return result; }
/// <summary> /// Add the stage variables from the mixin to the main one /// </summary> /// <param name="mixin">the ModuleMixin</param> private void AddStageVariables(ModuleMixin mixin) { mixin.InheritanceList.ForEach(AddStageVariables); CompositionsPerVariable.Where(x => mixin.LocalVirtualTable.Variables.Any(y => y.Variable == x.Key)).ToList().ForEach(externMixes => externMixes.Value.ForEach(AddStageVariables)); foreach (var variable in mixin.LocalVirtualTable.Variables) { if (variable.Variable.Qualifiers.Contains(XenkoStorageQualifier.Stage)) { var shaderName = variable.Shader.Name.Text; var sameVar = mainModuleMixin.ClassReferences.VariablesReferences.FirstOrDefault(x => x.Key.Name.Text == variable.Variable.Name.Text && (x.Key.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName == shaderName).Key; if (sameVar != null) continue; } if (!mainModuleMixin.ClassReferences.VariablesReferences.ContainsKey(variable.Variable)) mainModuleMixin.ClassReferences.VariablesReferences.Add(variable.Variable, new HashSet<ExpressionNodeCouple>()); } }
public static void Run(ShaderClassType shaderClassType, ModuleMixin mixin, List<ModuleMixin> mixins, LoggerResult errorLog) { var streamCreator = new XenkoStreamCreator(shaderClassType, mixin, mixins, errorLog); streamCreator.Run(); }
/// <summary> /// Build an ordered list of mixin defining the inheritance for stage values /// </summary> /// <param name="mixin">the mixin to add</param> private void BuildMixinInheritance(ModuleMixin mixin) { mixin.InheritanceList.ForEach(BuildMixinInheritance); MixinInheritance.Add(mixin); CompositionsPerVariable.Where(x => mixin.LocalVirtualTable.Variables.Any(y => y.Variable == x.Key)).ToList().ForEach(externMixes => externMixes.Value.ForEach(BuildMixinInheritance)); }
/// <summary> /// Get the base MethodDeclaration from its call and the mixin where the call is performed /// </summary> /// <param name="expression">the calling expression</param> /// <param name="mixin">the mixin where the call is performed</param> /// <returns>the base MethodDeclaration</returns> public MethodDeclaration GetBaseMethodFromExpression(Expression expression, ModuleMixin mixin) { var info = (VTableReference)expression.GetTag(XenkoTags.VirtualTableReference); var thisMethod = VirtualTable.GetMethod(info.Shader, info.Slot); if (thisMethod == null) return null; var startIndex = mixin == this ? InheritanceList.Count : InheritanceList.IndexOf(mixin); for (int i = startIndex - 1; i >= 0; --i) { var dep = InheritanceList[i]; var array = VirtualTable.VirtualTableGroup[dep.MixinName]; for (int j = 0; j < array.Length; ++j) { var method = array[j]; if (method == thisMethod) return dep.VirtualTable.VirtualTableGroup[dep.MixinName][j]; } } return null; }