Exemple #1
0
        /// <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);
        }