예제 #1
0
 // todo -- would be good to have this be an instance property because we need to clear dynamics every time we compile
 public static void AddDynamicElementType(ProcessedType processedType)
 {
     processedType.id = NextTypeId;
     typeMap[processedType.rawType] = processedType;
     dynamicTypes.Add(processedType);
     // templateTypes.Add(processedType);
     // todo -- maybe add to namespace map?
 }
예제 #2
0
        public TemplateRootNode GetParsedTemplate(ProcessedType processedType)
        {
            TemplateAttribute templateAttr = processedType.templateAttr;

            templateAttr.filePath = ResolveTemplateFilePath(processedType);
            if (templateAttr.fullPathId == null)
            {
                templateAttr.fullPathId = templateAttr.templateId == null
                    ? templateAttr.filePath
                    : templateAttr.filePath + "#" + templateAttr.templateId;
            }

            Debug.Assert(templateAttr.fullPathId != null, "templateAttr.fullPathId != null");

            if (templateMap.TryGetValue(templateAttr.fullPathId, out LightList <TemplateRootNode> list))
            {
                for (int i = 0; i < list.size; i++)
                {
                    if (list.array[i].processedType.rawType == processedType.rawType)
                    {
                        return(list.array[i]);
                    }
                }

                TemplateRootNode retn = list[0].Clone(processedType);
                list.Add(retn);
                return(retn);
            }

            list = new LightList <TemplateRootNode>(2);

            templateMap[templateAttr.fullPathId] = list;

            TemplateDefinition templateDefinition = GetTemplateDefinition(processedType);

            templateAttr.source = templateDefinition.contents;

            TemplateShell shell = xmlTemplateParser.GetOuterTemplateShell(templateAttr);

            TemplateRootNode templateRootNode = new TemplateRootNode(templateAttr.templateId, shell, processedType, null, default)
            {
                tagName = processedType.tagName
            };

            list.Add(templateRootNode);

            xmlTemplateParser.Parse(templateRootNode, processedType);

            return(templateRootNode);
        }
예제 #3
0
        private TemplateDefinition GetTemplateDefinition(ProcessedType processedType)
        {
            TemplateAttribute templateAttr = processedType.templateAttr;

            string templatePath = ResolveTemplateFilePath(templateAttr.templateType, templateAttr.filePath);

            switch (templateAttr.templateType)
            {
            case TemplateType.Internal: {
                string file = settings.TryReadFile(templatePath);

                if (file == null)
                {
                    throw new TemplateParseException(settings.templateResolutionBasePath, $"Cannot find template in (internal) path {templatePath}.");
                }

                return(new TemplateDefinition()
                    {
                        contents = file,
                        filePath = templateAttr.templateType == TemplateType.File ? processedType.rawType.AssemblyQualifiedName : templateAttr.filePath,
                        language = TemplateLanguage.XML
                    });
            }

            case TemplateType.DefaultFile:
            case TemplateType.File: {
                string file = settings.TryReadFile(templatePath);
                if (file == null)
                {
                    throw new TemplateParseException(settings.templateResolutionBasePath, $"Cannot find template in path {templatePath}.");
                }

                return(new TemplateDefinition()
                    {
                        contents = file,
                        filePath = templateAttr.filePath,
                        language = TemplateLanguage.XML
                    });
            }

            default:
                return(new TemplateDefinition()
                {
                    contents = templateAttr.source,
                    filePath = templatePath,
                    language = TemplateLanguage.XML
                });
            }
        }
예제 #4
0
        public static ProcessedType AddResolvedGenericElementType(Type newType, TemplateAttribute templateAttr, string tagName)
        {
            ProcessedType retn = null;

            if (!typeMap.TryGetValue(newType, out retn))
            {
                retn    = new ProcessedType(newType, templateAttr, tagName);
                retn.id = NextTypeId;
                typeMap.Add(retn.rawType, retn);
            }

            if (retn != null)
            {
                retn.references++;
            }

            return(retn);
        }
예제 #5
0
        internal void Parse(TemplateRootNode templateRootNode, ProcessedType processedType)
        {
            TemplateAttribute templateAttr = processedType.templateAttr;

            string filePath = templateAttr.filePath;

            if (parsedFiles.TryGetValue(filePath, out TemplateShell rootNode))
            {
                ParseContentTemplate(templateRootNode, rootNode, processedType);
                return;
            }

            TemplateShell shell = ParseOuterShell(templateAttr.filePath, templateAttr.source);

            parsedFiles.Add(filePath, shell);

            ParseContentTemplate(templateRootNode, shell, processedType);
        }
예제 #6
0
        private string ResolveTemplateFilePath(ProcessedType processedType)
        {
            TemplateAttribute templateAttr = processedType.templateAttr;

            if (templateAttr.templateType == TemplateType.Internal)
            {
                return(templateAttr.filePath);
            }

            if (settings.filePathResolver != null)
            {
                return(settings.filePathResolver(processedType.rawType, templateAttr.templateId));
            }

            string namespacePath = processedType.rawType.Namespace;

            if (namespacePath != null && namespacePath.Contains("."))
            {
                namespacePath = namespacePath.Replace(".", Path.DirectorySeparatorChar.ToString());
            }

            string xmlPath;

            // Special behavior for template attributes with no file path parameter. We figure out the whole path
            // based on a convention that looks for a given template like:
            //     namespace My.Name.Space { [Template] public class MyElement : UIElement ... }
            // right here:
            // basepath + My/Name/Space/ClassName.xml
            if (templateAttr.templateType == TemplateType.DefaultFile)
            {
                string basePath = namespacePath == null
                    ? processedType.rawType.Name
                    : Path.Combine(namespacePath, processedType.rawType.Name);

                string relativePath = basePath + settings.templateFileExtension;
                xmlPath = Path.GetFullPath(Path.Combine(settings.templateResolutionBasePath, relativePath));
                if (!File.Exists(xmlPath))
                {
                    throw new TemplateNotFoundException(processedType, xmlPath);
                }

                return(relativePath);
            }

            // first we try to find the template based on the resolution base path + a guessed namespace path
            if (namespacePath != null)
            {
                // namespace My.Name.Space.MyElement { [Template("MyElement.xml#id")] }
                // basepath + My/Name/Space/MyElement/MyElement.xml
                // templateRootNamespace = My/Name/Space
                xmlPath = Path.GetFullPath(Path.Combine(settings.templateResolutionBasePath, namespacePath, templateAttr.filePath));
                if (File.Exists(xmlPath))
                {
                    return(Path.Combine(namespacePath, templateAttr.filePath));
                }
            }

            // namespace My.Name.Space.MyElement { [Template("My/Name/Space/MyElement/MyElement.xml#id")] }
            // basepath + My/Name/Space/MyElement/MyElement.xml
            // templateRootNamespace = My/Name/Space
            // ------
            // If the previous method didn't find a template we probably have a full path in the template attribute.
            // This should be the mode that is compatible with non-convention paths and namespaces
            xmlPath = Path.GetFullPath(Path.Combine(settings.templateResolutionBasePath, templateAttr.filePath));
            if (File.Exists(xmlPath))
            {
                return(templateAttr.filePath);
            }

            throw new TemplateNotFoundException(processedType, xmlPath);
        }
예제 #7
0
 public RepeatNode(TemplateRootNode root, TemplateNode parent, ProcessedType processedType, StructList <AttributeDefinition> attributes, in TemplateLineInfo templateLineInfo) : base(root, parent, processedType, attributes, in templateLineInfo)
예제 #8
0
 public ExpandedTemplateNode(TemplateRootNode root, TemplateNode parent, ProcessedType processedType, StructList <AttributeDefinition> attributes, in TemplateLineInfo templateLineInfo)
예제 #9
0
 public SlotNode(TemplateRootNode root, TemplateNode parent, ProcessedType processedType, StructList <AttributeDefinition> attributes, in TemplateLineInfo templateLineInfo, string slotName, SlotType slotType)
예제 #10
0
        // this might be getting called too many times since im not sure im caching the result
        private void ParseContentTemplate(TemplateRootNode templateRootNode, TemplateShell shell, ProcessedType processedType)
        {
            XElement root = shell.GetElementTemplateContent(processedType.templateAttr.templateId);

            if (root == null)
            {
                throw new TemplateNotFoundException(processedType.templateAttr.filePath, processedType.templateAttr.templateId);
            }

            IXmlLineInfo xmlLineInfo = root;

            StructList <AttributeDefinition> attributes = StructList <AttributeDefinition> .Get();

            StructList <AttributeDefinition> injectedAttributes = StructList <AttributeDefinition> .Get();

            ParseAttributes(shell, "Contents", root.Attributes(), attributes, injectedAttributes, out string genericTypeResolver, out string requireType);

            if (attributes.size == 0)
            {
                StructList <AttributeDefinition> .Release(ref attributes);
            }

            if (injectedAttributes.size == 0)
            {
                StructList <AttributeDefinition> .Release(ref injectedAttributes);
            }

            templateRootNode.attributes          = ValidateRootAttributes(shell.filePath, attributes);
            templateRootNode.lineInfo            = new TemplateLineInfo(xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
            templateRootNode.genericTypeResolver = genericTypeResolver;
            templateRootNode.requireType         = requireType; // always null I think
            ParseChildren(templateRootNode, templateRootNode, root.Nodes());
        }
예제 #11
0
        // Namespace resolution
        //    if there is only one element with a name then no namespace is needed
        //    if there are multiple elements with a name
        //        namespace is required in order to match the correct one
        //    using declarations can provide implicit namespaces
        public static ProcessedType ResolveTagName(string tagName, string namespacePrefix, IReadOnlyList <string> namespaces)
        {
            FilterAssemblies();

            namespaces = namespaces ?? EmptyNamespaceList;

            if (string.IsNullOrEmpty(namespacePrefix))
            {
                namespacePrefix = null;
            }
            if (string.IsNullOrWhiteSpace(namespacePrefix))
            {
                namespacePrefix = null;
            }

            if (templateTypeMap.TryGetValue(tagName, out TypeList typeList))
            {
                // if this is null we resolve using just the tag name
                if (namespacePrefix == null)
                {
                    // if only one type has this tag name we can safely return it
                    if (typeList.types == null)
                    {
                        return(typeList.mainType.Reference());
                    }

                    // if there are multiple tags with this name, we need to search our namespaces
                    // if only one match is found, we can return it. If multiple are found, throw
                    // and ambiguous reference exception
                    LightList <ProcessedType> resultList = LightList <ProcessedType> .Get();

                    for (int i = 0; i < namespaces.Count; i++)
                    {
                        for (int j = 0; j < typeList.types.Length; j++)
                        {
                            string        namespaceName = namespaces[i];
                            ProcessedType testType      = typeList.types[j];
                            if (namespaceName == testType.namespaceName)
                            {
                                resultList.Add(testType);
                            }
                        }
                    }

                    if (resultList.size == 1)
                    {
                        ProcessedType retn = resultList[0];
                        resultList.Release();
                        return(retn.Reference());
                    }

                    List <string> list = resultList.Select((s) => s.namespaceName).ToList();
                    throw new ParseException("Ambiguous TagName reference: " + tagName + ". References found in namespaces " + StringUtil.ListToString(list, ", "));
                }

                if (typeList.types == null)
                {
                    if (namespacePrefix == typeList.mainType.namespaceName)
                    {
                        return(typeList.mainType.Reference());
                    }
                }
                else
                {
                    // if prefix is not null we can only return a match for that namespace
                    for (int j = 0; j < typeList.types.Length; j++)
                    {
                        ProcessedType testType = typeList.types[j];
                        if (namespacePrefix == testType.namespaceName)
                        {
                            return(testType.Reference());
                        }
                    }
                }

                return(null);
            }

            if (s_GenericMap.TryGetValue(tagName, out ProcessedType processedType))
            {
                return(processedType);
            }

            return(null);
        }
예제 #12
0
        private static void FilterAssemblies()
        {
            if (processedTypes)
            {
                return;
            }
            processedTypes = true;

            Stopwatch watch = new Stopwatch();

            watch.Start();

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            int        count      = 0;

            for (int i = 0; i < assemblies.Length; i++)
            {
                Assembly assembly = assemblies[i];

                if (assembly == null || assembly.IsDynamic)
                {
                    continue;
                }

                bool filteredOut        = !FilterAssembly(assembly);
                bool shouldProcessTypes = ShouldProcessTypes(assembly, filteredOut);

                if (!shouldProcessTypes)
                {
                    continue;
                }

                count++;

                try {
                    Type[] types = assembly.GetTypes();

                    for (int j = 0; j < types.Length; j++)
                    {
                        Type currentType = types[j];
                        // can be null if assembly referenced is unavailable
                        // ReSharper disable once ConditionIsAlwaysTrueOrFalse
                        if (currentType == null)
                        {
                            continue;
                        }

                        if (!filteredOut && currentType.IsClass && currentType.Name[0] != '<' && currentType.IsGenericTypeDefinition)
                        {
                            if (currentType.IsSubclassOf(typeof(UIElement)))
                            {
                                Attribute[] attrs   = Attribute.GetCustomAttributes(currentType, false);
                                string      tagName = GetTemplateAttribute(currentType, attrs, out TemplateAttribute templateAttr);

                                // todo -- support namespaces in the look up map
                                tagName = tagName.Split('`')[0];

                                ProcessedType processedType = new ProcessedType(currentType, templateAttr, tagName);
                                processedType.IsUnresolvedGeneric = true;
                                try {
                                    s_GenericMap.Add(tagName, processedType);
                                }
                                catch (Exception) {
                                    Debug.LogError($"UIForia does not support multiple elements with the same tag name. Tried to register type {processedType.rawType} for `{tagName}` " +
                                                   $"but this tag name was already taken by type {s_GenericMap[tagName].rawType}. For generic overload types with multiple arguments you need to supply a unique [TagName] attribute");
                                    continue;
                                }

                                typeMap[currentType] = processedType;

                                if (!s_NamespaceMap.TryGetValue(currentType.Namespace ?? "null", out LightList <Assembly> namespaceList))
                                {
                                    namespaceList = new LightList <Assembly>(2);
                                    s_NamespaceMap.Add(currentType.Namespace ?? "null", namespaceList);
                                }

                                if (!namespaceList.Contains(assembly))
                                {
                                    namespaceList.Add(assembly);
                                }

                                continue;
                            }
                        }

                        if (!filteredOut && currentType.IsClass && !currentType.IsGenericTypeDefinition)
                        {
                            Attribute[] attrs = Attribute.GetCustomAttributes(currentType, false);
                            Application.ProcessClassAttributes(currentType, attrs);

                            if (typeof(UIElement).IsAssignableFrom(currentType))
                            {
                                string tagName = GetTemplateAttribute(currentType, attrs, out TemplateAttribute templateAttr);

                                ProcessedType processedType = new ProcessedType(currentType, templateAttr, tagName);

                                if (templateAttr != null)
                                {
                                    templateTypes.Add(processedType);
                                }

                                // if (templateTypeMap.ContainsKey(tagName)) {
                                //     Debug.Log($"Tried to add template key `{tagName}` from type {currentType} but it was already defined by {templateTypeMap.GetOrDefault(tagName).rawType}");
                                // }

                                if (templateTypeMap.TryGetValue(tagName, out TypeList typeList))
                                {
                                    if (typeList.types != null)
                                    {
                                        Array.Resize(ref typeList.types, typeList.types.Length + 1);
                                        typeList.types[typeList.types.Length - 1] = processedType;
                                    }
                                    else
                                    {
                                        typeList.types    = new ProcessedType[2];
                                        typeList.types[0] = typeList.mainType;
                                        typeList.types[1] = processedType;
                                    }
                                }
                                else
                                {
                                    typeList.mainType        = processedType;
                                    templateTypeMap[tagName] = typeList;
                                }

                                // templateTypeMap.Add(tagName, processedType);
                                processedType.id     = NextTypeId;
                                typeMap[currentType] = processedType;
                            }
                        }

                        if (filteredOut && !currentType.IsPublic)
                        {
                            continue;
                        }

                        if (!s_NamespaceMap.TryGetValue(currentType.Namespace ?? "null", out LightList <Assembly> list))
                        {
                            list = new LightList <Assembly>(2);
                            s_NamespaceMap.Add(currentType.Namespace ?? "null", list);
                        }

                        if (!list.Contains(assembly))
                        {
                            list.Add(assembly);
                        }
                    }
                }
                catch (ReflectionTypeLoadException) {
                    Debug.Log($"{assembly.FullName}");
                    throw;
                }
            }

            watch.Stop();
            Debug.Log($"Loaded types in: {watch.ElapsedMilliseconds} ms from {count} assemblies");
        }
예제 #13
0
 public TemplateRootNode(string templateName, TemplateShell templateShell, ProcessedType processedType, StructList <AttributeDefinition> attributes, in TemplateLineInfo templateLineInfo) : base(null, null, processedType, attributes, in templateLineInfo)