Beispiel #1
0
        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);
                    }
                }
        }