/// <summary> /// Collect scripts to reflect from. /// </summary> /// <param name="scriptType">The Script type to collect.</param> /// <param name="reachedScripts">Scripts reached using static inclusions. Used also as recursion prevention.</param> private static void CollectIncludees(Type scriptType, Dictionary <Type, bool> reachedScripts) { Debug.Assert(scriptType.Name == ScriptModule.ScriptTypeName); // recursion prevention if (reachedScripts.ContainsKey(scriptType)) { return; } reachedScripts.Add(scriptType, false); // // reflect statically included script types recursively // var sa = ScriptIncludeesAttribute.Reflect(scriptType); if (sa != null && sa.Inclusions.Length > 0) { var module = scriptType.Module; var conditionalFlags = sa.InclusionsConditionalFlags; // recursively reflect statically included scripts for (int i = 0; i < sa.Inclusions.Length; ++i) { if (!conditionalFlags[i]) // allow reflecting of included script only if it is not conditional include { Type includedScript = module.ResolveType(sa.Inclusions[i]); if (includedScript != null) { CollectIncludees(includedScript, reachedScripts); } } } } }
/// <summary> /// Emit the Script attribute with includes,includers,relativePath and timeStamp info. /// </summary> /// <param name="emitAttributes">Specifies single infos to emit.</param> internal void SetScriptAttribute(ScriptAttributes emitAttributes) { // module to resolve type tokens from: ModuleBuilder real_builder = this.AssemblyBuilder.RealModuleBuilder; // [Script(timeStamp, relativePath)] if ((emitAttributes & ScriptAttributes.Script) != 0) { // construct the [Script] attribute: CustomAttributeBuilder cab = new CustomAttributeBuilder(Constructors.Script, new object[] { sourceTimestamp.Ticks, CompilationUnit.RelativeSourcePath }); ScriptTypeBuilder.SetCustomAttribute(cab); } // [ScriptIncluders(int[])] if ((emitAttributes & ScriptAttributes.ScriptIncluders) != 0 && CompilationUnit.Includers.Count > 0) { // determine includers type token, remove duplicities: int[] includers = ArrayUtils.Unique(Array.ConvertAll(CompilationUnit.Includers.ToArray(), x => real_builder.GetTypeToken(x.Includer.ScriptBuilder.ScriptType).Token)).ToArray(); // construct the [ScriptIncluders] attribute: CustomAttributeBuilder cab = new CustomAttributeBuilder(Constructors.ScriptIncluders, new object[] { includers }); ScriptTypeBuilder.SetCustomAttribute(cab); } // [ScriptIncludees(int[],byte[])] if ((emitAttributes & ScriptAttributes.ScriptIncludees) != 0 && CompilationUnit.Inclusions.Count > 0) { // determine inclusions type token, group by the token to remove duplicities: var inclusionsGroup = ArrayUtils.Group(CompilationUnit.Inclusions.ToArray(), x => real_builder.GetTypeToken(x.Includee.ScriptClassType).Token); // determine if single includees are at least once included unconditionally: int[] inclusions = new int[inclusionsGroup.Count]; bool[] inclusionsConditionalFlag = new bool[inclusions.Length]; int i = 0; foreach (var includee in inclusionsGroup) { // find any unconditional inclusion to mark this unified inclusion as unconditional inclusionsConditionalFlag[i] = ArrayUtils.LogicalAnd(includee.Value, x => x.IsConditional); // inclusions[i] = includee.Key; ++i; } // construct the [ScriptIncluders] attribute: CustomAttributeBuilder cab = new CustomAttributeBuilder(Constructors.ScriptIncludees, new object[] { inclusions, ScriptIncludeesAttribute.ConvertBoolsToBits(inclusionsConditionalFlag) }); ScriptTypeBuilder.SetCustomAttribute(cab); } // [ScriptDeclares(int[])] if ((emitAttributes & ScriptAttributes.ScriptDeclares) != 0) { List <int> declaredTypesToken = new List <int>(); foreach (PhpType type in CompilationUnit.GetDeclaredTypes()) { if (type.IsComplete && type.RealType != null) { declaredTypesToken.Add(real_builder.GetTypeToken(type.RealType).Token); } } if (declaredTypesToken.Count > 0) { // construct the [ScriptDeclares] attribute: CustomAttributeBuilder cab = new CustomAttributeBuilder(Constructors.ScriptDeclares, new object[] { declaredTypesToken.ToArray() }); ScriptTypeBuilder.SetCustomAttribute(cab); } } }