mirror of
https://github.com/zap-proto/cs.git
synced 2026-10-30 15:05:32 +00:00
Finishes the in-flight capnp→ZAP rebrand on this branch. The prior commits
renamed identifiers/namespaces/files/projects (Capnp.Net.Runtime→Zap.Net.Runtime,
CapnpC→ZapC, .capnp→.zap) but left the human-readable brand name "Cap'n Proto"
throughout doc-comments, .csproj/.nuspec descriptions, README, MSBuild .xaml
rule display names, and the generated XML doc. This completes brand neutrality:
- Replace 154 "Cap'n Proto" / 4 "Cap'n-Proto" / 1 "Cap'n'p" prose occurrences
with "ZAP" across 32 first-party files (runtime, generator, zapc-csharp,
MSBuild integration, chocolatey nuspecs, README, docs, XML doc).
- Revert the LICENSE provenance URL to the real upstream fork
(c80k/capnproto-dotnetcore) — upstream-fork license headers must stay.
- Canonicalize project/repo URLs to github.com/zap-proto/cs (were fabricated
c80k/zap-dotnetcore) in csproj/nuspec/VERIFICATION/README badges.
- Canonicalize docs URLs zap-protocol(.github.io|/zap-cs|/zap-cpp-core)
→ zap-proto.dev / github.com/zap-proto/{cs,cpp-core}.
- Collapse redundant "zap \"ZAP\"" PackageTags to "zap".
Verified consistent (no toolchain on host): every .sln/.csproj ProjectReference
resolves; all namespaces are Zap*/ZapC*; MSBuild task chain
(GenerateZapFileCodeBehindTask, ZapFiles ItemGroup, _ZapcCsharp_TaskAssembly)
is uniformly renamed; props/targets/xaml/coverage/chocolatey carry no capnp.
Deliberately preserved as upstream-derived test data (not first-party source):
upstream Cap'n Proto schema fixtures (rpc.zap, rpc-twoparty.zap, json.zap,
rpc-csharp.zap), golden compiler-error outputs (errors.txt), and the
machine-generated DO-NOT-EDIT test.zap.{c++,h}. Their "Cap'n Proto" strings are
the literal output of the external schema compiler the compat test matches.
293 lines
9.8 KiB
C#
293 lines
9.8 KiB
C#
namespace ZapC.CSharp.Generator.CodeGen
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using ZapC.CSharp.Generator.Model;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
|
|
using static SyntaxHelpers;
|
|
|
|
internal class CodeGenerator
|
|
{
|
|
readonly SchemaModel _model;
|
|
readonly GeneratorOptions _options;
|
|
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;
|
|
_options = options;
|
|
_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<MemberDeclarationSyntax> TransformEnum(TypeDefinition def)
|
|
{
|
|
yield return _commonGen.MakeEnum(def);
|
|
}
|
|
|
|
IEnumerable<TypeParameterSyntax> MakeTypeParameters(TypeDefinition def)
|
|
{
|
|
foreach (string name in def.GenericParameters)
|
|
{
|
|
yield return TypeParameter(_names.GetGenericTypeParameter(name).Identifier);
|
|
}
|
|
}
|
|
|
|
IEnumerable<TypeParameterConstraintClauseSyntax> MakeTypeParameterConstraints(TypeDefinition def)
|
|
{
|
|
foreach (string name in def.GenericParameters)
|
|
{
|
|
yield return TypeParameterConstraintClause(
|
|
_names.GetGenericTypeParameter(name).IdentifierName)
|
|
.AddConstraints(ClassOrStructConstraint(SyntaxKind.ClassConstraint));
|
|
}
|
|
}
|
|
|
|
IEnumerable<MemberDeclarationSyntax> TransformStruct(TypeDefinition def)
|
|
{
|
|
var topDecl = ClassDeclaration(_names.MakeTypeName(def).Identifier)
|
|
.AddModifiers(_names.TypeVisibilityModifier);
|
|
|
|
if (_names.EmitDomainClassesAndInterfaces)
|
|
{
|
|
topDecl = topDecl.AddBaseListTypes(SimpleBaseType(_names.Type<Zap.IZapSerializable>(Nullability.NonNullable)));
|
|
}
|
|
else
|
|
{
|
|
topDecl = topDecl.AddModifiers(Static);
|
|
}
|
|
|
|
|
|
if (def.GenericParameters.Count > 0)
|
|
{
|
|
topDecl = topDecl
|
|
.AddTypeParameterListParameters(MakeTypeParameters(def).ToArray())
|
|
.AddConstraintClauses(MakeTypeParameterConstraints(def).ToArray());
|
|
}
|
|
|
|
topDecl = topDecl
|
|
.AddMembers(_names.MakeTypeIdConst(def.Id))
|
|
.AddAttributeLists(_names.MakeTypeDecorationAttributes(def.Id));
|
|
|
|
if (def.UnionInfo != null)
|
|
{
|
|
topDecl = topDecl.AddMembers(_commonGen.MakeUnionSelectorEnum(def));
|
|
}
|
|
|
|
if (_names.EmitDomainClassesAndInterfaces)
|
|
{
|
|
topDecl = topDecl.AddMembers(_domClassGen.MakeDomainClassMembers(def));
|
|
}
|
|
|
|
topDecl = topDecl.AddMembers(
|
|
_readerGen.MakeReaderStruct(def),
|
|
_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<MemberDeclarationSyntax> TransformInterface(TypeDefinition def)
|
|
{
|
|
if (!_names.EmitDomainClassesAndInterfaces)
|
|
yield break;
|
|
|
|
yield return _interfaceGen.MakeInterface(def);
|
|
yield return _interfaceGen.MakeProxy(def);
|
|
yield return _interfaceGen.MakeSkeleton(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<MemberDeclarationSyntax> 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");
|
|
}
|
|
}
|
|
|
|
ClassDeclarationSyntax TransformForPipeliningSupport(GenFile file)
|
|
{
|
|
var classDecl = default(ClassDeclarationSyntax);
|
|
|
|
var q = new Queue<TypeDefinition>();
|
|
|
|
foreach (var inner in file.NestedTypes)
|
|
{
|
|
q.Enqueue(inner);
|
|
}
|
|
|
|
while (q.Count > 0)
|
|
{
|
|
var cur = q.Dequeue();
|
|
|
|
if (cur.Tag == TypeTag.Interface && _interfaceGen.RequiresPipeliningSupport(cur))
|
|
{
|
|
var members = _interfaceGen.MakePipeliningSupport(cur).ToArray();
|
|
|
|
if (members.Length > 0)
|
|
{
|
|
if (classDecl == null)
|
|
{
|
|
classDecl = ClassDeclaration(_names.MakePipeliningSupportExtensionClassName(file).Identifier)
|
|
.AddModifiers(_names.TypeVisibilityModifier, Static, Partial);
|
|
}
|
|
|
|
classDecl = classDecl.AddMembers(members);
|
|
}
|
|
}
|
|
|
|
foreach (var inner in cur.NestedTypes)
|
|
{
|
|
q.Enqueue(inner);
|
|
}
|
|
}
|
|
|
|
return classDecl;
|
|
}
|
|
|
|
internal string Transform(GenFile file)
|
|
{
|
|
_names.NullableEnable = file.NullableEnable ?? _options.NullableEnableDefault;
|
|
_names.EmitDomainClassesAndInterfaces = file.EmitDomainClassesAndInterfaces;
|
|
_names.TypeVisibility = file.TypeVisibility;
|
|
|
|
NameSyntax topNamespace = GenNames.NamespaceName(file.Namespace) ?? _names.TopNamespace;
|
|
|
|
var ns = NamespaceDeclaration(topNamespace);
|
|
|
|
if (file.EmitNullableDirective)
|
|
{
|
|
ns = ns.WithLeadingTrivia(
|
|
Trivia(
|
|
NullableDirectiveTrivia(
|
|
Token(_names.NullableEnable ? SyntaxKind.EnableKeyword : SyntaxKind.DisableKeyword),
|
|
true)))
|
|
.WithTrailingTrivia(
|
|
Trivia(
|
|
NullableDirectiveTrivia(
|
|
Token(SyntaxKind.RestoreKeyword),
|
|
true)));
|
|
}
|
|
|
|
foreach (var def in file.NestedTypes)
|
|
{
|
|
ns = ns.AddMembers(Transform(def).ToArray());
|
|
}
|
|
|
|
if (_names.EmitDomainClassesAndInterfaces)
|
|
{
|
|
var psc = TransformForPipeliningSupport(file);
|
|
|
|
if (psc != null)
|
|
{
|
|
ns = ns.AddMembers(psc);
|
|
}
|
|
}
|
|
|
|
var cu = CompilationUnit().AddUsings(
|
|
UsingDirective(ParseName("Zap")),
|
|
UsingDirective(ParseName("Zap.Rpc")),
|
|
UsingDirective(ParseName("System")),
|
|
UsingDirective(ParseName("System.CodeDom.Compiler")),
|
|
UsingDirective(ParseName("System.Collections.Generic")));
|
|
|
|
if (_names.NullableEnable)
|
|
{
|
|
cu = cu.AddUsings(
|
|
UsingDirective(ParseName("System.Diagnostics.CodeAnalysis")));
|
|
}
|
|
|
|
cu = cu.AddUsings(
|
|
UsingDirective(ParseName("System.Threading")),
|
|
UsingDirective(ParseName("System.Threading.Tasks")));
|
|
|
|
cu = cu.AddMembers(ns);
|
|
|
|
string content = cu.NormalizeWhitespace(" ", Environment.NewLine).ToFullString();
|
|
|
|
if (!string.IsNullOrWhiteSpace(file.HeaderText))
|
|
{
|
|
content = file.HeaderText + content;
|
|
}
|
|
|
|
return content;
|
|
}
|
|
|
|
public IReadOnlyList<FileGenerationResult> Generate()
|
|
{
|
|
var result = new List<FileGenerationResult>();
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|