/// <summary> /// Query rules. /// /// If RuleSet is null, then returns null. /// </summary> /// <param name="filterCriteria"></param> /// <returns></returns> /// <exception cref="Exception">Wrapped error</exception> public IPluralRulesEnumerable Query(PluralRuleInfo filterCriteria) { if (filterCriteria.RuleSet == null) { return(null); } ResultLine line = GetRules(filterCriteria.RuleSet); if (line.Error != null) { throw new Exception(line.Error.Message, line.Error); } if (line.Rules == null) { return(null); } if (line.Rules is IPluralRulesQueryable queryable) { // Set RuleSet to null return(queryable.Query(filterCriteria.ChangeRuleSet(null))); } return(null); }
/// <summary> /// </summary> /// <param name="filterCriteria"></param> /// <returns></returns> public virtual IPluralRulesEnumerable Query(PluralRuleInfo filterCriteria) { if (filterCriteria.Equals(PluralRuleInfo.Empty)) { return(this); } int c = 0; foreach (var rule in this) { if (filterCriteria.FilterMatch(rule.Info)) { c++; } } IPluralRule[] result = new IPluralRule[c]; int i = 0; foreach (var rule in this) { if (filterCriteria.FilterMatch(rule.Info)) { result[i++] = rule; } } return(new PluralRulesArray(result)); }
/// <summary> /// Evaluate <paramref name="number"/> against all rules in the scope stating from the last added. /// </summary> /// <param name="subset">RuleSet, Culture and Category must have non-null value. "" is valid. Case must be null and optional must be -1.</param> /// <param name="number">(optional) numeric and text representation of numberic value</param> /// <returns>Matching cases, first ones are optional, the last one is always mandatory (and only mandatory). Or null if evaluate failed.</returns> public IPluralRule[] Evaluate(PluralRuleInfo subset, IPluralNumber number) { for (int i = stack.Count - 1; i >= 0; i--) { if (stack[i] is IPluralRulesEvaluatable eval) { IPluralRule[] result = eval.Evaluate(subset, number); if (result != null) { return(result); } } } // Could not evaluate. return(null); }
/// <summary> /// Try to resolve ruleset and evaluate number. /// </summary> /// <param name="subset"></param> /// <param name="number"></param> /// <returns></returns> /// <exception cref="Exception">On wrapped error</exception> public IPluralRule[] Evaluate(PluralRuleInfo subset, IPluralNumber number) { if (subset.RuleSet != null) { ResultLine line = GetRules(subset.RuleSet); if (line.Error != null) { throw new Exception(line.Error.Message, line.Error); } if (line.Rules is IPluralRulesEvaluatable eval) { // Set RuleSet to null return(eval.Evaluate(subset.ChangeRuleSet(null), number)); } } return(null); }
/// <summary> /// If this info is a filter criteria, then tests whether <paramref name="info"/> matches the criteria. /// If any of the local fields is null, then that value is not compared. /// /// </summary> /// <param name="info"></param> /// <returns></returns> public bool FilterMatch(PluralRuleInfo info) { if (RuleSet != null && RuleSet != info.RuleSet) { return(false); } if (Category != null && Category != info.Category) { return(false); } if (Culture != null && Culture != info.Culture) { return(false); } if (Case != null && Case != info.Case) { return(false); } if (Optional != -1 && Optional != info.Optional) { return(false); } return(true); }
/// <summary> /// Create rule that compares to zero value. /// </summary> /// <param name="info"></param> public One(PluralRuleInfo info) : base(info) { }
/// <summary> /// Create rule that compares to zero value. /// </summary> /// <param name="info"></param> public Zero(PluralRuleInfo info) : base(info) { }
/// <summary> /// Create rule that evaluates with <paramref name="ruleExpression"/>. /// </summary> /// <param name="info"></param> /// <param name="infoExpression">info expression</param> /// <param name="ruleExpression"></param> /// <param name="samplesExpression"></param> public Expression(PluralRuleInfo info, IPluralRuleInfosExpression infoExpression, IExpression ruleExpression, params ISamplesExpression[] samplesExpression) : base(info) { this.Infos = infoExpression; this.Rule = ruleExpression; this.Samples = samplesExpression ?? NO_SAMPLES; }
/// <summary> /// Create rule. /// </summary> /// <param name="info">info</param> public PluralRule(PluralRuleInfo info) { this.Info = info; }
/// <summary> /// Create rule that always evaluates to true. /// </summary> /// <param name="info"></param> /// <param name="infosExp"></param> /// <param name="ruleExp"></param> /// <param name="samplesExps"></param> public TrueWithExpression(PluralRuleInfo info, IPluralRuleInfosExpression infosExp, IExpression ruleExp, params ISamplesExpression[] samplesExps) : base(info) { this.Infos = infosExp; this.Rule = ruleExp; this.Samples = samplesExps; }
/// <summary> /// Create rule that always evaluates to true. /// </summary> /// <param name="info"></param> public True(PluralRuleInfo info) : base(info) { }
/// <summary> /// Create rule /// </summary> /// <param name="info"></param> public Empty(PluralRuleInfo info) : base(info) { }
/// <summary> /// Evaluate cases /// </summary> /// <param name="subset">filter</param> /// <param name="number"></param> /// <returns>matching cases. First ones are optional, last one is non-optional. Or null if none matched.</returns> public IPluralRule[] Evaluate(PluralRuleInfo subset, IPluralNumber number) => Query(subset) is IPluralRulesEvaluatable eval?eval.Evaluate(subset, number) : null;
/// <summary> /// Filter rules by <paramref name="filterCriteria"/>. /// </summary> /// <param name="filterCriteria"></param> /// <returns><see cref="PluralRulesCasesEvaluatable"/> or <see cref="PluralRulesArray"/>, or null if content is empty</returns> public IPluralRulesEnumerable Query(PluralRuleInfo filterCriteria) { // Try get IPluralRulesEnumerable result = null; lock (m_lock) if (queries.TryGetValue(filterCriteria, out result)) { return(result); } // Query if (ruleSource is IPluralRulesQueryable queryable) { result = queryable.Query(filterCriteria); // Wrap into PluralRulesEvaluatable if (result != null && filterCriteria.Category != null && filterCriteria.Culture != null && filterCriteria.Case == null && filterCriteria.Optional == -1) { result = new PluralRulesCasesEvaluatable(result); } } else if (ruleSource is IEnumerable <IPluralRule> enumr) { // Filter rules StructList8 <IPluralRule> list = new StructList8 <IPluralRule>(); StructList8 <string> rulesets = new StructList8 <string>(); foreach (IPluralRule rule in enumr) { // Filter by criteria if (!filterCriteria.FilterMatch(rule.Info)) { continue; } // Gather a list of rulesets if (rule.Info.RuleSet != null && !rulesets.Contains(rule.Info.RuleSet)) { rulesets.Add(rule.Info.RuleSet); } // Add to list list.Add(rule); } // No result if (list.Count == 0) { result = null; } // Instantiate PluralRulesEvaluatable else if (rulesets.Count <= 1 && filterCriteria.Category != null && filterCriteria.Culture != null && filterCriteria.Case == null && filterCriteria.Optional == -1) { result = new PluralRulesCasesEvaluatable(list.ToArray()); } // Instantiate PluralRules. else { result = new PluralRulesArray(list.ToArray()); } } // Could not read source else { result = null; } // Write to cache, if is still new lock (m_lock) if (!queries.ContainsKey(filterCriteria)) { queries[filterCriteria] = result; } // Return result return(result); }
/// <summary> /// Query a collection of rules. /// </summary> /// <param name="rules"></param> /// <param name="filterCriteria">filter criteria</param> /// <returns>enumerable of rules, or null if could not run query with the <paramref name="filterCriteria"/></returns> public static IPluralRulesEnumerable Query(this IPluralRules rules, PluralRuleInfo filterCriteria) => rules is IPluralRulesQueryable queryable?queryable.Query(filterCriteria) : null;
/// <summary> /// Add placeholder and cases that apply to that placeholder. /// </summary> /// <param name="placeholder"></param> /// <param name="placeholderValue"></param> /// <param name="pluralRules"></param> /// <param name="culture"></param> public void AddPlaceholder(IPlaceholder placeholder, IPluralNumber placeholderValue, IPluralRules pluralRules, string culture) { IExpression e = placeholder?.Expression; if (e == null) { return; } // Query cases PluralRuleInfo query = new PluralRuleInfo(null, placeholder.PluralCategory, culture, null, -1); IPluralRule[] cases = pluralRules.Evaluate(query, placeholderValue); if (cases == null || cases.Length == 0) { return; } int optionalCount = cases.Length == 1 ? 0 : cases.Length - 1; int requiredCount = cases.Length > 0 ? 1 : 0; // Scan arguments StructList4 <int> argIndices = new StructList4 <int>(); GetArguments(e, ref argIndices); // Add and unify cases for (int ix = 0; ix < argIndices.Count; ix++) { int argIx = argIndices[ix]; // Find if argument already exists int prevIx = -1; for (int j = 0; j < arguments.Count; j++) { if (arguments[j].ArgumentIndex == argIx) { prevIx = j; break; } } if (prevIx < 0) { // Add argument Entry entry = new Entry { Cases = cases, ArgumentIndex = argIx, OptionalCases = optionalCount, RequiredCases = requiredCount }; arguments.Add(entry); this.Count *= (1 + cases.Length); this.count1 *= cases.Length; } else { // Previous entry Entry entry = arguments[prevIx]; // Unify entries StructList8 <IPluralRule> optionalCases = new StructList8 <IPluralRule>(IPluralRuleComparer.Default); StructList8 <IPluralRule> requiredCases = new StructList8 <IPluralRule>(IPluralRuleComparer.Default); foreach (var c in entry.Cases) { if (c.Info.Optional == 1) { optionalCases.AddIfNew(c); } else if (c.Info.Optional == 0) { requiredCases.AddIfNew(c); } } foreach (var c in cases) { if (c.Info.Optional == 1) { optionalCases.AddIfNew(c); } else if (c.Info.Optional == 0) { requiredCases.AddIfNew(c); } } StructList8 <IPluralRule> allCases = new StructList8 <IPluralRule>(IPluralRuleComparer.Default); for (int i = 0; i < optionalCases.Count; i++) { allCases.Add(optionalCases[i]); } for (int i = 0; i < requiredCases.Count; i++) { allCases.Add(requiredCases[i]); } // Create new entry Entry newEntry = new Entry { Cases = allCases.ToArray(), ArgumentIndex = argIx, OptionalCases = optionalCases.Count, RequiredCases = requiredCases.Count }; // Update arguments[prevIx] = newEntry; this.Count /= (1 + entry.Cases.Length); this.Count *= (1 + newEntry.Cases.Length); this.count1 /= entry.Cases.Length; this.count1 *= newEntry.Cases.Length; } } }