internal static SearchExpression ExplicitStringParser(SearchExpressionParserArgs args)
        {
            var outerText = args.text;
            var text      = ParserUtils.SimplifyExpression(outerText);

            if (text.length < 2 || !ParserUtils.HasQuotes(text))
            {
                return(null);
            }

            // Check for any string, since enclosed strings are not allowed, if we find a string token that means there are multiple strings in the text
            for (int i = 1; i < text.length - 2; ++i)
            {
                if (ParserUtils.IsQuote(text[i]))
                {
                    return(null);
                }
            }
            return(new SearchExpression(SearchExpressionType.Text, outerText, text.Substring(1, text.length - 2), ConstantEvaluator));
        }
        internal static SearchExpression FixedSetParser(SearchExpressionParserArgs args)
        {
            var outerText = args.text;
            var text      = ParserUtils.SimplifyExpression(outerText);

            if (text.length < 2 || text[0] != '[' || text[text.length - 1] != ']')
            {
                return(null);
            }
            var expressions = ParserUtils.GetExpressionsStartAndLength(text, out _);

            if (expressions.Length != 1 || expressions[0].startIndex != text.startIndex || expressions[0].length != text.length)
            {
                return(null);
            }

            var parameters = ParserUtils.ExtractArguments(text)
                             .Select(paramText => ParserManager.Parse(args.With(paramText).With(SearchExpressionParserFlags.ImplicitLiterals)))
                             .ToArray();

            var innerText = ParserUtils.SimplifyExpression(text.Substring(1, text.length - 2));

            return(new SearchExpression(SearchExpressionType.Set, outerText, innerText, SetEvaluator, parameters));
        }
        public static bool TryParse(StringView text, out QueryMarker marker)
        {
            marker = none;
            if (!IsQueryMarker(text))
            {
                return(false);
            }

            var innerText = text.Substring(k_StartToken.Length, text.Length - k_StartToken.Length - k_EndToken.Length);

            var indexOfColon = innerText.IndexOf(':');

            if (indexOfColon < 0)
            {
                return(false);
            }

            var controlType     = innerText.Substring(0, indexOfColon).Trim().ToString();
            var args            = new List <StringView>();
            var level           = 0;
            var currentArgStart = indexOfColon + 1;

            for (var i = currentArgStart; i < innerText.Length; ++i)
            {
                if (ParserUtils.IsOpener(innerText[i]))
                {
                    ++level;
                }
                if (ParserUtils.IsCloser(innerText[i]))
                {
                    --level;
                }
                if (innerText[i] != ',' || level != 0)
                {
                    continue;
                }
                if (i + 1 == innerText.Length)
                {
                    return(false);
                }

                args.Add(innerText.Substring(currentArgStart, i - currentArgStart).Trim());
                currentArgStart = i + 1;
            }

            if (currentArgStart == innerText.Length)
            {
                return(false); // No arguments
            }
            // Extract the final argument, since there is no comma after the last argument
            args.Add(innerText.Substring(currentArgStart, innerText.Length - currentArgStart).Trim());

            var queryMarkerArguments = new List <QueryMarkerArgument>();

            using (var context = SearchService.CreateContext(""))
            {
                foreach (var arg in args)
                {
                    var parserArgs = new SearchExpressionParserArgs(arg, context, SearchExpressionParserFlags.ImplicitLiterals);
                    SearchExpression expression = null;
                    try
                    {
                        expression = SearchExpression.Parse(parserArgs);
                    }
                    catch (SearchExpressionParseException)
                    { }

                    if (expression == null || !expression.types.HasAny(SearchExpressionType.Literal))
                    {
                        queryMarkerArguments.Add(new QueryMarkerArgument {
                            rawText = arg, expression = expression, value = expression == null ? arg.ToString() : null
                        });
                        continue;
                    }
                    var results             = expression.Execute(context);
                    var resolvedValue       = results.FirstOrDefault(item => item != null);
                    var resolvedValueObject = resolvedValue?.value;
                    queryMarkerArguments.Add(new QueryMarkerArgument {
                        rawText = arg, expression = expression, value = resolvedValueObject
                    });
                }
            }

            marker = new QueryMarker {
                type = controlType, text = text, args = queryMarkerArguments.ToArray()
            };
            return(true);
        }
        public static QueryMarker[] ParseAllMarkers(StringView text)
        {
            if (text.Length <= k_StartToken.Length + k_EndToken.Length)
            {
                return(null);
            }

            List <QueryMarker> markers = new List <QueryMarker>();
            var  startIndex            = -1;
            var  endIndex    = -1;
            var  nestedLevel = 0;
            bool inQuotes    = false;

            for (var i = 0; i < text.Length; ++i)
            {
                if (i + k_StartToken.Length > text.Length || i + k_EndToken.Length > text.Length)
                {
                    break;
                }

                if (ParserUtils.IsOpener(text[i]) && !inQuotes)
                {
                    ++nestedLevel;
                }
                if (ParserUtils.IsCloser(text[i]) && !inQuotes)
                {
                    --nestedLevel;
                }
                if (text[i] == '"' || text[i] == '\'')
                {
                    inQuotes = !inQuotes;
                }

                if (startIndex == -1 && nestedLevel == 0 && !inQuotes)
                {
                    var openerSv = text.Substring(i, k_StartToken.Length);
                    if (openerSv == k_StartToken)
                    {
                        startIndex = i;
                    }
                }

                if (endIndex == -1 && nestedLevel == 0 && !inQuotes)
                {
                    var closerSv = text.Substring(i, k_EndToken.Length);
                    if (closerSv == k_EndToken)
                    {
                        endIndex = i + k_EndToken.Length;
                    }
                }

                if (startIndex != -1 && endIndex != -1)
                {
                    var markerSv = text.Substring(startIndex, endIndex - startIndex);
                    if (TryParse(markerSv, out var marker))
                    {
                        markers.Add(marker);
                    }
                    startIndex = -1;
                    endIndex   = -1;
                }
            }

            return(markers.ToArray());
        }