public string[] ParseParamName(string vkName, PointerType pointerType, out string extension) { int pointerCount = pointerType.GetPointerCount(); while (pointerCount > 0 && vkName.StartsWith("p")) { vkName = vkName.Substring(1); pointerCount--; } if (vkName.Contains("_")) { extension = null; return(SplitSnakeCase(vkName)); } else { return(GetNameParts(vkName, out extension)); } }
public ParsedSpec Run() { var vkXml = this.xmlCache.GetVkXml(); var knownExtensions = new List <string>(); foreach (var vkExtension in vkXml.Element("registry").Element("extensions").Elements("extension")) { string name = vkExtension.Attribute("name").Value; var nameParts = name.Split('_'); string extensionSuffix = nameParts[1].ToLower(); if (!knownExtensions.Contains(extensionSuffix)) { knownExtensions.Add(extensionSuffix); } } var typeXml = new Dictionary <string, ParsedType>(); foreach (var vkType in vkXml.Element("registry").Element("types").Elements("type")) { string name = vkType.Attribute("name")?.Value ?? vkType.Element("name").Value; var categoryAttribute = vkType.Attribute("category"); TypeCategory category = categoryAttribute == null ? TypeCategory.None : (TypeCategory)Enum.Parse(typeof(TypeCategory), categoryAttribute.Value); string requires = vkType.Attribute("requires")?.Value; string parent = vkType.Attribute("parent")?.Value; string returnedOnly = vkType.Attribute("returnedonly")?.Value; bool isReturnedOnly = returnedOnly != null ? bool.Parse(returnedOnly) : false; bool isTypePointer = false; string type = vkType.Element("type")?.Value; if (type == "VK_MAKE_VERSION") { type += vkType.Element("type").NextNode.ToString(); } if (category == TypeCategory.funcpointer) { type = ((XText)vkType.Nodes().First()).Value.Split(' ')[1]; if (type.EndsWith("*")) { type = type.TrimEnd('*'); isTypePointer = true; } } string extension; string[] nameParts = GetNameParts(category == TypeCategory.funcpointer ? name.Substring(4) : name, out extension, knownExtensions); // VkDisplayModeKHR has two parents defined, but associated // handle should cover the requirements for the second // so just take the first if (parent != null) { parent = parent.Split(',').First(); } var newType = new ParsedType { VkName = name, Category = category, Requires = requires, Parent = parent, IsReturnedOnly = isReturnedOnly, NameParts = nameParts, Extension = extension, Type = type, IsTypePointer = isTypePointer }; foreach (var vkMember in vkType.Elements("member")) { var nameElement = vkMember.Element("name"); string memberName = nameElement.Value; string memberType = vkMember.Element("type").Value; string optional = vkMember.Attribute("optional")?.Value; bool isOptional = optional != null ? bool.Parse(optional) : false; ParsedFixedLength fixedLength = new ParsedFixedLength(); var typeNodes = nameElement.NodesBeforeSelf(); PointerType pointerType = GetPointerType(typeNodes); if (nameElement.NodesAfterSelf().Any()) { string enumName = vkMember.Element("enum")?.Value; if (enumName != null) { fixedLength.Value = enumName; fixedLength.Type = FixedLengthType.EnumReference; } else { fixedLength.Value = fixedLengthParser.Parse(nameElement.NextNode.ToString()); fixedLength.Type = FixedLengthType.IntegerLiteral; } } else { int fixedLengthIndex = memberName.IndexOf('['); if (fixedLengthIndex >= 0) { string fixedLengthString = memberName.Substring(fixedLengthIndex); memberName = memberName.Substring(0, fixedLengthIndex); fixedLength.Value = fixedLengthParser.Parse(fixedLengthString); fixedLength.Type = FixedLengthType.IntegerLiteral; } } string vkName = memberName; int pointerCount = pointerType.GetPointerCount(); while (pointerCount > 0 && memberName.StartsWith("p")) { memberName = memberName.Substring(1); pointerCount--; } ParsedLen[] dimensions = GetDimensions(name, vkMember, memberName); // Capture member name without array suffix string memberExtension; string[] memberNameParts = GetNameParts(memberName, out memberExtension, knownExtensions, false); string typeExtension; string[] typeNameParts = GetNameParts(memberType, out typeExtension, knownExtensions, true); string typeWithoutExtension = typeNameParts != null ? "Vk" + string.Join("", typeNameParts.Select(CapitaliseFirst)) : null; string values = vkMember.Attribute("values")?.Value; if (vkName == "sType" && values == null) { //HACK VkDebugReportLayerFlagsEXT doesn't specify a // fixed value for the sType field, so it must be // scraped from the following comment. if (vkMember.NextNode != null) { // Split on spaces and skip "Must" & "be" values = ((XComment)vkMember.NextNode).Value.Trim().Split(' ')[2]; } } newType.Members.Add(new ParsedMember { VkName = vkName, Type = memberType, TypeWithoutExtension = typeWithoutExtension, TypeExtension = typeExtension, IsOptional = isOptional, FixedLength = fixedLength, PointerType = pointerType, NameParts = memberNameParts, Extension = extension, Dimensions = dimensions, Values = values }); } // Special parsing is required for funcpointer parameters if (category == TypeCategory.funcpointer) { var functionTail = vkType.Element("name").NodesAfterSelf(); foreach (var typeElement in functionTail.Where(x => x.NodeType == XmlNodeType.Element).Cast <XElement>()) { string pre = ((XText)typeElement.PreviousNode).Value.Split(',').Last().Trim('(', ')', ';').TrimStart(); string post = ((XText)typeElement.NextNode).Value.Split(',').First().Trim('(', ')', ';').TrimEnd(); string paramName = new string(post.Reverse().TakeWhile(char.IsLetterOrDigit).Reverse().ToArray()); string typeString = pre + "@" + (post.Substring(0, post.Length - paramName.Length).Trim()); string paramType = typeElement.Value; PointerType pointerType = MapTypeString(typeString); string paramExtension; string[] paramNameParts = GetNameParts(paramName, out paramExtension, knownExtensions, false); newType.Members.Add(new ParsedMember { VkName = paramName, Type = paramType, PointerType = pointerType, NameParts = paramNameParts, Extension = paramExtension }); } } typeXml.Add(name, newType); } var enumXml = new Dictionary <string, ParsedEnum>(); foreach (var vkEnum in vkXml.Element("registry").Elements("enums")) { string name = vkEnum.Attribute("name").Value; string type = vkEnum.Attribute("type")?.Value; string extension; string[] nameParts = GetNameParts(name, out extension, knownExtensions); var newEnum = new ParsedEnum { VkName = name, Type = type, NameParts = nameParts, Extension = extension }; foreach (var vkField in vkEnum.Elements("enum")) { string fieldName = vkField.Attribute("name").Value; bool isBitmask = true; string value = vkField.Attribute("bitpos")?.Value; string comment = NormaliseComment(vkField.Attribute("comment")?.Value); if (value == null) { isBitmask = false; value = vkField.Attribute("value").Value; // Special case for mapping C "unsigned long long" // (64-bit unsigned integer) to C# UInt64 if (value == "(~0ULL)") { value = "(~0UL)"; } value = value.Trim('(', ')'); } IEnumerable <string> fieldNameParts = GetEnumFieldNameParts(nameParts, fieldName, knownExtensions); newEnum.Fields.Add(fieldName, new ParsedEnumField { VkName = fieldName, NameParts = fieldNameParts.ToArray(), IsBitmask = isBitmask, Value = value, Comment = comment != null ? new List <string> { comment } : null }); } enumXml.Add(name, newEnum); } var commandXml = new Dictionary <string, ParsedCommand>(); foreach (var vkCommand in vkXml.Element("registry").Element("commands").Elements("command")) { string name = vkCommand.Element("proto").Element("name").Value; string type = vkCommand.Element("proto").Element("type").Value; string extension; string[] nameParts = GetNameParts(name, out extension, knownExtensions); string[] verbExceptions = new[] { "cmd", "queue", "device" }; string verb = verbExceptions.Contains(nameParts[0]) ? nameParts[1] : nameParts[0]; string[] successCodes = vkCommand.Attribute("successcodes")?.Value?.Split(','); var newCommand = new ParsedCommand { VkName = name, Type = type, NameParts = nameParts, Extension = extension, Verb = verb, SuccessCodes = successCodes }; commandXml.Add(name, newCommand); foreach (var vkParam in vkCommand.Elements("param")) { var nameElement = vkParam.Element("name"); string paramName = nameElement.Value; string paramType = vkParam.Element("type").Value; string optional = vkParam.Attribute("optional")?.Value; bool isOptional; bool.TryParse(optional, out isOptional); var typeNodes = nameElement.NodesBeforeSelf(); PointerType pointerType = GetPointerType(typeNodes); ParsedLen[] dimensions = GetDimensions(name, vkParam, paramName); string paramExtension; string[] paramNameParts = GetNameParts(paramName, out paramExtension, knownExtensions, false); string typeExtension; string[] typeNameParts = GetNameParts(paramType, out typeExtension, knownExtensions, true); string typeWithoutExtension = typeNameParts != null ? "Vk" + string.Join("", typeNameParts.Select(CapitaliseFirst)) : null; newCommand.Params.Add(new ParsedParam { VkName = paramName, Type = paramType, TypeWithoutExtension = typeWithoutExtension, TypeExtension = typeExtension, PointerType = pointerType, NameParts = paramNameParts, Extension = paramExtension, IsOptional = isOptional, Dimensions = dimensions }); } } var vkFeature = vkXml.Element("registry").Elements("feature").Single(x => x.Attribute("api").Value == "vulkan"); var vkExtensions = vkXml.Element("registry").Element("extensions").Elements("extension").Where(x => x.Attribute("supported").Value == "vulkan"); var filteredSpec = FilterRequiredElement(typeXml, enumXml, commandXml, vkFeature, vkExtensions, knownExtensions); foreach (var defineType in typeXml.Values.Where(x => x.Category == TypeCategory.define && x.VkName.StartsWith("VK_API_VERSION_"))) { IEnumerable <string> fieldNameParts = GetEnumFieldNameParts(null, defineType.VkName, knownExtensions); filteredSpec.Constants.Add(defineType.VkName, new ParsedEnumField { VkName = defineType.VkName, NameParts = fieldNameParts.ToArray(), IsBitmask = false, Value = defineType.Type, Comment = null }); } var vkDocsXmlCache = new DownloadedFileCache(this.tempFilePath, "https://raw.githubusercontent.com/FacticiusVir/SharpVk-Docs/master/Docs/vkDocs.xml"); var vkDocsXml = XDocument.Load(vkDocsXmlCache.GetFileLocation().Result); foreach (var vkDocType in vkDocsXml.Element("docs").Element("types").Elements("type")) { string typeName = vkDocType.Attribute("name").Value; ParsedElement parsedElement = null; if (filteredSpec.Enumerations.ContainsKey(typeName)) { parsedElement = filteredSpec.Enumerations[typeName]; } else if (filteredSpec.Types.ContainsKey(typeName)) { parsedElement = filteredSpec.Types[typeName]; } if (parsedElement != null) { var comment = new List <string> { vkDocType.Attribute("summary").Value }; var specification = vkDocType.Element("specification"); comment.AddRange(specification.Elements("para").Select(x => x.Value)); var description = vkDocType.Element("description"); parsedElement.Comment = new List <string>(); comment.AddRange(description.Elements("para").Select(x => x.Value)); comment.RemoveAll(x => x.StartsWith(".Valid Usage")); int totalLength = 0; foreach (var para in comment) { totalLength += para.Length; if (totalLength > 2000) { break; } else { parsedElement.Comment.Add(NormaliseComment(para)); } } IEnumerable <ParsedElement> members = null; var parsedType = parsedElement as ParsedType; var parsedEnum = parsedElement as ParsedEnum; if (parsedType != null) { members = parsedType.Members; } else if (parsedEnum != null) { members = parsedEnum.Fields.Values; } if (members != null) { foreach (var vkDocMember in vkDocType.Element("members").Elements("member")) { string memberName = vkDocMember.Attribute("name").Value; string memberSummary = NormaliseComment(vkDocMember.Value); var member = members.FirstOrDefault(x => x.VkName == memberName); if (member != null) { member.Comment = new List <string> { memberSummary }; } } } } } foreach (var vkDocCommand in vkDocsXml.Element("docs").Element("commands").Elements("command")) { string commandName = vkDocCommand.Attribute("name").Value; if (filteredSpec.Commands.ContainsKey(commandName)) { var parsedCommand = filteredSpec.Commands[commandName]; parsedCommand.Comment = new List <string> { vkDocCommand.Attribute("summary").Value }; } } return(filteredSpec); }