private static void WriteGL(XmlSpecData glSpec, DotNetTranslator translator, DotNetFileWriter writer) { Console.WriteLine("GLDotNet.GL"); var glCommands = glSpec.Features.Where(x => x.Api == "gl" && (x.VersionMajor <= 3 || (x.VersionMajor == 4 && x.VersionMinor <= 5))).SelectMany(x => x.AddedCommands); var glApi = translator.Translate(glSpec, new DotNetTranslator.Options() { Prefix = "gl", CommandFilter = x => glCommands.Contains(x.Name), EnumGroupFilter = ShouldOutputEnumGroup, EnumFilter = ShouldOutputEnum }); //XmlSerializer.WriteToFile(glApi, "glDotNetData.xml"); writer.WriteFiles(glApi, new DotNetFileWriter.Options() { Prefix = "GL", OutputPath = @"..\..\..\GLDotNet.GL\", Namespace = "GLDotNet.GL", ConstantsFileName = "GLConstants.Generated.cs", ConstantsClassName = "GLConstants", EnumsFileName = "GLEnums.Generated.cs", CommandsFileName = "GLCommands.Generated.cs", CommandsClassName = "GLCommands", ContextFileName = "GLContext.Generated.cs", ContextClassName = "GLContext", ContextInitializeDelegatesByVersionNumber = true }); }
private void TranslateEnumGroups(XmlSpecData spec, DotNetApiData api, Options options) { foreach (var specEnumGroup in spec.EnumGroups.Where(x => options.EnumGroupFilter(x.Name))) { var enumGroupData = new DotNetEnumGroupData() { Name = specEnumGroup.Name, }; foreach (var enumName in specEnumGroup.Enums.Distinct()) { var xmlEnumData = spec.Enums.SingleOrDefault(x => x.Name == enumName); if (xmlEnumData == null || !options.EnumFilter(xmlEnumData)) continue; var enumData = api.Enums.SingleOrDefault(x => x.OriginalName == enumName); if (enumData == null) continue; enumGroupData.Enums.Add(enumData); if (spec.Enums.Single(x => x.Name == enumName).Type == "bitmask") enumGroupData.IsFlags = true; } api.EnumGroups.Add(enumGroupData); } }
public DotNetApiData Translate(XmlSpecData spec, Options options) { DotNetApiData api = new DotNetApiData(); this.TranslateEnums(spec, api, options); this.TranslateEnumGroups(spec, api, options); this.TranslateFunctions(spec, api, options); return api; }
private void TranslateEnums(XmlSpecData spec, DotNetApiData api, Options options) { foreach (var specEnum in spec.Enums.Where(x => options.EnumFilter(x))) { var enumData = new DotNetEnumData() { OriginalName = specEnum.Name, Name = this.InflectEnumName(specEnum.Name, options), Value = specEnum.Value, Type = specEnum.Value.Length <= 6 ? "uint" : "ulong" }; if (enumData.Value.StartsWith("-")) enumData.Value = string.Format("unchecked((uint){0})", enumData.Value); api.Enums.Add(enumData); } }
private void ParseEnums(XDocument doc, XmlSpecData data, Options options) { foreach (var enumSetNode in doc.Root.Elements("enums")) { foreach (var enumNode in enumSetNode.Elements()) { XmlEnumData enumData = new XmlEnumData() { Group = enumSetNode.GetAttributeValue("group"), Type = enumSetNode.GetAttributeValue("type"), Vendor = enumSetNode.GetAttributeValue("vendor"), Value = enumNode.GetAttributeValue("value"), Name = enumNode.GetAttributeValue("name") }; if (enumData.Name != null && data.Enums.SingleOrDefault(x => x.Name == enumData.Name) == null) data.Enums.Add(enumData); } } }
private void ParseEnumGroups(XDocument doc, XmlSpecData data, Options options) { var groupsNode = doc.Root.Element("groups"); if (groupsNode == null) return; foreach (var enumGroupNode in groupsNode.Elements()) { XmlEnumGroupData enumGroupData = new XmlEnumGroupData() { Name = enumGroupNode.GetAttributeValue("name") }; foreach (var enumNode in enumGroupNode.Elements()) { enumGroupData.Enums.Add(enumNode.GetAttributeValue("name")); } data.EnumGroups.Add(enumGroupData); } }
public XmlSpecData Parse(string file, string overridesFile, Options options) { XmlSpecData data = new XmlSpecData(); XDocument doc = XDocument.Load(file); this.ParseEnumGroups(doc, data, options); this.ParseEnums(doc, data, options); this.ParseCommands(doc, data, options); this.ParseFeatures(doc, data, options); this.ParseExtensions(doc, data, options); if (overridesFile != null) { doc = XDocument.Load(overridesFile); this.ParseOverrides(doc, data); } data.EnumGroups.Sort((x, y) => x.Name != null && y.Name != null ? x.Name.CompareTo(y.Name) : 0); data.Enums.Sort((x, y) => x.Name != null && y.Name != null ? x.Name.CompareTo(y.Name) : 0); data.Commands.Sort((x, y) => x.Name != null && y.Name != null ? x.Name.CompareTo(y.Name) : 0); return data; }
private void TranslateFunctions(XmlSpecData spec, DotNetApiData api, Options options) { foreach (var specCommand in spec.Commands.Where(x => options.CommandFilter(x))) { var specFeature = spec.Features.Where(x => x.Commands.Contains(specCommand.Name)).FirstOrDefault(); var functionData = new DotNetFunctionData() { IsNative = true, OriginalName = specCommand.Name, NativeName = this.InflectFunctionNativeName(specCommand.Name, options), DotNetName = this.InflectFunctionDotNetName(specCommand.Name, options), OriginalReturnType = specCommand.ReturnType, NativeReturnType = this.InflectNativeReturnType(specCommand), DotNetReturnType = this.InflectDotNetReturnType(specCommand) }; if (specFeature != null) { functionData.VersionMajor = specFeature.VersionMajor; functionData.VersionMinor = specFeature.VersionMinor; functionData.CanPInvoke = specFeature.VersionMajor == 1 && specFeature.VersionMinor <= 1; } if (functionData.NativeReturnType == "string") functionData.IsUnsafe = true; foreach (var specCommandParam in specCommand.Params) { var functionParamData = new DotNetFunctionParamData() { OriginalName = specCommandParam.Name, Name = this.InflectFunctionParamName(specCommandParam.Name), OriginalType = specCommandParam.Type, NativeType = this.InflectFunctionParamNativeType(specCommandParam), DotNetType = this.InflectFunctionParamDotNetType(specCommandParam), IsPointer = this.IsTypePointer(specCommandParam.Type), IsOutput = this.IsTypeOutput(specCommandParam.Type), ShouldUseGenerics = this.ShouldUseGenericsForType(specCommandParam.Type), ShouldUseFixed = this.ShouldUseFixedForParam(specCommandParam), ShouldUseAddressOfOperator = this.ShouldUseAddressOfOperatorForParam(specCommandParam) }; if (functionParamData.IsPointer) functionData.IsUnsafe = true; if (functionParamData.ShouldUseGenerics) functionData.ShouldUseGenerics = true; if (functionParamData.IsOutput && functionParamData.DotNetType == "IntPtr") { functionParamData.ShouldUseOut = true; } functionData.Params.Add(functionParamData); } api.Functions.Add(functionData); // Create overload which accepts the Enum variant. if (specCommand.Params.Any(x => this.IsTypeEnum(x, api))) { api.Functions.Add(this.ChangeFunctionParamsToEnums(functionData, specCommand.Params.Where(x => this.IsTypeEnum(x, api)))); } } foreach (var functionData in api.Functions.ToArray()) { var specCommand = spec.Commands.Single(x => x.Name == functionData.OriginalName); // Commands which take a pointer and it could be a single element. if (specCommand.Params.Any(x => this.ShouldChangeFunctionParamToRefOrOut(x))) { api.Functions.Add(this.ChangeFunctionParamsToRefOrOut(functionData, specCommand.Params.Where(x => this.ShouldChangeFunctionParamToRefOrOut(x)).Select(x => x.Name))); } // Commands which take a pointer and it could be a single element. if (specCommand.Params.Any(x => this.ShouldChangeFunctionParamToIntPtr(x))) { api.Functions.Add(this.ChangeFunctionParamsToIntPtr(functionData, specCommand.Params.Where(x => this.ShouldChangeFunctionParamToIntPtr(x)).Select(x => x.Name))); } } api.Functions.Sort((x, y) => x.OriginalName != null && y.OriginalName != null ? x.OriginalName.CompareTo(y.OriginalName) : 0); }
private void ParseCommands(XDocument doc, XmlSpecData data, Options options) { foreach (var commandSetNode in doc.Root.Elements("commands")) { foreach (var commandNode in commandSetNode.Elements()) { XmlCommandData commandData = new XmlCommandData() { Name = this.EnsureCommandNameHasPrefix(commandNode.GetElementValue("proto", "name"), options), ReturnType = commandNode.GetElementValue("proto", "ptype"), ReturnTypeGroup = commandNode.GetElementAttributeValue("proto", "group"), Alias = commandNode.GetElementAttributeValue("alias", "name") }; if (commandData.ReturnType == null) commandData.ReturnType = commandNode.Element("proto").GetTexts().First().Trim(); // "void *" => "void*" if (commandData.ReturnType.EndsWith(" *")) commandData.ReturnType = commandData.ReturnType.Substring(0, commandData.ReturnType.Length - 2) + "*"; foreach (var commandParamNode in commandNode.Elements("param")) { XmlCommandParamData commandParamData = new XmlCommandParamData() { Name = commandParamNode.GetElementValue("name"), Type = commandParamNode.GetElementValue("ptype"), TypeGroup = commandParamNode.GetAttributeValue("group"), Length = commandParamNode.GetAttributeValue("len") }; if (commandParamData.Type == null) { commandParamData.Type = commandParamNode.GetTexts().First().Trim(); } else { var texts = commandParamNode.GetTexts(); if (texts.Count() == 1 && texts.First().Contains("*")) { commandParamData.Type = commandParamData.Type + new string('*', texts.First().Count(x => x == '*')); } else if ( texts.Count() == 2 && texts.First().Trim() == "const" && texts.Last().Contains("*")) { commandParamData.Type = "const " + commandParamData.Type + new string('*', texts.Last().Count(x => x == '*')); } } // "const void *" => "const void*" if (commandParamData.Type.EndsWith(" *")) commandParamData.Type = commandParamData.Type.Substring(0, commandParamData.Type.Length - 2) + "*"; commandData.Params.Add(commandParamData); } data.Commands.Add(commandData); } } }
private void ParseOverrides(XDocument doc, XmlSpecData data) { foreach (var groupNode in doc.Root.Element("groups").Elements()) { var enumGroup = data.EnumGroups.SingleOrDefault(x => x.Name == groupNode.GetAttributeValue("name")); if (enumGroup == null) { enumGroup = new XmlEnumGroupData() { Name = groupNode.GetAttributeValue("name") }; data.EnumGroups.Add(enumGroup); } if (groupNode.Element("enums") != null) { foreach (string @enum in groupNode.Element("enums").Value.Split(',').Select(x => x.Trim())) { if (!enumGroup.Enums.Contains(@enum)) { enumGroup.Enums.Add(@enum); } } } } foreach (var commandNode in doc.Root.Element("commands").Elements()) { var command = data.Commands.Single(x => x.Name == commandNode.GetAttributeValue("name")); foreach (var commandParamNode in commandNode.Elements("param")) { var param = command.Params.Single(x => x.Name == commandParamNode.GetAttributeValue("name")); string typeGroup = commandParamNode.GetAttributeValue("group"); if (typeGroup != null) param.TypeGroup = typeGroup; } } }
private void ParseExtensions(XDocument doc, XmlSpecData data, Options options) { foreach (var extensionNode in doc.Root.Element("extensions").Elements("extension")) { var extensionData = new XmlExtensionData() { Name = extensionNode.GetAttributeValue("name"), }; foreach (var enumNode in extensionNode.Descendants("require").Descendants("enum")) { extensionData.Enums.Add(enumNode.GetAttributeValue("name")); } foreach (var commandNode in extensionNode.Descendants("require").Descendants("command")) { extensionData.Commands.Add(commandNode.GetAttributeValue("name")); } data.Extensions.Add(extensionData); } }
private void ParseFeatures(XDocument doc, XmlSpecData data, Options options) { foreach (var featureNode in doc.Root.Elements("feature")) { string[] versionParts = featureNode.GetAttributeValue("number").Split('.'); int versionMajor = int.Parse(versionParts[0]); int versionMinor = int.Parse(versionParts[1]); var featureData = new XmlFeatureData() { Api = featureNode.GetAttributeValue("api"), Name = featureNode.GetAttributeValue("name"), VersionMajor = versionMajor, VersionMinor = versionMinor }; foreach (var requireNode in featureNode.Elements("require")) { foreach (var enumNode in requireNode.Elements("enum")) { featureData.AddedEnums.Add(enumNode.GetAttributeValue("name")); } foreach (var commandNode in requireNode.Elements("command")) { featureData.AddedCommands.Add(this.EnsureCommandNameHasPrefix(commandNode.GetAttributeValue("name"), options)); } } foreach (var removeNode in featureNode.Elements("remove")) { foreach (var enumNode in removeNode.Elements("enum")) { featureData.RemovedEnums.Add(enumNode.GetAttributeValue("name")); } foreach (var commandNode in removeNode.Elements("command")) { featureData.RemovedCommands.Add(this.EnsureCommandNameHasPrefix(commandNode.GetAttributeValue("name"), options)); } } data.Features.Add(featureData); } }
private static void WriteGLVersions(XmlSpecData glSpec, DotNetTranslator translator, DotNetFileWriter writer) { string basePath = Path.Combine("..", "..", "..", "GLDotNet.GL"); var baseProjectFile = XDocument.Load(Path.Combine(basePath, "GLDotNet.GL.csproj")); var projectXmlNamespace = baseProjectFile.Root.GetDefaultNamespace(); baseProjectFile.Root.Descendants(projectXmlNamespace + "Compile").First().Parent.Name = projectXmlNamespace + "CompileItemGroup"; baseProjectFile.Root.Descendants(projectXmlNamespace + "Compile").Remove(); var glVersions = glSpec.Features .Where(x => x.Api == "gl") .OrderBy(x => x.VersionMajor) .ThenBy(x => x.VersionMinor) .ToArray(); // Start at 1 because GL version 1.0 seems to not work correctly... for (int i = 1; i < glVersions.Length; i++) { var path = basePath + glVersions[i].VersionMajor + glVersions[i].VersionMinor; var ns = "GLDotNet.GL" + glVersions[i].VersionMajor + glVersions[i].VersionMinor; var projectGuid = CalculateProjectGuid(ns); Console.WriteLine($"{ns} {projectGuid}"); var glEnums = new List<string>(); var glCommands = new List<string>(); for (int j = 0; j <= i; j++) { glEnums.AddRange(glVersions[j].AddedEnums); glCommands.AddRange(glVersions[j].AddedCommands); glEnums.RemoveAll(x => glVersions[j].RemovedEnums.Contains(x)); glCommands.RemoveAll(x => glVersions[j].RemovedCommands.Contains(x)); } Directory.CreateDirectory(path); var glApi = translator.Translate(glSpec, new DotNetTranslator.Options() { Prefix = "gl", CommandFilter = x => glCommands.Contains(x.Name), EnumGroupFilter = ShouldOutputEnumGroup, EnumFilter = x => ShouldOutputEnum(x) && glEnums.Contains(x.Name), DocsFolder = glVersions[i].VersionMajor >= 2 ? Path.Combine("docs", "man" + glVersions[i].VersionMajor.ToString()) : null }); writer.WriteFiles(glApi, new DotNetFileWriter.Options() { Prefix = "GL", OutputPath = path, Namespace = ns, ConstantsFileName = "GLConstants.Generated.cs", ConstantsClassName = "GLConstants", EnumsFileName = "GLEnums.Generated.cs", CommandsFileName = "GLCommands.Generated.cs", CommandsClassName = "GLCommands", ContextFileName = "GLContext.Methods.Generated.cs", ContextClassName = "GLContext" }); var projectFile = new XDocument(baseProjectFile); projectFile.Root.Descendants(projectXmlNamespace + "ProjectGuid").Single().Value = "{" + projectGuid.ToString().ToUpper() + "}"; projectFile.Root.Descendants(projectXmlNamespace + "RootNamespace").Single().Value = ns; projectFile.Root.Descendants(projectXmlNamespace + "AssemblyName").Single().Value = ns; foreach (var documentationNode in projectFile.Root.Descendants(projectXmlNamespace + "DocumentationFile")) documentationNode.Value = documentationNode.Value.Replace("GLDotNet.GL", ns); var compileItemGroup = projectFile.Root.Descendants(projectXmlNamespace + "CompileItemGroup").Single(); foreach (var file in Directory.EnumerateFiles(path, "*.cs").Select(x => Path.GetFileName(x))) { compileItemGroup.Add(new XElement(projectXmlNamespace + "Compile", new XAttribute("Include", file))); } compileItemGroup.Add(new XElement(projectXmlNamespace + "Compile", new XAttribute("Include", @"Properties\AssemblyInfo.cs"))); compileItemGroup.Name = projectXmlNamespace + "ItemGroup"; File.WriteAllText(Path.Combine(path, ns + ".csproj"), "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + Environment.NewLine + projectFile.ToString()); Directory.CreateDirectory(Path.Combine(path, "Properties")); TemplateEngine.Run("AssemblyVersion", Path.Combine(path, "Properties", "AssemblyVersion.cs"), new Dictionary<string, string>() { ["Namespace"] = ns, ["ProjectGuid"] = projectGuid.ToString() }); TemplateEngine.Run("GLContext", Path.Combine(path, "GLContext.Generated.cs"), new Dictionary<string, string>() { ["Namespace"] = ns }); } }