// SPDX-License-Identifier: AGPL-3.0-or-later // Copyright (C) 2022-2026 Aykut Alparslan KOC using System.Globalization; namespace Ferrite.TL.Schema; public sealed class LayerSchemaSymbol { private readonly IReadOnlyList _fields; public bool IsMethod { get; } public string Name { get; } public int Id { get; } public string ResultType { get; } public string? VectorElementType { get; } public IReadOnlyList Fields => _fields; public LayerSchemaSymbol(bool isMethod, string name, int id, string resultType, string? vectorElementType, IEnumerable fields) { IsMethod = isMethod; Name = name; Id = id; ResultType = resultType; VectorElementType = vectorElementType; _fields = Array.AsReadOnly(fields.ToArray()); } public LayerConstructor ToConstructor() { return new LayerConstructor(Name, Id, ResultType, _fields); } } public static class LayerSchemaReader { internal const int VectorConstructorId = unchecked((int)0x1cb5c415); private const string VectorIdentifier = "vector"; private const string VectorResultType = "Vector"; public static IReadOnlyList Read(string source) { if (!source.EndsWith("\n", StringComparison.Ordinal)) { source += "\n"; } var parser = new Parser(new Lexer(source)); var symbols = new List(); CombinatorDeclarationSyntax? combinator = parser.ParseCombinator(); while (combinator != null) { LayerSchemaSymbol? symbol = Convert(combinator); if (symbol != null) { symbols.Add(symbol); } combinator = parser.ParseCombinator(); } return symbols; } public static LayerSchema Build(int layer, IEnumerable symbols) { var constructors = new List(); var methods = new List(); var vectorResults = new List>(); foreach (LayerSchemaSymbol symbol in symbols) { if (symbol.IsMethod) { if (symbol.VectorElementType != null) { vectorResults.Add(new KeyValuePair( symbol.Id, symbol.VectorElementType)); } methods.Add(symbol.ToConstructor()); continue; } constructors.Add(symbol.ToConstructor()); } return new LayerSchema(layer, constructors, vectorResults, methods); } public static LayerSchema Read(int layer, string source) { return Build(layer, Read(source)); } public static LayerType ConvertType(TypeTermSyntax type) { string identifier = type.Identifier ?? throw new InvalidOperationException("Schema type is incomplete."); switch (identifier) { case "#": return new LayerType(LayerWireKind.Flags); case "int": return new LayerType(LayerWireKind.Int32); case "long": return new LayerType(LayerWireKind.Int64); case "double": return new LayerType(LayerWireKind.Double); case "int128": return new LayerType(LayerWireKind.Int128); case "int256": return new LayerType(LayerWireKind.Int256); case "int512": return new LayerType(LayerWireKind.Int512); case "bytes": return new LayerType(LayerWireKind.Bytes); case "string": return new LayerType(LayerWireKind.String); case "true": return new LayerType(LayerWireKind.True); case "Vector": case "vector": if (type.OptionalType == null) { throw new InvalidOperationException("Vector element type is missing."); } return new LayerType(LayerWireKind.Vector, null, identifier == "vector" || type.IsBare, ConvertType(type.OptionalType)); default: return new LayerType(LayerWireKind.Object, type.IsTypeOf ? null : Qualify(type.NamespaceIdentifier, identifier), type.IsBare); } } public static string Qualify(string? nameSpace, string identifier) { return nameSpace == null ? identifier : nameSpace + "." + identifier; } private static LayerSchemaSymbol? Convert(CombinatorDeclarationSyntax combinator) { if (combinator.CombinatorType == CombinatorType.Builtin) { return ConvertVector(combinator); } if (combinator.Name == null || combinator.Identifier == null || combinator.Type?.Identifier == null) { return null; } bool isMethod = combinator.CombinatorType == CombinatorType.Function; var fields = new List(); if (combinator.Arguments != null) { foreach (SimpleArgumentSyntax argument in combinator.Arguments) { if (argument.Identifier == null || argument.TypeTerm == null) { throw new InvalidOperationException("Schema argument is incomplete."); } fields.Add(new LayerField(argument.Identifier, ConvertType(argument.TypeTerm), argument.ConditionalDefinition?.Identifier, argument.ConditionalDefinition?.ConditionalArgumentBit)); } } uint id = uint.Parse(combinator.Name, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture); return new LayerSchemaSymbol(isMethod, Qualify(combinator.Namespace, combinator.Identifier), unchecked((int)id), Qualify(combinator.Type.NamespaceIdentifier, combinator.Type.Identifier), VectorElementType(combinator.Type), fields); } private static LayerSchemaSymbol? ConvertVector(CombinatorDeclarationSyntax combinator) { if (combinator.Identifier != VectorIdentifier || combinator.Type?.Identifier != VectorResultType || combinator.OptionalArguments == null || combinator.OptionalArguments.Count != 1 || combinator.OptionalArguments[0].Identifier == null) { return null; } return new LayerSchemaSymbol(false, VectorIdentifier, VectorConstructorId, VectorResultType + " " + combinator.OptionalArguments[0].Identifier, null, Array.Empty()); } private static string? VectorElementType(TypeTermSyntax type) { if (type.Identifier != "Vector" || type.OptionalType?.Identifier == null) { return null; } return Qualify(type.OptionalType.NamespaceIdentifier, type.OptionalType.Identifier); } }