New parser, no code skimming

This commit is contained in:
Garry Newman 2020-02-12 14:55:36 +00:00
parent 1436ce71f5
commit 9a36dd58ff
9 changed files with 93 additions and 260 deletions

View File

@ -1,153 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Generator
{
public partial class CodeParser
{
public string Content;
public CodeParser( string folder )
{
foreach ( var file in System.IO.Directory.GetFiles( folder, "*.h", System.IO.SearchOption.AllDirectories ) )
{
Content += System.IO.File.ReadAllText( file );
}
Content = Content.Replace( "\r\n", "\n" );
Content = Content.Replace( "\n\r", "\n" );
}
internal void ExtendDefinition( SteamApiDefinition def )
{
//
// Get a list of CallbackIds
//
def.CallbackIds = new Dictionary<string, int>();
//v1
{
var r = new Regex( @"enum { (k_[i|I](?:.+)) = ([0-9]+) };" );
var ma = r.Matches( Content );
foreach ( Match m in ma )
{
def.CallbackIds.Add( m.Groups[1].Value.Substring( 3 ).Replace( "Callbacks", "" ), int.Parse( m.Groups[2].Value ) );
}
}
//
// Associate callbackIds with structs
//
foreach ( var t in def.structs )
{
if ( !string.IsNullOrEmpty( t.CallbackId ) ) continue;
// Standard style
{
var r = new Regex( @"struct "+t.Name+@"\n{ ?\n(?:.)+enum { k_iCallback = (?:(.+) \+ ([0-9]+)|(.+)) };", RegexOptions.Multiline | RegexOptions.IgnoreCase );
var m = r.Match( Content );
if ( m.Success )
{
var kName = m.Groups[1].Value;
var num = m.Groups[2].Value;
if ( string.IsNullOrEmpty( kName ) )
{
kName = m.Groups[3].Value;
num = "0";
}
kName = "CallbackIdentifiers." + kName.Substring( 3 ).Replace( "Callbacks", "" );
t.CallbackId = $"{kName} + {num}";
}
}
// New style
{
var r = new Regex( @"DEFINE_CALLBACK\( "+t.Name+@", (.+) \+ ([0-9]+) \)" );
var m = r.Match( Content );
if ( m.Success )
{
var kName = m.Groups[1].Value;
var num = m.Groups[2].Value;
//kName = kName.Replace( "k_i", "CallbackIdentifiers." ).Replace( "Callbacks", "" );
kName = "CallbackIdentifiers." + kName.Substring( 3 ).Replace( "Callbacks", "" );
t.CallbackId = $"{kName} + {num}";
}
}
// Even Newer Style
{
var r = new Regex( @"STEAM_CALLBACK_BEGIN\( " + t.Name + @", (.+) \+ ([0-9]+) \)" );
var m = r.Match( Content );
if ( m.Success )
{
var kName = m.Groups[1].Value;
var num = m.Groups[2].Value;
//kName = kName.Replace( "k_i", "CallbackIdentifiers." ).Replace( "Callbacks", "" );
kName = "CallbackIdentifiers." + kName.Substring( 3 ).Replace( "Callbacks", "" );
t.CallbackId = $"{kName} + {num}";
}
}
}
//
// Find defines
//
def.Defines = new Dictionary<string, string>();
{
var r = new Regex( @"#define ([a-zA-Z_]+) ""(.+)""" );
var ma = r.Matches( Content );
foreach ( Match m in ma )
{
def.Defines.Add( m.Groups[1].Value.Replace( "Callbacks", "" ), m.Groups[2].Value );
}
}
//
// Find missing structs
//
{
var r = new Regex( @"struct ([a-zA-Z]+_t)" );
var ma = r.Matches( Content );
foreach ( Match m in ma )
{
var s = def.structs.SingleOrDefault( x => x.Name == m.Groups[1].Value );
if ( s == null )
{
Console.WriteLine( "Missing Struct: " + m.Groups[1].Value );
}
}
//Console.ReadKey();
}
//
// Change all struct bool fields to bytes (they're technically bytes anyway, and it helps with marshalling)
//
{
foreach ( var s in def.structs )
{
foreach ( var f in s.Fields )
{
if ( f.Type == "bool" )
f.Type = "byte";
}
}
}
}
}
}

View File

@ -8,7 +8,7 @@ namespace Generator
{
public partial class CodeWriter
{
public void GenerateVTableClass( string className, string filename )
public void GenerateVTableClass( SteamApiDefinition.Interface iface, string folder )
{
sb = new StringBuilder();
@ -23,26 +23,24 @@ namespace Generator
StartBlock( $"namespace Steamworks" );
{
StartBlock( $"internal class {className} : SteamInterface" );
StartBlock( $"internal class {iface.Name} : SteamInterface" );
{
WriteLine( $"public override IntPtr GetInterfacePointer() => GetApi.{className.Substring( 1 )}();" );
WriteLine( $"public override IntPtr GetInterfacePointer() => GetApi.{iface.Name.Substring( 1 )}();" );
WriteLine();
WriteLine();
StartBlock( $"internal {className}()" );
StartBlock( $"internal {iface.Name}()" );
{
WriteLine( $"SetupInterface();" );
}
EndBlock();
WriteLine();
var functions = def.methods.Where( x => x.ClassName == className );
foreach ( var func in functions )
foreach ( var func in iface.Methods )
{
if ( Cleanup.IsDeprecated( $"{func.ClassName}.{func.Name}" ) )
if ( Cleanup.IsDeprecated( $"{iface.Name}.{func.Name}" ) )
continue;
WriteFunction( func );
WriteFunction( iface, func );
WriteLine();
}
@ -51,19 +49,19 @@ namespace Generator
}
EndBlock();
System.IO.File.WriteAllText( $"{filename}", sb.ToString() );
System.IO.File.WriteAllText( $"{folder}{iface.Name}.cs", sb.ToString() );
}
private void WriteFunction( SteamApiDefinition.MethodDef func )
private void WriteFunction( SteamApiDefinition.Interface iface, SteamApiDefinition.Interface.Method func )
{
var returnType = BaseType.Parse( func.ReturnType, null, func.CallResult );
var returnType = BaseType.Parse( func.ReturnType, null );
returnType.Func = func.Name;
if ( func.Params == null )
func.Params = new SteamApiDefinition.MethodDef.ParamType[0];
func.Params = new SteamApiDefinition.Interface.Method.Param[0];
var args = func.Params.Select( x =>
{
var bt = BaseType.Parse( x.Type, x.Name );
var bt = BaseType.Parse( x.ParamType, x.ParamName );
bt.Func = func.Name;
return bt;
} ).ToArray();
@ -89,16 +87,16 @@ namespace Generator
var argstr = string.Join( ", ", args.Where( x => !x.ShouldSkipAsArgument ).Select( x => x.AsArgument() ) ); ;
var delegateargstr = string.Join( ", ", args.Select( x => x.AsNativeArgument() ) );
if ( returnType is SteamApiCallType sap )
{
sap.CallResult = func.CallResult;
//if ( returnType is SteamApiCallType sap )
// {
// sap.CallResult = func.CallResult;
argstr = string.Join( ", ", args.Select( x => x.AsArgument().Replace( "ref ", " /* ref */ " ) ) );
}
// argstr = string.Join( ", ", args.Select( x => x.AsArgument().Replace( "ref ", " /* ref */ " ) ) );
// }
WriteLine( $"#region FunctionMeta" );
WriteLine( $"[DllImport( Platform.LibraryName, EntryPoint = \"SteamAPI_{func.ClassName}_{func.Name}\")]" );
WriteLine( $"[DllImport( Platform.LibraryName, EntryPoint = \"{func.FlatName}\")]" );
if ( returnType.ReturnAttribute != null )
WriteLine( returnType.ReturnAttribute );

View File

@ -11,12 +11,9 @@ namespace Generator
public partial class CodeWriter
{
private SteamApiDefinition def;
public CodeParser Parser;
public CodeWriter( CodeParser parser, SteamApiDefinition def )
public CodeWriter( SteamApiDefinition def )
{
Parser = parser;
this.def = def;
WorkoutTypes();
}
@ -56,34 +53,15 @@ namespace Generator
}
{
GenerateGlobalFunctions( "SteamAPI", $"{folder}../Generated/SteamAPI.cs" );
GenerateGlobalFunctions( "SteamGameServer", $"{folder}../Generated/SteamGameServer.cs" );
GenerateGlobalFunctions( "SteamInternal", $"{folder}../Generated/SteamInternal.cs" );
// GenerateGlobalFunctions( "SteamAPI", $"{folder}../Generated/SteamAPI.cs" );
// GenerateGlobalFunctions( "SteamGameServer", $"{folder}../Generated/SteamGameServer.cs" );
// GenerateGlobalFunctions( "SteamInternal", $"{folder}../Generated/SteamInternal.cs" );
}
{
GenerateVTableClass( "ISteamApps", $"{folder}../Generated/Interfaces/ISteamApps.cs" );
GenerateVTableClass( "ISteamUtils", $"{folder}../Generated/Interfaces/ISteamUtils.cs" );
GenerateVTableClass( "ISteamParentalSettings", $"{folder}../Generated/Interfaces/ISteamParentalSettings.cs" );
GenerateVTableClass( "ISteamMusic", $"{folder}../Generated/Interfaces/ISteamMusic.cs" );
GenerateVTableClass( "ISteamVideo", $"{folder}../Generated/Interfaces/ISteamVideo.cs" );
GenerateVTableClass( "ISteamUser", $"{folder}../Generated/Interfaces/ISteamUser.cs" );
GenerateVTableClass( "ISteamMatchmakingServers", $"{folder}../Generated/Interfaces/ISteamMatchmakingServers.cs" );
GenerateVTableClass( "ISteamFriends", $"{folder}../Generated/Interfaces/ISteamFriends.cs" );
GenerateVTableClass( "ISteamGameServer", $"{folder}../Generated/Interfaces/ISteamGameServer.cs" );
GenerateVTableClass( "ISteamScreenshots", $"{folder}../Generated/Interfaces/ISteamScreenshots.cs" );
GenerateVTableClass( "ISteamUserStats", $"{folder}../Generated/Interfaces/ISteamUserStats.cs" );
GenerateVTableClass( "ISteamUGC", $"{folder}../Generated/Interfaces/ISteamUGC.cs" );
GenerateVTableClass( "ISteamRemoteStorage", $"{folder}../Generated/Interfaces/ISteamRemoteStorage.cs" );
GenerateVTableClass( "ISteamInventory", $"{folder}../Generated/Interfaces/ISteamInventory.cs" );
GenerateVTableClass( "ISteamNetworking", $"{folder}../Generated/Interfaces/ISteamNetworking.cs" );
GenerateVTableClass( "ISteamMatchmaking", $"{folder}../Generated/Interfaces/ISteamMatchmaking.cs" );
GenerateVTableClass( "ISteamParties", $"{folder}../Generated/Interfaces/ISteamParties.cs" );
GenerateVTableClass( "ISteamNetworkingUtils", $"{folder}../Generated/Interfaces/ISteamNetworkingUtils.cs" );
GenerateVTableClass( "ISteamNetworkingSockets", $"{folder}../Generated/Interfaces/ISteamNetworkingSockets.cs" );
GenerateVTableClass( "ISteamGameServerStats", $"{folder}../Generated/Interfaces/ISteamGameServerStats.cs" );
GenerateVTableClass( "ISteamInput", $"{folder}../Generated/Interfaces/ISteamInput.cs" );
}
foreach ( var iface in def.Interfaces )
{
GenerateVTableClass( iface, $"{folder}../Generated/Interfaces/" );
}
}
void WorkoutTypes()

View File

@ -10,6 +10,7 @@ namespace Generator
{
private void Constants()
{
/*
StartBlock( "internal static class CallbackIdentifiers" );
foreach ( var o in def.CallbackIds )
{
@ -23,6 +24,7 @@ namespace Generator
WriteLine( $"internal const string {o.Key} = \"{o.Value}\";" );
}
EndBlock();
*/
}
}
}

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
namespace Generator
{
/*
public partial class CodeWriter
{
public void GenerateGlobalFunctions( string startingWith, string filename )
@ -124,5 +125,8 @@ namespace Generator
WriteLine( $"public static extern {(returnType.IsReturnedWeird ? "void" : returnType.TypeNameFrom)} {func.Name}( {delegateargstr} );" );
WriteLine();
}
}
*/
}

View File

@ -40,7 +40,7 @@ namespace Generator
{
var callbackList = new List<SteamApiDefinition.StructDef>();
foreach ( var c in def.structs )
foreach ( var c in def.callback_structs )
{
var name = Cleanup.ConvertType( c.Name );
@ -55,7 +55,7 @@ namespace Generator
int defaultPack = c.IsPack4OnWindows ? 4 : 8;
var isCallback = !string.IsNullOrEmpty( c.CallbackId );
var isCallback = true;
var iface = "";
if ( isCallback )
iface = " : ICallbackData";
@ -117,7 +117,7 @@ namespace Generator
WriteLine( "#endregion" );
}
if ( !string.IsNullOrEmpty( c.CallbackId ) )
// if ( c.CallbackId ) )
{
callbackList.Add( c );
}

View File

@ -47,7 +47,6 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CodeParser\CodeParser.cs" />
<Compile Include="CodeWriter\GlobalFunctions.cs" />
<Compile Include="CodeWriter\ClassVTable.cs" />
<Compile Include="CodeWriter\Constants.cs" />

View File

@ -13,18 +13,14 @@ namespace Generator
static void Main( string[] args )
{
var content = System.IO.File.ReadAllText( "steam_sdk/steam_api.json" );
var content = System.IO.File.ReadAllText( "steam_api.json" );
var def = Newtonsoft.Json.JsonConvert.DeserializeObject<SteamApiDefinition>( content );
AddMissing( def );
var parser = new CodeParser( @"steam_sdk" );
parser.ExtendDefinition( def );
// AddMissing( def );
Definitions = def;
var generator = new CodeWriter( parser, def );
var generator = new CodeWriter( def );
generator.ToFolder( "../Facepunch.Steamworks/Generated/" );
}
@ -35,7 +31,7 @@ namespace Generator
var missing = Newtonsoft.Json.JsonConvert.DeserializeObject<SteamApiDefinition>( content );
output.structs.AddRange( missing.structs );
output.methods.AddRange( missing.methods );
// output.methods.AddRange( missing.methods );
foreach ( var s in output.structs )
{

View File

@ -9,15 +9,38 @@ namespace Generator
{
public class SteamApiDefinition
{
public class TypeDef
public class Interface
{
[JsonProperty( PropertyName = "typedef" )]
[JsonProperty( PropertyName = "classname" )]
public string Name { get; set; }
[JsonProperty( PropertyName = "type" )]
public string Type { get; set; }
[JsonProperty( PropertyName = "version_string" )]
public string VersionString { get; set; }
public class Method
{
public string ReturnType { get; set; }
public class Param
{
public string ParamType { get; set; }
public string ParamName { get; set; }
}
public Param[] Params { get; set; }
[JsonProperty( PropertyName = "methodname" )]
public string Name { get; set; }
[JsonProperty( PropertyName = "flat_name" )]
public string FlatName { get; set; }
}
public Method[] Methods { get; set; }
}
public List<TypeDef> typedefs { get; set; }
public Interface[] Interfaces { get; set; }
public class EnumDef
{
@ -37,6 +60,17 @@ namespace Generator
public EnumDef[] enums { get; set; }
public class TypeDef
{
[JsonProperty( PropertyName = "typedef" )]
public string Name { get; set; }
[JsonProperty( PropertyName = "type" )]
public string Type { get; set; }
}
public List<TypeDef> typedefs { get; set; }
public class StructDef
{
public class StructFields
@ -52,55 +86,30 @@ namespace Generator
[JsonProperty( PropertyName = "fields" )]
public StructFields[] Fields { get; set; }
public string CallbackId { get; set; }
public bool IsPack4OnWindows
{
get
{
// 4/8 packing is irrevant to these classes
if ( Name.Contains( "MatchMakingKeyValuePair_t" ) ) return true;
public bool IsPack4OnWindows
{
get
{
// 4/8 packing is irrevant to these classes
if ( Name.Contains( "MatchMakingKeyValuePair_t" ) ) return true;
if ( Fields.Any( x => x.Type.Contains( "CSteamID" ) ) )
return true;
if ( Fields.Any( x => x.Type.Contains( "CSteamID" ) ) )
return true;
return false;
}
}
return false;
}
}
}
public List<StructDef> structs { get; set; }
public class MethodDef
public class CallbackStructDef : StructDef
{
public class ParamType
{
[JsonProperty( PropertyName = "paramname" )]
public string Name { get; set; }
[JsonProperty( PropertyName = "paramtype" )]
public string Type { get; set; }
}
[JsonProperty( PropertyName = "classname" )]
public string ClassName { get; set; }
[JsonProperty( PropertyName = "methodname" )]
public string Name { get; set; }
[JsonProperty( PropertyName = "returntype" )]
public string ReturnType { get; set; }
[JsonProperty( PropertyName = "params" )]
public ParamType[] Params { get; set; }
[JsonProperty( PropertyName = "callresult" )]
public string CallResult { get; set; }
public bool NeedsSelfPointer = true;
[JsonProperty( PropertyName = "callback_id" )]
public int CallbackId { get; set; }
}
public List<MethodDef> methods { get; set; }
public Dictionary<string, int> CallbackIds { get; internal set; }
public Dictionary<string, string> Defines { get; internal set; }
public List<CallbackStructDef> callback_structs { get; set; }
}
}