public List <Token <Set> > SplitInput(string input, bool quote)
            {
                List <Token <Set> > res = new List <Token <Set> >();
                var ttt = ext.Matches(input);

                foreach (Match m in ttt)
                {
                    Token <Set> t;
                    switch (m.Value)
                    {
                    case "(":
                        t = new PToken <Set> {
                            priority = -1, lexemm = "("
                        };
                        break;

                    case ")":
                        t = new PToken <Set> {
                            priority = 10, lexemm = ")"
                        };
                        break;

                    case "&":
                        t = new BOpToken <Set> {
                            priority = 4, function = StubSmartIntersect, lexemm = "&"
                        };
                        break;

                    case "|":
                        t = new BOpToken <Set> {
                            priority = 2, function = (x, y) => new Set(x.Union(y)), lexemm = "|"
                        };
                        break;

                    case "!":
                        t = new UOpToken <Set> {
                            priority = 5, function = (x) => new Set(Enumerable.Range(0, ind.paragraph.Count).Except(x)), lexemm = "!"
                        };
                        break;

                    default:
                        t = new ValueToken <Set>(ind[quote ? m.Value : ind.normalizer.NormalizeWord(m.Value)])
                        {
                            lexemm = string.Concat("'", m.Value, "'")
                        };
                        break;
                    }
                    res.Add(t);
                }
                return(res);
            }
        public IEnumerable <string> Search(string query)
        {
            var tokens = ext.SplitInput(query, query.Contains("$"));
            Stack <PToken <Set> > stack  = new Stack <PToken <Set> >();
            List <Token <Set> >   output = new List <Token <Set> >();

            foreach (var t in tokens)
            {
                if (t is PToken <Set> )
                {
                    PToken <Set> pt = t as PToken <Set>;
                    if (stack.Count == 0)
                    {
                        stack.Push(pt);
                    }
                    else if (pt.priority == 10)
                    {
                        while (stack.Peek().priority != -1)
                        {
                            output.Add(stack.Pop());
                        }
                        stack.Pop();
                    }
                    else if (pt.priority == -1)
                    {
                        stack.Push(pt);
                    }
                    else
                    {
                        while (stack.Count != 0 && pt.priority < stack.Peek().priority)
                        {
                            output.Add(stack.Pop());
                        }
                        stack.Push(pt);
                    }
                }
                else
                {
                    output.Add(t);
                }
            }
            while (stack.Count != 0)
            {
                output.Add(stack.Pop());
            }
            Stack <Set> solveStack = new Stack <Set>();

            foreach (var t in output)
            {
                if (t is ValueToken <Set> )
                {
                    solveStack.Push((t as ValueToken <Set>).value);
                }
                else if (t is UOpToken <Set> )
                {
                    solveStack.Push((t as UOpToken <Set>).function(solveStack.Pop()));
                }
                else
                {
                    solveStack.Push((t as BOpToken <Set>).function(solveStack.Pop(), solveStack.Pop()));
                }
            }
            return(solveStack.Pop().Select(x => paragraph[x]));
        }