/// <summary> /// Parse string into key. /// </summary> /// <param name="lineFormat"></param> /// <param name="str"></param> /// <param name="result">key result or null if contained no content</param> /// <param name="prevPart">(optional) previous part to append to</param> /// <param name="appender">(optional) line appender to append with. If null, uses appender from <paramref name="prevPart"/>. If null, uses default appender.</param> /// <returns>true if parse was successful (even through resulted key might be null)</returns> public static bool TryParse(this ILineFormat lineFormat, string str, out ILine result, ILine prevPart = default, ILineFactory appender = default) { if (lineFormat is ILineFormatAppendParser appendParser) { return(appendParser.TryParse(str, out result, prevPart, appender)); } // Try get appender if (appender == null && !prevPart.TryGetAppender(out appender)) { result = null; return(false); } // Try parse IEnumerable <ILineArgument> args; if (lineFormat is ILineFormatParser parser && parser.TryParseArgs(str, out args)) { // Append arguments foreach (ILineArgument arg in parser.ParseArgs(str)) { if (!appender.TryCreate(prevPart, arg, out prevPart)) { result = null; return(false); } } result = prevPart; return(true); }
/// <summary> /// Append <paramref name="right"/> to <paramref name="left"/>. /// </summary> /// <param name="factory"></param> /// <param name="left">part to append to</param> /// <param name="right"></param> /// <param name="result"></param> /// <returns></returns> /// <exception cref="LineException">on append error</exception> public static bool TryConcat(this ILineFactory factory, ILine left, ILine right, out ILine result) { if (factory == null) { result = left; return(false); } ILine _result = left; StructList16 <ILine> _args = new StructList16 <ILine>(); for (ILine l = right; l != null; l = l.GetPreviousPart()) { if (l is ILineArgument || l is ILineArgumentEnumerable) { _args.Add(l); } } for (int i = _args.Count - 1; i >= 0; i--) { ILine l = _args[i]; if (l is ILineArgumentEnumerable enumr) { foreach (ILineArgument args_ in enumr) { if (!factory.TryCreate(args_, out _result)) { result = null; return(false); } } } if (l is ILineArgument args) { if (!factory.TryCreate(args, out _result)) { result = null; return(false); } } } result = _result; return(false); }
/// <summary> /// Try to clone <paramref name="line"/>. /// </summary> /// <param name="factory"></param> /// <param name="line"></param> /// <param name="clone"></param> /// <returns></returns> public static bool TryClone(this ILineFactory factory, ILine line, out ILine clone) { if (factory == null) { clone = line; return(false); } ILine result = null; StructList16 <ILine> args = new StructList16 <ILine>(); for (ILine l = line; l != null; l = l.GetPreviousPart()) { if (l is ILineArgument || l is ILineArgumentEnumerable) { args.Add(l); } } for (int i = args.Count - 1; i >= 0; i--) { ILine l = args[i]; if (l is ILineArgumentEnumerable enumr) { foreach (ILineArgument args_ in enumr) { if (!factory.TryCreate(result, args_, out result)) { clone = default; return(false); } } } if (l is ILineArgument arg) { if (!factory.TryCreate(result, args, out result)) { clone = default; return(false); } } } clone = result; return(true); }
/// <summary> /// Create line (part) with <paramref name="arguments"/>. /// </summary> /// <param name="factory"></param> /// <param name="previous"></param> /// <param name="arguments"></param> /// <returns>appended part</returns> /// <exception cref="LineException">If append failed due to unexpected reason</exception> public static ILine Create(this ILineFactory factory, ILine previous, ILineArgument arguments) { ILine result = null; if (factory.TryCreate(previous, arguments, out result)) { return(result); } ILineFactoryByArgument argumentAdapter; if (LineFactoryByArgumentAdapter.Default.TryGet(arguments.GetType(), out argumentAdapter) && argumentAdapter.TryCreate(factory, previous, arguments, out result)) { return(result); } throw new LineException(arguments, "Could not be appended"); }
/// <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); }