private XenkoStreamCreator(ShaderClassType shaderClassType, ModuleMixin mixin, List<ModuleMixin> mixins, LoggerResult errorLog)
 {
     shader = shaderClassType;
     mainModuleMixin = mixin;
     mixinInheritance = mixins;
     errorWarningLog = errorLog ?? new LoggerResult();
 }
예제 #2
0
        /// <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);
            }
        }
예제 #4
0
 /// <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));
 }
예제 #5
0
        /// <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);
        }
예제 #6
0
        /// <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);
            }
        }
예제 #7
0
        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];
            }
        }
예제 #8
0
        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;
        }
예제 #9
0
        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;
        }
예제 #10
0
        /// <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);
            }
        }
예제 #11
0
        /// <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);
        }
예제 #12
0
 /// <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;
 }
예제 #13
0
 /// <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);
 }
예제 #14
0
        /// <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);
        }
예제 #15
0
        /// <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));
 }
예제 #18
0
        /// <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);
                    }
                }
            }
        }
예제 #19
0
        /// <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));
        }
예제 #20
0
        /// <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;
        }
예제 #22
0
        /// <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;
        }
예제 #24
0
        /// <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();
        }
예제 #25
0
        /// <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;
        }
예제 #26
0
 /// <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();
 }
예제 #28
0
 /// <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));
 }
예제 #29
0
        /// <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;
        }