瀏覽代碼

code generation improvements

Vicente Penades Armengot 5 月之前
父節點
當前提交
6809ed06bd

+ 23 - 0
build/SharpGLTF.CodeGen.Core/CodeGen/CSharpEmitter.RuntimeEnum.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace SharpGLTF.CodeGen
+{    
+    partial class CSharpEmitter
+    {
+        /// <summary>
+        /// Represents an enum within <see cref="_RuntimeType"/>
+        /// </summary>
+        [System.Diagnostics.DebuggerDisplay("Enum: {_Name}")]
+        class _RuntimeEnum
+        {
+            internal _RuntimeEnum(string name) { _Name = name; }
+
+            private readonly string _Name;
+        }
+    }
+}
+

+ 47 - 0
build/SharpGLTF.CodeGen.Core/CodeGen/CSharpEmitter.RuntimeField.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace SharpGLTF.CodeGen
+{
+    using SchemaReflection;
+    
+    partial class CSharpEmitter
+    {
+        /// <summary>
+        /// Represents an field within <see cref="_RuntimeType"/>
+        /// </summary>
+        [System.Diagnostics.DebuggerDisplay("Enum: {_Name}")]
+        class _RuntimeField
+        {
+            #region lifecycle
+            internal _RuntimeField(FieldInfo f) { _PersistentField = f; }
+            #endregion
+
+            #region data
+
+            private readonly FieldInfo _PersistentField;
+
+            #endregion
+
+            #region properties
+
+            public string PrivateField { get; set; }
+            public string PublicProperty { get; set; }
+
+            public string CollectionContainer { get; set; }
+
+            // MinVal, MaxVal, readonly, static
+
+            // serialization sections
+            // deserialization sections
+            // validation sections
+            // clone sections
+
+            #endregion
+        }
+    }
+}
+

+ 89 - 0
build/SharpGLTF.CodeGen.Core/CodeGen/CSharpEmitter.RuntimeType.cs

@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace SharpGLTF.CodeGen
+{
+    using SchemaReflection;
+    
+    partial class CSharpEmitter
+    {
+        /// <summary>
+        /// Represents the runtime information associated to a given <see cref="SchemaType"/>
+        /// </summary>
+        [System.Diagnostics.DebuggerDisplay("{RuntimeNamespace}.{RuntimeName}")]
+        class _RuntimeType
+        {
+            #region lifecycle
+            internal _RuntimeType(SchemaType t) { _PersistentType = t; }
+
+            #endregion
+
+            #region data
+
+            /// <summary>
+            /// Schema type used for serialization
+            /// </summary>
+            private readonly SchemaType _PersistentType;
+
+            /// <summary>
+            /// Namespace in which the source code will be generated.
+            /// </summary>
+            public string RuntimeNamespace { get; set; }
+
+            /// <summary>
+            /// The name of the type used to generate the source code.
+            /// </summary>
+            public string RuntimeName { get; set; }
+
+            /// <summary>
+            /// Additional comments added to the generated source code.
+            /// </summary>
+            public List<string> RuntimeComments { get; } = new List<string>();
+
+            /// <summary>
+            /// Fields of this type.
+            /// </summary>
+            private readonly Dictionary<string, _RuntimeField> _Fields = new Dictionary<string, _RuntimeField>();
+
+            /// <summary>
+            /// Enums of this type.
+            /// </summary>
+            private readonly Dictionary<string, _RuntimeEnum> _Enums = new Dictionary<string, _RuntimeEnum>();
+
+            #endregion
+
+            #region API
+
+            public _RuntimeField UseField(FieldInfo finfo)
+            {
+                var key = $"{finfo.PersistentName}";
+
+                if (_Fields.TryGetValue(key, out _RuntimeField rfield)) return rfield;
+
+                rfield = new _RuntimeField(finfo);
+
+                _Fields[key] = rfield;
+
+                return rfield;
+            }
+
+            public _RuntimeEnum UseEnum(string name)
+            {
+                var key = name;
+
+                if (_Enums.TryGetValue(key, out _RuntimeEnum renum)) return renum;
+
+                renum = new _RuntimeEnum(name);
+
+                _Enums[key] = renum;
+
+                return renum;
+            }
+
+            #endregion
+        }
+    }
+}

+ 85 - 135
build/SharpGLTF.CodeGen.Core/CodeGen/EmitCSharp.cs

@@ -16,170 +16,73 @@ namespace SharpGLTF.CodeGen
     /// Takes a <see cref="SchemaReflection.SchemaType.Context"/> and emits
     /// all its enums and classes as c# source code
     /// </summary>
-    public class CSharpEmitter
+    public partial class CSharpEmitter
     {
-        #region runtime types
-
-        class _RuntimeType
-        {
-            internal _RuntimeType(SchemaType t) { _PersistentType = t; }
-
-            private readonly SchemaType _PersistentType;
-
-            public string RuntimeNamespace { get; set; }
-
-            public string RuntimeName { get; set; }
-
-            public List<string> Comments { get; } = new List<string>();
-
-            private readonly Dictionary<string, _RuntimeField> _Fields = new Dictionary<string, _RuntimeField>();
-            private readonly Dictionary<string, _RuntimeEnum> _Enums = new Dictionary<string, _RuntimeEnum>();            
-
-            public _RuntimeField UseField(FieldInfo finfo)
-            {
-                var key = $"{finfo.PersistentName}";
-
-                if (_Fields.TryGetValue(key, out _RuntimeField rfield)) return rfield;
-
-                rfield = new _RuntimeField(finfo);
-
-                _Fields[key] = rfield;
-
-                return rfield;
-            }
-
-            public _RuntimeEnum UseEnum(string name)
-            {
-                var key = name;
-
-                if (_Enums.TryGetValue(key, out _RuntimeEnum renum)) return renum;
-
-                renum = new _RuntimeEnum(name);
-
-                _Enums[key] = renum;
-
-                return renum;
-            }
-        }
-
-        class _RuntimeEnum
-        {
-            internal _RuntimeEnum(string name) { _Name = name; }
-
-            private readonly string _Name;
-        }
-
-        class _RuntimeField
-        {
-            internal _RuntimeField(FieldInfo f) { _PersistentField = f; }
-
-            private readonly FieldInfo _PersistentField;
-
-            public string PrivateField { get; set; }
-            public string PublicProperty { get; set; }
-
-            public string CollectionContainer { get; set; }
-            public string DictionaryContainer { get; set; }
-
-            // MinVal, MaxVal, readonly, static
-
-            // serialization sections
-            // deserialization sections
-            // validation sections
-            // clone sections
-        }        
+        #region data             
 
         private readonly Dictionary<string, _RuntimeType> _Types = new Dictionary<string, _RuntimeType>();
-
+        
         private string _DefaultCollectionContainer = "TItem[]";
 
-        #endregion
-
-        #region setup & declaration        
-
-        private static string _SanitizeName(string name)
-        {
-            return name.Replace(" ", string.Empty, StringComparison.OrdinalIgnoreCase);
-        }
-
-        private _RuntimeType _UseType(SchemaType stype)
-        {
-            var key = $"{stype.PersistentName}";
-
-            if (_Types.TryGetValue(key, out _RuntimeType rtype)) return rtype;
-
-            rtype = new _RuntimeType(stype)
-            {
-                RuntimeName = _SanitizeName(stype.PersistentName)
-            };
+        private System.Diagnostics.DebuggerBrowsableState? _FieldsBrowsableState;
 
-            _Types[key] = rtype;
+        #endregion
 
-            return rtype;
-        }
+        #region setup & declaration - types
 
-        private bool _TryGetType(SchemaType stype, out _RuntimeType rtype)
+        public void SetRuntimeName(string persistentName, string runtimeName, string runtimeNamespace = null)
         {
-            var key = $"{stype.PersistentName}";
+            if (!_Types.TryGetValue(persistentName, out _RuntimeType t)) return;
 
-            return _Types.TryGetValue(key, out rtype);
+            t.RuntimeNamespace = runtimeNamespace;
+            t.RuntimeName = runtimeName;
         }
 
-        private _RuntimeField _UseField(FieldInfo finfo) { return _UseType(finfo.DeclaringClass).UseField(finfo); }
-
-        public void SetRuntimeName(SchemaType stype, string newName, string runtimeNamespace = null)
+        public void SetRuntimeName(SchemaType stype, string runtimeName, string runtimeNamespace = null)
         {
             var t = _UseType(stype);
 
             t.RuntimeNamespace = runtimeNamespace;
-            t.RuntimeName = newName;
+            t.RuntimeName = runtimeName;
         }
 
         public void AddRuntimeComment(string persistentName, string comment)
         {
             if (!_Types.TryGetValue(persistentName, out _RuntimeType t)) return;
 
-            t.Comments.Add(comment);           
+            t.RuntimeComments.Add(comment);
         }
 
         public IReadOnlyList<string> GetRuntimeComments(SchemaType cls)
         {
             return !_TryGetType(cls, out var rtype)
                 ? Array.Empty<string>()
-                : (IReadOnlyList<string>)rtype.Comments;
-        }
-
-        public void SetRuntimeName(string persistentName, string runtimeName, string runtimeNamespace = null)
-        {
-            if (!_Types.TryGetValue(persistentName, out _RuntimeType t)) return;
-
-            t.RuntimeNamespace = runtimeNamespace;
-            t.RuntimeName = runtimeName;
+                : (IReadOnlyList<string>)rtype.RuntimeComments;
         }
 
+        /// <summary>
+        /// Gets the runtime name associated to the type with the given <paramref name="persistentName"/>
+        /// </summary>
+        /// <param name="persistentName">The persistent name of the type.</param>
+        /// <returns>The runtime name associated to the type.</returns>
         public string GetRuntimeName(string persistentName)
         {
             return _Types[persistentName].RuntimeName;
         }
 
+        /// <summary>
+        /// Gets the runtime namespace associated to the type with the given <paramref name="persistentName"/>
+        /// </summary>
+        /// <param name="persistentName">The persistent name of the type.</param>
+        /// <returns>The runtime namespace associated to the type.</returns>
         public string GetRuntimeNamespace(string persistentName)
         {
             return _Types[persistentName].RuntimeNamespace ?? Constants.OutputNamespace;
         }
 
-        public void SetFieldName(FieldInfo finfo, string name) { _UseField(finfo).PrivateField = name; }
-
-        public string GetFieldRuntimeName(FieldInfo finfo) { return _UseField(finfo).PrivateField; }
-
-        public void SetPropertyName(FieldInfo finfo, string name) { _UseField(finfo).PublicProperty = name; }
-
-        public string GetPropertyName(FieldInfo finfo) { return _UseField(finfo).PublicProperty; }
-
-
 
-        public void SetCollectionContainer(string container) { _DefaultCollectionContainer = container; }
 
-        public void SetCollectionContainer(FieldInfo finfo, string container) { _UseField(finfo).CollectionContainer = container; }        
+        public void SetDefaultCollectionContainer(string container) { _DefaultCollectionContainer = container; }
 
         public void SetFieldToChildrenList(SchemaType.Context ctx, string persistentName, string fieldName)
         {
@@ -203,11 +106,11 @@ namespace SharpGLTF.CodeGen
         {
             _UseType(type);
 
-            foreach(var f in type.Fields)
+            foreach (var f in type.Fields)
             {
-                var runtimeName = _SanitizeName(f.PersistentName).Replace("@","at", StringComparison.Ordinal);
+                var runtimeName = _SanitizeName(f.PersistentName).Replace("@", "at", StringComparison.Ordinal);
 
-                SetFieldName(f, $"_{runtimeName}");
+                SetFieldRuntimeName(f, $"_{runtimeName}");
                 SetPropertyName(f, runtimeName);
             }
         }
@@ -225,17 +128,59 @@ namespace SharpGLTF.CodeGen
 
         public void DeclareContext(SchemaType.Context context)
         {
-            foreach(var ctype in context.Classes)
-            {
-                DeclareClass(ctype);
-            }
+            foreach (var ctype in context.Classes) { DeclareClass(ctype); }
 
-            foreach (var etype in context.Enumerations)
+            foreach (var etype in context.Enumerations) { DeclareEnum(etype); }
+        }
+
+        #endregion
+
+        #region setup & declaration - fields
+
+        public void SetFieldRuntimeName(FieldInfo finfo, string name) { _UseField(finfo).PrivateField = name; }
+
+        public string GetFieldRuntimeName(FieldInfo finfo) { return _UseField(finfo).PrivateField; }
+
+        public void SetPropertyName(FieldInfo finfo, string name) { _UseField(finfo).PublicProperty = name; }
+
+        public string GetPropertyName(FieldInfo finfo) { return _UseField(finfo).PublicProperty; }
+
+        public void SetCollectionContainer(FieldInfo finfo, string container) { _UseField(finfo).CollectionContainer = container; }
+
+        #endregion
+
+        #region core API
+
+        private static string _SanitizeName(string name)
+        {
+            return name.Replace(" ", string.Empty, StringComparison.OrdinalIgnoreCase);
+        }
+
+        private _RuntimeType _UseType(SchemaType stype)
+        {
+            var key = $"{stype.PersistentName}";
+
+            if (_Types.TryGetValue(key, out _RuntimeType rtype)) return rtype;
+
+            rtype = new _RuntimeType(stype)
             {
-                DeclareEnum(etype);
-            }
+                RuntimeName = _SanitizeName(stype.PersistentName)
+            };
+
+            _Types[key] = rtype;
+
+            return rtype;
         }
 
+        private bool _TryGetType(SchemaType stype, out _RuntimeType rtype)
+        {
+            var key = $"{stype.PersistentName}";
+
+            return _Types.TryGetValue(key, out rtype);
+        }
+
+        private _RuntimeField _UseField(FieldInfo finfo) { return _UseType(finfo.DeclaringClass).UseField(finfo); }
+
         internal string _GetRuntimeName(SchemaType type) { return _GetRuntimeName(type, null); }
 
         private string _GetRuntimeName(SchemaType type, _RuntimeField extra)
@@ -509,9 +454,14 @@ namespace SharpGLTF.CodeGen
             if (type.BaseClass != null) classDecl += $" : {_GetRuntimeName(type.BaseClass)}";
             return classDecl;
         }
+        
+        internal IEnumerable<string> _EmitClassField(FieldInfo f)
+        {
+            if (_FieldsBrowsableState.HasValue)
+            {
+                yield return $"[System.Diagnostics.DebuggerBrowsable({_FieldsBrowsableState.Value})]";
+            }
 
-        internal IEnumerable<string> _GetClassField(FieldInfo f)
-        {            
             var tdecl = _GetRuntimeName(f.FieldType, _UseField(f));
             var fname = GetFieldRuntimeName(f);
 
@@ -638,7 +588,7 @@ namespace SharpGLTF.CodeGen
                 var trname = _Emitter._GetRuntimeName(f.FieldType);
                 var frname = _Emitter.GetFieldRuntimeName(f);
 
-                _Fields.AddRange(_Emitter._GetClassField(f));
+                _Fields.AddRange(_Emitter._EmitClassField(f));
 
                 AddFieldReflection(f);
 

+ 1 - 1
build/SharpGLTF.CodeGen.Core/MainSchemaProcessor.cs

@@ -74,7 +74,7 @@ namespace SharpGLTF
 
         public override void PrepareTypes(CSharpEmitter newEmitter, SchemaType.Context ctx)
         {
-            newEmitter.SetCollectionContainer("List<TItem>");
+            newEmitter.SetDefaultCollectionContainer("List<TItem>");
 
             const string rootName = "ModelRoot";
 

+ 28 - 20
build/SharpGLTF.CodeGen.Core/SchemaProcessing.cs

@@ -16,7 +16,7 @@ namespace SharpGLTF
 {
     public static class SchemaProcessing
     {
-        #region schema loader
+        #region Schema Loader
 
         public static SchemaType.Context LoadExtensionSchemaContext(string srcSchema)
         {
@@ -55,34 +55,19 @@ namespace SharpGLTF
                 .GetResult();
         }
 
-        static NJsonSchema.JsonReferenceResolver _Resolver(JSONSCHEMA schema, string basePath)
+        private static NJsonSchema.JsonReferenceResolver _Resolver(JSONSCHEMA schema, string basePath)
         {
             var generator = new NJsonSchema.NewtonsoftJson.Generation.NewtonsoftJsonSchemaGeneratorSettings();
 
             var solver = new NJsonSchema.JsonSchemaAppender(schema, generator.TypeNameGenerator);
 
             return new MyReferenceResolver(solver);
-        }
-
-        class MyReferenceResolver : NJsonSchema.JsonReferenceResolver
-        {
-            public MyReferenceResolver(NJsonSchema.JsonSchemaAppender resolver) : base(resolver) { }
-
-            public override Task<IJsonReference> ResolveFileReferenceAsync(string filePath, System.Threading.CancellationToken cancellationToken)
-            {
-                if (System.IO.File.Exists(filePath)) return base.ResolveFileReferenceAsync(filePath, cancellationToken);
-
-                filePath = System.IO.Path.GetFileName(filePath);
-                filePath = System.IO.Path.Combine(Constants.MainSchemaDir, filePath);
-
-                if (System.IO.File.Exists(filePath)) return base.ResolveFileReferenceAsync(filePath, cancellationToken);
-
-                throw new System.IO.FileNotFoundException(filePath);
-            }
-        }
+        }        
 
         #endregion
 
+        #region Code Emitter
+
         public static void EmitCodeFromSchema(string projectPath, string dstFile, SchemaType.Context ctx, IReadOnlyList<SchemaProcessor> extensions)
         {
             var dstDir = _FindTargetDirectory(projectPath);
@@ -117,5 +102,28 @@ namespace SharpGLTF
 
             return null;
         }
+
+        #endregion
+
+        #region nested types
+
+        class MyReferenceResolver : NJsonSchema.JsonReferenceResolver
+        {
+            public MyReferenceResolver(NJsonSchema.JsonSchemaAppender resolver) : base(resolver) { }
+
+            public override Task<IJsonReference> ResolveFileReferenceAsync(string filePath, System.Threading.CancellationToken cancellationToken)
+            {
+                if (System.IO.File.Exists(filePath)) return base.ResolveFileReferenceAsync(filePath, cancellationToken);
+
+                filePath = System.IO.Path.GetFileName(filePath);
+                filePath = System.IO.Path.Combine(Constants.MainSchemaDir, filePath);
+
+                if (System.IO.File.Exists(filePath)) return base.ResolveFileReferenceAsync(filePath, cancellationToken);
+
+                throw new System.IO.FileNotFoundException(filePath);
+            }
+        }
+
+        #endregion
     }
 }

+ 39 - 11
build/SharpGLTF.CodeGen.Core/SchemaReflection/SchemaTypes.cs

@@ -54,6 +54,8 @@ namespace SharpGLTF.SchemaReflection
 
         #region properties
 
+        public Context Owner => _Owner;
+
         /// <summary>
         /// Short version of <see cref="Identifier"/>
         /// </summary>
@@ -70,11 +72,6 @@ namespace SharpGLTF.SchemaReflection
                 return idx < 0 ? id : id.Substring(idx + 1);
             }
         }
-            
-
-        
-
-        public Context Owner => _Owner;
 
         #endregion
     }
@@ -328,7 +325,30 @@ namespace SharpGLTF.SchemaReflection
         {
             if (type == typeof(string)) { _FieldType = DeclaringClass.Owner.UseString(); return this; }
 
-            if (type.IsEnum) { _FieldType = DeclaringClass.Owner.UseEnum(type.Name, isNullable); return this; }
+            if (type.IsEnum)
+            {
+                var enumType = DeclaringClass.Owner.UseEnum(type.Name, isNullable);
+                _FieldType = enumType;                
+
+                if (!enumType.Values.Any())
+                {
+                    var names = Enum.GetNames(type);
+                    var values = Enum.GetValues(type).OfType<IConvertible>().Select(item => item.ToInt32(System.Globalization.CultureInfo.InvariantCulture)).ToList();
+
+                    var isSequential = values.Count == 0 || Enumerable.Range(0, names.Length).SequenceEqual(values);
+                    
+                    if (isSequential)
+                    {
+                        for (int i = 0; i < names.Length; i++)
+                        {
+                            var key = names[i];
+                            enumType.SetValue(key, i);
+                        }
+                    }                    
+                }
+
+                return this;
+            }
 
             _FieldType = DeclaringClass.Owner.UseBlittable(type.GetTypeInfo(), isNullable);
             return this;
@@ -382,6 +402,11 @@ namespace SharpGLTF.SchemaReflection
     {
         #region constructor
 
+        public static ClassType FromRuntimeClass(Context ctx, string name)
+        {
+            return new ClassType(ctx, name);
+        }
+
         internal ClassType(Context ctx, string name) : base(ctx)
         {
             _PersistentName = name;            
@@ -395,10 +420,10 @@ namespace SharpGLTF.SchemaReflection
 
         private readonly SortedSet<FieldInfo> _Fields = new SortedSet<FieldInfo>(FieldInfo.Comparer);
 
-        private ClassType _BaseClass;        
+        public ClassType BaseClass { get; set; }
 
         /// <summary>
-        /// True to prevent to codegen emitter to emit this class
+        /// True to prevent codegen emitter to emit this class
         /// </summary>
         public bool IgnoredByEmitter { get; set; }
 
@@ -406,8 +431,7 @@ namespace SharpGLTF.SchemaReflection
 
         #region properties
         public override string PersistentName => _PersistentName;
-        public IEnumerable<FieldInfo> Fields => _Fields;
-        public ClassType BaseClass { get => _BaseClass; set => _BaseClass = value; }
+        public IEnumerable<FieldInfo> Fields => _Fields;        
 
         #endregion
 
@@ -415,7 +439,11 @@ namespace SharpGLTF.SchemaReflection
 
         public FieldInfo GetField(string name)
         {
-            return _Fields.First(item => item.PersistentName == name);
+            var field = _Fields.FirstOrDefault(item => item.PersistentName == name);
+            if (field != null) return field;
+
+            var names = string.Join("\r\n", _Fields.Select(item => item.PersistentName));
+            throw new ArgumentException($"{name} not found, expected one of:\r\n{names}");
         }
 
         public FieldInfo UseField(string name)

+ 13 - 0
build/SharpGLTF.CodeGen.Core/SchemaReflection/SchemaTypesContext.cs

@@ -96,6 +96,19 @@ namespace SharpGLTF.SchemaReflection
                 if (ct != null) ct.IgnoredByEmitter = true;            
             }
 
+            public void IgnoredByCodeEmitter(Context otherContext)
+            {
+                foreach (var type in otherContext.Classes)
+                {
+                    IgnoredByCodeEmitter(type.PersistentName);
+                }
+
+                foreach (var type in otherContext.Enumerations)
+                {
+                    IgnoredByCodeEmitter(type.PersistentName);
+                }
+            }
+
             public void IgnoredByCodeEmittierMainSchema()
             {
                 IgnoredByCodeEmitter("glTF Property");