/// <summary> /// Add the parameters of <paramref name="qualifierKey"/> as criteria for qualifier. /// /// Every parameter of <paramref name="qualifierKey"/> will be required to match in the lines that will be compared with this qualifier. /// If a parameterValue in the <paramref name="qualifierKey"/> is "", then the compared key must not have that parameter, or it must be "". /// /// (Does not expect canoncials to be in same order in relation to different ParameterNames.) /// </summary> /// <param name="qualifier">configurable qualifier composition</param> /// <param name="qualifierKey">parameters</param> /// <param name="parameterInfos">(optional) infos for determining which keys are non-canonical</param> /// <returns><paramref name="qualifier"/></returns> public static ILineQualifier Rule(this ILineQualifier qualifier, ILine qualifierKey, IParameterInfos parameterInfos = null) { // Break qualifierKey into effective non-canonical parameters, and to canonical parameters and occurance index StructList12 <(ILineParameter, int)> list = new StructList12 <(ILineParameter, int)>(); qualifierKey.GetParameterPartsWithOccurance(ref list); // Add rules foreach ((ILineParameter parameter, int occuranceIndex) in list) { // Parameter with null is to be ignored if (parameter.ParameterName == null || parameter.ParameterValue == null) { continue; } // Ineffective key if (occuranceIndex > 0 && parameter.IsNonCanonicalKey(parameterInfos)) { continue; } // parameter with "" is expectation of empty or non-existant value. if (parameter.ParameterValue == "") { qualifier.Add(new LineParameterQualifier.IsEmpty(parameter.ParameterName, occuranceIndex)); } else { qualifier.Add(new LineParameterQualifier.IsEqualTo(parameter.ParameterName, occuranceIndex, parameter.ParameterValue)); } } return(qualifier); }
/// <summary> /// Add expected value rule. /// </summary> /// <param name="qualifier"></param> /// <param name="parameterName">parameter name this rule applies to</param> /// <param name="occuranceIndex">occurance index this rule applies to, or -1 to apply to every occurance of the parameter name</param> /// <param name="expectedParameterValue">expected value, or if "", then expects value to not occur</param> /// <returns><paramref name="qualifier"/></returns> public static ILineQualifier Rule(this ILineQualifier qualifier, string parameterName, int occuranceIndex, string expectedParameterValue) { if (expectedParameterValue == null) { throw new ArgumentNullException(nameof(expectedParameterValue)); } if (expectedParameterValue == "") { qualifier.Add(new LineParameterQualifier.IsEmpty(parameterName, occuranceIndex)); } else { qualifier.Add(new LineParameterQualifier.IsEqualTo(parameterName, occuranceIndex, expectedParameterValue)); } return(qualifier); }
/// <summary> /// Add expected value rule. /// </summary> /// <param name="qualifier"></param> /// <param name="parameterName">parameter name this rule applies to</param> /// <param name="occuranceIndex">occurnace index this rule applies to, or -1 to apply to every occurance of the parameter name</param> /// <param name="acceptedParameterValues">group of accepted parameter values</param> /// <returns><paramref name="qualifier"/></returns> public static ILineQualifier Rule(this ILineQualifier qualifier, string parameterName, int occuranceIndex, params string[] acceptedParameterValues) { if (acceptedParameterValues == null || acceptedParameterValues.Length == 0) { return(qualifier); } if (acceptedParameterValues.Length == 1) { qualifier.Rule(parameterName, occuranceIndex, acceptedParameterValues[0]); } else { qualifier.Add(new LineParameterQualifier.IsInGroup(parameterName, occuranceIndex, acceptedParameterValues)); } return(qualifier); }
/// <summary> /// Qualify <paramref name="line"/> against the qualifier rules. /// </summary> /// <param name="qualifier">(optional) qualifier</param> /// <param name="line"></param> /// <returns>true if line is qualified, false if disqualified</returns> public static bool Qualify(this ILineQualifier qualifier, ILine line) { // Evaluate whole line if (qualifier is ILineQualifierEvaluatable eval) { return(eval.Qualify(line)); } // Evaluate argument if (qualifier is ILineArgumentQualifier argumentQualifier) { if (argumentQualifier.NeedsOccuranceIndex) { // Break key into effective parameters with occurance index StructList12 <(ILineArgument, int)> list1 = new StructList12 <(ILineArgument, int)>(); line.GetArgumentPartsWithOccurance(ref list1); for (int i = 0; i < list1.Count; i++) { if (!argumentQualifier.QualifyArgument(list1[i].Item1, list1[i].Item2)) { return(false); } } } else { // Break key into parameters StructList12 <ILineArgument> list2 = new StructList12 <ILineArgument>(); line.GetArgumentParts(ref list2); for (int i = 0; i < list2.Count; i++) { if (!argumentQualifier.QualifyArgument(list2[i], -1)) { return(false); } } } } // no criteria, accept all return(true); }
/// <summary> /// Prune out arguments that are disqualified by <paramref name="qualifier"/>. /// </summary> /// <param name="line"></param> /// <param name="qualifier">Argument qualifier that is used for determining which parts to keep in the line</param> /// <param name="lineFactory">(optional) extra line factory</param> /// <returns>a modified <paramref name="line"/></returns> /// <exception cref="LineException"></exception> public static ILine Prune(this ILine line, ILineQualifier qualifier, ILineFactory lineFactory = null) { // Qualified parts to append. Order: tail to root. StructList12 <ILineArgument> list = new StructList12 <ILineArgument>(); ILineArgumentQualifier lineArgumentQualifier = qualifier as ILineArgumentQualifier; // Earliest qualified line part. The start tail, where to start appending qualified parts ILine startTail = line; // Line part's arguments. Order: root to tail StructList8 <ILineArgument> tmp = new StructList8 <ILineArgument>(); // Start tail buffered args. Order: root to tail StructList8 <ILineArgument> startTailArgsBuffer = new StructList8 <ILineArgument>(); // Add parts for (ILine l = line; l != null; l = l.GetPreviousPart()) { tmp.Clear(); if (l is ILineArgumentEnumerable lineArguments) { foreach (ILineArgument lineArgument in lineArguments) { tmp.Add(lineArgument); } } if (l is ILineArgument argument) { tmp.Add(argument); } // Now qualify bool linePartQualifies = true; string parameterName, parameterValue; for (int i = tmp.Count - 1; i >= 0; i--) { ILineArgument a = tmp[i]; bool argumentQualifies = true; if (lineArgumentQualifier != null) { // Qualify as an argument. if (!a.IsNonCanonicalKey()) { argumentQualifies = lineArgumentQualifier.QualifyArgument(a); } // Qualify as non-canonical parameter else if (a.TryGetParameter(out parameterName, out parameterValue)) { // Calculate occurance index int occIx = -1; if (lineArgumentQualifier.NeedsOccuranceIndex) { occIx = 0; for (int j = i - 1; j >= 0; j--) { ILineArgument b = list[j]; string parameterName2, parameterValue2; if (b.TryGetParameter(out parameterName2, out parameterValue2)) { continue; } if (parameterValue2 != null && parameterName == parameterName2) { occIx++; } } } argumentQualifies = lineArgumentQualifier.QualifyArgument(a, occIx); } } if (!argumentQualifies) { tmp.RemoveAt(i); } linePartQualifies &= argumentQualifies; } // This part didn't qualify if (!linePartQualifies) { // Append previous start tail to append args if (startTailArgsBuffer.Count > 0) { for (int i = 0; i < startTailArgsBuffer.Count; i++) { list.Add(startTailArgsBuffer[i]); } startTailArgsBuffer.Clear(); startTail = null; } // Add parts that did qualify to append list for (int i = 0; i < tmp.Count; i++) { list.Add(tmp[i]); } // preceding part might be better for start tail startTail = l.GetPreviousPart(); } else // This part qualified { // Add to start tail buffer, in case preceding startTail fails qualifications for (int i = 0; i < tmp.Count; i++) { startTailArgsBuffer.Add(tmp[i]); } } } // Append qualified parts. ILineFactory appender1 = null; line.TryGetAppender(out appender1); // Nothing qualified, no start, create dummy if (startTail == null && list.Count == 0) { // Create dummy ILineFactory appender2 = null; line.TryGetAppender(out appender2); ILinePart dummy = null; if (lineFactory == null || !lineFactory.TryCreate(null, out dummy)) { if (appender2 == null || !appender2.TryCreate(null, out dummy)) { throw new LineException(line, $"LineFactory doesn't have capability to create {nameof(ILinePart)}"); } } return(dummy); } // Append parts ILine result = startTail; for (int i = list.Count - 1; i >= 0; i--) { ILineArgument arg = list[i]; if (lineFactory == null || !lineFactory.TryCreate(result, arg, out result)) { if (appender1 == null || !appender1.TryCreate(result, arg, out result)) { throw new LineException(line, $"LineFactory doesn't have capability to concat {arg}"); } } } return(result); }
/// <summary> /// Qualifies lines against qualifier rules. /// </summary> /// <param name="qualifier">(optional) qualifier</param> /// <param name="lines"></param> /// <returns>all lines that were qualified</returns> public static IEnumerable <ILine> Qualify(this ILineQualifier qualifier, IEnumerable <ILine> lines) => qualifier is ILineQualifierLinesEvaluatable linesEval?linesEval.Qualify(lines) :
/// <summary> /// Add regular expression matching rule. /// </summary> /// <param name="qualifier"></param> /// <param name="parameterName">parameter name this rule applies to</param> /// <param name="occuranceIndex">occurnace index this rule applies to, or -1 to apply to every occurance of the parameter name</param> /// <param name="pattern">pattern</param> /// <returns><paramref name="qualifier"/></returns> public static ILineQualifier Rule(this ILineQualifier qualifier, string parameterName, int occuranceIndex, Regex pattern) { qualifier.Add(new LineParameterQualifier.Regex(parameterName, occuranceIndex, pattern)); return(qualifier); }
/// <summary> /// Qualifier by <paramref name="keyMatch"/>. /// /// If <see cref="ILinePatternMatch.Success"/> is false then return false. /// /// The whole <paramref name="keyMatch"/> is matched against every qualifier, if one disqualifies then returns false. /// </summary> /// <param name="qualifier"></param> /// <param name="keyMatch">(optional) </param> /// <returns>true if line is qualified, false if disqualified</returns> public static bool Qualify(this ILineQualifier qualifier, ILinePatternMatch keyMatch) => keyMatch != null && keyMatch.Success && qualifier.Qualify(keyMatch.ToLine());
/// <summary> /// Put all argument parts to <paramref name="list"/> with parameter occurance. /// /// If <paramref name="argumentQualifier"/> is provided, then filters out non-qualified arguments. /// </summary> /// <param name="line">(optional) line to read parameters of</param> /// <param name="list">list to add parts in order of from tail to root</param> /// <param name="argumentQualifier">(optional) parameter qualifier that validates each parameter</param> /// <param name="pruneIneffectiveParameters">(optional) If true, removes parameters that are not effetive: a null value, or reoccurance of non-canonical key</param> /// <param name="parameterInfos">(optional) extra parameter infos, used by <paramref name="pruneIneffectiveParameters"/> feature to detect which parameters are non-canonical keys.</param> /// <returns>array of parameters</returns> public static void GetArgumentPartsWithOccurance <LIST>(this ILine line, ref LIST list, ILineQualifier argumentQualifier = null, bool pruneIneffectiveParameters = false, IParameterInfos parameterInfos = null) where LIST : IList <(ILineArgument, int)>
/// <summary> /// Create new string serializer /// </summary> /// <param name="escapeCharacters">list of characters that are to be escaped</param> /// <param name="escapeControlCharacters">Escape characters 0x00 - 0x1f</param> /// <param name="unescapeCharacters">list of characters that are to be unescaped</param> /// <param name="unescapeControlCharacters">Unescape tnab0f</param> /// <param name="lineAppender">line appender that can append <see cref="ILineParameter"/> and <see cref="ILineString"/></param> /// <param name="qualifier">(optional) qualifier</param> public LineFormat(string escapeCharacters, bool escapeControlCharacters, string unescapeCharacters, bool unescapeControlCharacters, ILineFactory lineAppender, ILineQualifier qualifier) : base(lineAppender, qualifier) { // Regex.Escape doen't work for brackets [] //string escapeCharactersEscaped = Regex.Escape(escapeCharacters); string escapeCharactersEscaped = escapeCharacters.Select(c => c == ']' ? "\\]" : Regex.Escape("" + c)).Aggregate((a, b) => a + b); if (escapeControlCharacters) { LiteralEscape = new Regex("[" + escapeCharactersEscaped + "]|[\\x00-\\x1f]", opts); } else { LiteralEscape = new Regex("[" + escapeCharactersEscaped + "]", opts); } escapeChar = EscapeChar; string unescapeCharactersEscaped = unescapeCharacters.Select(c => c == ']' ? "\\]" : Regex.Escape("" + c)).Aggregate((a, b) => a + b); LiteralUnescape = new Regex( unescapeControlCharacters ? "\\\\([0abtfnrv" + unescapeCharactersEscaped + "]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})" : "\\\\[" + unescapeCharactersEscaped + "]" , opts); unescapeChar = UnescapeChar; }