yog-script-analyze 0.4.0

Yog Script (.ys, .yns) analyzed: its lexer, parser and syntax tree, names resolved, the class index model — what the build and the editors read a source with.
Documentation
namespace System.Logging;

using System.Collections.Generic;
using System.Text;

/// A message template read once (.NET's `LogValuesFormatter`): its text and
/// its holes (`"Moved {Count} items to {Target}"`), each named; `{{` and
/// `}}` are braces. A hole's alignment (`{Count,5}`) pads its value, its
/// format (`{Weight:F1}`) writes it as `ToString(format)` does.
public readonly sealed class LogValuesFormatter {
    /// What a log entry's state names its template by.
    public const string OriginalFormat = """{OriginalFormat}""";
    /// What a `null` value is written as.
    public const string NullValue = "(null)";

    public readonly string Template;
    /// Its holes' names, in order.
    public readonly List<string> ValueNames = new List<string>();
    private readonly List<string> _texts = new List<string>();
    private readonly List<i32> _alignments = new List<i32>();
    /// Each hole's format (`""`: none).
    private readonly List<string> _formats = new List<string>();

    public LogValuesFormatter(string format) {
        Template = format;
        let mut text = new StringBuilder();
        let mut i = 0;
        while (i < format.Length) {
            let c = format[i];
            if ((c == '{' || c == '}') && i + 1 < format.Length && format[i + 1] == c) {
                text.Append(c);
                i += 2;
            } else if (c == '{') {
                let end = HoleEnd(format, i + 1);
                if (end < 0) {
                    text.Append(format.Substring(i));
                    i = format.Length;
                } else {
                    _texts.Add(text.ToString());
                    text.Clear();
                    Hole(format.Substring(i + 1, end - i - 1));
                    i = end + 1;
                }
            } else {
                text.Append(c);
                i += 1;
            }
        }
        _texts.Add(text.ToString());
    }

    /// Where the hole opened before `from` closes (`-1`: it doesn't).
    private static i32 HoleEnd(string format, i32 from) {
        for (let mut j = from; j < format.Length; j += 1) {
            if (format[j] == '}') {
                return j;
            }
        }
        return -1;
    }

    /// Hole `inside` (`Name`, `Name,5`, `Name:N2`): its name, alignment and format noted.
    private void Hole(string inside) {
        let mut name = inside;
        let mut format = "";
        let colon = name.IndexOf(':');
        if (colon >= 0) {
            format = name.Substring(colon + 1);
            name = name.Substring(0, colon);
        }
        let mut alignment = 0;
        let comma = name.IndexOf(',');
        if (comma >= 0) {
            alignment = i32.Parse(name.Substring(comma + 1).Trim());
            name = name.Substring(0, comma);
        }
        ValueNames.Add(name.Trim());
        _alignments.Add(alignment);
        _formats.Add(format);
    }

    /// The message: its holes filled with `values`, in order.
    public string Format(object?[] values) {
        let mut written = new StringBuilder();
        for (let mut i = 0; i < _texts.Count; i += 1) {
            written.Append(_texts[i]);
            if (i < ValueNames.Count) {
                let value = i < values.Length ? Formatted(values[i], _formats[i]) : "";
                written.Append(Aligned(value, _alignments[i]));
            }
        }
        return written.ToString();
    }

    /// `value` written by `format` (`""`: as `FormatValue` does).
    private static string Formatted(object? value, string format) {
        if (format.Length == 0 || value == null) {
            return FormatValue(move value);
        }
        return string.Format("""{0:""" + format + """}""", move value);
    }

    /// `value` padded to `alignment` (right when positive, left when negative).
    private static string Aligned(string value, i32 alignment) {
        if (alignment > 0) {
            return value.PadLeft(alignment);
        }
        if (alignment < 0) {
            return value.PadRight(-alignment);
        }
        return value;
    }

    /// `value` as a message writes it: `(null)`; a sequence's items joined.
    public static string FormatValue(object? value) {
        if (value == null) {
            return NullValue;
        }
        if (value is string s) {
            return s;
        }
        if (value is IEnumerable<object?> items) {
            let mut written = new StringBuilder();
            let mut first = true;
            foreach (let item in items) {
                if (!first) {
                    written.Append(", ");
                }
                written.Append(item == null ? NullValue : item.ToString());
                first = false;
            }
            return written.ToString();
        }
        return value.ToString();
    }
}