static NestedText GenTypeTagBody(string typeName, string tagName, Signature tag) { var modifiedArgs = tag.Args .Map(x => new Arg( name: x.Name == tagName ? $"{x.Name}Value" : x.Name, // TODO: move to normalizer type: x.Type, kind: x.Kind )) .ToArr(); var argsWithoutFlags = modifiedArgs .Filter(x => x.Kind.Match(_: () => true, flags: _ => false)) .ToArr(); var tagArgs = argsWithoutFlags .Map(x => ( name: x.Name, lowerName: Helpers.LowerFirst(x.Name), type: TgTypeConverter.ConvertArgType(x), isRef: TgTypeConverter.IsRefArgType(x) )).ToArray(); return(Scope( Scope( Line($"internal const uint TypeNumber = {Helpers.TypeNumber(tag.TypeNumber)};"), Line("[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]"), Line("uint ITgTypeTag.TypeNumber => TypeNumber;"), Line("") ), tagArgs.Map(arg => Line($"public readonly {arg.type} {arg.name};")).Scope(), Line(""), Scope( Line($"public {tagName}("), IndentedScope(1, $",{Environment.NewLine}", tagArgs.Map(arg => Line($"{arg.type} {arg.lowerName}")) ), Line(") {"), IndentedScope(1, tagArgs.Map(arg => Line( $"{arg.name} = {arg.lowerName}" + $"{(arg.isRef ? $" ?? throw new ArgumentNullException(nameof({arg.lowerName}))" : "")};" )) ), Line("}") ), Line(""), WithGen.GenWith(argsWithoutFlags, tagName), Line(""), typeName != tagName ? Scope( Line($"public static implicit operator {typeName}({tagName} tag) => new {typeName}(tag);"), Line($"public static implicit operator Some<{typeName}>({tagName} tag) => new {typeName}(tag);"), Line("") ) : EmptyScope(), RelationsGen.GenRelations(tagName, argsWithoutFlags), Line(""), Line(""), SerializerGen.GenSerializer(modifiedArgs, typeNumber: None, "ITgTypeTag.SerializeTag"), Line(""), SerializerGen.GenTypeTagDeserialize(tagName, modifiedArgs) )); }
public static NestedText GenSerializer(Arr <Arg> args, Option <int> typeNumber, string funcName) { Text GenSerializer(TgType type) => type.Match( primitive: x => $"Write{x.Type}", typeRef: x => "WriteSerializable", vector: x => Concat( $"WriteVector<{TgTypeConverter.ConvertType(x.Type)}>(", GenSerializer(x.Type), ")" ) ); Option <Text> GenNonFlagArgSerializer(Arg arg) => arg.Kind.Match( _: () => throw new Exception("WTF"), required: _ => GenSerializer(arg.Type).Apply(Some), optional: x => arg.Type == TgType.OfPrimitive(PrimitiveType.True) ? None : Concat( $"WriteOption<{TgTypeConverter.ConvertType(arg.Type)}>(", GenSerializer(arg.Type), ")" ).Apply(Some) ).Map(s => Concat($"Write({arg.Name}, bw, ", s, ");") ); Text GenMaskSerializer(IEnumerable <(string, int)> maskArgs) => maskArgs.ToArr() .Apply(Optional).Filter(xs => xs.Count > 0) .Map(xs => xs .Map(x => $"MaskBit({x.Item2}, {x.Item1})").Map(String).Reduce((x, y) => Concat(x, " | ", y)) ) .IfNone("0") .Apply(mask => Concat("Write(", mask, ", bw, WriteInt);")); Option <Text> GenArgSerializer(Arg arg) => arg.Kind.Match( _: () => GenNonFlagArgSerializer(arg), flags: _ => args.Choose(x => x.Kind.Match( _: () => None, optional: optional => ($"{x.Name}", optional.Flag.Bit).Apply(Some) )).Apply(GenMaskSerializer) ); var body = args.Choose(GenArgSerializer).Map(Line).Scope().Apply(s => typeNumber .Map(Helpers.TypeNumber).Map(x => Line($"WriteUint(bw, {x});")).Map(typeNumSer => Scope(typeNumSer, s)) .IfNone(s) ); var def = Scope( Line($"void {funcName}(BinaryWriter bw)"), Line("{"), Indent(1, body), Line("}") ); return(def); }
public static NestedText GenTagYamlifier(Arr <Arg> args, string typeName) { Text GenYamlifier(bool tagOnly, TgType type) => type.Match( primitive: x => $"Yamlifier.Write{x.Type}", typeRef: x => $"{TgTypeConverter.ConvertType(type, cmpWrapper: false)}.Yamlify(tagOnly: {(tagOnly ? "true" : "false")})", vector: x => Concat( $"Yamlifier.StringifyVector<{TgTypeConverter.ConvertType(x.Type, cmpWrapper: false)}>(", GenYamlifier(tagOnly, x.Type), ")" ) );
public static NestedText GenWith(Arr <Arg> args, string typeName) => Scope( Line($"public {typeName} With("), IndentedScope(1, "," + Environment.NewLine, args .Map(arg => $"{TgTypeConverter.WrapArgTypeWithNullable(arg)} {Helpers.LowerFirst(arg.Name)} = null") .Map(Line) ), Line($") => new {typeName}("), IndentedScope(1, "," + Environment.NewLine, args .Map(arg => arg.Name).Map(argName => $"{Helpers.LowerFirst(argName)} ?? {argName}") .Map(Line) ), Line(");") );
public static NestedText GenRelations(string typeName, Arr <Arg> args) { var cmpTupleName = String("CmpTuple"); Text EmPt(Text text) => Concat("(", text, ")"); Func <Arr <Text>, Text> Tuple(bool type) => xs => xs.Count == 0 ? (type ? "Unit" : "Unit.Default") : xs.Count == 1 ? xs[0] : Join(", ", xs).Apply(EmPt); Text ArgsTuple(bool type, Func <Arg, Text> argStr) => args .Map(argStr) .Apply(Tuple(type)); var argsTuple = ArgsTuple(false, x => x.Name); var argsTupleType = ArgsTuple(true, x => TgTypeConverter.ConvertArgType(x)); var cmpTuple = Scope( Line("[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]"), Line(Concat(argsTupleType, " ", cmpTupleName, " =>")), Indent(1, Line(Concat(argsTuple, ";"))) ); var argsInterpolationStr = args .Map(x => Concat(x.Name, ": ", "{", x.Name, "}")) .Apply(xs => Join(", ", xs)) .Apply(x => Concat("$\"(", x, ")\"")); return(Scope(Environment.NewLine + Environment.NewLine, cmpTuple, GenEqRelations(typeName, cmpTupleName), GenCmpRelations(typeName, cmpTupleName), GenGetHashCode(cmpTupleName), GenToString(argsInterpolationStr) )); }
static NestedText GenFunc(Signature func, string funcName) { var argsWithoutFlags = func.Args .Filter(x => x.Kind.Match(_: () => true, flags: _ => false)) .ToArr(); var funcArgs = argsWithoutFlags .Map(x => ( name: x.Name, lowerName: Helpers.LowerFirst(x.Name), type: TgTypeConverter.ConvertArgType(x), isRef: TgTypeConverter.IsRefArgType(x) )).ToArray(); // usually it is a higher-order function, i am too lazy to modify the scheme just for this case var isWrapper = func.Args.Exists(x => x.Type == TgType.OfTypeRef("X") || x.Type == TgType.OfTypeRef("!X")); var resType = isWrapper ? "TFuncRes" : TgTypeConverter.ConvertType(func.ResultType); var classAccess = isWrapper ? "" : "public "; var classTemplates = isWrapper ? "<TFunc, TFuncRes>" : ""; var classAnnotations = isWrapper ? $": ITgFunc<{resType}> where TFunc : class, ITgFunc<{resType}>" : $": ITgFunc<{resType}>, IEquatable<{funcName}>, IComparable<{funcName}>, IComparable"; var resDes = isWrapper ? "Query.DeserializeResult(br);" // it is 'Query' all the time, i am too lazy : Concat("Read(br, ", SerializerGen.GenTypeDeserializer(func.ResultType), ");"); var resultDeserializer = Scope( Line($"{resType} ITgFunc<{resType}>.DeserializeResult(BinaryReader br) =>"), Indent(1, Line(resDes)) ); return(Scope( Line($"{classAccess}sealed class {funcName}{classTemplates} {classAnnotations}"), Line("{"), IndentedScope(1, funcArgs.Map(arg => Line($"public {arg.type} {arg.name} {{ get; }}")).Scope(), Scope( Line(""), Scope( Line($"public {funcName}("), IndentedScope(1, $",{Environment.NewLine}", funcArgs.Map(arg => Line($"{arg.type} {arg.lowerName}")) ), Line(") {"), IndentedScope(1, funcArgs.Map(arg => Line( $"{arg.name} = {arg.lowerName}" + $"{(arg.isRef ? $" ?? throw new ArgumentNullException(nameof({arg.lowerName}))" : "")};" )) ), Line("}") ), Line(""), Line(""), isWrapper ? Scope(new NestedText[0]) : Scope( WithGen.GenWith(argsWithoutFlags, funcName), Line(""), RelationsGen.GenRelations(funcName, argsWithoutFlags), Line("") ), SerializerGen.GenSerializer(func.Args, typeNumber: func.TypeNumber, "ITgSerializable.Serialize"), Line(""), resultDeserializer ) ), Line("}") )); }