From 9a7ccc6b131f0b87880918e42cc670dc0dacf7c7 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 01:26:30 -0400 Subject: [PATCH 01/15] Add capnpc-csharp tests skeleton. --- Capnp.Net.sln | 6 + .../Properties/Resources.Designer.cs | 63 +++++++++ capnpc-csharp.tests/Properties/Resources.resx | 121 ++++++++++++++++++ .../capnpc-csharp.tests.csproj | 39 ++++++ capnpc-csharp/Program.cs | 3 + 5 files changed, 232 insertions(+) create mode 100644 capnpc-csharp.tests/Properties/Resources.Designer.cs create mode 100644 capnpc-csharp.tests/Properties/Resources.resx create mode 100644 capnpc-csharp.tests/capnpc-csharp.tests.csproj diff --git a/Capnp.Net.sln b/Capnp.Net.sln index e12ef97..41f5968 100644 --- a/Capnp.Net.sln +++ b/Capnp.Net.sln @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Std EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Core21", "Capnp.Net.Runtime.Tests.Core21\Capnp.Net.Runtime.Tests.Core21.csproj", "{58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "capnpc-csharp.tests", "capnpc-csharp.tests\capnpc-csharp.tests.csproj", "{B77AC567-E232-4072-85C3-8689566BF3D4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}.Debug|Any CPU.Build.0 = Debug|Any CPU {58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}.Release|Any CPU.ActiveCfg = Release|Any CPU {58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}.Release|Any CPU.Build.0 = Release|Any CPU + {B77AC567-E232-4072-85C3-8689566BF3D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B77AC567-E232-4072-85C3-8689566BF3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B77AC567-E232-4072-85C3-8689566BF3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B77AC567-E232-4072-85C3-8689566BF3D4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/capnpc-csharp.tests/Properties/Resources.Designer.cs b/capnpc-csharp.tests/Properties/Resources.Designer.cs new file mode 100644 index 0000000..d7a8a0c --- /dev/null +++ b/capnpc-csharp.tests/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace capnpc_csharp.Tests.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("capnpc_csharp.Tests.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/capnpc-csharp.tests/Properties/Resources.resx b/capnpc-csharp.tests/Properties/Resources.resx new file mode 100644 index 0000000..2f96abe --- /dev/null +++ b/capnpc-csharp.tests/Properties/Resources.resx @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + \ No newline at end of file diff --git a/capnpc-csharp.tests/capnpc-csharp.tests.csproj b/capnpc-csharp.tests/capnpc-csharp.tests.csproj new file mode 100644 index 0000000..a8047be --- /dev/null +++ b/capnpc-csharp.tests/capnpc-csharp.tests.csproj @@ -0,0 +1,39 @@ + + + + netcoreapp2.2 + capnpc_csharp.Tests + + false + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/capnpc-csharp/Program.cs b/capnpc-csharp/Program.cs index 4da2ad2..fe758f2 100644 --- a/capnpc-csharp/Program.cs +++ b/capnpc-csharp/Program.cs @@ -1,6 +1,9 @@ using Capnp; using System; using System.IO; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleToAttribute("capnpc-csharp.tests")] namespace CapnpC { From 4411cd90d0eb32a150da1b11a43d66cd28fc986b Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 01:36:47 -0400 Subject: [PATCH 02/15] Test renaming of enumerants that are C# keywords. --- .../Properties/Resources.Designer.cs | 10 ++++ capnpc-csharp.tests/Properties/Resources.resx | 3 + .../Resources/UnitTest1.capnp.bin | Bin 0 -> 504 bytes capnpc-csharp.tests/UnitTest1.capnp | 5 ++ capnpc-csharp.tests/UnitTests.cs | 55 ++++++++++++++++++ .../capnpc-csharp.tests.csproj | 1 + 6 files changed, 74 insertions(+) create mode 100644 capnpc-csharp.tests/Resources/UnitTest1.capnp.bin create mode 100644 capnpc-csharp.tests/UnitTest1.capnp create mode 100644 capnpc-csharp.tests/UnitTests.cs diff --git a/capnpc-csharp.tests/Properties/Resources.Designer.cs b/capnpc-csharp.tests/Properties/Resources.Designer.cs index d7a8a0c..a67166c 100644 --- a/capnpc-csharp.tests/Properties/Resources.Designer.cs +++ b/capnpc-csharp.tests/Properties/Resources.Designer.cs @@ -59,5 +59,15 @@ namespace capnpc_csharp.Tests.Properties { resourceCulture = value; } } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] UnitTest1_capnp { + get { + object obj = ResourceManager.GetObject("UnitTest1_capnp", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/capnpc-csharp.tests/Properties/Resources.resx b/capnpc-csharp.tests/Properties/Resources.resx index 2f96abe..bc2d6ee 100644 --- a/capnpc-csharp.tests/Properties/Resources.resx +++ b/capnpc-csharp.tests/Properties/Resources.resx @@ -118,4 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\UnitTest1.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/capnpc-csharp.tests/Resources/UnitTest1.capnp.bin b/capnpc-csharp.tests/Resources/UnitTest1.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..b6ecdf86c135d4d5dd551f83024cfd2a695e39e4 GIT binary patch literal 504 zcmZQzU|_HVVhCVi5Ck%|1Mx*5mIq=MAZ7&Or9f;B#0(7VV3Gq!vNEtS_;}rzbMeUK z$y{Jj+=L@gstJf)fmj^3GPul@ubfBHCEQL307aO97-kP#0hD0~q%Q%nEf7Oo29dA? zQXu!EgV4Opl91Hm5<|V@#Dcs6sQ(xlVD^Fh8U)0yd8N6jMTvPOPy^8PS)t2=lraJ! zB)mW_h5%L|r3K>v>7>e%R1g;wevCk$;qn*EJs`Cp0CE>U5QEHz@W2eXeK2!C_JP8g P6No|Kf#z f.NestedTypes)) + { + if (GetTypeDef(id, defs) is Model.TypeDefinition def) return def; + } + return null; + } + + static Model.TypeDefinition GetTypeDef(ulong id, IEnumerable defs) + { + foreach (var def in defs) + { + if (def.Id == id) return def; + var sub = GetTypeDef(id, def.NestedTypes); + if (sub != null) return sub; + } + return null; + } + + static Model.SchemaModel Load(byte[] data) + { + WireFrame segments; + var input = new MemoryStream(data); + using (input) + { + segments = Framing.ReadSegments(input); + } + var dec = DeserializerState.CreateRoot(segments); + var reader = Schema.CodeGeneratorRequest.Reader.Create(dec); + var model = Model.SchemaModel.Create(reader); + return model; + } + } +} diff --git a/capnpc-csharp.tests/capnpc-csharp.tests.csproj b/capnpc-csharp.tests/capnpc-csharp.tests.csproj index a8047be..3be689f 100644 --- a/capnpc-csharp.tests/capnpc-csharp.tests.csproj +++ b/capnpc-csharp.tests/capnpc-csharp.tests.csproj @@ -19,6 +19,7 @@ + From e543b62e2bb5a50f01c49263e33fa42635773961 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 10:28:53 -0400 Subject: [PATCH 03/15] Test for absence of name clashes with immediately enclosing type. --- .../Resources/UnitTest1.capnp.bin | Bin 504 -> 816 bytes capnpc-csharp.tests/UnitTest1.capnp | 6 +++++- capnpc-csharp.tests/UnitTests.cs | 16 ++++++++++++++++ capnpc-csharp/Generator/CodeGenerator.cs | 4 +++- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/capnpc-csharp.tests/Resources/UnitTest1.capnp.bin b/capnpc-csharp.tests/Resources/UnitTest1.capnp.bin index b6ecdf86c135d4d5dd551f83024cfd2a695e39e4..ae47486724106d3236d29bd30325fcb8e2286f47 100644 GIT binary patch literal 816 zcmZ`%yG{a85S`^IMuR34b|%Ke!~_#t8!IS`iH5)jpjiwtyMQi*Ex$l16$u@mK|$-I zF!4L=Ip*rYQT9Xv;23refGJfRchDk5bME2HOF?dL zekLD_uko(&rXK-9BVYiWrKfEo-+!gW(@}kS08a+cI-7*G(S`m5hJfwN23UvvyK*{z zzn?w-j>+rc7xN}x+nG#}!@iRd*1HB=X@%XW>Ayyo7mw|J*q0q7kYB%}gnI+f`n;b2 zwQv~tFYPdbO{w>KMmv00ZXT1!Z}-CqS;<44>jnDZEi&tM`LqsGl_zW1^f9*{%RWr@ ztHSTg;$;Oo1KnBoUC@LSofhZ+$pcfokN*TZNAOWHte@ zD-erM4rG#_n7}e|hK8&mkben?ZGjk~9LN9ykZtl41BEAhFbXI_OlD-b@|E*Qx`f*a rkS#$#?3!1an_85ZS2Ed=QEc*ZMn^`D$(>C4jEs{nGD%PV!(;*g`@9`9 diff --git a/capnpc-csharp.tests/UnitTest1.capnp b/capnpc-csharp.tests/UnitTest1.capnp index 125190e..f638014 100644 --- a/capnpc-csharp.tests/UnitTest1.capnp +++ b/capnpc-csharp.tests/UnitTest1.capnp @@ -2,4 +2,8 @@ enum Enumerant { byte @0; -} \ No newline at end of file +} + +struct Foo { + foo @0: UInt8; +} diff --git a/capnpc-csharp.tests/UnitTests.cs b/capnpc-csharp.tests/UnitTests.cs index 0d10a48..2d4ea6b 100644 --- a/capnpc-csharp.tests/UnitTests.cs +++ b/capnpc-csharp.tests/UnitTests.cs @@ -18,6 +18,22 @@ namespace CapnpC Assert.AreEqual("@byte", GetTypeDef(0xc8461867c409f5d4, model).Enumerants[0].Literal); } + [TestMethod] + public void Test01NestedClash() + { + var model = Load(Resources.UnitTest1_capnp); + var structFoo = GetTypeDef(0x93db6ba5509bac24, model); + var codeGen = NewGeneratorFor(model); + codeGen.Transform(model.FilesToGenerate.First()); + var names = codeGen.GetNames(); + var fieldName = names.GetCodeIdentifier(structFoo.Fields[0]).ToString(); + Assert.AreEqual("Foo", structFoo.Name); + Assert.AreNotEqual(structFoo.Name, fieldName); + } + + static Generator.CodeGenerator NewGeneratorFor(Model.SchemaModel model) + => new Generator.CodeGenerator(model, new Generator.GeneratorOptions()); + static Model.TypeDefinition GetTypeDef(ulong id, Model.SchemaModel model) { foreach (var defs in model.FilesToGenerate.Select(f => f.NestedTypes)) diff --git a/capnpc-csharp/Generator/CodeGenerator.cs b/capnpc-csharp/Generator/CodeGenerator.cs index 785a50f..d066655 100644 --- a/capnpc-csharp/Generator/CodeGenerator.cs +++ b/capnpc-csharp/Generator/CodeGenerator.cs @@ -33,6 +33,8 @@ _interfaceGen = new InterfaceSnippetGen(_names); } + internal GenNames GetNames() => _names; + IEnumerable TransformEnum(TypeDefinition def) { yield return _commonGen.MakeEnum(def); @@ -143,7 +145,7 @@ } } - string Transform(GenFile file) + internal string Transform(GenFile file) { if (file.Namespace != null) { From 28993b43a15a22de944994cd22482cb9584c36a7 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 12:38:13 -0400 Subject: [PATCH 04/15] Test forward-inherited types. --- .../Properties/Resources.Designer.cs | 10 ++++++++++ capnpc-csharp.tests/Properties/Resources.resx | 3 +++ .../Resources/UnitTest2.capnp.bin | Bin 0 -> 2608 bytes capnpc-csharp.tests/UnitTest2.capnp | 11 +++++++++++ capnpc-csharp.tests/UnitTests.cs | 9 +++++++++ 5 files changed, 33 insertions(+) create mode 100644 capnpc-csharp.tests/Resources/UnitTest2.capnp.bin create mode 100644 capnpc-csharp.tests/UnitTest2.capnp diff --git a/capnpc-csharp.tests/Properties/Resources.Designer.cs b/capnpc-csharp.tests/Properties/Resources.Designer.cs index a67166c..6840817 100644 --- a/capnpc-csharp.tests/Properties/Resources.Designer.cs +++ b/capnpc-csharp.tests/Properties/Resources.Designer.cs @@ -69,5 +69,15 @@ namespace capnpc_csharp.Tests.Properties { return ((byte[])(obj)); } } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] UnitTest2_capnp { + get { + object obj = ResourceManager.GetObject("UnitTest2_capnp", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/capnpc-csharp.tests/Properties/Resources.resx b/capnpc-csharp.tests/Properties/Resources.resx index bc2d6ee..a67f487 100644 --- a/capnpc-csharp.tests/Properties/Resources.resx +++ b/capnpc-csharp.tests/Properties/Resources.resx @@ -118,6 +118,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\UnitTest2.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\UnitTest1.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/capnpc-csharp.tests/Resources/UnitTest2.capnp.bin b/capnpc-csharp.tests/Resources/UnitTest2.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..5a2eafcc0b95779d73149763083f37b1cf4e79de GIT binary patch literal 2608 zcmcguOK4L;6rI<^exzcpiXx>!aiNO@nvJxZO0|N5puq}N5JQ`4p-oE?by)~*{DJsc zq=Mo?cOou|C{z%Hu8L4lv`81?LKh+~>c$VA^XA=`m+6~45p=@Lo%@-4&)k{0FG?xZ z?_h9ST&)8=7gOqUT&V=+Ad2cMm`s5x)#Q#lFs@RKYOwRti65QuZ>wFYeYguJWvK6g z?y{Ttn#SIR%d^*~%WaSVjvvQ2z=XISVORv61=Yy3#S@PY(zQ@kUhZjY{XVm_1#_;i zw%}@|9zfYwYfv=}nLRz5T%j37-c-{4zhiA$~`%P4Di$m3VFXt=+9s z&nm3N^lRc}9x@?#nb$D9mHSsykKZi6GyR%)TN=XiV8i?N{luNk z9Wx)J?!z*0Ey9Td|G^Xe2|4*7<$aiX_VDDVUmsTBHS_Ql>%;Oue_?q@Hm@&Vygm1& z9$xPCAaE{#4jOm|z|TQGZ_4wdr6ajwDV-Y1PUa_7D{LJ6`<-?N;IF>Y?V)I!9Z=?9^c+uPb=bJi=i^Gk!Sr74e!KJ&)(`UHJ&S-o*3SK zC|k&m7geNPCRaQ&Rw}w-Ffd-si>hTBljzrAvP~G!X7m_vZUAin%@$6%+IDxe4>o-i z-Y(gg=Q`THc7uPrzrBbT+#l}&o7@}C$*4~<0haN&&a`7zH+gzm2eZt4+VX=XZj<=J z3ysQ0`cL!c-COzE6>BU`|sxw07!JKLy}*r$9w-IEl{nD3@-N?~v5@t&rARzY%(_*VV^$fx+>3uW0$a zTrQ24`)B=d5MAo7c;HIDBl({sa-rtC+6e`5nCDCUl-nBfU(KG)O0ui#GVuy7R_ro* O3p(Q%?*I~dchqksG(Y12 literal 0 HcmV?d00001 diff --git a/capnpc-csharp.tests/UnitTest2.capnp b/capnpc-csharp.tests/UnitTest2.capnp new file mode 100644 index 0000000..e4cbcb9 --- /dev/null +++ b/capnpc-csharp.tests/UnitTest2.capnp @@ -0,0 +1,11 @@ +@0xf6041efc5e8b1e59; + +interface Interface1(V1) {} + +interface Interface { + method @0 () -> (arg : AnyPointer); + method1 @1 () -> (arg : Interface1(AnyPointer)); + method2 @2 () -> (arg : Interface2(AnyPointer)); +} + +interface Interface2(V2) {} diff --git a/capnpc-csharp.tests/UnitTests.cs b/capnpc-csharp.tests/UnitTests.cs index 2d4ea6b..dd37864 100644 --- a/capnpc-csharp.tests/UnitTests.cs +++ b/capnpc-csharp.tests/UnitTests.cs @@ -31,6 +31,15 @@ namespace CapnpC Assert.AreNotEqual(structFoo.Name, fieldName); } + [TestMethod] + public void Test02ForwardInheritance() + { + var model = Load(Resources.UnitTest2_capnp); + var codeGen = NewGeneratorFor(model); + codeGen.Transform(model.FilesToGenerate.First()); + // Should not throw + } + static Generator.CodeGenerator NewGeneratorFor(Model.SchemaModel model) => new Generator.CodeGenerator(model, new Generator.GeneratorOptions()); From 4f431856baf1cb26a70d3e520689f85d456e9327 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 10:29:21 -0400 Subject: [PATCH 05/15] Test use of nodes imported from non-generated files. --- .../Properties/Resources.Designer.cs | 10 ++++++++++ capnpc-csharp.tests/Properties/Resources.resx | 3 +++ capnpc-csharp.tests/Resources/UnitTest3.capnp.bin | Bin 0 -> 848 bytes capnpc-csharp.tests/UnitTest3.capnp | 6 ++++++ capnpc-csharp.tests/UnitTests.cs | 7 +++++++ 5 files changed, 26 insertions(+) create mode 100644 capnpc-csharp.tests/Resources/UnitTest3.capnp.bin create mode 100644 capnpc-csharp.tests/UnitTest3.capnp diff --git a/capnpc-csharp.tests/Properties/Resources.Designer.cs b/capnpc-csharp.tests/Properties/Resources.Designer.cs index 6840817..26b2a07 100644 --- a/capnpc-csharp.tests/Properties/Resources.Designer.cs +++ b/capnpc-csharp.tests/Properties/Resources.Designer.cs @@ -79,5 +79,15 @@ namespace capnpc_csharp.Tests.Properties { return ((byte[])(obj)); } } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] UnitTest3_capnp { + get { + object obj = ResourceManager.GetObject("UnitTest3_capnp", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/capnpc-csharp.tests/Properties/Resources.resx b/capnpc-csharp.tests/Properties/Resources.resx index a67f487..20c6d62 100644 --- a/capnpc-csharp.tests/Properties/Resources.resx +++ b/capnpc-csharp.tests/Properties/Resources.resx @@ -118,6 +118,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\UnitTest3.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\UnitTest2.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/capnpc-csharp.tests/Resources/UnitTest3.capnp.bin b/capnpc-csharp.tests/Resources/UnitTest3.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..c0a1dae51d34da223a748dbfd981e4e9e939341d GIT binary patch literal 848 zcmZQzU|`4uVhCVi5CkG&LzEDvO}05OosU)UiD6Er!*eyR_&ndA8h^vsL8NjCNCu?g%?6JyA%uOvWNK8&e zQU$UX-CQJTFcZxj1`ePoNFU6doIrjM5TBd)@n7ZglusbO77(M`2jT;Tar#pNB#Fg6 zAb-vRVz4``tP=C`@=Fp+GV}9_LFy3zE-+>0&_OPA>4u=s$ d(j~}$;y{cZj}Y~U^apZx7ZB^C2Ov-k1OQ2Lc9sAD literal 0 HcmV?d00001 diff --git a/capnpc-csharp.tests/UnitTest3.capnp b/capnpc-csharp.tests/UnitTest3.capnp new file mode 100644 index 0000000..14abe12 --- /dev/null +++ b/capnpc-csharp.tests/UnitTest3.capnp @@ -0,0 +1,6 @@ +@0xb7158f7fa52b8db6; + +using Cxx = import "/capnp/c++.capnp"; + +$Cxx.namespace("Foo.Bar.Baz"); + diff --git a/capnpc-csharp.tests/UnitTests.cs b/capnpc-csharp.tests/UnitTests.cs index dd37864..987f6e1 100644 --- a/capnpc-csharp.tests/UnitTests.cs +++ b/capnpc-csharp.tests/UnitTests.cs @@ -40,6 +40,13 @@ namespace CapnpC // Should not throw } + [TestMethod] + public void Test03NonGeneratedNodeSkip() + { + var model = Load(Resources.UnitTest3_capnp); + // Should not throw + } + static Generator.CodeGenerator NewGeneratorFor(Model.SchemaModel model) => new Generator.CodeGenerator(model, new Generator.GeneratorOptions()); From 881a59b2c988a779dd175f0135860520e012278f Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 12:01:08 -0400 Subject: [PATCH 06/15] Test namespace generation in imported types. --- .../Properties/Resources.Designer.cs | 10 ++++++++ capnpc-csharp.tests/Properties/Resources.resx | 3 +++ .../Resources/UnitTest10.capnp.bin | Bin 0 -> 1616 bytes capnpc-csharp.tests/UnitTest10.capnp | 9 +++++++ capnpc-csharp.tests/UnitTest10b.capnp | 7 +++++ capnpc-csharp.tests/UnitTests.cs | 24 ++++++++++++++++++ capnpc-csharp/Generator/GenNames.cs | 2 +- 7 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 capnpc-csharp.tests/Resources/UnitTest10.capnp.bin create mode 100644 capnpc-csharp.tests/UnitTest10.capnp create mode 100644 capnpc-csharp.tests/UnitTest10b.capnp diff --git a/capnpc-csharp.tests/Properties/Resources.Designer.cs b/capnpc-csharp.tests/Properties/Resources.Designer.cs index 26b2a07..ad396a7 100644 --- a/capnpc-csharp.tests/Properties/Resources.Designer.cs +++ b/capnpc-csharp.tests/Properties/Resources.Designer.cs @@ -70,6 +70,16 @@ namespace capnpc_csharp.Tests.Properties { } } + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] UnitTest10_capnp { + get { + object obj = ResourceManager.GetObject("UnitTest10_capnp", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// diff --git a/capnpc-csharp.tests/Properties/Resources.resx b/capnpc-csharp.tests/Properties/Resources.resx index 20c6d62..43736d8 100644 --- a/capnpc-csharp.tests/Properties/Resources.resx +++ b/capnpc-csharp.tests/Properties/Resources.resx @@ -118,6 +118,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\UnitTest10.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\UnitTest3.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/capnpc-csharp.tests/Resources/UnitTest10.capnp.bin b/capnpc-csharp.tests/Resources/UnitTest10.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..dade3aa90ae451daf5849f33963c81461de09820 GIT binary patch literal 1616 zcmaJ>ziSjx5T3o{qKO7CL5ZDMiAGFf=Qe^6jRX|@(b&j(o^XZlj=N2vK}aN3Vv~Rb zEdr^6jkYFYM2kcl@y9>lzYr^fD1P62JMQhv?G4PE_h#PAelzoCMMOS<9d*k9HbVuG zui#_YcY_1)6wb?#BKz!m6l+m>Wbn(g$(Iv<-W;&n{ACBGdGIcH2wX%^#?PbEw`bn1 z>~5`>aG?kUvsXr6Pe1zg*1zA2INzW=0_l*s8zr2(Eb^>}#_7wd_nZRwKZce#Pe2}r z?1XoH?#YkR$LZBU+{IN{-V7GD-#>koMI~|)#t*QMLAK(Bsx3|a?s+ly{niHi!nj)R z!1L~haRYY04g=7iZxdPZ9c*K3RT1YB6z3q>w{gf$b+~D&@r_C|9veMVj_RhavD`Zf zMDsxyISalz6;~RN&R!7hJI@7Vd>E3M`#9-Ozl*h67+#1PTpsdjLiXb$<>6rmBQ(+d zO0yo7D|!JkXcM=^Y`0z<*`N3+&R(3afj=+q{C%)?_b1P%!2b7mhB`M-&Qo5V&tb7R z!Z0$X7DsWlW}4RF|B}}IPLlCuV{Bzzo~b=CYvJuz1B{B)Q8t0Xy^WaYDs`galb}7CDe{wvcYTz0RAj*Svha&WY-o_aQLzB{C(=U%y*~f%&mt{BNao&Ca8~W6h86 VmVSzp{!8Eye*mB(rE# new Generator.CodeGenerator(model, new Generator.GeneratorOptions()); diff --git a/capnpc-csharp/Generator/GenNames.cs b/capnpc-csharp/Generator/GenNames.cs index f71a253..ea6b3a3 100644 --- a/capnpc-csharp/Generator/GenNames.cs +++ b/capnpc-csharp/Generator/GenNames.cs @@ -235,7 +235,7 @@ namespace CapnpC.Generator return qtype; } - NameSyntax GetQName(Model.Type type, TypeDefinition scope) + internal NameSyntax GetQName(Model.Type type, TypeDefinition scope) { // FIXME: With the help of the 'scope' parameter we will be able to generate abbreviated // qualified names. Unfortunately the commented approach is too naive. It will fail if From 84385bbecd848197a162cc93e7695c8667863be1 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 11:57:37 -0400 Subject: [PATCH 07/15] Test annotations and constants in schemas processed for generation. --- .../Properties/Resources.Designer.cs | 10 ++++++++++ capnpc-csharp.tests/Properties/Resources.resx | 3 +++ .../Resources/UnitTest20.capnp.bin | Bin 0 -> 736 bytes capnpc-csharp.tests/UnitTest20.capnp | 5 +++++ capnpc-csharp.tests/UnitTests.cs | 9 +++++++++ 5 files changed, 27 insertions(+) create mode 100644 capnpc-csharp.tests/Resources/UnitTest20.capnp.bin create mode 100644 capnpc-csharp.tests/UnitTest20.capnp diff --git a/capnpc-csharp.tests/Properties/Resources.Designer.cs b/capnpc-csharp.tests/Properties/Resources.Designer.cs index ad396a7..65b57b9 100644 --- a/capnpc-csharp.tests/Properties/Resources.Designer.cs +++ b/capnpc-csharp.tests/Properties/Resources.Designer.cs @@ -90,6 +90,16 @@ namespace capnpc_csharp.Tests.Properties { } } + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] UnitTest20_capnp { + get { + object obj = ResourceManager.GetObject("UnitTest20_capnp", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// diff --git a/capnpc-csharp.tests/Properties/Resources.resx b/capnpc-csharp.tests/Properties/Resources.resx index 43736d8..5c256ea 100644 --- a/capnpc-csharp.tests/Properties/Resources.resx +++ b/capnpc-csharp.tests/Properties/Resources.resx @@ -121,6 +121,9 @@ ..\Resources\UnitTest10.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\UnitTest20.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\UnitTest3.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/capnpc-csharp.tests/Resources/UnitTest20.capnp.bin b/capnpc-csharp.tests/Resources/UnitTest20.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..48f5e96c07e29ed4b7740691d998d795288f8924 GIT binary patch literal 736 zcmZQzU|@&_VhCVi5CkUtNHfmj~MW&vU#lR*$j_ycJM26iyX10-1)*cc|2WUWZ7 z+I@~2EQ*`R1xj@RaVZe1<5mWjdFP!f)AZ!QIgoo;fi8gA16KfL6awi_KwJyN5SKwD zDu5I-*yRvDjI5V(w0`EX-~z~8kl%2bn+cS=1;iltBAZ(P new Generator.CodeGenerator(model, new Generator.GeneratorOptions()); From 2b3d833f6d2d2e0d7fdeff433e6736f614363063 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 12:59:57 -0400 Subject: [PATCH 08/15] Clean up schema paths. --- capnpc-csharp/Schema/schema-with-offsets.capnp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/capnpc-csharp/Schema/schema-with-offsets.capnp b/capnpc-csharp/Schema/schema-with-offsets.capnp index 709eaab..45fe760 100644 --- a/capnpc-csharp/Schema/schema-with-offsets.capnp +++ b/capnpc-csharp/Schema/schema-with-offsets.capnp @@ -1,6 +1,6 @@ -# F:/Downloads/capnproto-c++-win32-0.7.0/capnproto-c++-0.7.0/src/capnp/schema-priv.capnp +# schema.capnp @0xa93fc509624c72d9; -$import "/F:/Downloads/capnproto-c++-win32-0.7.0/capnproto-c++-0.7.0/src/capnp/c++.capnp".namespace("capnp::schema"); +$import "/capnp/c++.capnp".namespace("capnp::schema"); struct Node @0xe682ab4cf923a417 { # 40 bytes, 6 ptrs id @0 :UInt64; # bits[0, 64) displayName @1 :Text; # ptr[0] From 1aff6150367b77be27c1eaa4e024624ae6064476 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 13:02:32 -0400 Subject: [PATCH 09/15] Test for success on Schema.capnp. --- .../Properties/Resources.Designer.cs | 10 ++++++++++ capnpc-csharp.tests/Properties/Resources.resx | 3 +++ .../Resources/schema-with-offsets.capnp.bin | Bin 0 -> 32728 bytes capnpc-csharp.tests/UnitTests.cs | 9 +++++++++ 4 files changed, 22 insertions(+) create mode 100644 capnpc-csharp.tests/Resources/schema-with-offsets.capnp.bin diff --git a/capnpc-csharp.tests/Properties/Resources.Designer.cs b/capnpc-csharp.tests/Properties/Resources.Designer.cs index 65b57b9..7c7c2e9 100644 --- a/capnpc-csharp.tests/Properties/Resources.Designer.cs +++ b/capnpc-csharp.tests/Properties/Resources.Designer.cs @@ -60,6 +60,16 @@ namespace capnpc_csharp.Tests.Properties { } } + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] schema_with_offsets_capnp { + get { + object obj = ResourceManager.GetObject("schema_with_offsets_capnp", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// diff --git a/capnpc-csharp.tests/Properties/Resources.resx b/capnpc-csharp.tests/Properties/Resources.resx index 5c256ea..6d2bda3 100644 --- a/capnpc-csharp.tests/Properties/Resources.resx +++ b/capnpc-csharp.tests/Properties/Resources.resx @@ -133,4 +133,7 @@ ..\Resources\UnitTest1.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\schema-with-offsets.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/capnpc-csharp.tests/Resources/schema-with-offsets.capnp.bin b/capnpc-csharp.tests/Resources/schema-with-offsets.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..1b61d19b96dfc024e9758bc7601e89eee6f97438 GIT binary patch literal 32728 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 qGV(jfG~^HBVEfz$4*nj7GA2u(iGQadU(S new Generator.CodeGenerator(model, new Generator.GeneratorOptions()); From 8d9c3a8b572dbb84959e4aedfc06d863255fc886 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 10:28:36 -0400 Subject: [PATCH 10/15] Fix by renaming enumerants that happen to be keywords. This fixes e.g. the compilation of capnp/schema.capnp. --- capnpc-csharp/Model/Enumerant.cs | 6 +++++- capnpc-csharp/Model/IdentifierRenamer.cs | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 capnpc-csharp/Model/IdentifierRenamer.cs diff --git a/capnpc-csharp/Model/Enumerant.cs b/capnpc-csharp/Model/Enumerant.cs index 99d53fc..96d9137 100644 --- a/capnpc-csharp/Model/Enumerant.cs +++ b/capnpc-csharp/Model/Enumerant.cs @@ -2,8 +2,12 @@ { class Enumerant { + string _literal; public TypeDefinition TypeDefinition { get; set; } - public string Literal { get; set; } + public string Literal { + get => _literal; + set => _literal = IdentifierRenamer.ToNonKeyword(value); + } public ushort? Ordinal { get; set; } public int CodeOrder { get; set; } } diff --git a/capnpc-csharp/Model/IdentifierRenamer.cs b/capnpc-csharp/Model/IdentifierRenamer.cs new file mode 100644 index 0000000..9c6ff07 --- /dev/null +++ b/capnpc-csharp/Model/IdentifierRenamer.cs @@ -0,0 +1,22 @@ +using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CapnpC.Model +{ + public class IdentifierRenamer + { + public static bool IsAnyKeyword(string str) + { + return SyntaxFacts.GetKeywordKind(str) != SyntaxKind.None + || SyntaxFacts.GetContextualKeywordKind(str) != SyntaxKind.None; + } + public static string ToNonKeyword(string str) + { + // Capnp schema identifiers should be already valid, but could be a keyword + if (IsAnyKeyword(str)) return $"@{str}"; + return str; + } + } +} From a0fcb9367690b3cd77352949119f7c35292907e9 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 02:14:40 -0400 Subject: [PATCH 11/15] Fix a type name clash with the immediately enclosing type. --- capnpc-csharp/Generator/GenNames.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/capnpc-csharp/Generator/GenNames.cs b/capnpc-csharp/Generator/GenNames.cs index ea6b3a3..251d393 100644 --- a/capnpc-csharp/Generator/GenNames.cs +++ b/capnpc-csharp/Generator/GenNames.cs @@ -563,7 +563,8 @@ namespace CapnpC.Generator } var typeNames = new HashSet(def.NestedTypes.Select(t => MakeTypeName(t))); - + typeNames.Add(MakeTypeName(def)); + foreach (var member in def.Fields) { var memberName = new Name(SyntaxHelpers.MakeCamel(member.Name)); From 92a7c03cb256aa428377a6ad1ae1a1085384979c Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 09:45:48 -0400 Subject: [PATCH 12/15] Fix attempted use of incomplete dependent types in schema model. Resolve node hierarchy and names in a new 1st pass before generating types in pass2. Consider imported files. --- capnpc-csharp/Model/SchemaModel.cs | 441 ++++++++++++------- capnpc-csharp/Model/Type.cs | 7 + capnpc-csharp/Model/TypeDefinitionManager.cs | 28 +- 3 files changed, 308 insertions(+), 168 deletions(-) diff --git a/capnpc-csharp/Model/SchemaModel.cs b/capnpc-csharp/Model/SchemaModel.cs index 0e6b5be..23e0906 100644 --- a/capnpc-csharp/Model/SchemaModel.cs +++ b/capnpc-csharp/Model/SchemaModel.cs @@ -9,19 +9,18 @@ namespace CapnpC.Model class SchemaModel { readonly Schema.CodeGeneratorRequest.Reader _request; - readonly List _files = new List(); - readonly Stack _typeNest = new Stack(); + readonly List _generatedFiles = new List(); + Dictionary _allDefinitions = new Dictionary(); readonly TypeDefinitionManager _typeDefMgr = new TypeDefinitionManager(); - Method _currentMethod; - Dictionary _id2node; + readonly Dictionary _id2node = new Dictionary(); public SchemaModel(Schema.CodeGeneratorRequest.Reader request) { _request = request; } - public IReadOnlyList FilesToGenerate => _files; + public IReadOnlyList FilesToGenerate => _generatedFiles; Schema.Node.Reader IdToNode(ulong id) { @@ -42,69 +41,196 @@ namespace CapnpC.Model throw new InvalidSchemaException("No nodes, nothing to generate"); } - try + foreach (var node in _request.Nodes) { - _id2node = _request.Nodes.ToDictionary(n => n.Id); - } - catch (ArgumentException) - { - throw new InvalidSchemaException("Nodes with duplicate IDs detected"); - } - - foreach (var reqFile in _request.RequestedFiles) - { - var file = new GenFile() + if (_id2node.TryGetValue(node.Id, out var existingNode)) { - Name = reqFile.Filename - }; + throw new InvalidSchemaException($"Node {node.StrId()} \"{node.DisplayName}\" has a duplicate ID, prior node was \"{existingNode.DisplayName}\""); + } + _id2node[node.Id] = node; + } - _files.Add(file); - _typeNest.Push(file); + BuildPass1(); + BuildPass2(); + } - var fileNode = IdToNode(reqFile.Id); + // First pass: create type definitions for each node. - if (!fileNode.IsFile) - throw new InvalidSchemaException("Expected a file node"); + struct Pass1State + { + public HashSet unprocessedNodes; + public bool isGenerated; + public IHasNestedDefinitions parent; + } - ProcessFile(fileNode); - - _typeNest.Pop(); + void BuildPass1() + { + Pass1State state = new Pass1State() + { + unprocessedNodes = new HashSet(_id2node.Keys) + }; + var requestedFiles = _request.RequestedFiles.ToDictionary(req => req.Id); + foreach (var node in _id2node.Values.Where(n => n.IsFile)) + { + GenFile file; + state.isGenerated = requestedFiles.TryGetValue(node.Id, out var req); + state.parent = null; + if (state.isGenerated) + { + file = (GenFile)ProcessNodePass1(node.Id, req.Filename, state); + _generatedFiles.Add(file); + } + else + { + file = (GenFile)ProcessNodePass1(node.Id, node.DisplayName, state); + } + _allDefinitions.Add(node.Id, file); + } + if (state.unprocessedNodes.Count != 0) + { + throw new InvalidSchemaException("Unreferenced nodes were present in the schema."); } } - void ProcessFile(Schema.Node.Reader fileReader) + TypeDefinition CreateTypeDef(Schema.Node.Reader node, IHasNestedDefinitions parent) { - foreach (var annotation in fileReader.Annotations) + var kind = node.GetKind(); + var def = _typeDefMgr.Create(node.Id, kind.GetTypeTag()); + def.DeclaringElement = parent; + if (kind == NodeKind.Group) + ((TypeDefinition)parent).NestedGroups.Add(def); + else + parent.NestedTypes.Add(def); + return def; + } + + IHasNestedDefinitions ProcessNodePass1(ulong id, string name, Pass1State state) + { + if (!_id2node.TryGetValue(id, out var node)) + { + if (!state.isGenerated) return null; + throw new InvalidSchemaException($"The node {id.StrId()} was necessary for backend codegen but is missing."); + } + + if (!state.unprocessedNodes.Remove(id)) + throw new InvalidSchemaException($"The node \"{node.DisplayName}\" {node.StrId()} has been declared recursively."); + + GenFile file = null; + bool processNestedNodes = false; + bool processFields = false; + bool processInterfaceMethods = false; + + switch (node.GetKind()) + { + case NodeKind.Annotation: + case NodeKind.Const: + // A dummy TypeDefinition is created to node hierarchy + break; + case NodeKind.File: + if (state.parent != null) + throw new InvalidSchemaException("Did not expect file nodes to appear as nested nodes"); + file = new GenFile(); + file.Namespace = null; // TODO + processNestedNodes = true; + break; + case NodeKind.Enum: + break; + case NodeKind.Interface: + processNestedNodes = true; + processFields = true; + processInterfaceMethods = true; + break; + case NodeKind.Struct: + case NodeKind.Group: + processNestedNodes = true; + processFields = true; + break; + default: + throw new InvalidSchemaException($"Don't know how to process node {node.StrId()} \"{node.DisplayName}\""); + } + + TypeDefinition def = null; + if (file != null) + { + state.parent = file; + file.Name = name; + } + else + { + state.parent = def = CreateTypeDef(node, state.parent); + def.Name = name; + } + + if (processNestedNodes && node.NestedNodes != null) + foreach (var nested in node.NestedNodes) + { + ProcessNodePass1(nested.Id, nested.Name, state); + } + if (processFields && node.Fields != null) + foreach (var field in node.Fields.Where(f => f.IsGroup)) + { + var group = IdToNode(field.Group_TypeId); + if (!group.IsStruct || !group.Struct_IsGroup) + { + throw new InvalidSchemaException($"Expected node with id {group.StrId()} to be a struct definition"); + } + ProcessNodePass1(field.Group_TypeId, field.Name, state); + } + if (processInterfaceMethods && node.Interface_Methods != null) + foreach (var method in node.Interface_Methods) + { + var pnode = IdToNode(method.ParamStructType); + if (pnode.ScopeId == 0) ProcessNodePass1(pnode.Id, null, state); // Anonymous generated type + pnode = IdToNode(method.ResultStructType); + if (pnode.ScopeId == 0) ProcessNodePass1(pnode.Id, null, state); // Anonymous generated type + } + return state.parent; + } + + // 2nd pass: Generate types based on definitions + + struct Pass2State + { + public Method currentMethod; + public HashSet processedNodes; + } + + void BuildPass2() + { + var files = _allDefinitions.Select(d => (Id: d.Key, File: d.Value as GenFile)).Where(d => d.File != null); + var state = new Pass2State() { processedNodes = new HashSet() }; + foreach (var file in files) + { + var node = IdToNode(file.Id); + ProcessFileAnnotations(node, file.File); + ProcessNestedNodes(node.NestedNodes, state); + } + } + + void ProcessNestedNodes(IEnumerable nestedNodes, Pass2State state) + { + foreach (var nestedNode in nestedNodes) + { + ProcessNode(nestedNode.Id, state); + } + } + + void ProcessFileAnnotations(Schema.Node.Reader fileNode, GenFile fileElement) + { + foreach (var annotation in fileNode.Annotations) { if (annotation.Id == 0xb9c6f99ebf805f2c) // Cxx namespace { - ((GenFile)_typeNest.Peek()).Namespace = annotation.Value.Text.Split("::"); + fileElement.Namespace = annotation.Value.Text.Split(new string[1] { "::" }, default); } } - - foreach (var nestedNode in fileReader.NestedNodes) - { - var node = IdToNode(nestedNode.Id); - - ProcessNode(node, nestedNode.Name); - } } - TypeDefinition GetOrCreateTypeDef(ulong id, TypeTag tag) => _typeDefMgr.GetOrCreate(id, tag); - TypeDefinition GetGroupTypeDef(ulong id, string name) - { - var nodeReader = _id2node[id]; - - if (!nodeReader.IsStruct) - throw new InvalidSchemaException($"Expected node with id {id} to be a struct definition"); - - return ProcessStruct(nodeReader, name); - } - void ProcessBrand(Schema.Brand.Reader brandReader, Type type) + void ProcessBrand(Schema.Brand.Reader brandReader, Type type, Pass2State state) { foreach (var scopeReader in brandReader.Scopes) { - var whatToBind = GetOrCreateTypeDef(scopeReader.ScopeId, TypeTag.Unknown); + var whatToBind = ProcessNode(scopeReader.ScopeId, state); int index = 0; switch (0) @@ -121,7 +247,7 @@ namespace CapnpC.Model switch (0) { case 0 when bindingReader.IsType: - type.BindGenericParameter(typeParameter, ProcessType(bindingReader.Type)); + type.BindGenericParameter(typeParameter, ProcessType(bindingReader.Type, state)); break; case 0 when bindingReader.IsUnbound: @@ -146,7 +272,8 @@ namespace CapnpC.Model } } } - Type ProcessType(Schema.Type.Reader typeReader) + + Type ProcessType(Schema.Type.Reader typeReader, Pass2State state) { Type result; @@ -159,7 +286,7 @@ namespace CapnpC.Model return Types.FromParameter( new GenericParameter() { - DeclaringEntity = GetOrCreateTypeDef(typeReader.AnyPointer_Parameter_ScopeId, TypeTag.Unknown), + DeclaringEntity = ProcessNode(typeReader.AnyPointer_Parameter_ScopeId, state), Index = typeReader.AnyPointer_Parameter_ParameterIndex }); @@ -167,7 +294,7 @@ namespace CapnpC.Model return Types.FromParameter( new GenericParameter() { - DeclaringEntity = _currentMethod ?? throw new InvalidOperationException("current method not set"), + DeclaringEntity = state.currentMethod ?? throw new InvalidOperationException("current method not set"), Index = typeReader.AnyPointer_ImplicitMethodParameter_ParameterIndex }); @@ -205,7 +332,7 @@ namespace CapnpC.Model return Types.F64; case 0 when typeReader.IsEnum: - return Types.FromDefinition(GetOrCreateTypeDef(typeReader.Enum_TypeId, TypeTag.Enum)); + return Types.FromDefinition(ProcessNode(typeReader.Enum_TypeId, state, TypeTag.Enum)); case 0 when typeReader.IsFloat32: return Types.F32; @@ -223,16 +350,16 @@ namespace CapnpC.Model return Types.S8; case 0 when typeReader.IsInterface: - result = Types.FromDefinition(GetOrCreateTypeDef(typeReader.Interface_TypeId, TypeTag.Interface)); - ProcessBrand(typeReader.Interface_Brand, result); + result = Types.FromDefinition(ProcessNode(typeReader.Interface_TypeId, state, TypeTag.Interface)); + ProcessBrand(typeReader.Interface_Brand, result, state); return result; case 0 when typeReader.IsList: - return Types.List(ProcessType(typeReader.List_ElementType)); + return Types.List(ProcessType(typeReader.List_ElementType, state)); case 0 when typeReader.IsStruct: - result = Types.FromDefinition(GetOrCreateTypeDef(typeReader.Struct_TypeId, TypeTag.Struct)); - ProcessBrand(typeReader.Struct_Brand, result); + result = Types.FromDefinition(ProcessNode(typeReader.Struct_TypeId, state, TypeTag.Struct)); + ProcessBrand(typeReader.Struct_Brand, result, state); return result; case 0 when typeReader.IsText: @@ -365,7 +492,7 @@ namespace CapnpC.Model return value; } - void ProcessFields(Schema.Node.Reader reader, TypeDefinition declaringType, List fields) + void ProcessFields(Schema.Node.Reader reader, TypeDefinition declaringType, List fields, Pass2State state) { if (reader.Fields == null) { @@ -389,15 +516,15 @@ namespace CapnpC.Model switch (0) { case 0 when fieldReader.IsGroup: - field.Type = Types.FromDefinition(GetGroupTypeDef( - fieldReader.Group_TypeId, fieldReader.Name)); + var def = ProcessNode(fieldReader.Group_TypeId, state, TypeTag.Group); + field.Type = Types.FromDefinition(def); break; case 0 when fieldReader.IsSlot: field.DefaultValue = ProcessValue(fieldReader.Slot_DefaultValue); field.DefaultValueIsExplicit = fieldReader.Slot_HadExplicitDefault; field.Offset = fieldReader.Slot_Offset; - field.Type = ProcessType(fieldReader.Slot_Type); + field.Type = ProcessType(fieldReader.Slot_Type, state); field.DefaultValue.Type = field.Type; break; @@ -411,7 +538,7 @@ namespace CapnpC.Model } } - void ProcessInterfaceOrStructTail(TypeDefinition def, Schema.Node.Reader reader) + TypeDefinition ProcessInterfaceOrStructTail(TypeDefinition def, Schema.Node.Reader reader, Pass2State state) { def.IsGeneric = reader.IsGeneric; @@ -423,18 +550,9 @@ namespace CapnpC.Model } } - _typeNest.Push(def); + ProcessNestedNodes(reader.NestedNodes, state); - if (reader.NestedNodes != null) - { - foreach (var nestedReader in reader.NestedNodes) - { - var node = IdToNode(nestedReader.Id); - ProcessNode(node, nestedReader.Name); - } - } - - ProcessFields(reader, def, def.Fields); + ProcessFields(reader, def, def.Fields, state); if (reader.IsInterface) { @@ -450,12 +568,12 @@ namespace CapnpC.Model { method.GenericParameters.Add(implicitParameterReader.Name); } - _currentMethod = method; + state.currentMethod = method; def.Methods.Add(method); var paramNode = IdToNode(methodReader.ParamStructType); - var paramType = ProcessParameterList(paramNode, methodReader.ParamBrand, method.Params); + var paramType = ProcessParameterList(paramNode, methodReader.ParamBrand, method.Params, state); if (paramType != null) { paramType.SpecialName = SpecialName.MethodParamsStruct; @@ -470,7 +588,7 @@ namespace CapnpC.Model method.ParamsStruct.InheritFreeParameters(method); var resultNode = IdToNode(methodReader.ResultStructType); - var resultType = ProcessParameterList(resultNode, methodReader.ResultBrand, method.Results); + var resultType = ProcessParameterList(resultNode, methodReader.ResultBrand, method.Results, state); if (resultType != null) { resultType.SpecialName = SpecialName.MethodResultStruct; @@ -485,24 +603,13 @@ namespace CapnpC.Model method.ResultStruct.InheritFreeParameters(method); } - _currentMethod = null; + state.currentMethod = null; } - - _typeNest.Pop(); + return def; } - TypeDefinition ProcessStruct(Schema.Node.Reader structReader, string name) + TypeDefinition ProcessStruct(Schema.Node.Reader structReader, TypeDefinition def, Pass2State state) { - var def = GetOrCreateTypeDef( - structReader.Id, - structReader.Struct_IsGroup ? TypeTag.Group : TypeTag.Struct); - - def.DeclaringElement = _typeNest.Peek(); - if (structReader.Struct_IsGroup) - ((TypeDefinition)def.DeclaringElement).NestedGroups.Add(def); - else - def.DeclaringElement.NestedTypes.Add(def); - def.Name = name; def.StructDataWordCount = structReader.Struct_DataWordCount; def.StructPointerCount = structReader.Struct_PointerCount; @@ -513,12 +620,10 @@ namespace CapnpC.Model 16u * structReader.Struct_DiscriminantOffset); } - ProcessInterfaceOrStructTail(def, structReader); - - return def; + return ProcessInterfaceOrStructTail(def, structReader, state); } - TypeDefinition ProcessParameterList(Schema.Node.Reader reader, Schema.Brand.Reader brandReader, List list) + TypeDefinition ProcessParameterList(Schema.Node.Reader reader, Schema.Brand.Reader brandReader, List list, Pass2State state) { //# If a named parameter list was specified in the method //# declaration (rather than a single struct parameter type) then a corresponding struct type is @@ -533,58 +638,38 @@ namespace CapnpC.Model throw new InvalidSchemaException("Expected a struct"); } + var def = ProcessNode(reader.Id, state, TypeTag.Struct); + if (reader.ScopeId == 0) { // Auto-generated => Named parameter list - ProcessFields(reader, null, list); - return ProcessStruct(reader, null); + foreach (var field in def.Fields) list.Add(field); + return def; } else { // Single, anonymous, struct-typed parameter - var def = GetOrCreateTypeDef(reader.Id, TypeTag.Struct); var type = Types.FromDefinition(def); - ProcessBrand(brandReader, type); + ProcessBrand(brandReader, type, state); var anon = new Field() { Type = type }; list.Add(anon); return null; } } - TypeDefinition ProcessInterface(Schema.Node.Reader ifaceReader, string name) + TypeDefinition ProcessInterface(Schema.Node.Reader ifaceReader, TypeDefinition def, Pass2State state) { - var def = GetOrCreateTypeDef( - ifaceReader.Id, - TypeTag.Interface); - - def.DeclaringElement = _typeNest.Peek(); - def.DeclaringElement.NestedTypes.Add(def); - def.Name = name; - foreach (var superClassReader in ifaceReader.Interface_Superclasses) { - var superClass = GetOrCreateTypeDef( - superClassReader.Id, - TypeTag.Interface); - + var superClass = ProcessNode(superClassReader.Id, state, TypeTag.Interface); def.Superclasses.Add(Types.FromDefinition(superClass)); } - ProcessInterfaceOrStructTail(def, ifaceReader); - - return def; + return ProcessInterfaceOrStructTail(def, ifaceReader, state); } - void ProcessEnum(Schema.Node.Reader enumReader, string name) + TypeDefinition ProcessEnum(Schema.Node.Reader enumReader, TypeDefinition def, Pass2State state) { - var def = GetOrCreateTypeDef(enumReader.Id, TypeTag.Enum); - - def.DeclaringElement = _typeNest.Peek(); - def.DeclaringElement.NestedTypes.Add(def); - def.Name = name; - - _typeNest.Push(def); - foreach (var fieldReader in enumReader.Enumerants) { var field = new Enumerant() @@ -601,46 +686,41 @@ namespace CapnpC.Model def.Enumerants.Add(field); } - - _typeNest.Pop(); + return def; } - void ProcessConst(Schema.Node.Reader constReader, string name) + Value ProcessConst(Schema.Node.Reader constReader, Pass2State state) { var value = ProcessValue(constReader.Const_Value); - value.Type = ProcessType(constReader.Const_Type); - - _typeNest.Peek().Constants.Add(value); + value.Type = ProcessType(constReader.Const_Type, state); + return value; } - void ProcessNode(Schema.Node.Reader node, string name) + TypeDefinition ProcessNode(ulong id, Pass2State state, TypeTag tag = default) { - switch (0) + var node = IdToNode(id); + var kind = node.GetKind(); + if (tag == TypeTag.Unknown) tag = kind.GetTypeTag(); + var def = _typeDefMgr.GetExisting(id, tag); + if (state.processedNodes.Contains(id)) return def; + state.processedNodes.Add(id); + + switch (kind) { - case 0 when node.IsAnnotation: - break; - - case 0 when node.IsConst: - ProcessConst(node, name); - break; - - case 0 when node.IsEnum: - ProcessEnum(node, name); - break; - - case 0 when node.IsFile: - throw new InvalidSchemaException("Did not expect file nodes to appear as nested nodes"); - - case 0 when node.IsInterface: - ProcessInterface(node, name); - break; - - case 0 when node.IsStruct: - ProcessStruct(node, name); - break; - + case NodeKind.Annotation: + return def; + case NodeKind.Const: + def.DeclaringElement.Constants.Add(ProcessConst(node, state)); + return def; + case NodeKind.Enum: + return ProcessEnum(node, def, state); + case NodeKind.Interface: + return ProcessInterface(node, def, state); + case NodeKind.Struct: + case NodeKind.Group: + return ProcessStruct(node, def, state); default: - throw new InvalidSchemaException($"Don't know how to process node {node.DisplayName}"); + throw new InvalidProgramException($"An unexpected node {node.StrId()} was found during the 2nd schema model building pass."); } } @@ -651,4 +731,55 @@ namespace CapnpC.Model return model; } } + + public enum NodeKind + { + Unknown, + Annotation, + Const, + Enum, + File, + Interface, + Struct, + Group + } + + public static class SchemaExtensions + { + public static string GetName(this Schema.Node.Reader node) + => node.DisplayName.Substring((int)node.DisplayNamePrefixLength); + + public static string StrId(this Schema.Node.Reader node) + => $"0x{node.Id.ToString("X")}"; + + public static string StrId(this ulong nodeId) + => $"0x{nodeId.ToString("X")}"; + + public static NodeKind GetKind(this Schema.Node.Reader node) + { + if (node.IsStruct) + return node.Struct_IsGroup ? NodeKind.Group : NodeKind.Struct; + if (node.IsInterface) return NodeKind.Interface; + if (node.IsEnum) return NodeKind.Enum; + if (node.IsConst) return NodeKind.Const; + if (node.IsAnnotation) return NodeKind.Annotation; + if (node.IsFile) return NodeKind.File; + return NodeKind.Unknown; + } + + internal static TypeTag GetTypeTag(this NodeKind kind) + { + switch (kind) + { + case NodeKind.Enum: return TypeTag.Enum; + case NodeKind.Interface: return TypeTag.Interface; + case NodeKind.Struct: return TypeTag.Struct; + case NodeKind.Group: return TypeTag.Group; + default: return TypeTag.Unknown; + } + } + + internal static TypeTag GetTypeTag(this Schema.Node.Reader node) + => node.GetKind().GetTypeTag(); + } } diff --git a/capnpc-csharp/Model/Type.cs b/capnpc-csharp/Model/Type.cs index 3512b2b..c1017df 100644 --- a/capnpc-csharp/Model/Type.cs +++ b/capnpc-csharp/Model/Type.cs @@ -9,9 +9,16 @@ namespace CapnpC.Model { class Type: AbstractType { + // Representation of a type expression in the schema language + public TypeDefinition Definition { get; set; } + // The model for all nodes that are not file nodes - they define types + public GenericParameter Parameter { get; set; } + // A reference to type parameter in this scope + public Type ElementType { get; set; } + // The type of a list element, if this is a list. readonly Dictionary _parameterBindings = new Dictionary(); diff --git a/capnpc-csharp/Model/TypeDefinitionManager.cs b/capnpc-csharp/Model/TypeDefinitionManager.cs index 7c1562e..a734026 100644 --- a/capnpc-csharp/Model/TypeDefinitionManager.cs +++ b/capnpc-csharp/Model/TypeDefinitionManager.cs @@ -8,7 +8,19 @@ namespace CapnpC.Model readonly Dictionary _id2def = new Dictionary(); - public TypeDefinition GetOrCreate(ulong id, TypeTag tag) + public TypeDefinition Create(ulong id, TypeTag tag) + { + if (_id2def.ContainsKey(id)) + { + throw new ArgumentException(nameof(id), $"Attempting to redefine {tag.ToString()} {id.StrId()}."); + } + + var def = new TypeDefinition(tag, id); + _id2def.Add(id, def); + return def; + } + + public TypeDefinition GetExisting(ulong id, TypeTag tag) { if (_id2def.TryGetValue(id, out var def)) { @@ -20,19 +32,9 @@ namespace CapnpC.Model { throw new ArgumentOutOfRangeException(nameof(tag), "Type tag does not match existing type"); } + return def; } - else - { - def = new TypeDefinition(tag, id); - _id2def.Add(id, def); - } - - return def; - } - - public TypeDefinition GetExisting(ulong id) - { - return _id2def[id]; + throw new ArgumentOutOfRangeException($"Attempting to retrieve nonexistend node {id.StrId()}."); } } } From dd83132b5d11106e062f3ea032779a5f1b90c183 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 10:24:10 -0400 Subject: [PATCH 13/15] Fix crash when referencing nodes from imported, non-generated schemas. --- capnpc-csharp/Model/SchemaModel.cs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/capnpc-csharp/Model/SchemaModel.cs b/capnpc-csharp/Model/SchemaModel.cs index 23e0906..830e211 100644 --- a/capnpc-csharp/Model/SchemaModel.cs +++ b/capnpc-csharp/Model/SchemaModel.cs @@ -22,16 +22,18 @@ namespace CapnpC.Model public IReadOnlyList FilesToGenerate => _generatedFiles; + Schema.Node.Reader? IdToNode(ulong id, bool mustExist) + { + if (_id2node.TryGetValue(id, out var node)) + return node; + if (mustExist) + throw new InvalidSchemaException($"Node with ID {id.StrId()} is required by the codegen backend but is missing."); + return null; + } + Schema.Node.Reader IdToNode(ulong id) { - try - { - return _id2node[id]; - } - catch (KeyNotFoundException) - { - throw new InvalidSchemaException($"Node with ID {id} is missing"); - } + return (Schema.Node.Reader)IdToNode(id, true); } void Build() @@ -192,6 +194,7 @@ namespace CapnpC.Model struct Pass2State { public Method currentMethod; + public bool isGenerated; public HashSet processedNodes; } @@ -202,6 +205,7 @@ namespace CapnpC.Model foreach (var file in files) { var node = IdToNode(file.Id); + state.isGenerated = _request.RequestedFiles.Where(req => req.Id == file.Id).Any(); ProcessFileAnnotations(node, file.File); ProcessNestedNodes(node.NestedNodes, state); } @@ -698,7 +702,7 @@ namespace CapnpC.Model TypeDefinition ProcessNode(ulong id, Pass2State state, TypeTag tag = default) { - var node = IdToNode(id); + if (!(IdToNode(id, state.isGenerated) is Schema.Node.Reader node)) return null; var kind = node.GetKind(); if (tag == TypeTag.Unknown) tag = kind.GetTypeTag(); var def = _typeDefMgr.GetExisting(id, tag); From 884040bd669264e154655abacccdc40b43d8ed8a Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 11:38:43 -0400 Subject: [PATCH 14/15] Fix namespace generation in imported types. --- capnpc-csharp/Generator/CodeGenerator.cs | 13 ++------- capnpc-csharp/Generator/GenNames.cs | 34 +++++++++++------------- capnpc-csharp/Model/SchemaModel.cs | 26 +++++++++--------- capnpc-csharp/Model/TypeDefinition.cs | 10 +++++++ 4 files changed, 41 insertions(+), 42 deletions(-) diff --git a/capnpc-csharp/Generator/CodeGenerator.cs b/capnpc-csharp/Generator/CodeGenerator.cs index d066655..1d268d2 100644 --- a/capnpc-csharp/Generator/CodeGenerator.cs +++ b/capnpc-csharp/Generator/CodeGenerator.cs @@ -147,18 +147,9 @@ internal string Transform(GenFile file) { - if (file.Namespace != null) - { - _names.TopNamespace = IdentifierName(MakeCamel(file.Namespace[0])); + NameSyntax topNamespace = GenNames.NamespaceName(file.Namespace) ?? _names.TopNamespace; - foreach (string name in file.Namespace.Skip(1)) - { - var temp = IdentifierName(MakeCamel(name)); - _names.TopNamespace = QualifiedName(_names.TopNamespace, temp); - } - } - - var ns = NamespaceDeclaration(_names.TopNamespace); + var ns = NamespaceDeclaration(topNamespace); foreach (var def in file.NestedTypes) { diff --git a/capnpc-csharp/Generator/GenNames.cs b/capnpc-csharp/Generator/GenNames.cs index 251d393..f842413 100644 --- a/capnpc-csharp/Generator/GenNames.cs +++ b/capnpc-csharp/Generator/GenNames.cs @@ -213,28 +213,23 @@ namespace CapnpC.Generator } } - NameSyntax GetQName(TypeDefinition def) + public static NameSyntax NamespaceName(string[] @namespace) { - var stack = new Stack(); - - stack.Push(MakeGenericTypeName(def, NameUsage.Default)); - - while (def.DeclaringElement is TypeDefinition pdef) + NameSyntax ident = null; + if (@namespace != null) { - stack.Push(MakeGenericTypeName(pdef, NameUsage.Namespace)); - def = pdef; + ident = IdentifierName(SyntaxHelpers.MakeCamel(@namespace[0])); + foreach (string name in @namespace.Skip(1)) + { + var temp = IdentifierName(SyntaxHelpers.MakeCamel(name)); + ident = QualifiedName(ident, temp); + } } - - var qtype = TopNamespace; - - foreach (var name in stack) - { - qtype = QualifiedName(qtype, name); - } - - return qtype; + return ident; } + NameSyntax GetNamespaceFor(TypeDefinition def) => NamespaceName(def?.File?.Namespace); + internal NameSyntax GetQName(Model.Type type, TypeDefinition scope) { // FIXME: With the help of the 'scope' parameter we will be able to generate abbreviated @@ -262,7 +257,10 @@ namespace CapnpC.Generator def = pdef; } - var qtype = TopNamespace; + var qtype = + GetNamespaceFor(type.Definition) + ?? GetNamespaceFor(scope) + ?? TopNamespace; foreach (var name in stack) { diff --git a/capnpc-csharp/Model/SchemaModel.cs b/capnpc-csharp/Model/SchemaModel.cs index 830e211..33b448a 100644 --- a/capnpc-csharp/Model/SchemaModel.cs +++ b/capnpc-csharp/Model/SchemaModel.cs @@ -132,7 +132,7 @@ namespace CapnpC.Model if (state.parent != null) throw new InvalidSchemaException("Did not expect file nodes to appear as nested nodes"); file = new GenFile(); - file.Namespace = null; // TODO + file.Namespace = GetNamespaceAnnotation(node); processNestedNodes = true; break; case NodeKind.Enum: @@ -189,6 +189,18 @@ namespace CapnpC.Model return state.parent; } + string[] GetNamespaceAnnotation(Schema.Node.Reader fileNode) + { + foreach (var annotation in fileNode.Annotations) + { + if (annotation.Id == 0xb9c6f99ebf805f2c) // Cxx namespace + { + return annotation.Value.Text.Split(new string[1] { "::" }, default); + } + } + return null; + } + // 2nd pass: Generate types based on definitions struct Pass2State @@ -206,7 +218,6 @@ namespace CapnpC.Model { var node = IdToNode(file.Id); state.isGenerated = _request.RequestedFiles.Where(req => req.Id == file.Id).Any(); - ProcessFileAnnotations(node, file.File); ProcessNestedNodes(node.NestedNodes, state); } } @@ -219,17 +230,6 @@ namespace CapnpC.Model } } - void ProcessFileAnnotations(Schema.Node.Reader fileNode, GenFile fileElement) - { - foreach (var annotation in fileNode.Annotations) - { - if (annotation.Id == 0xb9c6f99ebf805f2c) // Cxx namespace - { - fileElement.Namespace = annotation.Value.Text.Split(new string[1] { "::" }, default); - } - } - } - void ProcessBrand(Schema.Brand.Reader brandReader, Type type, Pass2State state) { foreach (var scopeReader in brandReader.Scopes) diff --git a/capnpc-csharp/Model/TypeDefinition.cs b/capnpc-csharp/Model/TypeDefinition.cs index ce00e2c..382df18 100644 --- a/capnpc-csharp/Model/TypeDefinition.cs +++ b/capnpc-csharp/Model/TypeDefinition.cs @@ -54,6 +54,16 @@ namespace CapnpC.Model } } + public GenFile File + { + get + { + IHasNestedDefinitions cur = this; + while (cur is TypeDefinition def) cur = def.DeclaringElement; + return cur as GenFile; + } + } + public IEnumerable AllTypeParameters { get From d6d83d54a22d658e03811959edb99e2742b97af8 Mon Sep 17 00:00:00 2001 From: Kuba Ober Date: Thu, 29 Aug 2019 12:10:23 -0400 Subject: [PATCH 15/15] Fix annotations and constants: Factor out type definitions, and add definitions of annotations and constants. The TypeDefinition is no longer overloaded for Annotation and Constant nodes, and the generator is happy again. --- capnpc-csharp/Generator/CodeGenerator.cs | 2 +- capnpc-csharp/Model/Annotation.cs | 19 +++ capnpc-csharp/Model/Constant.cs | 19 +++ capnpc-csharp/Model/DefinitionManager.cs | 67 ++++++++++ capnpc-csharp/Model/GenFile.cs | 20 ++- capnpc-csharp/Model/IDefinition.cs | 10 ++ capnpc-csharp/Model/IHasNestedDefinitions.cs | 12 +- capnpc-csharp/Model/SchemaModel.cs | 128 +++++++++---------- capnpc-csharp/Model/TypeDefinition.cs | 17 ++- capnpc-csharp/Model/TypeDefinitionManager.cs | 40 ------ capnpc-csharp/Model/TypeTag.cs | 5 +- 11 files changed, 215 insertions(+), 124 deletions(-) create mode 100644 capnpc-csharp/Model/Annotation.cs create mode 100644 capnpc-csharp/Model/Constant.cs create mode 100644 capnpc-csharp/Model/DefinitionManager.cs create mode 100644 capnpc-csharp/Model/IDefinition.cs delete mode 100644 capnpc-csharp/Model/TypeDefinitionManager.cs diff --git a/capnpc-csharp/Generator/CodeGenerator.cs b/capnpc-csharp/Generator/CodeGenerator.cs index 1d268d2..e401b3a 100644 --- a/capnpc-csharp/Generator/CodeGenerator.cs +++ b/capnpc-csharp/Generator/CodeGenerator.cs @@ -104,7 +104,7 @@ yield return _interfaceGen.MakePipeliningSupport(def); } - if (def.NestedTypes.Count > 0) + if (def.NestedTypes.Any()) { var ns = ClassDeclaration( _names.MakeTypeName(def, NameUsage.Namespace).ToString()) diff --git a/capnpc-csharp/Model/Annotation.cs b/capnpc-csharp/Model/Annotation.cs new file mode 100644 index 0000000..6dbbd9a --- /dev/null +++ b/capnpc-csharp/Model/Annotation.cs @@ -0,0 +1,19 @@ + +namespace CapnpC.Model +{ + class Annotation : IDefinition + { + public ulong Id { get; } + public TypeTag Tag { get => TypeTag.Annotation; } + public IHasNestedDefinitions DeclaringElement { get; } + + public Type Type { get; set; } + + public Annotation(ulong id, IHasNestedDefinitions parent) + { + Id = id; + DeclaringElement = parent; + parent.NestedDefinitions.Add(this); + } + } +} diff --git a/capnpc-csharp/Model/Constant.cs b/capnpc-csharp/Model/Constant.cs new file mode 100644 index 0000000..a992ca0 --- /dev/null +++ b/capnpc-csharp/Model/Constant.cs @@ -0,0 +1,19 @@ + +namespace CapnpC.Model +{ + class Constant : IDefinition + { + public ulong Id { get; } + public TypeTag Tag { get => TypeTag.Const; } + public IHasNestedDefinitions DeclaringElement { get; } + + public Value Value { get; set; } + + public Constant(ulong id, IHasNestedDefinitions parent) + { + Id = id; + DeclaringElement = parent; + parent.NestedDefinitions.Add(this); + } + } +} diff --git a/capnpc-csharp/Model/DefinitionManager.cs b/capnpc-csharp/Model/DefinitionManager.cs new file mode 100644 index 0000000..4a88fc6 --- /dev/null +++ b/capnpc-csharp/Model/DefinitionManager.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace CapnpC.Model +{ + class DefinitionManager + { + readonly Dictionary _id2def = new Dictionary(); + + public GenFile CreateFile(ulong id) + => CreateId(id, () => new GenFile(id)); + public GenFile GetExistingFile(ulong id) + => GetId(id, TypeTag.File); + + public TypeDefinition CreateTypeDef(ulong id, TypeTag tag, IHasNestedDefinitions decl) + => CreateId(id, () => new TypeDefinition(tag, id, decl)); + public TypeDefinition GetExistingTypeDef(ulong id, TypeTag tag) + { + var def = GetId(id, tag); + if (def.Tag == TypeTag.Unknown) def.Tag = tag; + return def; + } + + public Annotation CreateAnnotation(ulong id, IHasNestedDefinitions decl) + => CreateId(id, () => new Annotation(id, decl)); + public Annotation GetExistingAnnotation(ulong id) + => GetId(id, TypeTag.Annotation); + + public Constant CreateConstant(ulong id, IHasNestedDefinitions decl) + => CreateId(id, () => new Constant(id, decl)); + public Constant GetExistingConstant(ulong id) + => GetId(id, TypeTag.Const); + + public IDefinition GetExistingDef(ulong id, TypeTag tag) + => GetId(id, tag); + + public IEnumerable Files + { + get => _id2def.Values.Where(d => d.Tag == TypeTag.File).Select(f => f as GenFile); + } + + T CreateId(ulong id, Func creator) where T : class, IDefinition + { + if (_id2def.TryGetValue(id, out var d)) + { + throw new ArgumentException(nameof(id), $"Attempting to redefine {d.Tag.ToString()} {id.StrId()} (as {nameof(T)})."); + } + var def = creator(); + _id2def.Add(id, def); + return def as T; + } + + T GetId(ulong id, TypeTag tag) where T : IDefinition + { + if (!_id2def.TryGetValue(id, out var anyDef)) + { + throw new ArgumentOutOfRangeException($"Attempting to retrieve nonexistent node {id.StrId()}."); + } + if (!(anyDef is T def) || (tag != TypeTag.Unknown && def.Tag != tag)) + { + throw new ArgumentOutOfRangeException($"Attempting to retrieve {tag.ToString()} {id.StrId()}, but found {anyDef.Tag.ToString()} instead."); + } + return def; + } + } +} diff --git a/capnpc-csharp/Model/GenFile.cs b/capnpc-csharp/Model/GenFile.cs index 045c975..f912303 100644 --- a/capnpc-csharp/Model/GenFile.cs +++ b/capnpc-csharp/Model/GenFile.cs @@ -1,15 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; namespace CapnpC.Model { - class GenFile: IHasNestedDefinitions + class GenFile: IDefinition, IHasNestedDefinitions { + public ulong Id { get; } + public TypeTag Tag { get => TypeTag.File; } + public IHasNestedDefinitions DeclaringElement { get; } + public string Name { get; set; } public string[] Namespace { get; set; } - public List NestedTypes { get; } = new List(); - public List Constants { get; } = new List(); + public IEnumerable NestedTypes { get => this.GetNestedTypes(); } + public ICollection NestedDefinitions { get; } = new List(); + public ICollection Constants { get; } = new List(); + + public GenFile(ulong id) + { + Id = id; + } } } diff --git a/capnpc-csharp/Model/IDefinition.cs b/capnpc-csharp/Model/IDefinition.cs new file mode 100644 index 0000000..e226d40 --- /dev/null +++ b/capnpc-csharp/Model/IDefinition.cs @@ -0,0 +1,10 @@ + +namespace CapnpC.Model +{ + interface IDefinition + { + ulong Id { get; } + TypeTag Tag { get; } + IHasNestedDefinitions DeclaringElement { get; } + } +} diff --git a/capnpc-csharp/Model/IHasNestedDefinitions.cs b/capnpc-csharp/Model/IHasNestedDefinitions.cs index e9e030b..3885c60 100644 --- a/capnpc-csharp/Model/IHasNestedDefinitions.cs +++ b/capnpc-csharp/Model/IHasNestedDefinitions.cs @@ -1,10 +1,18 @@ using System.Collections.Generic; +using System.Linq; namespace CapnpC.Model { interface IHasNestedDefinitions { - List NestedTypes { get; } - List Constants { get; } + IEnumerable NestedTypes { get; } + ICollection NestedDefinitions { get; } + ICollection Constants { get; } + } + + static partial class Extensions + { + public static IEnumerable GetNestedTypes(this IHasNestedDefinitions def) + => def.NestedDefinitions.Select(d => d as TypeDefinition).Where(d => d != null); } } diff --git a/capnpc-csharp/Model/SchemaModel.cs b/capnpc-csharp/Model/SchemaModel.cs index 33b448a..4ebafec 100644 --- a/capnpc-csharp/Model/SchemaModel.cs +++ b/capnpc-csharp/Model/SchemaModel.cs @@ -10,8 +10,7 @@ namespace CapnpC.Model { readonly Schema.CodeGeneratorRequest.Reader _request; readonly List _generatedFiles = new List(); - Dictionary _allDefinitions = new Dictionary(); - readonly TypeDefinitionManager _typeDefMgr = new TypeDefinitionManager(); + readonly DefinitionManager _typeDefMgr = new DefinitionManager(); readonly Dictionary _id2node = new Dictionary(); @@ -52,8 +51,9 @@ namespace CapnpC.Model _id2node[node.Id] = node; } - BuildPass1(); - BuildPass2(); + var requestedFiles = _request.RequestedFiles.ToDictionary(req => req.Id); + BuildPass1(requestedFiles); + BuildPass2(requestedFiles); } // First pass: create type definitions for each node. @@ -65,13 +65,12 @@ namespace CapnpC.Model public IHasNestedDefinitions parent; } - void BuildPass1() + void BuildPass1(Dictionary requestedFiles) { Pass1State state = new Pass1State() { unprocessedNodes = new HashSet(_id2node.Keys) }; - var requestedFiles = _request.RequestedFiles.ToDictionary(req => req.Id); foreach (var node in _id2node.Values.Where(n => n.IsFile)) { GenFile file; @@ -86,7 +85,6 @@ namespace CapnpC.Model { file = (GenFile)ProcessNodePass1(node.Id, node.DisplayName, state); } - _allDefinitions.Add(node.Id, file); } if (state.unprocessedNodes.Count != 0) { @@ -94,30 +92,14 @@ namespace CapnpC.Model } } - TypeDefinition CreateTypeDef(Schema.Node.Reader node, IHasNestedDefinitions parent) + IDefinition ProcessNodePass1(ulong id, string name, Pass1State state) { - var kind = node.GetKind(); - var def = _typeDefMgr.Create(node.Id, kind.GetTypeTag()); - def.DeclaringElement = parent; - if (kind == NodeKind.Group) - ((TypeDefinition)parent).NestedGroups.Add(def); - else - parent.NestedTypes.Add(def); - return def; - } - - IHasNestedDefinitions ProcessNodePass1(ulong id, string name, Pass1State state) - { - if (!_id2node.TryGetValue(id, out var node)) - { - if (!state.isGenerated) return null; - throw new InvalidSchemaException($"The node {id.StrId()} was necessary for backend codegen but is missing."); - } - + if (!(IdToNode(id, state.isGenerated) is Schema.Node.Reader node)) + return null; if (!state.unprocessedNodes.Remove(id)) - throw new InvalidSchemaException($"The node \"{node.DisplayName}\" {node.StrId()} has been declared recursively."); + return null; - GenFile file = null; + IDefinition def = null; bool processNestedNodes = false; bool processFields = false; bool processInterfaceMethods = false; @@ -125,14 +107,16 @@ namespace CapnpC.Model switch (node.GetKind()) { case NodeKind.Annotation: + return _typeDefMgr.CreateAnnotation(id, state.parent); case NodeKind.Const: - // A dummy TypeDefinition is created to node hierarchy - break; + return _typeDefMgr.CreateConstant(id, state.parent); case NodeKind.File: if (state.parent != null) throw new InvalidSchemaException("Did not expect file nodes to appear as nested nodes"); - file = new GenFile(); + var file = _typeDefMgr.CreateFile(id); file.Namespace = GetNamespaceAnnotation(node); + file.Name = name; + def = file; processNestedNodes = true; break; case NodeKind.Enum: @@ -151,17 +135,13 @@ namespace CapnpC.Model throw new InvalidSchemaException($"Don't know how to process node {node.StrId()} \"{node.DisplayName}\""); } - TypeDefinition def = null; - if (file != null) + if (def == null) { - state.parent = file; - file.Name = name; - } - else - { - state.parent = def = CreateTypeDef(node, state.parent); - def.Name = name; + var typeDef = _typeDefMgr.CreateTypeDef(id, node.GetTypeTag(), state.parent); + typeDef.Name = name; + def = typeDef; } + state.parent = def as IHasNestedDefinitions; if (processNestedNodes && node.NestedNodes != null) foreach (var nested in node.NestedNodes) @@ -186,7 +166,7 @@ namespace CapnpC.Model pnode = IdToNode(method.ResultStructType); if (pnode.ScopeId == 0) ProcessNodePass1(pnode.Id, null, state); // Anonymous generated type } - return state.parent; + return def; } string[] GetNamespaceAnnotation(Schema.Node.Reader fileNode) @@ -210,14 +190,13 @@ namespace CapnpC.Model public HashSet processedNodes; } - void BuildPass2() + void BuildPass2(Dictionary requestedFiles) { - var files = _allDefinitions.Select(d => (Id: d.Key, File: d.Value as GenFile)).Where(d => d.File != null); var state = new Pass2State() { processedNodes = new HashSet() }; - foreach (var file in files) + foreach (var file in _typeDefMgr.Files) { var node = IdToNode(file.Id); - state.isGenerated = _request.RequestedFiles.Where(req => req.Id == file.Id).Any(); + state.isGenerated = requestedFiles.ContainsKey(file.Id); ProcessNestedNodes(node.NestedNodes, state); } } @@ -234,7 +213,7 @@ namespace CapnpC.Model { foreach (var scopeReader in brandReader.Scopes) { - var whatToBind = ProcessNode(scopeReader.ScopeId, state); + var whatToBind = ProcessTypeDef(scopeReader.ScopeId, state); int index = 0; switch (0) @@ -290,7 +269,7 @@ namespace CapnpC.Model return Types.FromParameter( new GenericParameter() { - DeclaringEntity = ProcessNode(typeReader.AnyPointer_Parameter_ScopeId, state), + DeclaringEntity = ProcessTypeDef(typeReader.AnyPointer_Parameter_ScopeId, state), Index = typeReader.AnyPointer_Parameter_ParameterIndex }); @@ -336,7 +315,7 @@ namespace CapnpC.Model return Types.F64; case 0 when typeReader.IsEnum: - return Types.FromDefinition(ProcessNode(typeReader.Enum_TypeId, state, TypeTag.Enum)); + return Types.FromDefinition(ProcessTypeDef(typeReader.Enum_TypeId, state, TypeTag.Enum)); case 0 when typeReader.IsFloat32: return Types.F32; @@ -354,7 +333,7 @@ namespace CapnpC.Model return Types.S8; case 0 when typeReader.IsInterface: - result = Types.FromDefinition(ProcessNode(typeReader.Interface_TypeId, state, TypeTag.Interface)); + result = Types.FromDefinition(ProcessTypeDef(typeReader.Interface_TypeId, state, TypeTag.Interface)); ProcessBrand(typeReader.Interface_Brand, result, state); return result; @@ -362,7 +341,7 @@ namespace CapnpC.Model return Types.List(ProcessType(typeReader.List_ElementType, state)); case 0 when typeReader.IsStruct: - result = Types.FromDefinition(ProcessNode(typeReader.Struct_TypeId, state, TypeTag.Struct)); + result = Types.FromDefinition(ProcessTypeDef(typeReader.Struct_TypeId, state, TypeTag.Struct)); ProcessBrand(typeReader.Struct_Brand, result, state); return result; @@ -520,7 +499,7 @@ namespace CapnpC.Model switch (0) { case 0 when fieldReader.IsGroup: - var def = ProcessNode(fieldReader.Group_TypeId, state, TypeTag.Group); + var def = ProcessTypeDef(fieldReader.Group_TypeId, state, TypeTag.Group); field.Type = Types.FromDefinition(def); break; @@ -642,7 +621,7 @@ namespace CapnpC.Model throw new InvalidSchemaException("Expected a struct"); } - var def = ProcessNode(reader.Id, state, TypeTag.Struct); + var def = ProcessTypeDef(reader.Id, state, TypeTag.Struct); if (reader.ScopeId == 0) { @@ -665,7 +644,7 @@ namespace CapnpC.Model { foreach (var superClassReader in ifaceReader.Interface_Superclasses) { - var superClass = ProcessNode(superClassReader.Id, state, TypeTag.Interface); + var superClass = ProcessTypeDef(superClassReader.Id, state, TypeTag.Interface); def.Superclasses.Add(Types.FromDefinition(superClass)); } @@ -693,36 +672,47 @@ namespace CapnpC.Model return def; } - Value ProcessConst(Schema.Node.Reader constReader, Pass2State state) + Constant ProcessConst(Schema.Node.Reader constReader, Constant @const, Pass2State state) { var value = ProcessValue(constReader.Const_Value); value.Type = ProcessType(constReader.Const_Type, state); - return value; + @const.Value = value; + return @const; } - TypeDefinition ProcessNode(ulong id, Pass2State state, TypeTag tag = default) + TypeDefinition ProcessTypeDef(ulong id, Pass2State state, TypeTag tag = default) + { + var def = ProcessNode(id, state, tag); + var typeDef = def as TypeDefinition; + if (def == null) + throw new ArgumentException( + $"Expected node {id.StrId()} to be a TypeDefinition but got {def.GetType().Name} instead.", + nameof(id)); + return typeDef; + } + + IDefinition ProcessNode(ulong id, Pass2State state, TypeTag tag = default) { if (!(IdToNode(id, state.isGenerated) is Schema.Node.Reader node)) return null; var kind = node.GetKind(); if (tag == TypeTag.Unknown) tag = kind.GetTypeTag(); - var def = _typeDefMgr.GetExisting(id, tag); + var def = _typeDefMgr.GetExistingDef(id, tag); if (state.processedNodes.Contains(id)) return def; state.processedNodes.Add(id); - switch (kind) + switch (def) { - case NodeKind.Annotation: + case Annotation annotation: + return annotation; + case Constant constant: + def.DeclaringElement.Constants.Add(ProcessConst(node, constant, state)); return def; - case NodeKind.Const: - def.DeclaringElement.Constants.Add(ProcessConst(node, state)); - return def; - case NodeKind.Enum: - return ProcessEnum(node, def, state); - case NodeKind.Interface: - return ProcessInterface(node, def, state); - case NodeKind.Struct: - case NodeKind.Group: - return ProcessStruct(node, def, state); + case TypeDefinition typeDef when kind == NodeKind.Enum: + return ProcessEnum(node, typeDef, state); + case TypeDefinition typeDef when kind == NodeKind.Interface: + return ProcessInterface(node, typeDef, state); + case TypeDefinition typeDef when kind == NodeKind.Struct || kind == NodeKind.Group: + return ProcessStruct(node, typeDef, state); default: throw new InvalidProgramException($"An unexpected node {node.StrId()} was found during the 2nd schema model building pass."); } diff --git a/capnpc-csharp/Model/TypeDefinition.cs b/capnpc-csharp/Model/TypeDefinition.cs index 382df18..910d4bd 100644 --- a/capnpc-csharp/Model/TypeDefinition.cs +++ b/capnpc-csharp/Model/TypeDefinition.cs @@ -2,7 +2,7 @@ using System.Linq; namespace CapnpC.Model { - class TypeDefinition : AbstractType, IHasNestedDefinitions, IHasGenericParameters + class TypeDefinition : AbstractType, IDefinition, IHasNestedDefinitions, IHasGenericParameters { public class DiscriminationInfo { @@ -16,23 +16,30 @@ namespace CapnpC.Model public uint TagOffset { get; } } - public TypeDefinition(TypeTag tag, ulong id) + public TypeDefinition(TypeTag tag, ulong id, IHasNestedDefinitions parent) { Tag = tag; Id = id; + DeclaringElement = parent; + if (tag == TypeTag.Group) + ((TypeDefinition)parent).NestedGroups.Add(this); + else + parent.NestedDefinitions.Add(this); } public ulong Id { get; } - public IHasNestedDefinitions DeclaringElement { get; set; } + public IHasNestedDefinitions DeclaringElement { get; } + public Method UsingMethod { get; set; } public string Name { get; set; } public SpecialName SpecialName { get; set; } public DiscriminationInfo UnionInfo { get; set; } public new List Fields => base.Fields; public List Enumerants { get; } = new List(); - public List NestedTypes { get; } = new List(); + public ICollection NestedDefinitions { get; } = new List(); + public IEnumerable NestedTypes { get => this.GetNestedTypes(); } public List NestedGroups { get; } = new List(); - public List Constants { get; } = new List(); + public ICollection Constants { get; } = new List(); public List Methods { get; } = new List(); public List Superclasses { get; } = new List(); public List GenericParameters { get; } = new List(); diff --git a/capnpc-csharp/Model/TypeDefinitionManager.cs b/capnpc-csharp/Model/TypeDefinitionManager.cs deleted file mode 100644 index a734026..0000000 --- a/capnpc-csharp/Model/TypeDefinitionManager.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace CapnpC.Model -{ - class TypeDefinitionManager - { - readonly Dictionary _id2def = - new Dictionary(); - - public TypeDefinition Create(ulong id, TypeTag tag) - { - if (_id2def.ContainsKey(id)) - { - throw new ArgumentException(nameof(id), $"Attempting to redefine {tag.ToString()} {id.StrId()}."); - } - - var def = new TypeDefinition(tag, id); - _id2def.Add(id, def); - return def; - } - - public TypeDefinition GetExisting(ulong id, TypeTag tag) - { - if (_id2def.TryGetValue(id, out var def)) - { - if (def.Tag == TypeTag.Unknown) - { - def.Tag = tag; - } - else if (tag != TypeTag.Unknown && def.Tag != tag) - { - throw new ArgumentOutOfRangeException(nameof(tag), "Type tag does not match existing type"); - } - return def; - } - throw new ArgumentOutOfRangeException($"Attempting to retrieve nonexistend node {id.StrId()}."); - } - } -} diff --git a/capnpc-csharp/Model/TypeTag.cs b/capnpc-csharp/Model/TypeTag.cs index 66b7d5e..122b6d7 100644 --- a/capnpc-csharp/Model/TypeTag.cs +++ b/capnpc-csharp/Model/TypeTag.cs @@ -28,6 +28,9 @@ Group, Interface, Enum, - AnyEnum + AnyEnum, + Const, + Annotation, + File } }