Ctrl K
ComunidadGuías…

Ferrite.TL.Schema/LayerSchemaReader.cs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// 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<LayerField> _fields;

    public bool IsMethod { get; }
    public string Name { get; }
    public int Id { get; }
    public string ResultType { get; }
    public string? VectorElementType { get; }
    public IReadOnlyList<LayerField> Fields => _fields;

    public LayerSchemaSymbol(bool isMethod, string name, int id, string resultType,
        string? vectorElementType, IEnumerable<LayerField> 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<LayerSchemaSymbol> Read(string source)
    {
        if (!source.EndsWith("\n", StringComparison.Ordinal))
        {
            source += "\n";
        }

        var parser = new Parser(new Lexer(source));
        var symbols = new List<LayerSchemaSymbol>();
        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<LayerSchemaSymbol> symbols)
    {
        var constructors = new List<LayerConstructor>();
        var methods = new List<LayerConstructor>();
        var vectorResults = new List<KeyValuePair<int, string>>();
        foreach (LayerSchemaSymbol symbol in symbols)
        {
            if (symbol.IsMethod)
            {
                if (symbol.VectorElementType != null)
                {
                    vectorResults.Add(new KeyValuePair<int, string>(
                        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<LayerField>();
        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<LayerField>());
    }

    private static string? VectorElementType(TypeTermSyntax type)
    {
        if (type.Identifier != "Vector" || type.OptionalType?.Identifier == null)
        {
            return null;
        }
        return Qualify(type.OptionalType.NamespaceIdentifier, type.OptionalType.Identifier);
    }
}