using AIStudio.Models.Matching; namespace AIStudio.Models; /// /// Collects the rules of one family as they are stated. /// /// /// The order rules are stated in changes nothing about which one wins -- that is what the computed /// specificity is for. It matters in one place only: a variant which inherits takes what the rule /// before it stated, so that a family can say what its models have in common once and then say /// only what makes each variant different. /// /// What the rules name as their origin, which is the family's name. public sealed class ModelFamilyBuilder(string origin) { private readonly List stated = []; /// /// States a rule which chooses the model. /// /// The name, or the part of it, this rule answers for. In normalized form. /// The rule, to go on stating. public ModelRuleBuilder Rule(string text) => this.Add(text, ModelRuleKind.SELECTOR); /// /// States a rule which adjusts whatever chose the model. /// /// The name, or the part of it, this rule answers for. In normalized form. /// The rule, to go on stating. public ModelRuleBuilder Modifier(string text) => this.Add(text, ModelRuleKind.MODIFIER); /// /// Turns everything stated into rules. /// /// The rules, in the order they were stated. internal IReadOnlyList Build() { // // The same text may well be stated twice, with different conditions on top -- that is how // a variant of a generation is written. What cannot be done is naming that text to inherit // from, because it names two rules and taking either of them would be a coin toss. Found // before anything is built, so that where the two stand in the file makes no difference. // var statedMoreThanOnce = this.stated .GroupBy(statement => statement.PatternText, StringComparer.Ordinal) .Where(group => group.Count() > 1) .Select(group => group.Key) .ToHashSet(StringComparer.Ordinal); var built = new List(this.stated.Count); var byPatternText = new Dictionary(StringComparer.Ordinal); ModelProfileChange? previous = null; foreach (var statement in this.stated) { var rule = statement.Build(statement.InheritanceBasis(byPatternText, statedMoreThanOnce, previous)); built.Add(rule); byPatternText[rule.Pattern.Text] = rule.Change; previous = rule.Change; } return built; } private ModelRuleBuilder Add(string text, ModelRuleKind kind) { var statement = new ModelRuleBuilder(text, kind, origin); this.stated.Add(statement); return statement; } }