diff --git a/Capnp.Net.sln b/Capnp.Net.sln
index 8e20bf5..15732e6 100644
--- a/Capnp.Net.sln
+++ b/Capnp.Net.sln
@@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "capnpc-csharp.tests", "capn
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnpc.Csharp.MsBuild.Generation", "Capnpc.Csharp.MsBuild.Generation\Capnpc.Csharp.MsBuild.Generation.csproj", "{1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CapnpC.CSharp.Generator", "CapnpC.CSharp.Generator\CapnpC.CSharp.Generator.csproj", "{C3A3BB49-356E-4762-A190-76D877BE18F7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -45,6 +47,10 @@ Global
{1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C3A3BB49-356E-4762-A190-76D877BE18F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C3A3BB49-356E-4762-A190-76D877BE18F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C3A3BB49-356E-4762-A190-76D877BE18F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C3A3BB49-356E-4762-A190-76D877BE18F7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/CapnpC.CSharp.Generator/CapnpC.CSharp.Generator.csproj b/CapnpC.CSharp.Generator/CapnpC.CSharp.Generator.csproj
new file mode 100644
index 0000000..53233fd
--- /dev/null
+++ b/CapnpC.CSharp.Generator/CapnpC.CSharp.Generator.csproj
@@ -0,0 +1,15 @@
+
+
+
+ netcoreapp2.1
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CapnpC.CSharp.Generator/CapnpCompilation.cs b/CapnpC.CSharp.Generator/CapnpCompilation.cs
new file mode 100644
index 0000000..9f1a0a4
--- /dev/null
+++ b/CapnpC.CSharp.Generator/CapnpCompilation.cs
@@ -0,0 +1,49 @@
+using Capnp;
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace CapnpC.CSharp.Generator
+{
+ ///
+ /// Provides methods for controlling both the C# code generator backend and the frontend "capnpc"
+ ///
+ public static class CapnpCompilation
+ {
+ ///
+ /// Generates C# code from given input stream
+ ///
+ /// input stream containing the binary code generation request, which the frontend capnpc emits
+ /// generation result
+ /// if is null
+ public static GenerationResult GenerateFromStream(Stream input)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ try
+ {
+ WireFrame segments;
+
+ using (input)
+ {
+ segments = Framing.ReadSegments(input);
+ }
+
+ var dec = DeserializerState.CreateRoot(segments);
+ var reader = Schema.CodeGeneratorRequest.Reader.Create(dec);
+ var model = Model.SchemaModel.Create(reader);
+ var codeGen = new CodeGen.CodeGenerator(model, new CodeGen.GeneratorOptions());
+ return new GenerationResult(codeGen.Generate());
+ }
+ catch (Exception exception)
+ {
+ return new GenerationResult(exception);
+ }
+ }
+
+ public static GenerationResult InvokeCapnpcAndGenerate()
+ {
+ }
+ }
+}
diff --git a/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs b/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs
new file mode 100644
index 0000000..c983ccc
--- /dev/null
+++ b/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs
@@ -0,0 +1,190 @@
+namespace CapnpC.CSharp.Generator.CodeGen
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using CapnpC.CSharp.Generator.Model;
+ using Microsoft.CodeAnalysis;
+ using Microsoft.CodeAnalysis.CSharp;
+ using Microsoft.CodeAnalysis.CSharp.Syntax;
+ using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+ using static SyntaxHelpers;
+
+ class CodeGenerator
+ {
+ readonly SchemaModel _model;
+ readonly GenNames _names;
+ readonly CommonSnippetGen _commonGen;
+ readonly DomainClassSnippetGen _domClassGen;
+ readonly ReaderSnippetGen _readerGen;
+ readonly WriterSnippetGen _writerGen;
+ readonly InterfaceSnippetGen _interfaceGen;
+
+ public CodeGenerator(SchemaModel model, GeneratorOptions options)
+ {
+ _model = model;
+ _names = new GenNames(options);
+ _commonGen = new CommonSnippetGen(_names);
+ _domClassGen = new DomainClassSnippetGen(_names);
+ _readerGen = new ReaderSnippetGen(_names);
+ _writerGen = new WriterSnippetGen(_names);
+ _interfaceGen = new InterfaceSnippetGen(_names);
+ }
+
+ internal GenNames GetNames() => _names;
+
+ IEnumerable TransformEnum(TypeDefinition def)
+ {
+ yield return _commonGen.MakeEnum(def);
+ }
+
+ IEnumerable MakeTypeParameters(TypeDefinition def)
+ {
+ foreach (string name in def.GenericParameters)
+ {
+ yield return TypeParameter(_names.GetGenericTypeParameter(name).Identifier);
+ }
+ }
+
+ IEnumerable MakeTypeParameterConstraints(TypeDefinition def)
+ {
+ foreach (string name in def.GenericParameters)
+ {
+ yield return TypeParameterConstraintClause(
+ _names.GetGenericTypeParameter(name).IdentifierName)
+ .AddConstraints(ClassOrStructConstraint(SyntaxKind.ClassConstraint));
+ }
+ }
+
+ IEnumerable TransformStruct(TypeDefinition def)
+ {
+ var topDecl = ClassDeclaration(_names.MakeTypeName(def).Identifier)
+ .AddModifiers(Public)
+ .AddBaseListTypes(SimpleBaseType(Type()));
+
+ if (def.GenericParameters.Count > 0)
+ {
+ topDecl = topDecl
+ .AddTypeParameterListParameters(MakeTypeParameters(def).ToArray())
+ .AddConstraintClauses(MakeTypeParameterConstraints(def).ToArray());
+ }
+
+ if (def.UnionInfo != null)
+ {
+ topDecl = topDecl.AddMembers(_commonGen.MakeUnionSelectorEnum(def));
+ }
+
+ topDecl = topDecl.AddMembers(_domClassGen.MakeDomainClassMembers(def));
+ topDecl = topDecl.AddMembers(_readerGen.MakeReaderStruct(def));
+ topDecl = topDecl.AddMembers(_writerGen.MakeWriterStruct(def));
+
+ foreach (var nestedGroup in def.NestedGroups)
+ {
+ topDecl = topDecl.AddMembers(Transform(nestedGroup).ToArray());
+ }
+
+ foreach (var nestedDef in def.NestedTypes)
+ {
+ topDecl = topDecl.AddMembers(Transform(nestedDef).ToArray());
+ }
+
+ yield return topDecl;
+ }
+
+ IEnumerable TransformInterface(TypeDefinition def)
+ {
+ yield return _interfaceGen.MakeInterface(def);
+ yield return _interfaceGen.MakeProxy(def);
+ yield return _interfaceGen.MakeSkeleton(def);
+
+ if (_interfaceGen.RequiresPipeliningSupport(def))
+ {
+ yield return _interfaceGen.MakePipeliningSupport(def);
+ }
+
+ if (def.NestedTypes.Any())
+ {
+ var ns = ClassDeclaration(
+ _names.MakeTypeName(def, NameUsage.Namespace).ToString())
+ .AddModifiers(Public, Static);
+
+ if (def.GenericParameters.Count > 0)
+ {
+ ns = ns
+ .AddTypeParameterListParameters(MakeTypeParameters(def).ToArray())
+ .AddConstraintClauses(MakeTypeParameterConstraints(def).ToArray());
+ }
+
+ foreach (var nestedDef in def.NestedTypes)
+ {
+ ns = ns.AddMembers(Transform(nestedDef).ToArray());
+ }
+
+ yield return ns;
+ }
+ }
+
+ IEnumerable Transform(TypeDefinition def)
+ {
+ switch (def.Tag)
+ {
+ case TypeTag.Enum:
+ return TransformEnum(def);
+
+ case TypeTag.Group:
+ case TypeTag.Struct:
+ return TransformStruct(def);
+
+ case TypeTag.Interface:
+ return TransformInterface(def);
+
+ default:
+ throw new NotSupportedException($"Cannot declare type of kind {def.Tag} here");
+ }
+ }
+
+ internal string Transform(GenFile file)
+ {
+ NameSyntax topNamespace = GenNames.NamespaceName(file.Namespace) ?? _names.TopNamespace;
+
+ var ns = NamespaceDeclaration(topNamespace);
+
+ foreach (var def in file.NestedTypes)
+ {
+ ns = ns.AddMembers(Transform(def).ToArray());
+ }
+
+ var cu = CompilationUnit().AddUsings(
+ UsingDirective(ParseName("Capnp")),
+ UsingDirective(ParseName("Capnp.Rpc")),
+ UsingDirective(ParseName("System")),
+ UsingDirective(ParseName("System.Collections.Generic")),
+ UsingDirective(ParseName("System.Threading")),
+ UsingDirective(ParseName("System.Threading.Tasks")));
+
+ cu = cu.AddMembers(ns);
+
+ return cu.NormalizeWhitespace().ToFullString();
+ }
+
+ public IReadOnlyList Generate()
+ {
+ var result = new List();
+
+ foreach (var file in _model.FilesToGenerate)
+ {
+ try
+ {
+ result.Add(new FileGenerationResult(file.Name, Transform(file)));
+ }
+ catch (System.Exception exception)
+ {
+ result.Add(new FileGenerationResult(file.Name, exception));
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs
new file mode 100644
index 0000000..d89b873
--- /dev/null
+++ b/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs
@@ -0,0 +1,91 @@
+using System.Collections.Generic;
+using System.Linq;
+using CapnpC.CSharp.Generator.Model;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+using static CapnpC.CSharp.Generator.CodeGen.SyntaxHelpers;
+
+namespace CapnpC.CSharp.Generator.CodeGen
+{
+ class CommonSnippetGen
+ {
+ readonly GenNames _names;
+
+ public CommonSnippetGen(GenNames names)
+ {
+ _names = names;
+ }
+
+ public EnumDeclarationSyntax MakeUnionSelectorEnum(TypeDefinition def)
+ {
+ var whichEnum = EnumDeclaration(_names.UnionDiscriminatorEnum.ToString())
+ .AddModifiers(Public)
+ .AddBaseListTypes(SimpleBaseType(Type()));
+
+ var discFields = def.Fields.Where(f => f.DiscValue.HasValue);
+
+ foreach (var discField in discFields)
+ {
+ whichEnum = whichEnum.AddMembers(
+ EnumMemberDeclaration(_names.GetCodeIdentifier(discField).Identifier)
+ .WithEqualsValue(
+ EqualsValueClause(LiteralExpression(
+ SyntaxKind.NumericLiteralExpression,
+ Literal(discField.DiscValue.Value)))));
+ }
+
+ var ndecl = EnumMemberDeclaration(_names.UnionDiscriminatorUndefined.ToString()).WithEqualsValue(
+ EqualsValueClause(
+ LiteralExpression(
+ SyntaxKind.NumericLiteralExpression,
+ Literal(Schema.Field.Reader.NoDiscriminant))));
+
+ whichEnum = whichEnum.AddMembers(ndecl);
+
+ return whichEnum;
+ }
+
+ public EnumDeclarationSyntax MakeEnum(TypeDefinition def)
+ {
+ var decl = EnumDeclaration(def.Name)
+ .AddModifiers(Public)
+ .AddBaseListTypes(SimpleBaseType(Type()));
+
+ foreach (var enumerant in def.Enumerants.OrderBy(e => e.CodeOrder))
+ {
+ var mdecl = EnumMemberDeclaration(enumerant.Literal);
+
+ if (enumerant.Ordinal.HasValue)
+ {
+ mdecl = mdecl.WithEqualsValue(
+ EqualsValueClause(
+ LiteralExpression(
+ SyntaxKind.NumericLiteralExpression,
+ Literal(enumerant.Ordinal.Value))));
+ }
+
+ decl = decl.AddMembers(mdecl);
+ }
+
+ return decl;
+ }
+
+ public static IEnumerable MakeCommaSeparatedList(IEnumerable expressions)
+ {
+ bool first = true;
+
+ foreach (var expr in expressions)
+ {
+ if (first)
+ first = false;
+ else
+ yield return Token(SyntaxKind.CommaToken);
+
+ yield return expr;
+ }
+ }
+
+ }
+}
diff --git a/CapnpC.CSharp.Generator/CodeGen/DomainClassSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/DomainClassSnippetGen.cs
new file mode 100644
index 0000000..fb41086
--- /dev/null
+++ b/CapnpC.CSharp.Generator/CodeGen/DomainClassSnippetGen.cs
@@ -0,0 +1,970 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using CapnpC.CSharp.Generator.Model;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+using static CapnpC.CSharp.Generator.CodeGen.SyntaxHelpers;
+
+namespace CapnpC.CSharp.Generator.CodeGen
+{
+ class DomainClassSnippetGen
+ {
+ readonly GenNames _names;
+
+ public DomainClassSnippetGen(GenNames names)
+ {
+ _names = names;
+ }
+
+ MemberDeclarationSyntax MakeUnionField(Field field)
+ {
+ var type = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.DomainClassNullable);
+
+ switch (field.Type.Tag)
+ {
+ case TypeTag.Void:
+ return null;
+
+ default:
+ return PropertyDeclaration(type,
+ _names.GetCodeIdentifier(field).Identifier)
+ .AddModifiers(Public).AddAccessorListAccessors(
+ AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
+ .WithExpressionBody(
+ ArrowExpressionClause(
+ ConditionalExpression(
+ BinaryExpression(
+ SyntaxKind.EqualsExpression,
+ _names.UnionDiscriminatorField.IdentifierName,
+ MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ _names.UnionDiscriminatorEnum.IdentifierName,
+ _names.GetCodeIdentifier(field).IdentifierName)),
+ CastExpression(type,
+ _names.UnionContentField.IdentifierName),
+ LiteralExpression(
+ SyntaxKind.NullLiteralExpression))))
+ .WithSemicolonToken(
+ Token(SyntaxKind.SemicolonToken)),
+ AccessorDeclaration(
+ SyntaxKind.SetAccessorDeclaration)
+ .WithBody(
+ Block(
+ ExpressionStatement(
+ AssignmentExpression(
+ SyntaxKind.SimpleAssignmentExpression,
+ _names.UnionDiscriminatorField.IdentifierName,
+ MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ _names.UnionDiscriminatorEnum.IdentifierName,
+ _names.GetCodeIdentifier(field).IdentifierName))),
+ ExpressionStatement(
+ AssignmentExpression(
+ SyntaxKind.SimpleAssignmentExpression,
+ _names.UnionContentField.IdentifierName,
+ IdentifierName("value"))))));
+ }
+ }
+
+ MemberDeclarationSyntax MakeStructField(Field field)
+ {
+ if (field.Type.Tag == TypeTag.Void)
+ {
+ return null;
+ }
+
+ var prop = PropertyDeclaration(_names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.DomainClass),
+ _names.GetCodeIdentifier(field).Identifier)
+ .AddModifiers(Public).AddAccessorListAccessors(
+ AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
+ AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
+
+ if (field.DefaultValueIsExplicit && field.Type.IsValueType)
+ {
+ prop = prop.WithInitializer(
+ EqualsValueClause(MakeDefaultValue(field)))
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
+ }
+
+ return prop;
+ }
+
+ MemberDeclarationSyntax MakeUnionDiscriminatorField()
+ {
+ return FieldDeclaration(
+ VariableDeclaration(_names.UnionDiscriminatorEnum.IdentifierName)
+ .AddVariables(
+ VariableDeclarator(_names.UnionDiscriminatorField.Identifier)
+ .WithInitializer(
+ EqualsValueClause(
+ MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ _names.UnionDiscriminatorEnum.IdentifierName,
+ _names.UnionDiscriminatorUndefined.IdentifierName)))))
+ .AddModifiers(Private);
+ }
+
+ MemberDeclarationSyntax MakeUnionContentField()
+ {
+ return FieldDeclaration(
+ VariableDeclaration(SyntaxHelpers.Type