450 lines
17 KiB
C#
Raw Normal View History

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 WriterSnippetGen
{
readonly GenNames _names;
public WriterSnippetGen(GenNames names)
{
_names = names;
}
IEnumerable<MemberDeclarationSyntax> MakeWriterStructMembers(TypeDefinition structType)
{
yield return ConstructorDeclaration(_names.WriterStruct.Identifier)
.AddModifiers(Public)
.WithBody(
Block(
ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
ThisExpression(),
IdentifierName(SerializerStateWorder.SetStructName)))
.AddArgumentListArguments(
Argument(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(structType.StructDataWordCount))),
Argument(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(structType.StructPointerCount)))))));
}
IEnumerable<MemberDeclarationSyntax> MakeGroupWriterStructMembers()
{
yield return ConstructorDeclaration(_names.WriterStruct.Identifier)
.AddModifiers(Public)
.WithBody(Block());
}
PropertyDeclarationSyntax MakeWriterProperty(
TypeSyntax type,
string name,
ExpressionSyntax getter,
ExpressionSyntax setter,
bool cast,
bool cond)
{
if (cast)
{
getter = CastExpression(type, getter);
}
if (cond)
{
getter = ConditionalExpression(
BinaryExpression(
SyntaxKind.EqualsExpression,
_names.UnionDiscriminatorProp.IdentifierName,
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
_names.UnionDiscriminatorEnum.IdentifierName,
IdentifierName(name))),
getter,
LiteralExpression(
SyntaxKind.DefaultLiteralExpression,
Token(SyntaxKind.DefaultKeyword)));
}
var accessors = new AccessorDeclarationSyntax[setter != null ? 2 : 1];
accessors[0] = AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithExpressionBody(ArrowExpressionClause(getter))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
if (setter != null)
{
accessors[1] = AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithExpressionBody(ArrowExpressionClause(setter))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
}
return PropertyDeclaration(type, name)
.AddModifiers(Public)
.AddAccessorListAccessors(accessors);
}
ExpressionSyntax MakePointerSyntax(TypeSyntax type, object index) =>
InvocationExpression(
GenericName(nameof(Capnp.SerializerState.BuildPointer))
.AddTypeArgumentListArguments(type))
.AddArgumentListArguments(
Argument(ValueOf(index)));
ExpressionSyntax MakeReadCapSyntax(TypeSyntax type, object index) =>
InvocationExpression(
GenericName(nameof(Capnp.SerializerState.ReadCap))
.AddTypeArgumentListArguments(type))
.AddArgumentListArguments(
Argument(ValueOf(index)));
ExpressionSyntax MakeTypedPointerSyntax(object index, TypeSyntax type) =>
InvocationExpression(
GenericName(nameof(Capnp.SerializerState.BuildPointer))
.AddTypeArgumentListArguments(type))
.AddArgumentListArguments(
Argument(ValueOf(index)));
ExpressionSyntax MakeLinkSyntax(object index, bool suppressNullableWarning)
{
ExpressionSyntax value = IdentifierName("value");
if (suppressNullableWarning)
{
value = _names.SuppressNullableWarning(value);
}
return InvocationExpression(
IdentifierName(SerializerStateWorder.LinkName))
.AddArgumentListArguments(
Argument(ValueOf(index)),
Argument(value));
}
ExpressionSyntax MakeLinkObjectSyntax(object index) =>
InvocationExpression(
IdentifierName(nameof(Capnp.SerializerState.LinkObject)))
.AddArgumentListArguments(
Argument(ValueOf(index)),
Argument(IdentifierName("value")));
PropertyDeclarationSyntax MakeWriterRefTypeProperty(
TypeSyntax type,
string name,
ExpressionSyntax getter,
ExpressionSyntax setter,
bool cast,
bool cond)
{
if (cond)
{
type = _names.MakeNullableRefType(type);
}
var prop = MakeWriterProperty(type, name, getter, setter, cast, cond);
if (cond && _names.NullableEnable)
{
prop = prop.AddAttributeLists(
AttributeList(
SingletonSeparatedList(
Attribute(
IdentifierName("DisallowNull")))));
}
return prop;
}
PropertyDeclarationSyntax MakePointerProperty(TypeSyntax type, string name, object index, bool cast, bool cond)
{
ExpressionSyntax getter = MakePointerSyntax(type, index);
ExpressionSyntax setter = MakeLinkSyntax(index, cond);
return MakeWriterRefTypeProperty(type, name, getter, setter, cast, cond);
}
PropertyDeclarationSyntax MakePointerAsStructProperty(TypeSyntax type, string name, object index, bool cast, bool cond)
{
ExpressionSyntax getter = MakeTypedPointerSyntax(index, type);
ExpressionSyntax setter = MakeLinkSyntax(index, cond);
return MakeWriterRefTypeProperty(type, name, getter, setter, cast, cond);
}
PropertyDeclarationSyntax MakeProperty(
TypeSyntax outerType,
TypeSyntax innerType,
string name,
string readName,
string writeName,
object indexOrBitOffset,
ExpressionSyntax secondArg,
bool cast,
bool cond,
bool pasd)
{
var getter = InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
ThisExpression(),
IdentifierName(readName)))
.AddArgumentListArguments(
Argument(ValueOf(indexOrBitOffset)),
Argument(secondArg));
ExpressionSyntax value = IdentifierName("value");
if (cast)
{
value = CastExpression(innerType, value);
}
var setter = InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
ThisExpression(),
IdentifierName(writeName)))
.AddArgumentListArguments(
Argument(ValueOf(indexOrBitOffset)),
Argument(value),
Argument(secondArg));
if (pasd)
{
setter.AddArgumentListArguments(Argument(secondArg));
}
return MakeWriterProperty(outerType, name, getter, setter, cast, cond);
}
PropertyDeclarationSyntax MakePrimitiveProperty<T>(Field field, string readName)
{
return MakeProperty(
_names.Type<T>(Nullability.NonNullable),
null,
_names.GetCodeIdentifier(field).ToString(),
readName,
nameof(Capnp.SerializerExtensions.WriteData),
field.BitOffset.Value,
ValueOf(field.DefaultValue.ScalarValue),
false,
field.DiscValue.HasValue,
true);
}
PropertyDeclarationSyntax MakeEnumProperty(Field field, string readName)
{
return MakeProperty(
_names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.NotRelevant, Nullability.NonNullable),
_names.Type<ushort>(Nullability.NonNullable),
_names.GetCodeIdentifier(field).ToString(),
readName,
nameof(Capnp.SerializerExtensions.WriteData),
field.BitOffset.Value,
ValueOf(field.DefaultValue.ScalarValue),
true,
field.DiscValue.HasValue,
true);
}
PropertyDeclarationSyntax MakeTextProperty(Field field)
{
return MakeProperty(
_names.Type<string>(Nullability.NullableRef),
null,
_names.GetCodeIdentifier(field).ToString(),
nameof(Capnp.SerializerState.ReadText),
nameof(Capnp.SerializerState.WriteText),
(int)field.Offset,
ValueOf(field.DefaultValue.ScalarValue),
false,
field.DiscValue.HasValue,
false);
}
PropertyDeclarationSyntax MakeStructProperty(Field field)
{
var qtype = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer, Nullability.NonNullable);
return MakePointerAsStructProperty(qtype, _names.GetCodeIdentifier(field).ToString(),
(int)field.Offset, false, field.DiscValue.HasValue);
}
PropertyDeclarationSyntax MakeGroupProperty(Field field)
{
TypeSyntax type = QualifiedName(
_names.MakeTypeName(field.Type.Definition).IdentifierName,
_names.WriterStruct.IdentifierName);
var getter = InvocationExpression(
GenericName(nameof(Capnp.SerializerState.Rewrap))
.AddTypeArgumentListArguments(type));
if (field.DiscValue.HasValue)
{
type = _names.MakeNullableRefType(type);
}
return MakeWriterProperty(type, _names.GetCodeIdentifier(field).ToString(), getter, null, false, field.DiscValue.HasValue);
}
PropertyDeclarationSyntax MakeListProperty(Field field)
{
var qtype = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer, Nullability.NonNullable);
return MakePointerProperty(qtype, _names.GetCodeIdentifier(field).ToString(),
(int)field.Offset, false, field.DiscValue.HasValue);
}
PropertyDeclarationSyntax MakePointerProperty(Field field)
{
var type = IdentifierName(nameof(Capnp.DynamicSerializerState));
return MakePointerProperty(type, _names.GetCodeIdentifier(field).ToString(), (int)field.Offset, false, field.DiscValue.HasValue);
}
PropertyDeclarationSyntax MakeCapProperty(Field field)
{
var nonNullableType = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer, Nullability.NonNullable);
var nullableType = _names.MakeTypeSyntax(field.Type, field.DeclaringType, TypeUsage.Writer, Nullability.NullableRef);
int index = (int)field.Offset;
string name = _names.GetCodeIdentifier(field).ToString();
ExpressionSyntax getter = MakeReadCapSyntax(nonNullableType, index);
ExpressionSyntax setter = MakeLinkObjectSyntax(index);
return MakeWriterProperty(nullableType, name, getter, setter, false, field.DiscValue.HasValue);
}
PropertyDeclarationSyntax MakeWriterUnionSelector(TypeDefinition def)
{
return MakeProperty(
_names.UnionDiscriminatorEnum.IdentifierName,
_names.Type<ushort>(Nullability.NonNullable),
_names.UnionDiscriminatorProp.ToString(),
nameof(Capnp.SerializerExtensions.ReadDataUShort),
nameof(Capnp.SerializerExtensions.WriteData),
def.UnionInfo.TagOffset,
ValueOf(default(ushort)),
true, false, true);
}
PropertyDeclarationSyntax MakeWriterFieldProperty(Field field)
{
switch (field.Type.Tag)
{
case TypeTag.Bool:
return MakePrimitiveProperty<bool>(field,
nameof(Capnp.SerializerExtensions.ReadDataBool));
case TypeTag.S8:
return MakePrimitiveProperty<sbyte>(field,
nameof(Capnp.SerializerExtensions.ReadDataSByte));
case TypeTag.U8:
return MakePrimitiveProperty<byte>(field,
nameof(Capnp.SerializerExtensions.ReadDataByte));
case TypeTag.S16:
return MakePrimitiveProperty<short>(field,
nameof(Capnp.SerializerExtensions.ReadDataShort));
case TypeTag.U16:
return MakePrimitiveProperty<ushort>(field,
nameof(Capnp.SerializerExtensions.ReadDataUShort));
case TypeTag.S32:
return MakePrimitiveProperty<int>(field,
nameof(Capnp.SerializerExtensions.ReadDataInt));
case TypeTag.U32:
return MakePrimitiveProperty<uint>(field,
nameof(Capnp.SerializerExtensions.ReadDataUInt));
case TypeTag.S64:
return MakePrimitiveProperty<long>(field,
nameof(Capnp.SerializerExtensions.ReadDataLong));
case TypeTag.U64:
return MakePrimitiveProperty<ulong>(field,
nameof(Capnp.SerializerExtensions.ReadDataULong));
case TypeTag.F32:
return MakePrimitiveProperty<float>(field,
nameof(Capnp.SerializerExtensions.ReadDataFloat));
case TypeTag.F64:
return MakePrimitiveProperty<double>(field,
nameof(Capnp.SerializerExtensions.ReadDataDouble));
case TypeTag.Enum:
return MakeEnumProperty(field, nameof(Capnp.SerializerExtensions.ReadDataUShort));
case TypeTag.Text:
return MakeTextProperty(field);
case TypeTag.Struct:
return MakeStructProperty(field);
case TypeTag.Group:
return MakeGroupProperty(field);
case TypeTag.List:
case TypeTag.Data:
return MakeListProperty(field);
case TypeTag.AnyPointer:
case TypeTag.StructPointer:
case TypeTag.ListPointer:
return MakePointerProperty(field);
case TypeTag.CapabilityPointer:
case TypeTag.Interface:
return MakeCapProperty(field);
default:
return null;
}
}
public ClassDeclarationSyntax MakeWriterStruct(TypeDefinition def)
{
var WriterDecl = ClassDeclaration(_names.WriterStruct.ToString())
.AddModifiers(Public)
.AddBaseListTypes(
SimpleBaseType(IdentifierName(nameof(Capnp.SerializerState))));
var members = def.Tag == TypeTag.Group ?
MakeGroupWriterStructMembers() :
MakeWriterStructMembers(def);
WriterDecl = WriterDecl.AddMembers(members.ToArray());
if (def.UnionInfo != null)
{
WriterDecl = WriterDecl.AddMembers(MakeWriterUnionSelector(def));
}
foreach (var field in def.Fields)
{
var propDecl = MakeWriterFieldProperty(field);
if (propDecl != null)
{
WriterDecl = WriterDecl.AddMembers(propDecl);
}
}
return WriterDecl;
}
}
}