mirror of
https://github.com/FabInfra/capnproto-dotnetcore_Runtime.git
synced 2025-04-21 02:26:31 +02:00
Merge pull request #8 from Bertec/feature/codegen-fixes-1
Backend Fixes Part 1
This commit is contained in:
commit
e68be281ec
@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Std
|
|||||||
EndProject
|
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}"
|
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
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "capnpc-csharp.tests", "capnpc-csharp.tests\capnpc-csharp.tests.csproj", "{B77AC567-E232-4072-85C3-8689566BF3D4}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
123
capnpc-csharp.tests/Properties/Resources.Designer.cs
generated
Normal file
123
capnpc-csharp.tests/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// 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.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace capnpc_csharp.Tests.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// 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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
|
/// </summary>
|
||||||
|
internal static byte[] schema_with_offsets_capnp {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("schema_with_offsets_capnp", resourceCulture);
|
||||||
|
return ((byte[])(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
|
/// </summary>
|
||||||
|
internal static byte[] UnitTest1_capnp {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("UnitTest1_capnp", resourceCulture);
|
||||||
|
return ((byte[])(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
|
/// </summary>
|
||||||
|
internal static byte[] UnitTest10_capnp {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("UnitTest10_capnp", resourceCulture);
|
||||||
|
return ((byte[])(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
|
/// </summary>
|
||||||
|
internal static byte[] UnitTest2_capnp {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("UnitTest2_capnp", resourceCulture);
|
||||||
|
return ((byte[])(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
|
/// </summary>
|
||||||
|
internal static byte[] UnitTest20_capnp {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("UnitTest20_capnp", resourceCulture);
|
||||||
|
return ((byte[])(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
|
/// </summary>
|
||||||
|
internal static byte[] UnitTest3_capnp {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("UnitTest3_capnp", resourceCulture);
|
||||||
|
return ((byte[])(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
139
capnpc-csharp.tests/Properties/Resources.resx
Normal file
139
capnpc-csharp.tests/Properties/Resources.resx
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<data name="UnitTest10_capnp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\UnitTest10.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name="UnitTest20_capnp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\UnitTest20.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name="UnitTest3_capnp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\UnitTest3.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name="UnitTest2_capnp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\UnitTest2.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name="UnitTest1_capnp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\UnitTest1.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
<data name="schema_with_offsets_capnp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\schema-with-offsets.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
BIN
capnpc-csharp.tests/Resources/UnitTest1.capnp.bin
Normal file
BIN
capnpc-csharp.tests/Resources/UnitTest1.capnp.bin
Normal file
Binary file not shown.
BIN
capnpc-csharp.tests/Resources/UnitTest10.capnp.bin
Normal file
BIN
capnpc-csharp.tests/Resources/UnitTest10.capnp.bin
Normal file
Binary file not shown.
BIN
capnpc-csharp.tests/Resources/UnitTest2.capnp.bin
Normal file
BIN
capnpc-csharp.tests/Resources/UnitTest2.capnp.bin
Normal file
Binary file not shown.
BIN
capnpc-csharp.tests/Resources/UnitTest20.capnp.bin
Normal file
BIN
capnpc-csharp.tests/Resources/UnitTest20.capnp.bin
Normal file
Binary file not shown.
BIN
capnpc-csharp.tests/Resources/UnitTest3.capnp.bin
Normal file
BIN
capnpc-csharp.tests/Resources/UnitTest3.capnp.bin
Normal file
Binary file not shown.
BIN
capnpc-csharp.tests/Resources/schema-with-offsets.capnp.bin
Normal file
BIN
capnpc-csharp.tests/Resources/schema-with-offsets.capnp.bin
Normal file
Binary file not shown.
9
capnpc-csharp.tests/UnitTest1.capnp
Normal file
9
capnpc-csharp.tests/UnitTest1.capnp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@0x93d3c4d19cd84a4c;
|
||||||
|
|
||||||
|
enum Enumerant {
|
||||||
|
byte @0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
foo @0: UInt8;
|
||||||
|
}
|
9
capnpc-csharp.tests/UnitTest10.capnp
Normal file
9
capnpc-csharp.tests/UnitTest10.capnp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@0xbbfd48ae4b99d012;
|
||||||
|
|
||||||
|
using Cxx = import "/capnp/c++.capnp";
|
||||||
|
|
||||||
|
$Cxx.namespace("Foo::Bar::Baz");
|
||||||
|
|
||||||
|
struct Outer {
|
||||||
|
inner @0: import "UnitTest10b.capnp".Inner ;
|
||||||
|
}
|
7
capnpc-csharp.tests/UnitTest10b.capnp
Normal file
7
capnpc-csharp.tests/UnitTest10b.capnp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@0xaf95c1c78b01be97;
|
||||||
|
|
||||||
|
using Cxx = import "/capnp/c++.capnp";
|
||||||
|
|
||||||
|
$Cxx.namespace("Foo::Garf::Snarf");
|
||||||
|
|
||||||
|
struct Inner {}
|
11
capnpc-csharp.tests/UnitTest2.capnp
Normal file
11
capnpc-csharp.tests/UnitTest2.capnp
Normal file
@ -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) {}
|
5
capnpc-csharp.tests/UnitTest20.capnp
Normal file
5
capnpc-csharp.tests/UnitTest20.capnp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@0xcebb7a61a86a7492;
|
||||||
|
|
||||||
|
annotation anAnnotation(file): Text;
|
||||||
|
|
||||||
|
const aConstant :UInt16 = 42;
|
6
capnpc-csharp.tests/UnitTest3.capnp
Normal file
6
capnpc-csharp.tests/UnitTest3.capnp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
@0xb7158f7fa52b8db6;
|
||||||
|
|
||||||
|
using Cxx = import "/capnp/c++.capnp";
|
||||||
|
|
||||||
|
$Cxx.namespace("Foo.Bar.Baz");
|
||||||
|
|
129
capnpc-csharp.tests/UnitTests.cs
Normal file
129
capnpc-csharp.tests/UnitTests.cs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
using capnpc_csharp.Tests.Properties;
|
||||||
|
using Capnp;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace CapnpC
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class UnitTests
|
||||||
|
{
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test00Enumerant()
|
||||||
|
{
|
||||||
|
var model = Load(Resources.UnitTest1_capnp);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test02ForwardInheritance()
|
||||||
|
{
|
||||||
|
var model = Load(Resources.UnitTest2_capnp);
|
||||||
|
var codeGen = NewGeneratorFor(model);
|
||||||
|
codeGen.Transform(model.FilesToGenerate.First());
|
||||||
|
// Should not throw
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test03NonGeneratedNodeSkip()
|
||||||
|
{
|
||||||
|
var model = Load(Resources.UnitTest3_capnp);
|
||||||
|
// Should not throw
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test10ImportedNamespaces()
|
||||||
|
{
|
||||||
|
var model = Load(Resources.UnitTest10_capnp);
|
||||||
|
var codeGen = NewGeneratorFor(model);
|
||||||
|
var genFile = model.FilesToGenerate.First();
|
||||||
|
var outerTypeDef = genFile.NestedTypes.First();
|
||||||
|
var outerType = Model.Types.FromDefinition(outerTypeDef);
|
||||||
|
var innerType = outerTypeDef.Fields[0].Type;
|
||||||
|
var innerTypeDef = innerType.Definition;
|
||||||
|
var names = codeGen.GetNames();
|
||||||
|
var outerNameSyntax = names.GetQName(outerType, outerTypeDef);
|
||||||
|
var innerNameSyntax = names.GetQName(innerType, outerTypeDef);
|
||||||
|
string[] outerNamespace = { "Foo", "Bar", "Baz" };
|
||||||
|
string[] innerNamespace = { "Foo", "Garf", "Snarf" };
|
||||||
|
CollectionAssert.AreEqual(outerNamespace, (outerTypeDef.DeclaringElement as Model.GenFile).Namespace);
|
||||||
|
CollectionAssert.AreEqual(innerNamespace, (innerType.Definition.DeclaringElement as Model.GenFile).Namespace);
|
||||||
|
string outerNSStr = String.Join('.', outerNamespace);
|
||||||
|
string innerNSStr = String.Join('.', innerNamespace);
|
||||||
|
Assert.AreEqual($"{outerNSStr}.Outer", outerNameSyntax.ToString());
|
||||||
|
Assert.AreEqual($"{innerNSStr}.Inner", innerNameSyntax.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test20AnnotationAndConst()
|
||||||
|
{
|
||||||
|
var model = Load(Resources.UnitTest20_capnp);
|
||||||
|
var codeGen = NewGeneratorFor(model);
|
||||||
|
codeGen.Transform(model.FilesToGenerate.First());
|
||||||
|
// Should not throw
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Test30SchemaCapnp()
|
||||||
|
{
|
||||||
|
var model = Load(Resources.schema_with_offsets_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());
|
||||||
|
|
||||||
|
static Model.TypeDefinition GetTypeDef(ulong id, Model.SchemaModel model)
|
||||||
|
{
|
||||||
|
foreach (var defs in model.FilesToGenerate.Select(f => f.NestedTypes))
|
||||||
|
{
|
||||||
|
if (GetTypeDef(id, defs) is Model.TypeDefinition def) return def;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Model.TypeDefinition GetTypeDef(ulong id, IEnumerable<Model.TypeDefinition> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
capnpc-csharp.tests/capnpc-csharp.tests.csproj
Normal file
40
capnpc-csharp.tests/capnpc-csharp.tests.csproj
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||||
|
<RootNamespace>capnpc_csharp.Tests</RootNamespace>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\capnpc-csharp\capnpc-csharp.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="*.cs" />
|
||||||
|
<Compile Include="UnitTests.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Properties\Resources.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Update="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -33,6 +33,8 @@
|
|||||||
_interfaceGen = new InterfaceSnippetGen(_names);
|
_interfaceGen = new InterfaceSnippetGen(_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal GenNames GetNames() => _names;
|
||||||
|
|
||||||
IEnumerable<MemberDeclarationSyntax> TransformEnum(TypeDefinition def)
|
IEnumerable<MemberDeclarationSyntax> TransformEnum(TypeDefinition def)
|
||||||
{
|
{
|
||||||
yield return _commonGen.MakeEnum(def);
|
yield return _commonGen.MakeEnum(def);
|
||||||
@ -102,7 +104,7 @@
|
|||||||
yield return _interfaceGen.MakePipeliningSupport(def);
|
yield return _interfaceGen.MakePipeliningSupport(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def.NestedTypes.Count > 0)
|
if (def.NestedTypes.Any())
|
||||||
{
|
{
|
||||||
var ns = ClassDeclaration(
|
var ns = ClassDeclaration(
|
||||||
_names.MakeTypeName(def, NameUsage.Namespace).ToString())
|
_names.MakeTypeName(def, NameUsage.Namespace).ToString())
|
||||||
@ -143,20 +145,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string Transform(GenFile file)
|
internal string Transform(GenFile file)
|
||||||
{
|
{
|
||||||
if (file.Namespace != null)
|
NameSyntax topNamespace = GenNames.NamespaceName(file.Namespace) ?? _names.TopNamespace;
|
||||||
{
|
|
||||||
_names.TopNamespace = IdentifierName(MakeCamel(file.Namespace[0]));
|
|
||||||
|
|
||||||
foreach (string name in file.Namespace.Skip(1))
|
var ns = NamespaceDeclaration(topNamespace);
|
||||||
{
|
|
||||||
var temp = IdentifierName(MakeCamel(name));
|
|
||||||
_names.TopNamespace = QualifiedName(_names.TopNamespace, temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var ns = NamespaceDeclaration(_names.TopNamespace);
|
|
||||||
|
|
||||||
foreach (var def in file.NestedTypes)
|
foreach (var def in file.NestedTypes)
|
||||||
{
|
{
|
||||||
|
@ -213,29 +213,24 @@ namespace CapnpC.Generator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NameSyntax GetQName(TypeDefinition def)
|
public static NameSyntax NamespaceName(string[] @namespace)
|
||||||
{
|
{
|
||||||
var stack = new Stack<SimpleNameSyntax>();
|
NameSyntax ident = null;
|
||||||
|
if (@namespace != null)
|
||||||
stack.Push(MakeGenericTypeName(def, NameUsage.Default));
|
|
||||||
|
|
||||||
while (def.DeclaringElement is TypeDefinition pdef)
|
|
||||||
{
|
{
|
||||||
stack.Push(MakeGenericTypeName(pdef, NameUsage.Namespace));
|
ident = IdentifierName(SyntaxHelpers.MakeCamel(@namespace[0]));
|
||||||
def = pdef;
|
foreach (string name in @namespace.Skip(1))
|
||||||
|
{
|
||||||
|
var temp = IdentifierName(SyntaxHelpers.MakeCamel(name));
|
||||||
|
ident = QualifiedName(ident, temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return ident;
|
||||||
var qtype = TopNamespace;
|
|
||||||
|
|
||||||
foreach (var name in stack)
|
|
||||||
{
|
|
||||||
qtype = QualifiedName(qtype, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return qtype;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NameSyntax GetQName(Model.Type type, TypeDefinition scope)
|
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
|
// 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
|
// qualified names. Unfortunately the commented approach is too naive. It will fail if
|
||||||
@ -262,7 +257,10 @@ namespace CapnpC.Generator
|
|||||||
def = pdef;
|
def = pdef;
|
||||||
}
|
}
|
||||||
|
|
||||||
var qtype = TopNamespace;
|
var qtype =
|
||||||
|
GetNamespaceFor(type.Definition)
|
||||||
|
?? GetNamespaceFor(scope)
|
||||||
|
?? TopNamespace;
|
||||||
|
|
||||||
foreach (var name in stack)
|
foreach (var name in stack)
|
||||||
{
|
{
|
||||||
@ -563,7 +561,8 @@ namespace CapnpC.Generator
|
|||||||
}
|
}
|
||||||
|
|
||||||
var typeNames = new HashSet<Name>(def.NestedTypes.Select(t => MakeTypeName(t)));
|
var typeNames = new HashSet<Name>(def.NestedTypes.Select(t => MakeTypeName(t)));
|
||||||
|
typeNames.Add(MakeTypeName(def));
|
||||||
|
|
||||||
foreach (var member in def.Fields)
|
foreach (var member in def.Fields)
|
||||||
{
|
{
|
||||||
var memberName = new Name(SyntaxHelpers.MakeCamel(member.Name));
|
var memberName = new Name(SyntaxHelpers.MakeCamel(member.Name));
|
||||||
|
19
capnpc-csharp/Model/Annotation.cs
Normal file
19
capnpc-csharp/Model/Annotation.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
capnpc-csharp/Model/Constant.cs
Normal file
19
capnpc-csharp/Model/Constant.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
capnpc-csharp/Model/DefinitionManager.cs
Normal file
67
capnpc-csharp/Model/DefinitionManager.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace CapnpC.Model
|
||||||
|
{
|
||||||
|
class DefinitionManager
|
||||||
|
{
|
||||||
|
readonly Dictionary<ulong, IDefinition> _id2def = new Dictionary<ulong, IDefinition>();
|
||||||
|
|
||||||
|
public GenFile CreateFile(ulong id)
|
||||||
|
=> CreateId<GenFile>(id, () => new GenFile(id));
|
||||||
|
public GenFile GetExistingFile(ulong id)
|
||||||
|
=> GetId<GenFile>(id, TypeTag.File);
|
||||||
|
|
||||||
|
public TypeDefinition CreateTypeDef(ulong id, TypeTag tag, IHasNestedDefinitions decl)
|
||||||
|
=> CreateId<TypeDefinition>(id, () => new TypeDefinition(tag, id, decl));
|
||||||
|
public TypeDefinition GetExistingTypeDef(ulong id, TypeTag tag)
|
||||||
|
{
|
||||||
|
var def = GetId<TypeDefinition>(id, tag);
|
||||||
|
if (def.Tag == TypeTag.Unknown) def.Tag = tag;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Annotation CreateAnnotation(ulong id, IHasNestedDefinitions decl)
|
||||||
|
=> CreateId<Annotation>(id, () => new Annotation(id, decl));
|
||||||
|
public Annotation GetExistingAnnotation(ulong id)
|
||||||
|
=> GetId<Annotation>(id, TypeTag.Annotation);
|
||||||
|
|
||||||
|
public Constant CreateConstant(ulong id, IHasNestedDefinitions decl)
|
||||||
|
=> CreateId<Constant>(id, () => new Constant(id, decl));
|
||||||
|
public Constant GetExistingConstant(ulong id)
|
||||||
|
=> GetId<Constant>(id, TypeTag.Const);
|
||||||
|
|
||||||
|
public IDefinition GetExistingDef(ulong id, TypeTag tag)
|
||||||
|
=> GetId<IDefinition>(id, tag);
|
||||||
|
|
||||||
|
public IEnumerable<GenFile> Files
|
||||||
|
{
|
||||||
|
get => _id2def.Values.Where(d => d.Tag == TypeTag.File).Select(f => f as GenFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
T CreateId<T>(ulong id, Func<IDefinition> 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<T>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,12 @@
|
|||||||
{
|
{
|
||||||
class Enumerant
|
class Enumerant
|
||||||
{
|
{
|
||||||
|
string _literal;
|
||||||
public TypeDefinition TypeDefinition { get; set; }
|
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 ushort? Ordinal { get; set; }
|
||||||
public int CodeOrder { get; set; }
|
public int CodeOrder { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace CapnpC.Model
|
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 Name { get; set; }
|
||||||
public string[] Namespace { get; set; }
|
public string[] Namespace { get; set; }
|
||||||
|
|
||||||
public List<TypeDefinition> NestedTypes { get; } = new List<TypeDefinition>();
|
public IEnumerable<TypeDefinition> NestedTypes { get => this.GetNestedTypes(); }
|
||||||
public List<Value> Constants { get; } = new List<Value>();
|
public ICollection<IDefinition> NestedDefinitions { get; } = new List<IDefinition>();
|
||||||
|
public ICollection<Constant> Constants { get; } = new List<Constant>();
|
||||||
|
|
||||||
|
public GenFile(ulong id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
capnpc-csharp/Model/IDefinition.cs
Normal file
10
capnpc-csharp/Model/IDefinition.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
namespace CapnpC.Model
|
||||||
|
{
|
||||||
|
interface IDefinition
|
||||||
|
{
|
||||||
|
ulong Id { get; }
|
||||||
|
TypeTag Tag { get; }
|
||||||
|
IHasNestedDefinitions DeclaringElement { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,18 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace CapnpC.Model
|
namespace CapnpC.Model
|
||||||
{
|
{
|
||||||
interface IHasNestedDefinitions
|
interface IHasNestedDefinitions
|
||||||
{
|
{
|
||||||
List<TypeDefinition> NestedTypes { get; }
|
IEnumerable<TypeDefinition> NestedTypes { get; }
|
||||||
List<Value> Constants { get; }
|
ICollection<IDefinition> NestedDefinitions { get; }
|
||||||
|
ICollection<Constant> Constants { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static partial class Extensions
|
||||||
|
{
|
||||||
|
public static IEnumerable<TypeDefinition> GetNestedTypes(this IHasNestedDefinitions def)
|
||||||
|
=> def.NestedDefinitions.Select(d => d as TypeDefinition).Where(d => d != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
capnpc-csharp/Model/IdentifierRenamer.cs
Normal file
22
capnpc-csharp/Model/IdentifierRenamer.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,30 +9,30 @@ namespace CapnpC.Model
|
|||||||
class SchemaModel
|
class SchemaModel
|
||||||
{
|
{
|
||||||
readonly Schema.CodeGeneratorRequest.Reader _request;
|
readonly Schema.CodeGeneratorRequest.Reader _request;
|
||||||
readonly List<GenFile> _files = new List<GenFile>();
|
readonly List<GenFile> _generatedFiles = new List<GenFile>();
|
||||||
readonly Stack<IHasNestedDefinitions> _typeNest = new Stack<IHasNestedDefinitions>();
|
readonly DefinitionManager _typeDefMgr = new DefinitionManager();
|
||||||
readonly TypeDefinitionManager _typeDefMgr = new TypeDefinitionManager();
|
|
||||||
Method _currentMethod;
|
|
||||||
|
|
||||||
Dictionary<ulong, Schema.Node.Reader> _id2node;
|
readonly Dictionary<ulong, Schema.Node.Reader> _id2node = new Dictionary<ulong, Schema.Node.Reader>();
|
||||||
|
|
||||||
public SchemaModel(Schema.CodeGeneratorRequest.Reader request)
|
public SchemaModel(Schema.CodeGeneratorRequest.Reader request)
|
||||||
{
|
{
|
||||||
_request = request;
|
_request = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<GenFile> FilesToGenerate => _files;
|
public IReadOnlyList<GenFile> 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)
|
Schema.Node.Reader IdToNode(ulong id)
|
||||||
{
|
{
|
||||||
try
|
return (Schema.Node.Reader)IdToNode(id, true);
|
||||||
{
|
|
||||||
return _id2node[id];
|
|
||||||
}
|
|
||||||
catch (KeyNotFoundException)
|
|
||||||
{
|
|
||||||
throw new InvalidSchemaException($"Node with ID {id} is missing");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Build()
|
void Build()
|
||||||
@ -42,69 +42,178 @@ namespace CapnpC.Model
|
|||||||
throw new InvalidSchemaException("No nodes, nothing to generate");
|
throw new InvalidSchemaException("No nodes, nothing to generate");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
foreach (var node in _request.Nodes)
|
||||||
{
|
{
|
||||||
_id2node = _request.Nodes.ToDictionary(n => n.Id);
|
if (_id2node.TryGetValue(node.Id, out var existingNode))
|
||||||
}
|
|
||||||
catch (ArgumentException)
|
|
||||||
{
|
|
||||||
throw new InvalidSchemaException("Nodes with duplicate IDs detected");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var reqFile in _request.RequestedFiles)
|
|
||||||
{
|
|
||||||
var file = new GenFile()
|
|
||||||
{
|
{
|
||||||
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);
|
var requestedFiles = _request.RequestedFiles.ToDictionary(req => req.Id);
|
||||||
_typeNest.Push(file);
|
BuildPass1(requestedFiles);
|
||||||
|
BuildPass2(requestedFiles);
|
||||||
|
}
|
||||||
|
|
||||||
var fileNode = IdToNode(reqFile.Id);
|
// First pass: create type definitions for each node.
|
||||||
|
|
||||||
if (!fileNode.IsFile)
|
struct Pass1State
|
||||||
throw new InvalidSchemaException("Expected a file node");
|
{
|
||||||
|
public HashSet<ulong> unprocessedNodes;
|
||||||
|
public bool isGenerated;
|
||||||
|
public IHasNestedDefinitions parent;
|
||||||
|
}
|
||||||
|
|
||||||
ProcessFile(fileNode);
|
void BuildPass1(Dictionary<ulong, Schema.CodeGeneratorRequest.RequestedFile.Reader> requestedFiles)
|
||||||
|
{
|
||||||
_typeNest.Pop();
|
Pass1State state = new Pass1State()
|
||||||
|
{
|
||||||
|
unprocessedNodes = new HashSet<ulong>(_id2node.Keys)
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state.unprocessedNodes.Count != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidSchemaException("Unreferenced nodes were present in the schema.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessFile(Schema.Node.Reader fileReader)
|
IDefinition ProcessNodePass1(ulong id, string name, Pass1State state)
|
||||||
{
|
{
|
||||||
foreach (var annotation in fileReader.Annotations)
|
if (!(IdToNode(id, state.isGenerated) is Schema.Node.Reader node))
|
||||||
|
return null;
|
||||||
|
if (!state.unprocessedNodes.Remove(id))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
IDefinition def = null;
|
||||||
|
bool processNestedNodes = false;
|
||||||
|
bool processFields = false;
|
||||||
|
bool processInterfaceMethods = false;
|
||||||
|
|
||||||
|
switch (node.GetKind())
|
||||||
|
{
|
||||||
|
case NodeKind.Annotation:
|
||||||
|
return _typeDefMgr.CreateAnnotation(id, state.parent);
|
||||||
|
case NodeKind.Const:
|
||||||
|
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");
|
||||||
|
var file = _typeDefMgr.CreateFile(id);
|
||||||
|
file.Namespace = GetNamespaceAnnotation(node);
|
||||||
|
file.Name = name;
|
||||||
|
def = file;
|
||||||
|
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}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def == null)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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 def;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] GetNamespaceAnnotation(Schema.Node.Reader fileNode)
|
||||||
|
{
|
||||||
|
foreach (var annotation in fileNode.Annotations)
|
||||||
{
|
{
|
||||||
if (annotation.Id == 0xb9c6f99ebf805f2c) // Cxx namespace
|
if (annotation.Id == 0xb9c6f99ebf805f2c) // Cxx namespace
|
||||||
{
|
{
|
||||||
((GenFile)_typeNest.Peek()).Namespace = annotation.Value.Text.Split("::");
|
return annotation.Value.Text.Split(new string[1] { "::" }, default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var nestedNode in fileReader.NestedNodes)
|
// 2nd pass: Generate types based on definitions
|
||||||
|
|
||||||
|
struct Pass2State
|
||||||
|
{
|
||||||
|
public Method currentMethod;
|
||||||
|
public bool isGenerated;
|
||||||
|
public HashSet<ulong> processedNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildPass2(Dictionary<ulong, Schema.CodeGeneratorRequest.RequestedFile.Reader> requestedFiles)
|
||||||
|
{
|
||||||
|
var state = new Pass2State() { processedNodes = new HashSet<ulong>() };
|
||||||
|
foreach (var file in _typeDefMgr.Files)
|
||||||
{
|
{
|
||||||
var node = IdToNode(nestedNode.Id);
|
var node = IdToNode(file.Id);
|
||||||
|
state.isGenerated = requestedFiles.ContainsKey(file.Id);
|
||||||
ProcessNode(node, nestedNode.Name);
|
ProcessNestedNodes(node.NestedNodes, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDefinition GetOrCreateTypeDef(ulong id, TypeTag tag) => _typeDefMgr.GetOrCreate(id, tag);
|
void ProcessNestedNodes(IEnumerable<Schema.Node.NestedNode.Reader> nestedNodes, Pass2State state)
|
||||||
TypeDefinition GetGroupTypeDef(ulong id, string name)
|
|
||||||
{
|
{
|
||||||
var nodeReader = _id2node[id];
|
foreach (var nestedNode in nestedNodes)
|
||||||
|
{
|
||||||
if (!nodeReader.IsStruct)
|
ProcessNode(nestedNode.Id, state);
|
||||||
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)
|
foreach (var scopeReader in brandReader.Scopes)
|
||||||
{
|
{
|
||||||
var whatToBind = GetOrCreateTypeDef(scopeReader.ScopeId, TypeTag.Unknown);
|
var whatToBind = ProcessTypeDef(scopeReader.ScopeId, state);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
switch (0)
|
switch (0)
|
||||||
@ -121,7 +230,7 @@ namespace CapnpC.Model
|
|||||||
switch (0)
|
switch (0)
|
||||||
{
|
{
|
||||||
case 0 when bindingReader.IsType:
|
case 0 when bindingReader.IsType:
|
||||||
type.BindGenericParameter(typeParameter, ProcessType(bindingReader.Type));
|
type.BindGenericParameter(typeParameter, ProcessType(bindingReader.Type, state));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0 when bindingReader.IsUnbound:
|
case 0 when bindingReader.IsUnbound:
|
||||||
@ -146,7 +255,8 @@ namespace CapnpC.Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type ProcessType(Schema.Type.Reader typeReader)
|
|
||||||
|
Type ProcessType(Schema.Type.Reader typeReader, Pass2State state)
|
||||||
{
|
{
|
||||||
Type result;
|
Type result;
|
||||||
|
|
||||||
@ -159,7 +269,7 @@ namespace CapnpC.Model
|
|||||||
return Types.FromParameter(
|
return Types.FromParameter(
|
||||||
new GenericParameter()
|
new GenericParameter()
|
||||||
{
|
{
|
||||||
DeclaringEntity = GetOrCreateTypeDef(typeReader.AnyPointer_Parameter_ScopeId, TypeTag.Unknown),
|
DeclaringEntity = ProcessTypeDef(typeReader.AnyPointer_Parameter_ScopeId, state),
|
||||||
Index = typeReader.AnyPointer_Parameter_ParameterIndex
|
Index = typeReader.AnyPointer_Parameter_ParameterIndex
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -167,7 +277,7 @@ namespace CapnpC.Model
|
|||||||
return Types.FromParameter(
|
return Types.FromParameter(
|
||||||
new GenericParameter()
|
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
|
Index = typeReader.AnyPointer_ImplicitMethodParameter_ParameterIndex
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -205,7 +315,7 @@ namespace CapnpC.Model
|
|||||||
return Types.F64;
|
return Types.F64;
|
||||||
|
|
||||||
case 0 when typeReader.IsEnum:
|
case 0 when typeReader.IsEnum:
|
||||||
return Types.FromDefinition(GetOrCreateTypeDef(typeReader.Enum_TypeId, TypeTag.Enum));
|
return Types.FromDefinition(ProcessTypeDef(typeReader.Enum_TypeId, state, TypeTag.Enum));
|
||||||
|
|
||||||
case 0 when typeReader.IsFloat32:
|
case 0 when typeReader.IsFloat32:
|
||||||
return Types.F32;
|
return Types.F32;
|
||||||
@ -223,16 +333,16 @@ namespace CapnpC.Model
|
|||||||
return Types.S8;
|
return Types.S8;
|
||||||
|
|
||||||
case 0 when typeReader.IsInterface:
|
case 0 when typeReader.IsInterface:
|
||||||
result = Types.FromDefinition(GetOrCreateTypeDef(typeReader.Interface_TypeId, TypeTag.Interface));
|
result = Types.FromDefinition(ProcessTypeDef(typeReader.Interface_TypeId, state, TypeTag.Interface));
|
||||||
ProcessBrand(typeReader.Interface_Brand, result);
|
ProcessBrand(typeReader.Interface_Brand, result, state);
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
case 0 when typeReader.IsList:
|
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:
|
case 0 when typeReader.IsStruct:
|
||||||
result = Types.FromDefinition(GetOrCreateTypeDef(typeReader.Struct_TypeId, TypeTag.Struct));
|
result = Types.FromDefinition(ProcessTypeDef(typeReader.Struct_TypeId, state, TypeTag.Struct));
|
||||||
ProcessBrand(typeReader.Struct_Brand, result);
|
ProcessBrand(typeReader.Struct_Brand, result, state);
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
case 0 when typeReader.IsText:
|
case 0 when typeReader.IsText:
|
||||||
@ -365,7 +475,7 @@ namespace CapnpC.Model
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessFields(Schema.Node.Reader reader, TypeDefinition declaringType, List<Field> fields)
|
void ProcessFields(Schema.Node.Reader reader, TypeDefinition declaringType, List<Field> fields, Pass2State state)
|
||||||
{
|
{
|
||||||
if (reader.Fields == null)
|
if (reader.Fields == null)
|
||||||
{
|
{
|
||||||
@ -389,15 +499,15 @@ namespace CapnpC.Model
|
|||||||
switch (0)
|
switch (0)
|
||||||
{
|
{
|
||||||
case 0 when fieldReader.IsGroup:
|
case 0 when fieldReader.IsGroup:
|
||||||
field.Type = Types.FromDefinition(GetGroupTypeDef(
|
var def = ProcessTypeDef(fieldReader.Group_TypeId, state, TypeTag.Group);
|
||||||
fieldReader.Group_TypeId, fieldReader.Name));
|
field.Type = Types.FromDefinition(def);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0 when fieldReader.IsSlot:
|
case 0 when fieldReader.IsSlot:
|
||||||
field.DefaultValue = ProcessValue(fieldReader.Slot_DefaultValue);
|
field.DefaultValue = ProcessValue(fieldReader.Slot_DefaultValue);
|
||||||
field.DefaultValueIsExplicit = fieldReader.Slot_HadExplicitDefault;
|
field.DefaultValueIsExplicit = fieldReader.Slot_HadExplicitDefault;
|
||||||
field.Offset = fieldReader.Slot_Offset;
|
field.Offset = fieldReader.Slot_Offset;
|
||||||
field.Type = ProcessType(fieldReader.Slot_Type);
|
field.Type = ProcessType(fieldReader.Slot_Type, state);
|
||||||
field.DefaultValue.Type = field.Type;
|
field.DefaultValue.Type = field.Type;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -411,7 +521,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;
|
def.IsGeneric = reader.IsGeneric;
|
||||||
|
|
||||||
@ -423,18 +533,9 @@ namespace CapnpC.Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_typeNest.Push(def);
|
ProcessNestedNodes(reader.NestedNodes, state);
|
||||||
|
|
||||||
if (reader.NestedNodes != null)
|
ProcessFields(reader, def, def.Fields, state);
|
||||||
{
|
|
||||||
foreach (var nestedReader in reader.NestedNodes)
|
|
||||||
{
|
|
||||||
var node = IdToNode(nestedReader.Id);
|
|
||||||
ProcessNode(node, nestedReader.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessFields(reader, def, def.Fields);
|
|
||||||
|
|
||||||
if (reader.IsInterface)
|
if (reader.IsInterface)
|
||||||
{
|
{
|
||||||
@ -450,12 +551,12 @@ namespace CapnpC.Model
|
|||||||
{
|
{
|
||||||
method.GenericParameters.Add(implicitParameterReader.Name);
|
method.GenericParameters.Add(implicitParameterReader.Name);
|
||||||
}
|
}
|
||||||
_currentMethod = method;
|
state.currentMethod = method;
|
||||||
|
|
||||||
def.Methods.Add(method);
|
def.Methods.Add(method);
|
||||||
|
|
||||||
var paramNode = IdToNode(methodReader.ParamStructType);
|
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)
|
if (paramType != null)
|
||||||
{
|
{
|
||||||
paramType.SpecialName = SpecialName.MethodParamsStruct;
|
paramType.SpecialName = SpecialName.MethodParamsStruct;
|
||||||
@ -470,7 +571,7 @@ namespace CapnpC.Model
|
|||||||
method.ParamsStruct.InheritFreeParameters(method);
|
method.ParamsStruct.InheritFreeParameters(method);
|
||||||
|
|
||||||
var resultNode = IdToNode(methodReader.ResultStructType);
|
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)
|
if (resultType != null)
|
||||||
{
|
{
|
||||||
resultType.SpecialName = SpecialName.MethodResultStruct;
|
resultType.SpecialName = SpecialName.MethodResultStruct;
|
||||||
@ -485,24 +586,13 @@ namespace CapnpC.Model
|
|||||||
method.ResultStruct.InheritFreeParameters(method);
|
method.ResultStruct.InheritFreeParameters(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentMethod = null;
|
state.currentMethod = null;
|
||||||
}
|
}
|
||||||
|
return def;
|
||||||
_typeNest.Pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.StructDataWordCount = structReader.Struct_DataWordCount;
|
||||||
def.StructPointerCount = structReader.Struct_PointerCount;
|
def.StructPointerCount = structReader.Struct_PointerCount;
|
||||||
|
|
||||||
@ -513,12 +603,10 @@ namespace CapnpC.Model
|
|||||||
16u * structReader.Struct_DiscriminantOffset);
|
16u * structReader.Struct_DiscriminantOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessInterfaceOrStructTail(def, structReader);
|
return ProcessInterfaceOrStructTail(def, structReader, state);
|
||||||
|
|
||||||
return def;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDefinition ProcessParameterList(Schema.Node.Reader reader, Schema.Brand.Reader brandReader, List<Field> list)
|
TypeDefinition ProcessParameterList(Schema.Node.Reader reader, Schema.Brand.Reader brandReader, List<Field> list, Pass2State state)
|
||||||
{
|
{
|
||||||
//# If a named parameter list was specified in the method
|
//# If a named parameter list was specified in the method
|
||||||
//# declaration (rather than a single struct parameter type) then a corresponding struct type is
|
//# declaration (rather than a single struct parameter type) then a corresponding struct type is
|
||||||
@ -533,58 +621,38 @@ namespace CapnpC.Model
|
|||||||
throw new InvalidSchemaException("Expected a struct");
|
throw new InvalidSchemaException("Expected a struct");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var def = ProcessTypeDef(reader.Id, state, TypeTag.Struct);
|
||||||
|
|
||||||
if (reader.ScopeId == 0)
|
if (reader.ScopeId == 0)
|
||||||
{
|
{
|
||||||
// Auto-generated => Named parameter list
|
// Auto-generated => Named parameter list
|
||||||
ProcessFields(reader, null, list);
|
foreach (var field in def.Fields) list.Add(field);
|
||||||
return ProcessStruct(reader, null);
|
return def;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Single, anonymous, struct-typed parameter
|
// Single, anonymous, struct-typed parameter
|
||||||
var def = GetOrCreateTypeDef(reader.Id, TypeTag.Struct);
|
|
||||||
var type = Types.FromDefinition(def);
|
var type = Types.FromDefinition(def);
|
||||||
ProcessBrand(brandReader, type);
|
ProcessBrand(brandReader, type, state);
|
||||||
var anon = new Field() { Type = type };
|
var anon = new Field() { Type = type };
|
||||||
list.Add(anon);
|
list.Add(anon);
|
||||||
return null;
|
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)
|
foreach (var superClassReader in ifaceReader.Interface_Superclasses)
|
||||||
{
|
{
|
||||||
var superClass = GetOrCreateTypeDef(
|
var superClass = ProcessTypeDef(superClassReader.Id, state, TypeTag.Interface);
|
||||||
superClassReader.Id,
|
|
||||||
TypeTag.Interface);
|
|
||||||
|
|
||||||
def.Superclasses.Add(Types.FromDefinition(superClass));
|
def.Superclasses.Add(Types.FromDefinition(superClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessInterfaceOrStructTail(def, ifaceReader);
|
return ProcessInterfaceOrStructTail(def, ifaceReader, state);
|
||||||
|
|
||||||
return def;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
foreach (var fieldReader in enumReader.Enumerants)
|
||||||
{
|
{
|
||||||
var field = new Enumerant()
|
var field = new Enumerant()
|
||||||
@ -601,46 +669,52 @@ namespace CapnpC.Model
|
|||||||
|
|
||||||
def.Enumerants.Add(field);
|
def.Enumerants.Add(field);
|
||||||
}
|
}
|
||||||
|
return def;
|
||||||
_typeNest.Pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessConst(Schema.Node.Reader constReader, string name)
|
Constant ProcessConst(Schema.Node.Reader constReader, Constant @const, Pass2State state)
|
||||||
{
|
{
|
||||||
var value = ProcessValue(constReader.Const_Value);
|
var value = ProcessValue(constReader.Const_Value);
|
||||||
value.Type = ProcessType(constReader.Const_Type);
|
value.Type = ProcessType(constReader.Const_Type, state);
|
||||||
|
@const.Value = value;
|
||||||
_typeNest.Peek().Constants.Add(value);
|
return @const;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessNode(Schema.Node.Reader node, string name)
|
TypeDefinition ProcessTypeDef(ulong id, Pass2State state, TypeTag tag = default)
|
||||||
{
|
{
|
||||||
switch (0)
|
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.GetExistingDef(id, tag);
|
||||||
|
if (state.processedNodes.Contains(id)) return def;
|
||||||
|
state.processedNodes.Add(id);
|
||||||
|
|
||||||
|
switch (def)
|
||||||
{
|
{
|
||||||
case 0 when node.IsAnnotation:
|
case Annotation annotation:
|
||||||
break;
|
return annotation;
|
||||||
|
case Constant constant:
|
||||||
case 0 when node.IsConst:
|
def.DeclaringElement.Constants.Add(ProcessConst(node, constant, state));
|
||||||
ProcessConst(node, name);
|
return def;
|
||||||
break;
|
case TypeDefinition typeDef when kind == NodeKind.Enum:
|
||||||
|
return ProcessEnum(node, typeDef, state);
|
||||||
case 0 when node.IsEnum:
|
case TypeDefinition typeDef when kind == NodeKind.Interface:
|
||||||
ProcessEnum(node, name);
|
return ProcessInterface(node, typeDef, state);
|
||||||
break;
|
case TypeDefinition typeDef when kind == NodeKind.Struct || kind == NodeKind.Group:
|
||||||
|
return ProcessStruct(node, typeDef, state);
|
||||||
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;
|
|
||||||
|
|
||||||
default:
|
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 +725,55 @@ namespace CapnpC.Model
|
|||||||
return 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,16 @@ namespace CapnpC.Model
|
|||||||
{
|
{
|
||||||
class Type: AbstractType
|
class Type: AbstractType
|
||||||
{
|
{
|
||||||
|
// Representation of a type expression in the schema language
|
||||||
|
|
||||||
public TypeDefinition Definition { get; set; }
|
public TypeDefinition Definition { get; set; }
|
||||||
|
// The model for all nodes that are not file nodes - they define types
|
||||||
|
|
||||||
public GenericParameter Parameter { get; set; }
|
public GenericParameter Parameter { get; set; }
|
||||||
|
// A reference to type parameter in this scope
|
||||||
|
|
||||||
public Type ElementType { get; set; }
|
public Type ElementType { get; set; }
|
||||||
|
// The type of a list element, if this is a list.
|
||||||
|
|
||||||
readonly Dictionary<GenericParameter, Type> _parameterBindings =
|
readonly Dictionary<GenericParameter, Type> _parameterBindings =
|
||||||
new Dictionary<GenericParameter, Type>();
|
new Dictionary<GenericParameter, Type>();
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
namespace CapnpC.Model
|
namespace CapnpC.Model
|
||||||
{
|
{
|
||||||
class TypeDefinition : AbstractType, IHasNestedDefinitions, IHasGenericParameters
|
class TypeDefinition : AbstractType, IDefinition, IHasNestedDefinitions, IHasGenericParameters
|
||||||
{
|
{
|
||||||
public class DiscriminationInfo
|
public class DiscriminationInfo
|
||||||
{
|
{
|
||||||
@ -16,23 +16,30 @@ namespace CapnpC.Model
|
|||||||
public uint TagOffset { get; }
|
public uint TagOffset { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeDefinition(TypeTag tag, ulong id)
|
public TypeDefinition(TypeTag tag, ulong id, IHasNestedDefinitions parent)
|
||||||
{
|
{
|
||||||
Tag = tag;
|
Tag = tag;
|
||||||
Id = id;
|
Id = id;
|
||||||
|
DeclaringElement = parent;
|
||||||
|
if (tag == TypeTag.Group)
|
||||||
|
((TypeDefinition)parent).NestedGroups.Add(this);
|
||||||
|
else
|
||||||
|
parent.NestedDefinitions.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong Id { get; }
|
public ulong Id { get; }
|
||||||
public IHasNestedDefinitions DeclaringElement { get; set; }
|
public IHasNestedDefinitions DeclaringElement { get; }
|
||||||
|
|
||||||
public Method UsingMethod { get; set; }
|
public Method UsingMethod { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public SpecialName SpecialName { get; set; }
|
public SpecialName SpecialName { get; set; }
|
||||||
public DiscriminationInfo UnionInfo { get; set; }
|
public DiscriminationInfo UnionInfo { get; set; }
|
||||||
public new List<Field> Fields => base.Fields;
|
public new List<Field> Fields => base.Fields;
|
||||||
public List<Enumerant> Enumerants { get; } = new List<Enumerant>();
|
public List<Enumerant> Enumerants { get; } = new List<Enumerant>();
|
||||||
public List<TypeDefinition> NestedTypes { get; } = new List<TypeDefinition>();
|
public ICollection<IDefinition> NestedDefinitions { get; } = new List<IDefinition>();
|
||||||
|
public IEnumerable<TypeDefinition> NestedTypes { get => this.GetNestedTypes(); }
|
||||||
public List<TypeDefinition> NestedGroups { get; } = new List<TypeDefinition>();
|
public List<TypeDefinition> NestedGroups { get; } = new List<TypeDefinition>();
|
||||||
public List<Value> Constants { get; } = new List<Value>();
|
public ICollection<Constant> Constants { get; } = new List<Constant>();
|
||||||
public List<Method> Methods { get; } = new List<Method>();
|
public List<Method> Methods { get; } = new List<Method>();
|
||||||
public List<Type> Superclasses { get; } = new List<Type>();
|
public List<Type> Superclasses { get; } = new List<Type>();
|
||||||
public List<string> GenericParameters { get; } = new List<string>();
|
public List<string> GenericParameters { get; } = new List<string>();
|
||||||
@ -54,6 +61,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<GenericParameter> AllTypeParameters
|
public IEnumerable<GenericParameter> AllTypeParameters
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace CapnpC.Model
|
|
||||||
{
|
|
||||||
class TypeDefinitionManager
|
|
||||||
{
|
|
||||||
readonly Dictionary<ulong, TypeDefinition> _id2def =
|
|
||||||
new Dictionary<ulong, TypeDefinition>();
|
|
||||||
|
|
||||||
public TypeDefinition GetOrCreate(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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
def = new TypeDefinition(tag, id);
|
|
||||||
_id2def.Add(id, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TypeDefinition GetExisting(ulong id)
|
|
||||||
{
|
|
||||||
return _id2def[id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,6 +28,9 @@
|
|||||||
Group,
|
Group,
|
||||||
Interface,
|
Interface,
|
||||||
Enum,
|
Enum,
|
||||||
AnyEnum
|
AnyEnum,
|
||||||
|
Const,
|
||||||
|
Annotation,
|
||||||
|
File
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
using Capnp;
|
using Capnp;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleToAttribute("capnpc-csharp.tests")]
|
||||||
|
|
||||||
namespace CapnpC
|
namespace CapnpC
|
||||||
{
|
{
|
||||||
|
@ -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;
|
@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
|
struct Node @0xe682ab4cf923a417 { # 40 bytes, 6 ptrs
|
||||||
id @0 :UInt64; # bits[0, 64)
|
id @0 :UInt64; # bits[0, 64)
|
||||||
displayName @1 :Text; # ptr[0]
|
displayName @1 :Text; # ptr[0]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user