// Takes in SyntaxData and creates a .cs binding file static void GenerateBinding(SyntaxData syntax, string fileName) { // local references var ExportTag = syntax.tag; var comments = syntax.comments; var functions = syntax.functions; var enums = syntax.enums; var Funcs = syntax.funcs; var types = syntax.types; var tps = syntax.tps; var eps = syntax.eps; // ---------------------------------------------------------------------------- // Begin generating bindings here using SyntaxTree // ---------------------------------------------------------------------------- var codetree = CompilationUnit().AddUsings(UsingDirective(ParseName("System"))) .AddUsings(UsingDirective(ParseName("System.IO"))) .AddUsings(UsingDirective(ParseName("System.Collections.Generic"))) .AddUsings(UsingDirective(ParseName("System.Security"))) .AddUsings(UsingDirective(ParseName("System.Runtime.InteropServices"))); var Raylibnamespace = NamespaceDeclaration(ParseName("Raylib")).NormalizeWhitespace(); foreach (var Enumtype in eps.Values) { var Enum = EnumDeclaration(Enumtype.Name).WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); foreach (var Member in Enumtype.Enums) { var enummember = EnumMemberDeclaration( Identifier(Member.Key)) .WithEqualsValue( EqualsValueClause( LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(Member.Value)))); Enum = Enum.AddMembers(enummember); } Raylibnamespace = Raylibnamespace.AddMembers(Enum); } foreach (var Type in tps.Values) { var Struct = StructDeclaration(Type.Name).WithAttributeLists( SingletonList( AttributeList( SingletonSeparatedList( Attribute( IdentifierName("StructLayout")) .WithArgumentList( AttributeArgumentList( SeparatedList <AttributeArgumentSyntax>( new SyntaxNodeOrToken[] { AttributeArgument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("LayoutKind"), IdentifierName("Sequential"))), Token(SyntaxKind.CommaToken), AttributeArgument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("CharSet"), IdentifierName("Ansi"))) .WithNameEquals( NameEquals( IdentifierName("CharSet"))) }))))))) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))); bool IsUnsafe = false; var FixedStructTypes = new List <string>(); foreach (var Member in Type.Members) { var IsStruct = false; var TypeName = (Member.Type.IsPointer ? "IntPtr" : Member.Type.Name).Trim(); if (TypeName.Contains("struct")) { IsStruct = true; TypeName = TypeName.Substring(TypeName.LastIndexOf("struct") + "struct".Length); } if (TypeName.Contains("enum")) { TypeName = TypeName.Substring(TypeName.LastIndexOf("enum") + "enum".Length); } if (TypeName.Contains("unsigned int")) { TypeName = TypeName.Replace("unsigned int", "uint"); } if (TypeName.Contains("unsigned char")) { TypeName = TypeName.Replace("unsigned char", "byte"); } var IsFixed = false; var VariableDec = VariableDeclarator(Member.Name); if (TypeName.Contains("[")) { int arraycount = int.Parse(TypeName.Split('[', ']')[1].Substring("0x".Length), System.Globalization.NumberStyles.HexNumber); TypeName = TypeName.Split('[', ']')[0].Trim(); if (IsStruct) { if (!FixedStructTypes.Contains($"_{TypeName}_e_FixedBuffer_{arraycount}")) { FixedStructTypes.Add($"_{TypeName}_e_FixedBuffer_{arraycount}"); var FixedBufferStruct = StructDeclaration($"_{TypeName}_e_FixedBuffer_{arraycount}") .WithModifiers( TokenList( new[] { Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.UnsafeKeyword) })); for (int i = 0; i < arraycount; i++) { FixedBufferStruct = FixedBufferStruct.AddMembers( FieldDeclaration( VariableDeclaration( IdentifierName(TypeName)) .WithVariables( SingletonSeparatedList <VariableDeclaratorSyntax>( VariableDeclarator( Identifier($"{Member.Name}{i}"))))) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword)))); } FixedBufferStruct = FixedBufferStruct.AddMembers(IndexerDeclaration( RefType( IdentifierName(TypeName))) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))) .WithParameterList( BracketedParameterList( SingletonSeparatedList <ParameterSyntax>( Parameter( Identifier("index")) .WithType( PredefinedType( Token(SyntaxKind.IntKeyword)))))) .WithAccessorList( AccessorList( SingletonList <AccessorDeclarationSyntax>( AccessorDeclaration( SyntaxKind.GetAccessorDeclaration) .WithBody( Block( SingletonList <StatementSyntax>( FixedStatement( VariableDeclaration( PointerType( IdentifierName(TypeName))) .WithVariables( SingletonSeparatedList <VariableDeclaratorSyntax>( VariableDeclarator( Identifier("e")) .WithInitializer( EqualsValueClause( PrefixUnaryExpression( SyntaxKind.AddressOfExpression, IdentifierName($"{Member.Name}0")))))), ReturnStatement( RefExpression( ElementAccessExpression( IdentifierName("e")) .WithArgumentList( BracketedArgumentList( SingletonSeparatedList <ArgumentSyntax>( Argument( IdentifierName("index"))))))))))))))); Raylibnamespace = Raylibnamespace.AddMembers(FixedBufferStruct); } TypeName = $"_{TypeName}_e_FixedBuffer_{arraycount}"; } else { VariableDec = VariableDec.WithArgumentList( BracketedArgumentList( SingletonSeparatedList <ArgumentSyntax>( Argument( LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(arraycount)))))); IsFixed = true; IsUnsafe = true; } } var variable = VariableDeclaration(ParseTypeName(TypeName)).AddVariables(VariableDec); var field = FieldDeclaration(variable).AddModifiers(Token(SyntaxKind.PublicKeyword)); if (IsFixed) { field = field.AddModifiers(Token(SyntaxKind.FixedKeyword)); } Struct = Struct.AddMembers(field); } if (IsUnsafe) { Struct = Struct.AddModifiers(Token(SyntaxKind.UnsafeKeyword)); } Raylibnamespace = Raylibnamespace.AddMembers(Struct); } { var RaylibClass = ClassDeclaration(fileName) .WithAttributeLists( SingletonList <AttributeListSyntax>( AttributeList( SingletonSeparatedList <AttributeSyntax>( Attribute( IdentifierName("SuppressUnmanagedCodeSecurity")))))) .WithModifiers( TokenList( new[] { Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.PartialKeyword) })); var LibraryNameField = FieldDeclaration( VariableDeclaration( PredefinedType( Token(SyntaxKind.StringKeyword))) .WithVariables( SingletonSeparatedList <VariableDeclaratorSyntax>( VariableDeclarator( Identifier("nativeLibName")) .WithInitializer( EqualsValueClause( LiteralExpression( SyntaxKind.StringLiteralExpression, Literal("raylib"))))))) .WithModifiers( TokenList( new[] { Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.ConstKeyword) })); RaylibClass = RaylibClass.AddMembers(LibraryNameField); foreach (var Func in Funcs) { var typename = Func.ReturnType.IsPointer ? "IntPtr" : Func.ReturnType.Name; var Function = MethodDeclaration(ParseTypeName(typename), Identifier(Func.Name)) .WithAttributeLists( SingletonList( AttributeList( SingletonSeparatedList( Attribute( IdentifierName("DllImport")) .WithArgumentList( AttributeArgumentList( SeparatedList <AttributeArgumentSyntax>( new SyntaxNodeOrToken[] { AttributeArgument( IdentifierName("nativeLibName")), Token(SyntaxKind.CommaToken), AttributeArgument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("CallingConvention"), IdentifierName("Cdecl"))) .WithNameEquals( NameEquals( IdentifierName("CallingConvention"))) }))))))) .WithModifiers( TokenList( new[] { Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.ExternKeyword) })).WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); for (int i = 0; i < Func.Params.Count; i++) { var Param = Func.Params[i]; var TypeName = (Param.Type.IsPointer ? "IntPtr" : Param.Type.Name).Trim(); if (TypeName.Contains("unsigned int")) { TypeName = TypeName.Replace("unsigned int", "uint"); } if (TypeName.Contains("...")) { TypeName = "params object[]"; Param.Name = "args"; } if (TypeName.Contains("unsigned char")) { TypeName = TypeName.Replace("unsigned char", "byte"); } if (TypeName.Contains("struct")) { TypeName = TypeName.Substring(TypeName.LastIndexOf("struct") + "struct".Length); } Function = Function.AddParameterListParameters( Parameter( Identifier(Param.Name)) .WithType( IdentifierName(TypeName))); } RaylibClass = RaylibClass.AddMembers(Function); } Raylibnamespace = Raylibnamespace.AddMembers(RaylibClass); } codetree = codetree.AddMembers(Raylibnamespace); Console.WriteLine(codetree.NormalizeWhitespace().ToFullString()); File.WriteAllText($"{fileName}.cs", codetree.NormalizeWhitespace().ToFullString()); Console.WriteLine("Finished generating bindings for file "); Console.ReadLine(); /* Raylib-cs * Raylib.cs - Core bindings to raylib * Copyright 2019 Chris Dill * * Release under zLib License. * See LICENSE for details. */ }
// Takes the source from a raylib module and stores the syntax data static SyntaxData GetSyntax(string[] sourcefile, string tag, Dictionary <string, string> TypeMap, string[] typesfile) { var syntax = new SyntaxData(tag); // local references var ExportTag = syntax.tag; var comments = syntax.comments; var functions = syntax.functions; var enums = syntax.enums; var Funcs = syntax.funcs; var types = syntax.types; var tps = syntax.tps; var eps = syntax.eps; for (int i = 0; i < sourcefile.Length; i++) { var source = sourcefile[i].Split("//".ToCharArray())[0].Trim(); // Comments test if (source.StartsWith("*") || source.StartsWith("//")) { comments.Add(source); } if (source.Contains(ExportTag)) { if (!source.Contains("#define")) { source = source.TrimStart(ExportTag.ToCharArray()).Trim(); if (!source.Contains("{")) { // Some functions go across multiple lines if (source[source.Length - 1] == ',') { i++; var nextLine = sourcefile[i].Split("//".ToCharArray())[0].Trim(); source += " " + nextLine; } functions.Add(source); } } } if (source.Contains("typedef")) { if (source.Split(' ')[1].Trim() == "struct") { if (source.Contains('}')) { types.Add(source.Split('}', ';')[1].Trim()); } else { int t = 1; var src = sourcefile[i + t]; while (!src.Contains('}')) { src = sourcefile[i + t]; t++; } types.Add(src.Trim('}', ';').Trim()); } } } } // Break down function string for (int i = 0; i < functions.Count; i++) { var func = functions[i]; var returntype = func.Split('(')[0].Split(' ').Length == 3 ? func.Split('(')[0].Split(' ')[0] + " " + func.Split('(')[0].Split(' ')[1] : func.Split('(')[0].Split(' ')[0]; types.Add(returntype); func = func.Substring(returntype.Length).Trim(); //@TODO extra comma in param list var funcname = func.Split('(')[0].Trim(); var Func = new Function(funcname, returntype); if (func.Contains(',')) { var Params = func.Split('(', ')')[1].Split(','); for (int t = 0; t < Params.Length; t++) { var Param = Params[t]; Param = Param.Trim(); if (Param == "...") { Func.Params.Add(new FunctionParam(Param, new Type("...", false))); } else { var TypeAndVar = Param.Trim().Split(' '); if (TypeAndVar.Length == 2) { var type = TypeAndVar[0]; var Var = TypeAndVar[1]; types.Add(type); } else if (TypeAndVar.Length == 3) { var type = TypeAndVar[0] + " " + TypeAndVar[1]; var Var = TypeAndVar[2]; types.Add(type); } Func.Params.Add(new FunctionParam(Param)); } } } else if (func.Contains(' ')) { var Param = func.Split('(', ')')[1]; var TypeAndVar = Param.Trim().Split(' '); var type = TypeAndVar[0]; var Var = TypeAndVar[1]; types.Add(type); Func.Params.Add(new FunctionParam(Param)); } Funcs.Add(Func); } for (int i = 0; i < sourcefile.Length; i++) { var source = sourcefile[i].Split("//".ToCharArray())[0].Trim(); if (source.Contains("typedef")) { if (source.Split(' ')[1].Trim() != "struct") { if (source.Split(' ')[1].Trim() == "enum") { if (source.Contains('}')) { enums.Add(source.Split('}', ';')[1].Trim()); } else { int t = 1; var src = sourcefile[i + t]; while (!src.Contains('}')) { src = sourcefile[i + t]; t++; } enums.Add(src.Trim('}', ';').Trim()); } } else { TypeMap.Add(source.Split(" ".ToCharArray(), 3)[2].Trim(';').Trim(), source.Split(" ".ToCharArray(), 3)[1].Trim()); } } else { } } else if (source.Contains("#define") && source.Split(' ').Length > 2 && source.Split(' ')[1] != (ExportTag)) { if (types.Contains(source.Split(" ".ToCharArray(), 3)[1].Trim(';').Trim())) { TypeMap.Add(source.Split(" ".ToCharArray(), 3)[1].Trim(';').Trim(), source.Split(" ".ToCharArray(), 3)[2].Trim()); } } } for (int i = 0; i < Funcs.Count; i++) { var Func = Funcs[i]; if (TypeMap.ContainsKey(Func.ReturnType.Name)) { Func.ReturnType.Name = TypeMap[Func.ReturnType.Name]; } for (int t = 0; t < Func.Params.Count; t++) { if (TypeMap.ContainsKey(Func.Params[t].Type.Name)) { Func.Params[t] = new FunctionParam(Func.Params[t].Name, new Type(TypeMap[Func.Params[t].Type.Name], Func.Params[t].Type.IsPointer)); } } Funcs[i] = Func; } for (int i = 0; i < typesfile.Length; i++) { var typestr = typesfile[i]; if (typestr.Contains("UserDefinedType: ") && !typestr.Contains("UserDefinedType: ")) { var type = typestr.Substring("UserDefinedType: ".Length).Trim(); if (types.Contains(type) && type[0] != ' ' && !tps.Any(x => x.Key == type)) { var usertype = new UserDefinedTypeData(type); int t = 1; typestr = typesfile[i + t]; while (!(typestr.Contains("UserDefinedType: ") && typestr["UserDefinedType: ".Length - 1] == ' ')) { if (typestr.Contains("Member")) { var tpsrc = typesfile[i + t]; var MemberNameandType = tpsrc.Substring(tpsrc.IndexOf("Type:") + "Type:".Length).Trim().Split(','); var MemberName = MemberNameandType[1].Trim(); var MemberType = MemberNameandType[0].Trim(); if (MemberType.Contains("<unnamed-enum-false>")) { MemberType = "bool"; } var isptr = MemberType[MemberType.Length - 1] == '*'; var offset = int.Parse(tpsrc.Split(',')[0].Split(':')[1].Trim().Substring("this+0x".Length), System.Globalization.NumberStyles.HexNumber); if (isptr) { MemberType = MemberType.Remove(MemberType.Length - 1); } usertype.Members.Add(new TypeMember(MemberName, new Type(MemberType, isptr), offset)); if (typesfile[i + t + 1].Contains(MemberType.Trim("struct".ToCharArray())) && typesfile[i + t + 1].Contains("UserDefinedType: ")) { t++; } } t++; typestr = typesfile[i + t]; } tps.Add(usertype.Name, usertype); } } if (typestr.Contains("Enum : ")) { var Enum = typestr.Substring("Enum : ".Length).Split(',')[0].Trim(); if (enums.Contains(Enum) && Enum != "bool") { var UserDefineEnum = new UserDefinedEnumData(Enum); int t = 1; typestr = typesfile[i + t]; while (typestr.Contains("Constant")) { var intstr = typestr.Split(",".ToCharArray(), 2)[0].Split(':')[1].Split(' ')[4].Substring("0x".Length).Trim(); int Int = int.Parse(intstr, System.Globalization.NumberStyles.HexNumber); var name = typestr.Split(",".ToCharArray(), 4)[3].Trim(); UserDefineEnum.Enums.Add(new KeyValuePair <string, int>(name, Int)); t++; typestr = typesfile[i + t]; } eps.Add(Enum, UserDefineEnum); } } } types.IntersectWith(tps.Select(x => x.Key)); return(syntax); }