public static async Task Main() { var projectPath = Path.GetFullPath(Path.Combine("..", "..", "..")); var externalsPath = Path.Combine(projectPath, "externals"); var bindingsProjectPath = Path.GetFullPath(Path.Combine(projectPath, "..", "..", "CoreLoader.OpenGL")); var gl4Docs = Path.Combine(projectPath, "OpenGL-Refpages", "gl4"); var constRegex = new Regex(@"^#define (GL_\S+)\s+((0x)?[0-9a-fA-F]+)$"); var nativeConstants = (await File.ReadAllLinesAsync(Path.Combine(externalsPath, "glcorearb.h"))) .Where(line => line.StartsWith("#define GL_")) .Select(line => constRegex.Match(line)) .Where(match => match.Success) .ToDictionary(match => match.Groups[1].Value, match => Convert.ToUInt32(match.Groups[2].Value, match.Groups[3].Success ? 16 : 10)); CodeAnalyzer codeAnalyzer; using (var glFileStream = File.Open(Path.Combine(bindingsProjectPath, "GL.cs"), FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var glFileReader = new StreamReader(glFileStream)) { codeAnalyzer = new CodeAnalyzer(await glFileReader.ReadToEndAsync()); } CodeAnalyzer nativeCodeAnalyzer; using (var nativeGlFileStream = File.Open(Path.Combine(bindingsProjectPath, "GlNative.cs"), FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var nativeGlFileReader = new StreamReader(nativeGlFileStream)) { nativeCodeAnalyzer = new CodeAnalyzer(await nativeGlFileReader.ReadToEndAsync()); } var codeUnit = new BindingCodeUnit(); var enumGenerator = new EnumGenerator(codeUnit, nativeConstants); GenerateConstClass(codeUnit, nativeConstants); //currently only migrating gl* foreach (var file in Directory.EnumerateFiles(gl4Docs, "gl*.xml")) { if (file.StartsWith("gl_")) { continue; } try { var generator = new BindingCodeGenerator(file); await generator.GenerateCodeAsync(codeUnit, codeAnalyzer, nativeCodeAnalyzer, enumGenerator); } catch (Exception e) { Console.WriteLine($"Failed to generate code for {Path.GetFileName(file)}: " + e); } } codeUnit.GenerateClasses(bindingsProjectPath); }
private void GenerateFunction(BindingCodeUnit codeUnit, CodeAnalyzer codeAnalyzer, CodeAnalyzer nativeCodeAnalyzer, EnumGenerator enumGenerator, XElement funcElement) { var funcDef = funcElement.Descendants(_rootNamespace + "funcdef").First(); var functionName = funcDef.Descendants(_rootNamespace + "function").First().Value; if (functionName.StartsWith("gl")) { functionName = functionName.Substring(2); } var returnType = TypeHelper.GetType(funcDef.Value, out var enumType); //var returnTypeReference = enumType == EnumType.None ? TypeHelper.GetReturnType(returnType) : enumGenerator.CreateEnum(functionName, "return", enumType, null); //todo get enum definition var returnTypeReference = TypeHelper.GetReturnType(returnType); var delegateName = functionName + "Func"; var delegateType = new CodeTypeDelegate(delegateName) { ReturnType = returnTypeReference }; var args = XElementToParams(funcElement); if (!nativeCodeAnalyzer.HasField(functionName)) { var parameters = args.Select(param => TypeHelper.GetParameterType(param.Type, param.TypeName, param.Name)).ToArray(); delegateType.Parameters.AddRange(parameters); codeUnit.NativeGeneratedClass.Members.Add(delegateType); var field = new CodeMemberField(new CodeTypeReference(delegateName), functionName) { Attributes = MemberAttributes.Public | MemberAttributes.Static }; codeUnit.NativeGeneratedClass.Members.Add(field); } if (!codeAnalyzer.HasCallTo($"{BindingCodeUnit.NativeClassName}.{functionName}")) { var method = new CodeMemberMethod { Name = functionName, ReturnType = returnTypeReference, Attributes = MemberAttributes.Public | MemberAttributes.Static }; method.Parameters.AddRange(args.Select(param => { List <string> enumFieldNames = null; if (param.EnumType != EnumType.None) { enumFieldNames = GetEnumFieldNames(param.Name); } if (enumFieldNames == null || enumFieldNames.Count == 0) { param.EnumType = EnumType.None; return(TypeHelper.GetParameterType(param.Type, param.TypeName, param.Name)); } return(new CodeParameterDeclarationExpression(enumGenerator.CreateEnum(functionName, param.Name, param.EnumType, enumFieldNames), param.Name)); }).ToArray()); //adds [MethodImpl(MethodImplOptions.AggressiveInlining)] method.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(nameof(MethodImplAttribute)), new CodeAttributeArgument(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(nameof(MethodImplOptions)), nameof(MethodImplOptions.AggressiveInlining))))); var argCalls = args.Select(param => { CodeExpression argExpression = new CodeArgumentReferenceExpression(param.Name); if (param.EnumType != EnumType.None) { return(new CodeCastExpression(typeof(uint), argExpression)); } if (param.Type?.IsByRef == true) { argExpression = new CodeDirectionExpression(FieldDirection.Ref, argExpression); } return(argExpression); }).ToArray(); var callStatement = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(BindingCodeUnit.NativeClassName), functionName, argCalls); if (returnType != typeof(void)) { method.Statements.Add(new CodeMethodReturnStatement(callStatement)); } else { method.Statements.Add(callStatement); } codeUnit.ApiGeneratedClass.Members.Add(method); } }
public async Task GenerateCodeAsync(BindingCodeUnit codeUnit, CodeAnalyzer codeAnalyzer, CodeAnalyzer nativeCodeAnalyzer, EnumGenerator enumGenerator) { using (var fileStream = File.Open(_xmlFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new StreamReader(fileStream, Encoding.UTF8)) { var content = await reader.ReadToEndAsync(); content = EntityRegex.Replace(content, ""); content = content.Replace("xlink:href", "href"); _xDocument = XDocument.Parse(content); _rootNamespace = _xDocument.Root.GetDefaultNamespace(); foreach (var func in _xDocument.Descendants(_rootNamespace + "funcprototype")) { GenerateFunction(codeUnit, codeAnalyzer, nativeCodeAnalyzer, enumGenerator, func); } } }