Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
QueryParser.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18 */
19 
20 /* Generated By:JavaCC: Do not edit this line. QueryParser.java */
21 
22 using System;
23 using System.Collections.Generic;
24 using System.Diagnostics;
25 using System.Globalization;
26 using System.IO;
27 using System.Text;
28 using Lucene.Net.Analysis;
29 using Lucene.Net.Analysis.Tokenattributes;
30 using Lucene.Net.Search;
31 using Lucene.Net.Support;
32 using Lucene.Net.Util;
33 using Analyzer = Lucene.Net.Analysis.Analyzer;
34 using CachingTokenFilter = Lucene.Net.Analysis.CachingTokenFilter;
35 using TokenStream = Lucene.Net.Analysis.TokenStream;
36 using DateField = Lucene.Net.Documents.DateField;
37 using DateTools = Lucene.Net.Documents.DateTools;
38 using Term = Lucene.Net.Index.Term;
39 using BooleanClause = Lucene.Net.Search.BooleanClause;
40 using BooleanQuery = Lucene.Net.Search.BooleanQuery;
41 using FuzzyQuery = Lucene.Net.Search.FuzzyQuery;
42 using MatchAllDocsQuery = Lucene.Net.Search.MatchAllDocsQuery;
43 using MultiPhraseQuery = Lucene.Net.Search.MultiPhraseQuery;
44 using MultiTermQuery = Lucene.Net.Search.MultiTermQuery;
45 using PhraseQuery = Lucene.Net.Search.PhraseQuery;
46 using PrefixQuery = Lucene.Net.Search.PrefixQuery;
47 using Query = Lucene.Net.Search.Query;
48 using Single = Lucene.Net.Support.Single;
49 using TermQuery = Lucene.Net.Search.TermQuery;
50 using TermRangeQuery = Lucene.Net.Search.TermRangeQuery;
51 using WildcardQuery = Lucene.Net.Search.WildcardQuery;
52 using Version = Lucene.Net.Util.Version;
53 
54 namespace Lucene.Net.QueryParsers
55 {
56  /// <summary> This class is generated by JavaCC. The most important method is
57  /// <see cref="Parse(String)" />.
58  ///
59  /// The syntax for query strings is as follows:
60  /// A Query is a series of clauses.
61  /// A clause may be prefixed by:
62  /// <list type="bullet">
63  /// <item> a plus (<c>+</c>) or a minus (<c>-</c>) sign, indicating
64  /// that the clause is required or prohibited respectively; or</item>
65  /// <item> a term followed by a colon, indicating the field to be searched.
66  /// This enables one to construct queries which search multiple fields.</item>
67  /// </list>
68  ///
69  /// A clause may be either:
70  /// <list type="bullet">
71  /// <item> a term, indicating all the documents that contain this term; or</item>
72  /// <item> a nested query, enclosed in parentheses. Note that this may be used
73  /// with a <c>+</c>/<c>-</c> prefix to require any of a set of
74  /// terms.</item>
75  /// </list>
76  ///
77  /// Thus, in BNF, the query grammar is:
78  /// <code>
79  /// Query ::= ( Clause )*
80  /// Clause ::= ["+", "-"] [&lt;TERM&gt; ":"] ( &lt;TERM&gt; | "(" Query ")" )
81  /// </code>
82  ///
83  /// <p/>
84  /// Examples of appropriately formatted queries can be found in the <a
85  /// href="../../../../../../queryparsersyntax.html">query syntax
86  /// documentation</a>.
87  /// <p/>
88  ///
89  /// <p/>
90  /// In <see cref="TermRangeQuery" />s, QueryParser tries to detect date values, e.g.
91  /// <tt>date:[6/1/2005 TO 6/4/2005]</tt> produces a range query that searches
92  /// for "date" fields between 2005-06-01 and 2005-06-04. Note that the format
93  /// of the accepted input depends on the <see cref="Locale" />.
94  /// By default a date is converted into a search term using the deprecated
95  /// <see cref="DateField" /> for compatibility reasons.
96  /// To use the new <see cref="DateTools" /> to convert dates, a
97  /// <see cref="Lucene.Net.Documents.DateTools.Resolution" /> has to be set.
98  /// <p/>
99  /// <p/>
100  /// The date resolution that shall be used for RangeQueries can be set
101  /// using <see cref="SetDateResolution(DateTools.Resolution)" />
102  /// or <see cref="SetDateResolution(String, DateTools.Resolution)" />. The former
103  /// sets the default date resolution for all fields, whereas the latter can
104  /// be used to set field specific date resolutions. Field specific date
105  /// resolutions take, if set, precedence over the default date resolution.
106  /// <p/>
107  /// <p/>
108  /// If you use neither <see cref="DateField" /> nor <see cref="DateTools" /> in your
109  /// index, you can create your own
110  /// query parser that inherits QueryParser and overwrites
111  /// <see cref="GetRangeQuery(String, String, String, bool)" /> to
112  /// use a different method for date conversion.
113  /// <p/>
114  ///
115  /// <p/>Note that QueryParser is <em>not</em> thread-safe.<p/>
116  ///
117  /// <p/><b>NOTE</b>: there is a new QueryParser in contrib, which matches
118  /// the same syntax as this class, but is more modular,
119  /// enabling substantial customization to how a query is created.
120  ///
121  /// <p/><b>NOTE</b>: there is a new QueryParser in contrib, which matches
122  /// the same syntax as this class, but is more modular,
123  /// enabling substantial customization to how a query is created.
124  /// <b>NOTE</b>: You must specify the required <see cref="Version" /> compatibility when
125  /// creating QueryParser:
126  /// <list type="bullet">
127  /// <item>As of 2.9, <see cref="EnablePositionIncrements" /> is true by default.</item>
128  /// </list>
129  /// </summary>
131  {
132 
133  private static int CONJ_NONE = 0;
134  private static int CONJ_AND = 1;
135  private static int CONJ_OR = 2;
136 
137  private static int MOD_NONE = 0;
138  private static int MOD_NOT = 10;
139  private static int MOD_REQ = 11;
140 
141  // make it possible to call setDefaultOperator() without accessing
142  // the nested class:
143  /// <summary>Alternative form of QueryParser.Operator.AND </summary>
144  public static Operator AND_OPERATOR = Operator.AND;
145 
146  /// <summary>Alternative form of QueryParser.Operator.OR </summary>
147  public static Operator OR_OPERATOR = Operator.OR;
148 
149  /// <summary>The actual operator that parser uses to combine query terms </summary>
150  private Operator operator_Renamed = OR_OPERATOR;
151 
152  private bool lowercaseExpandedTerms = true;
153  private RewriteMethod multiTermRewriteMethod = MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT;
154  private bool allowLeadingWildcard = false;
155  private bool enablePositionIncrements = true;
156 
157  // LUCENENET-423 - DateRange differences with Java and .NET
158  private bool _useJavaStyleDateRangeParsing = false;
159 
160  private Analyzer analyzer;
161  private String field;
162  private int phraseSlop = 0;
163  private float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity;
164  private int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
165  private System.Globalization.CultureInfo locale = System.Globalization.CultureInfo.CurrentCulture;
166 
167  // the default date resolution
168  private DateTools.Resolution dateResolution = null;
169  // maps field names to date resolutions
170  private IDictionary<String, DateTools.Resolution> fieldToDateResolution = null;
171 
172  // The collator to use when determining range inclusion,
173  // for use when constructing RangeQuerys.
174  private System.Globalization.CompareInfo rangeCollator = null;
175 
176  /* The default operator_Renamed for parsing queries.
177  * Use {@link QueryParser#setDefaultOperator} to change it.
178  */
179 
180  public enum Operator
181  {
182  OR,
183  AND
184  }
185 
186  /* Constructs a query parser.
187  * @param matchVersion Lucene version to match. See <a href="#version">above</a>)
188  * @param f the default field for query terms.
189  * @param a used to find terms in the query text.
190  */
191 
192  public QueryParser(Version matchVersion, String f, Analyzer a)
193  : this(new FastCharStream(new StringReader("")))
194  {
195  analyzer = a;
196  field = f;
197  if (matchVersion.OnOrAfter(Version.LUCENE_29))
198  {
199  enablePositionIncrements = true;
200  }
201  else
202  {
203  enablePositionIncrements = false;
204  }
205 
206  // LUCENENET-423 - DateRange differences with Java and .NET
207  if (matchVersion.OnOrAfter(Version.LUCENE_30))
208  {
209  _useJavaStyleDateRangeParsing = true;
210  }
211  }
212 
213  /// <summary>Parses a query string, returning a {@link Lucene.Net.Search.Query}.</summary>
214  /// <param name="query"> the query string to be parsed.
215  /// </param>
216  /// <throws> ParseException if the parsing fails </throws>
217  public virtual Query Parse(String query)
218  {
219  ReInit(new FastCharStream(new StringReader(query)));
220  try
221  {
222  // TopLevelQuery is a Query followed by the end-of-input (EOF)
223  Query res = TopLevelQuery(field);
224  return res ?? NewBooleanQuery(false);
225  }
226  catch (ParseException tme)
227  {
228  // rethrow to include the original query:
229  throw new ParseException("Cannot parse '" + query + "': " + tme.Message, tme);
230  }
231  catch (TokenMgrError tme)
232  {
233  throw new ParseException("Cannot parse '" + query + "': " + tme.Message, tme);
234  }
235  catch (BooleanQuery.TooManyClauses tmc)
236  {
237  throw new ParseException("Cannot parse '" + query + "': too many bool clauses", tmc);
238  }
239  }
240 
241  /// <value> Returns the analyzer. </value>
242  public virtual Analyzer Analyzer
243  {
244  get { return analyzer; }
245  }
246 
247  /// <value> Returns the field. </value>
248  public virtual string Field
249  {
250  get { return field; }
251  }
252 
253  /// <summary>
254  /// Gets or sets the minimal similarity for fuzzy queries.
255  /// Default is 0.5f.
256  /// </summary>
257  public virtual float FuzzyMinSim
258  {
259  get { return fuzzyMinSim; }
260  set { this.fuzzyMinSim = value; }
261  }
262 
263  /// <summary> Gets or sets the prefix length for fuzzy queries. </summary>
264  /// <value> Returns the fuzzyPrefixLength. </value>
265  public virtual int FuzzyPrefixLength
266  {
267  get { return fuzzyPrefixLength; }
268  set { this.fuzzyPrefixLength = value; }
269  }
270 
271  /// <summary> Gets or sets the default slop for phrases. If zero, then exact phrase matches
272  /// are required. Default value is zero.
273  /// </summary>
274  public virtual int PhraseSlop
275  {
276  set { this.phraseSlop = value; }
277  get { return phraseSlop; }
278  }
279 
280  /// <summary> Set to <c>true</c> to allow leading wildcard characters.
281  /// <p/>
282  /// When set, <c>*</c> or <c>?</c> are allowed as
283  /// the first character of a PrefixQuery and WildcardQuery.
284  /// Note that this can produce very slow
285  /// queries on big indexes.
286  /// <p/>
287  /// Default: false.
288  /// </summary>
289  public virtual bool AllowLeadingWildcard
290  {
291  set { this.allowLeadingWildcard = value; }
292  get { return allowLeadingWildcard; }
293  }
294 
295  /// <summary>Set to <c>true</c> to enable position increments in result query.
296  /// <p/>
297  /// When set, result phrase and multi-phrase queries will
298  /// be aware of position increments.
299  /// Useful when e.g. a StopFilter increases the position increment of
300  /// the token that follows an omitted token.
301  /// <p/>
302  /// Default: false.
303  /// </summary>
304  public virtual bool EnablePositionIncrements
305  {
306  set { this.enablePositionIncrements = value; }
307  get { return enablePositionIncrements; }
308  }
309 
310  /// <summary> Gets or sets the boolean operator of the QueryParser.
311  /// In default mode (<c>OR_OPERATOR</c>) terms without any modifiers
312  /// are considered optional: for example <c>capital of Hungary</c> is equal to
313  /// <c>capital OR of OR Hungary</c>.<br/>
314  /// In <c>AND_OPERATOR</c> mode terms are considered to be in conjunction: the
315  /// above mentioned query is parsed as <c>capital AND of AND Hungary</c>
316  /// </summary>
317  public virtual Operator DefaultOperator
318  {
319  set { this.operator_Renamed = value; }
320  get { return operator_Renamed; }
321  }
322 
323  /// <summary> Whether terms of wildcard, prefix, fuzzy and range queries are to be automatically
324  /// lower-cased or not. Default is <c>true</c>.
325  /// </summary>
326  public virtual bool LowercaseExpandedTerms
327  {
328  set { this.lowercaseExpandedTerms = value; }
329  get { return lowercaseExpandedTerms; }
330  }
331 
332 
333  /// <summary> By default QueryParser uses <see cref="MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT" />
334  /// when creating a PrefixQuery, WildcardQuery or RangeQuery. This implementation is generally preferable because it
335  /// a) Runs faster b) Does not have the scarcity of terms unduly influence score
336  /// c) avoids any "TooManyBooleanClauses" exception.
337  /// However, if your application really needs to use the
338  /// old-fashioned BooleanQuery expansion rewriting and the above
339  /// points are not relevant then use this to change
340  /// the rewrite method.
341  /// </summary>
342  public virtual RewriteMethod MultiTermRewriteMethod
343  {
344  set { multiTermRewriteMethod = value; }
345  get { return multiTermRewriteMethod; }
346  }
347 
348  /// <summary>Gets or sets locale used by date range parsing.</summary>
349  public virtual CultureInfo Locale
350  {
351  set { this.locale = value; }
352  get { return locale; }
353  }
354 
355  /// <summary> Sets the default date resolution used by RangeQueries for fields for which no
356  /// specific date resolutions has been set. Field specific resolutions can be set
357  /// with {@link #SetDateResolution(String, DateTools.Resolution)}.
358  ///
359  /// </summary>
360  /// <param name="dateResolution">the default date resolution to set
361  /// </param>
362  public virtual void SetDateResolution(DateTools.Resolution dateResolution)
363  {
364  this.dateResolution = dateResolution;
365  }
366 
367  /// <summary> Sets the date resolution used by RangeQueries for a specific field.
368  ///
369  /// </summary>
370  /// <param name="fieldName">field for which the date resolution is to be set
371  /// </param>
372  /// <param name="dateResolution">date resolution to set
373  /// </param>
374  public virtual void SetDateResolution(String fieldName, DateTools.Resolution dateResolution)
375  {
376  if (fieldName == null)
377  {
378  throw new ArgumentException("Field cannot be null.");
379  }
380 
381  if (fieldToDateResolution == null)
382  {
383  // lazily initialize HashMap
384  fieldToDateResolution = new HashMap<String, DateTools.Resolution>();
385  }
386 
387  fieldToDateResolution.Add(fieldName, dateResolution);
388  }
389 
390  /// <summary> Returns the date resolution that is used by RangeQueries for the given field.
391  /// Returns null, if no default or field specific date resolution has been set
392  /// for the given field.
393  /// </summary>
394  public virtual DateTools.Resolution getDateResolution(String fieldName)
395  {
396  if (fieldName == null)
397  {
398  throw new ArgumentException("Field cannot be null.");
399  }
400 
401  if (fieldToDateResolution == null)
402  {
403  // no field specific date resolutions set; return default date resolution instead
404  return this.dateResolution;
405  }
406 
407  DateTools.Resolution resolution = fieldToDateResolution[fieldName];
408  if (resolution == null)
409  {
410  // no date resolutions set for the given field; return default date resolution instead
411  resolution = this.dateResolution;
412  }
413 
414  return resolution;
415  }
416 
417  /// <summary> Gets or sets the collator used to determine index term inclusion in ranges
418  /// for RangeQuerys.
419  /// <p/>
420  /// <strong>WARNING:</strong> Setting the rangeCollator to a non-null
421  /// collator using this method will cause every single index Term in the
422  /// Field referenced by lowerTerm and/or upperTerm to be examined.
423  /// Depending on the number of index Terms in this Field, the operation could
424  /// be very slow.
425  ///
426  /// </summary>
427  /// <value> the collator to use when constructing RangeQuerys </value>
428  public virtual CompareInfo RangeCollator
429  {
430  set { rangeCollator = value; }
431  get { return rangeCollator; }
432  }
433 
434  protected internal virtual void AddClause(List<BooleanClause> clauses, int conj, int mods, Query q)
435  {
436  bool required, prohibited;
437 
438  // If this term is introduced by AND, make the preceding term required,
439  // unless it's already prohibited
440  if (clauses.Count > 0 && conj == CONJ_AND)
441  {
442  BooleanClause c = clauses[clauses.Count - 1];
443  if (!c.IsProhibited)
444  c.Occur = Occur.MUST;
445  }
446 
447  if (clauses.Count > 0 && operator_Renamed == AND_OPERATOR && conj == CONJ_OR)
448  {
449  // If this term is introduced by OR, make the preceding term optional,
450  // unless it's prohibited (that means we leave -a OR b but +a OR b-->a OR b)
451  // notice if the input is a OR b, first term is parsed as required; without
452  // this modification a OR b would parsed as +a OR b
453  BooleanClause c = clauses[clauses.Count - 1];
454  if (!c.IsProhibited)
455  c.Occur = Occur.SHOULD;
456  }
457 
458  // We might have been passed a null query; the term might have been
459  // filtered away by the analyzer.
460  if (q == null)
461  return;
462 
463  if (operator_Renamed == OR_OPERATOR)
464  {
465  // We set REQUIRED if we're introduced by AND or +; PROHIBITED if
466  // introduced by NOT or -; make sure not to set both.
467  prohibited = (mods == MOD_NOT);
468  required = (mods == MOD_REQ);
469  if (conj == CONJ_AND && !prohibited)
470  {
471  required = true;
472  }
473  }
474  else
475  {
476  // We set PROHIBITED if we're introduced by NOT or -; We set REQUIRED
477  // if not PROHIBITED and not introduced by OR
478  prohibited = (mods == MOD_NOT);
479  required = (!prohibited && conj != CONJ_OR);
480  }
481  if (required && !prohibited)
482  clauses.Add(NewBooleanClause(q, Occur.MUST));
483  else if (!required && !prohibited)
484  clauses.Add(NewBooleanClause(q, Occur.SHOULD));
485  else if (!required && prohibited)
486  clauses.Add(NewBooleanClause(q, Occur.MUST_NOT));
487  else
488  throw new SystemException("Clause cannot be both required and prohibited");
489  }
490 
491 
492  /// <exception cref="ParseException">throw in overridden method to disallow
493  /// </exception>
494  protected internal virtual Query GetFieldQuery(String field, String queryText)
495  {
496  // Use the analyzer to get all the tokens, and then build a TermQuery,
497  // PhraseQuery, or nothing based on the term count
498 
499  TokenStream source;
500  try
501  {
502  source = analyzer.ReusableTokenStream(field, new StringReader(queryText));
503  source.Reset();
504  }
505  catch (IOException)
506  {
507  source = analyzer.TokenStream(field, new StringReader(queryText));
508  }
509  CachingTokenFilter buffer = new CachingTokenFilter(source);
510  ITermAttribute termAtt = null;
511  IPositionIncrementAttribute posIncrAtt = null;
512  int numTokens = 0;
513 
514  bool success = false;
515  try
516  {
517  buffer.Reset();
518  success = true;
519  }
520  catch (IOException)
521  {
522  // success==false if we hit an exception
523  }
524  if (success)
525  {
526  if (buffer.HasAttribute<ITermAttribute>())
527  {
528  termAtt = buffer.GetAttribute<ITermAttribute>();
529  }
530  if (buffer.HasAttribute<IPositionIncrementAttribute>())
531  {
532  posIncrAtt = buffer.GetAttribute<IPositionIncrementAttribute>();
533  }
534  }
535 
536  int positionCount = 0;
537  bool severalTokensAtSamePosition = false;
538 
539  bool hasMoreTokens = false;
540  if (termAtt != null)
541  {
542  try
543  {
544  hasMoreTokens = buffer.IncrementToken();
545  while (hasMoreTokens)
546  {
547  numTokens++;
548  int positionIncrement = (posIncrAtt != null) ? posIncrAtt.PositionIncrement : 1;
549  if (positionIncrement != 0)
550  {
551  positionCount += positionIncrement;
552  }
553  else
554  {
555  severalTokensAtSamePosition = true;
556  }
557  hasMoreTokens = buffer.IncrementToken();
558  }
559  }
560  catch (IOException)
561  {
562  // ignore
563  }
564  }
565  try
566  {
567  // rewind the buffer stream
568  buffer.Reset();
569 
570  // close original stream - all tokens buffered
571  source.Close();
572  }
573  catch (IOException)
574  {
575  // ignore
576  }
577 
578  if (numTokens == 0)
579  return null;
580  else if (numTokens == 1)
581  {
582  String term = null;
583  try
584  {
585  bool hasNext = buffer.IncrementToken();
586  Debug.Assert(hasNext);
587  term = termAtt.Term;
588  }
589  catch (IOException)
590  {
591  // safe to ignore, because we know the number of tokens
592  }
593  return NewTermQuery(new Term(field, term));
594  }
595  else
596  {
597  if (severalTokensAtSamePosition)
598  {
599  if (positionCount == 1)
600  {
601  // no phrase query:
602  BooleanQuery q = NewBooleanQuery(true);
603  for (int i = 0; i < numTokens; i++)
604  {
605  String term = null;
606  try
607  {
608  bool hasNext = buffer.IncrementToken();
609  Debug.Assert(hasNext);
610  term = termAtt.Term;
611  }
612  catch (IOException)
613  {
614  // safe to ignore, because we know the number of tokens
615  }
616 
617  Query currentQuery = NewTermQuery(
618  new Term(field, term));
619  q.Add(currentQuery, Occur.SHOULD);
620  }
621  return q;
622  }
623  else
624  {
625  // phrase query:
626  MultiPhraseQuery mpq = NewMultiPhraseQuery();
627  mpq.Slop = phraseSlop;
628  List<Term> multiTerms = new List<Term>();
629  int position = -1;
630  for (int i = 0; i < numTokens; i++)
631  {
632  String term = null;
633  int positionIncrement = 1;
634  try
635  {
636  bool hasNext = buffer.IncrementToken();
637  Debug.Assert(hasNext == true);
638  term = termAtt.Term;
639  if (posIncrAtt != null)
640  {
641  positionIncrement = posIncrAtt.PositionIncrement;
642  }
643  }
644  catch (IOException)
645  {
646  // safe to ignore, because we know the number of tokens
647  }
648 
649  if (positionIncrement > 0 && multiTerms.Count > 0)
650  {
651  if (enablePositionIncrements)
652  {
653  mpq.Add(multiTerms.ToArray(), position);
654  }
655  else
656  {
657  mpq.Add(multiTerms.ToArray());
658  }
659  multiTerms.Clear();
660  }
661  position += positionIncrement;
662  multiTerms.Add(new Term(field, term));
663  }
664  if (enablePositionIncrements)
665  {
666  mpq.Add(multiTerms.ToArray(), position);
667  }
668  else
669  {
670  mpq.Add(multiTerms.ToArray());
671  }
672  return mpq;
673  }
674  }
675  else
676  {
677  PhraseQuery pq = NewPhraseQuery();
678  pq.Slop = phraseSlop;
679  int position = -1;
680 
681 
682  for (int i = 0; i < numTokens; i++)
683  {
684  String term = null;
685  int positionIncrement = 1;
686 
687  try
688  {
689  bool hasNext = buffer.IncrementToken();
690  Debug.Assert(hasNext == true);
691  term = termAtt.Term;
692  if (posIncrAtt != null)
693  {
694  positionIncrement = posIncrAtt.PositionIncrement;
695  }
696  }
697  catch (IOException)
698  {
699  // safe to ignore, because we know the number of tokens
700  }
701 
702  if (enablePositionIncrements)
703  {
704  position += positionIncrement;
705  pq.Add(new Term(field, term), position);
706  }
707  else
708  {
709  pq.Add(new Term(field, term));
710  }
711  }
712  return pq;
713  }
714  }
715  }
716 
717 
718  /// <summary> Base implementation delegates to {@link #GetFieldQuery(String,String)}.
719  /// This method may be overridden, for example, to return
720  /// a SpanNearQuery instead of a PhraseQuery.
721  ///
722  /// </summary>
723  /// <exception cref="ParseException">throw in overridden method to disallow
724  /// </exception>
725  protected internal virtual Query GetFieldQuery(String field, String queryText, int slop)
726  {
727  Query query = GetFieldQuery(field, queryText);
728 
729  if (query is PhraseQuery)
730  {
731  ((PhraseQuery)query).Slop = slop;
732  }
733  if (query is MultiPhraseQuery)
734  {
735  ((MultiPhraseQuery)query).Slop = slop;
736  }
737 
738  return query;
739  }
740 
741  /// <exception cref="ParseException">throw in overridden method to disallow
742  /// </exception>
743  protected internal virtual Query GetRangeQuery(String field,
744  String part1,
745  String part2,
746  bool inclusive)
747  {
748  if (lowercaseExpandedTerms)
749  {
750  part1 = part1.ToLower();
751  part2 = part2.ToLower();
752  }
753 
754  try
755  {
756  DateTime d1, d2;
757  if (_useJavaStyleDateRangeParsing)
758  {
759  // TODO: This doesn't emulate java perfectly.
760  // Java allows parsing of the string up to the end of the pattern
761  // and then ignores everything else. .NET will throw an exception,
762  // so this will fail in those cases, though the code below is clear
763  // that users can only specify the date, not the time.
764  var shortFormat = locale.DateTimeFormat.ShortDatePattern;
765  d1 = DateTime.ParseExact(part1, shortFormat, locale);
766  d2 = DateTime.ParseExact(part2, shortFormat, locale);
767  }
768  else
769  {
770  d1 = DateTime.Parse(part1, locale);
771  d2 = DateTime.Parse(part2, locale);
772  }
773 
774  if (inclusive)
775  {
776  // The user can only specify the date, not the time, so make sure
777  // the time is set to the latest possible time of that date to really
778  // include all documents:
779  var cal = locale.Calendar;
780  d2 = cal.AddHours(d2, 23);
781  d2 = cal.AddMinutes(d2, 59);
782  d2 = cal.AddSeconds(d2, 59);
783  d2 = cal.AddMilliseconds(d2, 999);
784  }
785  DateTools.Resolution resolution = getDateResolution(field);
786  if (resolution == null)
787  {
788  // no default or field specific date resolution has been set,
789  // use deprecated DateField to maintain compatibility with
790  // pre-1.9 Lucene versions.
791  part1 = DateField.DateToString(d1);
792  part2 = DateField.DateToString(d2);
793  }
794  else
795  {
796  part1 = DateTools.DateToString(d1, resolution);
797  part2 = DateTools.DateToString(d2, resolution);
798  }
799  }
800  catch (Exception)
801  {
802  }
803 
804  return NewRangeQuery(field, part1, part2, inclusive);
805  }
806 
807  /// <summary> Builds a new BooleanQuery instance</summary>
808  /// <param name="disableCoord">disable coord
809  /// </param>
810  /// <returns> new BooleanQuery instance
811  /// </returns>
812  protected internal virtual BooleanQuery NewBooleanQuery(bool disableCoord)
813  {
814  return new BooleanQuery(disableCoord);
815  }
816 
817  /// <summary> Builds a new BooleanClause instance</summary>
818  /// <param name="q">sub query
819  /// </param>
820  /// <param name="occur">how this clause should occur when matching documents
821  /// </param>
822  /// <returns> new BooleanClause instance
823  /// </returns>
824  protected internal virtual BooleanClause NewBooleanClause(Query q, Occur occur)
825  {
826  return new BooleanClause(q, occur);
827  }
828 
829  /// <summary> Builds a new TermQuery instance</summary>
830  /// <param name="term">term
831  /// </param>
832  /// <returns> new TermQuery instance
833  /// </returns>
834  protected internal virtual Query NewTermQuery(Term term)
835  {
836  return new TermQuery(term);
837  }
838 
839  /// <summary> Builds a new PhraseQuery instance</summary>
840  /// <returns> new PhraseQuery instance
841  /// </returns>
842  protected internal virtual PhraseQuery NewPhraseQuery()
843  {
844  return new PhraseQuery();
845  }
846 
847  /// <summary> Builds a new MultiPhraseQuery instance</summary>
848  /// <returns> new MultiPhraseQuery instance
849  /// </returns>
850  protected internal virtual MultiPhraseQuery NewMultiPhraseQuery()
851  {
852  return new MultiPhraseQuery();
853  }
854 
855  /// <summary> Builds a new PrefixQuery instance</summary>
856  /// <param name="prefix">Prefix term
857  /// </param>
858  /// <returns> new PrefixQuery instance
859  /// </returns>
860  protected internal virtual Query NewPrefixQuery(Term prefix)
861  {
862  return new PrefixQuery(prefix) { RewriteMethod = multiTermRewriteMethod };
863  }
864 
865  /// <summary> Builds a new FuzzyQuery instance</summary>
866  /// <param name="term">Term
867  /// </param>
868  /// <param name="minimumSimilarity">minimum similarity
869  /// </param>
870  /// <param name="prefixLength">prefix length
871  /// </param>
872  /// <returns> new FuzzyQuery Instance
873  /// </returns>
874  protected internal virtual Query NewFuzzyQuery(Term term, float minimumSimilarity, int prefixLength)
875  {
876  // FuzzyQuery doesn't yet allow constant score rewrite
877  return new FuzzyQuery(term, minimumSimilarity, prefixLength);
878  }
879 
880  /// <summary> Builds a new TermRangeQuery instance</summary>
881  /// <param name="field">Field
882  /// </param>
883  /// <param name="part1">min
884  /// </param>
885  /// <param name="part2">max
886  /// </param>
887  /// <param name="inclusive">true if range is inclusive
888  /// </param>
889  /// <returns> new TermRangeQuery instance
890  /// </returns>
891  protected internal virtual Query NewRangeQuery(String field, String part1, String part2, bool inclusive)
892  {
893  return new TermRangeQuery(field, part1, part2, inclusive, inclusive, rangeCollator) { RewriteMethod = multiTermRewriteMethod };
894  }
895 
896  /// <summary> Builds a new MatchAllDocsQuery instance</summary>
897  /// <returns> new MatchAllDocsQuery instance
898  /// </returns>
899  protected internal virtual Query NewMatchAllDocsQuery()
900  {
901  return new MatchAllDocsQuery();
902  }
903 
904  /// <summary> Builds a new WildcardQuery instance</summary>
905  /// <param name="t">wildcard term
906  /// </param>
907  /// <returns> new WildcardQuery instance
908  /// </returns>
909  protected internal virtual Query NewWildcardQuery(Term t)
910  {
911  return new WildcardQuery(t) { RewriteMethod = multiTermRewriteMethod };
912  }
913 
914  /// <summary> Factory method for generating query, given a set of clauses.
915  /// By default creates a boolean query composed of clauses passed in.
916  ///
917  /// Can be overridden by extending classes, to modify query being
918  /// returned.
919  ///
920  /// </summary>
921  /// <param name="clauses">List that contains {@link BooleanClause} instances
922  /// to join.
923  ///
924  /// </param>
925  /// <returns> Resulting {@link Query} object.
926  /// </returns>
927  /// <exception cref="ParseException">throw in overridden method to disallow
928  /// </exception>
929  protected internal virtual Query GetBooleanQuery(IList<BooleanClause> clauses)
930  {
931  return GetBooleanQuery(clauses, false);
932  }
933 
934  /// <summary> Factory method for generating query, given a set of clauses.
935  /// By default creates a boolean query composed of clauses passed in.
936  ///
937  /// Can be overridden by extending classes, to modify query being
938  /// returned.
939  ///
940  /// </summary>
941  /// <param name="clauses">List that contains {@link BooleanClause} instances
942  /// to join.
943  /// </param>
944  /// <param name="disableCoord">true if coord scoring should be disabled.
945  ///
946  /// </param>
947  /// <returns> Resulting {@link Query} object.
948  /// </returns>
949  /// <exception cref="ParseException">throw in overridden method to disallow
950  /// </exception>
951  protected internal virtual Query GetBooleanQuery(IList<BooleanClause> clauses, bool disableCoord)
952  {
953  if (clauses.Count == 0)
954  {
955  return null; // all clause words were filtered away by the analyzer.
956  }
957  BooleanQuery query = NewBooleanQuery(disableCoord);
958  foreach (var clause in clauses)
959  {
960  query.Add(clause);
961  }
962  return query;
963  }
964 
965  /// <summary> Factory method for generating a query. Called when parser
966  /// parses an input term token that contains one or more wildcard
967  /// characters (? and *), but is not a prefix term token (one
968  /// that has just a single * character at the end)
969  /// <p/>
970  /// Depending on settings, prefix term may be lower-cased
971  /// automatically. It will not go through the default Analyzer,
972  /// however, since normal Analyzers are unlikely to work properly
973  /// with wildcard templates.
974  /// <p/>
975  /// Can be overridden by extending classes, to provide custom handling for
976  /// wildcard queries, which may be necessary due to missing analyzer calls.
977  ///
978  /// </summary>
979  /// <param name="field">Name of the field query will use.
980  /// </param>
981  /// <param name="termStr">Term token that contains one or more wild card
982  /// characters (? or *), but is not simple prefix term
983  ///
984  /// </param>
985  /// <returns> Resulting {@link Query} built for the term
986  /// </returns>
987  /// <exception cref="ParseException">throw in overridden method to disallow
988  /// </exception>
989  protected internal virtual Query GetWildcardQuery(String field, String termStr)
990  {
991  if ("*".Equals(field))
992  {
993  if ("*".Equals(termStr)) return NewMatchAllDocsQuery();
994  }
995  if (!allowLeadingWildcard && (termStr.StartsWith("*") || termStr.StartsWith("?")))
996  throw new ParseException("'*' or '?' not allowed as first character in WildcardQuery");
997  if (lowercaseExpandedTerms)
998  {
999  termStr = termStr.ToLower();
1000  }
1001  Term t = new Term(field, termStr);
1002  return NewWildcardQuery(t);
1003  }
1004 
1005  /// <summary> Factory method for generating a query (similar to
1006  /// {@link #getWildcardQuery}). Called when parser parses an input term
1007  /// token that uses prefix notation; that is, contains a single '*' wildcard
1008  /// character as its last character. Since this is a special case
1009  /// of generic wildcard term, and such a query can be optimized easily,
1010  /// this usually results in a different query object.
1011  /// <p/>
1012  /// Depending on settings, a prefix term may be lower-cased
1013  /// automatically. It will not go through the default Analyzer,
1014  /// however, since normal Analyzers are unlikely to work properly
1015  /// with wildcard templates.
1016  /// <p/>
1017  /// Can be overridden by extending classes, to provide custom handling for
1018  /// wild card queries, which may be necessary due to missing analyzer calls.
1019  ///
1020  /// </summary>
1021  /// <param name="field">Name of the field query will use.
1022  /// </param>
1023  /// <param name="termStr">Term token to use for building term for the query
1024  /// (<b>without</b> trailing '*' character!)
1025  ///
1026  /// </param>
1027  /// <returns> Resulting {@link Query} built for the term
1028  /// </returns>
1029  /// <exception cref="ParseException">throw in overridden method to disallow
1030  /// </exception>
1031  protected internal virtual Query GetPrefixQuery(String field, String termStr)
1032  {
1033  if (!allowLeadingWildcard && termStr.StartsWith("*"))
1034  throw new ParseException("'*' not allowed as first character in PrefixQuery");
1035  if (lowercaseExpandedTerms)
1036  {
1037  termStr = termStr.ToLower();
1038  }
1039  Term t = new Term(field, termStr);
1040  return NewPrefixQuery(t);
1041  }
1042 
1043  /// <summary> Factory method for generating a query (similar to
1044  /// {@link #getWildcardQuery}). Called when parser parses
1045  /// an input term token that has the fuzzy suffix (~) appended.
1046  ///
1047  /// </summary>
1048  /// <param name="field">Name of the field query will use.
1049  /// </param>
1050  /// <param name="termStr">Term token to use for building term for the query
1051  ///
1052  /// </param>
1053  /// <returns> Resulting {@link Query} built for the term
1054  /// </returns>
1055  /// <exception cref="ParseException">throw in overridden method to disallow
1056  /// </exception>
1057  protected internal virtual Query GetFuzzyQuery(String field, String termStr, float minSimilarity)
1058  {
1059  if (lowercaseExpandedTerms)
1060  {
1061  termStr = termStr.ToLower();
1062  }
1063  Term t = new Term(field, termStr);
1064  return NewFuzzyQuery(t, minSimilarity, fuzzyPrefixLength);
1065  }
1066 
1067 
1068  /// <summary> Returns a String where the escape char has been
1069  /// removed, or kept only once if there was a double escape.
1070  ///
1071  /// Supports escaped unicode characters, e. g. translates
1072  /// <c>\\u0041</c> to <c>A</c>.
1073  ///
1074  /// </summary>
1075  private String DiscardEscapeChar(String input)
1076  {
1077  // Create char array to hold unescaped char sequence
1078  char[] output = new char[input.Length];
1079 
1080  // The Length of the output can be less than the input
1081  // due to discarded escape chars. This variable holds
1082  // the actual Length of the output
1083  int Length = 0;
1084 
1085  // We remember whether the last processed character was
1086  // an escape character
1087  bool lastCharWasEscapeChar = false;
1088 
1089  // The multiplier the current unicode digit must be multiplied with.
1090  // E. g. the first digit must be multiplied with 16^3, the second with 16^2...
1091  int codePointMultiplier = 0;
1092 
1093  // Used to calculate the codepoint of the escaped unicode character
1094  int codePoint = 0;
1095 
1096  for (int i = 0; i < input.Length; i++)
1097  {
1098  char curChar = input[i];
1099  if (codePointMultiplier > 0)
1100  {
1101  codePoint += HexToInt(curChar) * codePointMultiplier;
1102  codePointMultiplier = Number.URShift(codePointMultiplier, 4);
1103  if (codePointMultiplier == 0)
1104  {
1105  output[Length++] = (char)codePoint;
1106  codePoint = 0;
1107  }
1108  }
1109  else if (lastCharWasEscapeChar)
1110  {
1111  if (curChar == 'u')
1112  {
1113  // found an escaped unicode character
1114  codePointMultiplier = 16 * 16 * 16;
1115  }
1116  else
1117  {
1118  // this character was escaped
1119  output[Length] = curChar;
1120  Length++;
1121  }
1122  lastCharWasEscapeChar = false;
1123  }
1124  else
1125  {
1126  if (curChar == '\\')
1127  {
1128  lastCharWasEscapeChar = true;
1129  }
1130  else
1131  {
1132  output[Length] = curChar;
1133  Length++;
1134  }
1135  }
1136  }
1137 
1138  if (codePointMultiplier > 0)
1139  {
1140  throw new ParseException("Truncated unicode escape sequence.");
1141  }
1142 
1143  if (lastCharWasEscapeChar)
1144  {
1145  throw new ParseException("Term can not end with escape character.");
1146  }
1147 
1148  return new String(output, 0, Length);
1149  }
1150 
1151  /// <summary>Returns the numeric value of the hexadecimal character </summary>
1152  private static int HexToInt(char c)
1153  {
1154  if ('0' <= c && c <= '9')
1155  {
1156  return c - '0';
1157  }
1158  else if ('a' <= c && c <= 'f')
1159  {
1160  return c - 'a' + 10;
1161  }
1162  else if ('A' <= c && c <= 'F')
1163  {
1164  return c - 'A' + 10;
1165  }
1166  else
1167  {
1168  throw new ParseException("None-hex character in unicode escape sequence: " + c);
1169  }
1170  }
1171 
1172  /// <summary> Returns a String where those characters that QueryParser
1173  /// expects to be escaped are escaped by a preceding <c></c>.
1174  /// </summary>
1175  public static String Escape(String s)
1176  {
1177  StringBuilder sb = new StringBuilder();
1178  for (int i = 0; i < s.Length; i++)
1179  {
1180  char c = s[i];
1181  // These characters are part of the query syntax and must be escaped
1182  if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':'
1183  || c == '^' || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~'
1184  || c == '*' || c == '?' || c == '|' || c == '&')
1185  {
1186  sb.Append('\\');
1187  }
1188  sb.Append(c);
1189  }
1190  return sb.ToString();
1191  }
1192 
1193  /// <summary> Command line tool to test QueryParser, using {@link Lucene.Net.Analysis.SimpleAnalyzer}.
1194  /// Usage:<br/>
1195  /// <c>java Lucene.Net.QueryParsers.QueryParser &lt;input&gt;</c>
1196  /// </summary>
1197  [STAThread]
1198  public static void Main(String[] args)
1199  {
1200  if (args.Length == 0)
1201  {
1202  Console.WriteLine("Usage: java org.apache.lucene.queryParser.QueryParser <input>");
1203  Environment.Exit(0);
1204  }
1205  QueryParser qp = new QueryParser(Version.LUCENE_CURRENT, "field", new SimpleAnalyzer());
1206  Query q = qp.Parse(args[0]);
1207  Console.WriteLine(q.ToString("field"));
1208  }
1209 
1210  // * Query ::= ( Clause )*
1211  // * Clause ::= ["+", "-"] [<TermToken> ":"] ( <TermToken> | "(" Query ")" )
1212  public int Conjunction()
1213  {
1214  int ret = CONJ_NONE;
1215  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1216  {
1217  case AndToken:
1218  case OrToken:
1219  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1220  {
1221  case AndToken:
1222  Jj_consume_token(AndToken);
1223  ret = CONJ_AND;
1224  break;
1225  case OrToken:
1226  Jj_consume_token(OrToken);
1227  ret = CONJ_OR;
1228  break;
1229  default:
1230  jj_la1[0] = jj_gen;
1231  Jj_consume_token(-1);
1232  throw new ParseException();
1233  }
1234  break;
1235  default:
1236  jj_la1[1] = jj_gen;
1237  break;
1238  }
1239  {
1240  if (true) return ret;
1241  }
1242  throw new ApplicationException("Missing return statement in function");
1243  }
1244 
1245  public int Modifiers()
1246  {
1247  int ret = MOD_NONE;
1248  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1249  {
1250  case NotToken:
1251  case PlusToken:
1252  case MinusToken:
1253  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1254  {
1255  case PlusToken:
1256  Jj_consume_token(PlusToken);
1257  ret = MOD_REQ;
1258  break;
1259  case MinusToken:
1260  Jj_consume_token(MinusToken);
1261  ret = MOD_NOT;
1262  break;
1263  case NotToken:
1264  Jj_consume_token(NotToken);
1265  ret = MOD_NOT;
1266  break;
1267  default:
1268  jj_la1[2] = jj_gen;
1269  Jj_consume_token(-1);
1270  throw new ParseException();
1271  }
1272  break;
1273  default:
1274  jj_la1[3] = jj_gen;
1275  break;
1276  }
1277  {
1278  if (true) return ret;
1279  }
1280  throw new Exception("Missing return statement in function");
1281  }
1282 
1283  // This makes sure that there is no garbage after the query string
1284  public Query TopLevelQuery(String field)
1285  {
1286  Query q;
1287  q = Query(field);
1288  Jj_consume_token(0);
1289  {
1290  if (true) return q;
1291  }
1292  throw new Exception("Missing return statement in function");
1293  }
1294 
1295  public Query Query(String field)
1296  {
1297  List<BooleanClause> clauses = new List<BooleanClause>();
1298  Query q, firstQuery = null;
1299  int conj, mods;
1300  mods = Modifiers();
1301  q = Clause(field);
1302  AddClause(clauses, CONJ_NONE, mods, q);
1303  if (mods == MOD_NONE)
1304  firstQuery = q;
1305  while (true)
1306  {
1307  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1308  {
1309  case AndToken:
1310  case OrToken:
1311  case NotToken:
1312  case PlusToken:
1313  case MinusToken:
1314  case LParanToken:
1315  case StarToken:
1316  case QuotedToken:
1317  case TermToken:
1318  case PrefixTermToken:
1319  case WildTermToken:
1320  case RangeInStartToken:
1321  case RangeExStartToken:
1322  case NumberToken:
1323  break;
1324  default:
1325  jj_la1[4] = jj_gen;
1326  goto label_1;
1327  }
1328 
1329  conj = Conjunction();
1330  mods = Modifiers();
1331  q = Clause(field);
1332  AddClause(clauses, conj, mods, q);
1333  }
1334 
1335  label_1:
1336 
1337  if (clauses.Count == 1 && firstQuery != null)
1338  {
1339  if (true) return firstQuery;
1340  }
1341 
1342  return GetBooleanQuery(clauses);
1343  }
1344 
1345  public Query Clause(String field)
1346  {
1347  Query q;
1348  Token fieldToken = null, boost = null;
1349  if (Jj_2_1(2))
1350  {
1351  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1352  {
1353  case TermToken:
1354  fieldToken = Jj_consume_token(TermToken);
1355  Jj_consume_token(ColonToken);
1356  field = DiscardEscapeChar(fieldToken.image);
1357  break;
1358  case StarToken:
1359  Jj_consume_token(StarToken);
1360  Jj_consume_token(ColonToken);
1361  field = "*";
1362  break;
1363  default:
1364  jj_la1[5] = jj_gen;
1365  Jj_consume_token(-1);
1366  throw new ParseException();
1367  }
1368  }
1369  else
1370  {
1371  ;
1372  }
1373  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1374  {
1375  case StarToken:
1376  case QuotedToken:
1377  case TermToken:
1378  case PrefixTermToken:
1379  case WildTermToken:
1380  case RangeInStartToken:
1381  case RangeExStartToken:
1382  case NumberToken:
1383  q = Term(field);
1384  break;
1385  case LParanToken:
1386  Jj_consume_token(LParanToken);
1387  q = Query(field);
1388  Jj_consume_token(RParenToken);
1389  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1390  {
1391  case CaratToken:
1392  Jj_consume_token(CaratToken);
1393  boost = Jj_consume_token(NumberToken);
1394  break;
1395  default:
1396  jj_la1[6] = jj_gen;
1397  break;
1398  }
1399  break;
1400  default:
1401  jj_la1[7] = jj_gen;
1402  Jj_consume_token(-1);
1403  throw new ParseException();
1404  }
1405  if (boost != null)
1406  {
1407  try
1408  {
1409  float f = Single.Parse(boost.image);
1410  q.Boost = f;
1411  }
1412  catch (Exception)
1413  {
1414  }
1415  }
1416  {
1417  if (true) return q;
1418  }
1419  throw new Exception("Missing return statement in function");
1420  }
1421 
1422  public Query Term(String field)
1423  {
1424  Token term, boost = null, fuzzySlop = null, goop1, goop2;
1425  bool prefix = false;
1426  bool wildcard = false;
1427  bool fuzzy = false;
1428  Query q;
1429  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1430  {
1431  case StarToken:
1432  case TermToken:
1433  case PrefixTermToken:
1434  case WildTermToken:
1435  case NumberToken:
1436  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1437  {
1438  case TermToken:
1439  term = Jj_consume_token(TermToken);
1440  break;
1441  case StarToken:
1442  term = Jj_consume_token(StarToken);
1443  wildcard = true;
1444  break;
1445  case PrefixTermToken:
1446  term = Jj_consume_token(PrefixTermToken);
1447  prefix = true;
1448  break;
1449  case WildTermToken:
1450  term = Jj_consume_token(WildTermToken);
1451  wildcard = true;
1452  break;
1453  case NumberToken:
1454  term = Jj_consume_token(NumberToken);
1455  break;
1456  default:
1457  jj_la1[8] = jj_gen;
1458  Jj_consume_token(-1);
1459  throw new ParseException();
1460  }
1461  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1462  {
1463  case FuzzySlopToken:
1464  fuzzySlop = Jj_consume_token(FuzzySlopToken);
1465  fuzzy = true;
1466  break;
1467  default:
1468  jj_la1[9] = jj_gen;
1469  break;
1470  }
1471  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1472  {
1473  case CaratToken:
1474  Jj_consume_token(CaratToken);
1475  boost = Jj_consume_token(NumberToken);
1476  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1477  {
1478  case FuzzySlopToken:
1479  fuzzySlop = Jj_consume_token(FuzzySlopToken);
1480  fuzzy = true;
1481  break;
1482  default:
1483  jj_la1[10] = jj_gen;
1484  break;
1485  }
1486  break;
1487  default:
1488  jj_la1[11] = jj_gen;
1489  break;
1490  }
1491  String termImage = DiscardEscapeChar(term.image);
1492  if (wildcard)
1493  {
1494  q = GetWildcardQuery(field, termImage);
1495  }
1496  else if (prefix)
1497  {
1498  q = GetPrefixQuery(field,
1499  DiscardEscapeChar(term.image.Substring(0, (term.image.Length - 1) - (0))));
1500  }
1501  else if (fuzzy)
1502  {
1503  float fms = fuzzyMinSim;
1504  try
1505  {
1506  fms = Single.Parse(fuzzySlop.image.Substring(1));
1507  }
1508  catch (Exception)
1509  {
1510  }
1511  if (fms < 0.0f || fms > 1.0f)
1512  {
1513  {
1514  if (true)
1515  throw new ParseException(
1516  "Minimum similarity for a FuzzyQuery has to be between 0.0f and 1.0f !");
1517  }
1518  }
1519  q = GetFuzzyQuery(field, termImage, fms);
1520  }
1521  else
1522  {
1523  q = GetFieldQuery(field, termImage);
1524  }
1525  break;
1526  case RangeInStartToken:
1527  Jj_consume_token(RangeInStartToken);
1528  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1529  {
1530  case RangeInGoopToken:
1531  goop1 = Jj_consume_token(RangeInGoopToken);
1532  break;
1533  case RangeInQuotedToken:
1534  goop1 = Jj_consume_token(RangeInQuotedToken);
1535  break;
1536  default:
1537  jj_la1[12] = jj_gen;
1538  Jj_consume_token(-1);
1539  throw new ParseException();
1540  }
1541  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1542  {
1543  case RangeInToToken:
1544  Jj_consume_token(RangeInToToken);
1545  break;
1546  default:
1547  jj_la1[13] = jj_gen;
1548  break;
1549  }
1550  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1551  {
1552  case RangeInGoopToken:
1553  goop2 = Jj_consume_token(RangeInGoopToken);
1554  break;
1555  case RangeInQuotedToken:
1556  goop2 = Jj_consume_token(RangeInQuotedToken);
1557  break;
1558  default:
1559  jj_la1[14] = jj_gen;
1560  Jj_consume_token(-1);
1561  throw new ParseException();
1562  }
1563  Jj_consume_token(RangeInEndToken);
1564  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1565  {
1566  case CaratToken:
1567  Jj_consume_token(CaratToken);
1568  boost = Jj_consume_token(NumberToken);
1569  break;
1570  default:
1571  jj_la1[15] = jj_gen;
1572  break;
1573  }
1574  if (goop1.kind == RangeInQuotedToken)
1575  {
1576  goop1.image = goop1.image.Substring(1, (goop1.image.Length - 1) - (1));
1577  }
1578  if (goop2.kind == RangeInQuotedToken)
1579  {
1580  goop2.image = goop2.image.Substring(1, (goop2.image.Length - 1) - (1));
1581  }
1582  q = GetRangeQuery(field, DiscardEscapeChar(goop1.image), DiscardEscapeChar(goop2.image), true);
1583  break;
1584  case RangeExStartToken:
1585  Jj_consume_token(RangeExStartToken);
1586  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1587  {
1588  case RangeExGoopToken:
1589  goop1 = Jj_consume_token(RangeExGoopToken);
1590  break;
1591  case RangeExQuotedToken:
1592  goop1 = Jj_consume_token(RangeExQuotedToken);
1593  break;
1594  default:
1595  jj_la1[16] = jj_gen;
1596  Jj_consume_token(-1);
1597  throw new ParseException();
1598  }
1599  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1600  {
1601  case RangeExToToken:
1602  Jj_consume_token(RangeExToToken);
1603  break;
1604  default:
1605  jj_la1[17] = jj_gen;
1606  break;
1607  }
1608  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1609  {
1610  case RangeExGoopToken:
1611  goop2 = Jj_consume_token(RangeExGoopToken);
1612  break;
1613  case RangeExQuotedToken:
1614  goop2 = Jj_consume_token(RangeExQuotedToken);
1615  break;
1616  default:
1617  jj_la1[18] = jj_gen;
1618  Jj_consume_token(-1);
1619  throw new ParseException();
1620  }
1621  Jj_consume_token(RangeExEndToken);
1622  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1623  {
1624  case CaratToken:
1625  Jj_consume_token(CaratToken);
1626  boost = Jj_consume_token(NumberToken);
1627  break;
1628  default:
1629  jj_la1[19] = jj_gen;
1630  break;
1631  }
1632  if (goop1.kind == RangeExQuotedToken)
1633  {
1634  goop1.image = goop1.image.Substring(1, (goop1.image.Length - 1) - (1));
1635  }
1636  if (goop2.kind == RangeExQuotedToken)
1637  {
1638  goop2.image = goop2.image.Substring(1, (goop2.image.Length - 1) - (1));
1639  }
1640 
1641  q = GetRangeQuery(field, DiscardEscapeChar(goop1.image), DiscardEscapeChar(goop2.image), false);
1642  break;
1643  case QuotedToken:
1644  term = Jj_consume_token(QuotedToken);
1645  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1646  {
1647  case FuzzySlopToken:
1648  fuzzySlop = Jj_consume_token(FuzzySlopToken);
1649  break;
1650  default:
1651  jj_la1[20] = jj_gen;
1652  break;
1653  }
1654  switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
1655  {
1656  case CaratToken:
1657  Jj_consume_token(CaratToken);
1658  boost = Jj_consume_token(NumberToken);
1659  break;
1660  default:
1661  jj_la1[21] = jj_gen;
1662  break;
1663  }
1664  int s = phraseSlop;
1665 
1666  if (fuzzySlop != null)
1667  {
1668  try
1669  {
1670  s = (int)Single.Parse(fuzzySlop.image.Substring(1));
1671  }
1672  catch (Exception)
1673  {
1674  }
1675  }
1676  q = GetFieldQuery(field, DiscardEscapeChar(term.image.Substring(1, (term.image.Length - 1) - (1))),
1677  s);
1678  break;
1679  default:
1680  jj_la1[22] = jj_gen;
1681  Jj_consume_token(-1);
1682  throw new ParseException();
1683  }
1684  if (boost != null)
1685  {
1686  float f = (float)1.0;
1687  try
1688  {
1689  f = Single.Parse(boost.image);
1690  }
1691  catch (Exception)
1692  {
1693  /* Should this be handled somehow? (defaults to "no boost", if
1694  * boost number is invalid)
1695  */
1696  }
1697 
1698  // avoid boosting null queries, such as those caused by stop words
1699  if (q != null)
1700  {
1701  q.Boost = f;
1702  }
1703  }
1704  {
1705  if (true) return q;
1706  }
1707  throw new Exception("Missing return statement in function");
1708  }
1709 
1710  private bool Jj_2_1(int xla)
1711  {
1712  jj_la = xla;
1713  jj_lastpos = jj_scanpos = token;
1714  try
1715  {
1716  return !Jj_3_1();
1717  }
1718  catch (LookaheadSuccess)
1719  {
1720  return true;
1721  }
1722  finally
1723  {
1724  Jj_save(0, xla);
1725  }
1726  }
1727 
1728  private bool Jj_3R_2()
1729  {
1730  if (jj_scan_token(TermToken)) return true;
1731  if (jj_scan_token(ColonToken)) return true;
1732  return false;
1733  }
1734 
1735  private bool Jj_3_1()
1736  {
1737  Token xsp;
1738  xsp = jj_scanpos;
1739  if (Jj_3R_2())
1740  {
1741  jj_scanpos = xsp;
1742  if (Jj_3R_3()) return true;
1743  }
1744  return false;
1745  }
1746 
1747  private bool Jj_3R_3()
1748  {
1749  if (jj_scan_token(StarToken)) return true;
1750  if (jj_scan_token(ColonToken)) return true;
1751  return false;
1752  }
1753 
1754  /* Generated Token Manager. */
1756  /* Current token. */
1757  public Token token;
1758  /* Next token. */
1759  public Token jj_nt;
1760  private int jj_ntk;
1761  private Token jj_scanpos, jj_lastpos;
1762  private int jj_la;
1763  private int jj_gen;
1764  private int[] jj_la1 = new int[23];
1765  private static int[] jj_la1_0;
1766  private static int[] jj_la1_1;
1767 
1768  private static void Jj_la1_init_0()
1769  {
1770  jj_la1_0 = new int[]
1771  {
1772  0x300, 0x300, 0x1c00, 0x1c00, 0x3ed3f00, 0x90000, 0x20000, 0x3ed2000, 0x2690000, 0x100000,
1773  0x100000, 0x20000, 0x30000000, 0x4000000, 0x30000000, 0x20000, 0x0, 0x40000000, 0x0, 0x20000
1774  , 0x100000, 0x20000, 0x3ed0000,
1775  };
1776  }
1777 
1778  private static void Jj_la1_init_1()
1779  {
1780  jj_la1_1 = new int[]
1781  {
1782  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0,
1783  0x3, 0x0, 0x0, 0x0, 0x0,
1784  };
1785  }
1786 
1787  private JJCalls[] jj_2_rtns = new JJCalls[1];
1788  private bool jj_rescan = false;
1789  private int jj_gc = 0;
1790 
1791  /// <summary>Constructor with user supplied CharStream. </summary>
1792  protected internal QueryParser(ICharStream stream)
1793  {
1794  token_source = new QueryParserTokenManager(stream);
1795  token = new Token();
1796  jj_ntk = -1;
1797  jj_gen = 0;
1798  for (int i = 0; i < 23; i++) jj_la1[i] = -1;
1799  for (int i = 0; i < jj_2_rtns.Length; i++) jj_2_rtns[i] = new JJCalls();
1800  }
1801 
1802  /// <summary>Reinitialise. </summary>
1803  public void ReInit(ICharStream stream)
1804  {
1805  token_source.ReInit(stream);
1806  token = new Token();
1807  jj_ntk = -1;
1808  jj_gen = 0;
1809  for (int i = 0; i < 23; i++) jj_la1[i] = -1;
1810  for (int i = 0; i < jj_2_rtns.Length; i++) jj_2_rtns[i] = new JJCalls();
1811  }
1812 
1813  /// <summary>Constructor with generated Token Manager. </summary>
1815  {
1816  token_source = tm;
1817  token = new Token();
1818  jj_ntk = -1;
1819  jj_gen = 0;
1820  for (int i = 0; i < 23; i++) jj_la1[i] = -1;
1821  for (int i = 0; i < jj_2_rtns.Length; i++) jj_2_rtns[i] = new JJCalls();
1822  }
1823 
1824  /// <summary>Reinitialise. </summary>
1825  public void ReInit(QueryParserTokenManager tm)
1826  {
1827  token_source = tm;
1828  token = new Token();
1829  jj_ntk = -1;
1830  jj_gen = 0;
1831  for (int i = 0; i < 23; i++) jj_la1[i] = -1;
1832  for (int i = 0; i < jj_2_rtns.Length; i++) jj_2_rtns[i] = new JJCalls();
1833  }
1834 
1835  private Token Jj_consume_token(int kind)
1836  {
1837  Token oldToken;
1838  if ((oldToken = token).next != null) token = token.next;
1839  else token = token.next = token_source.GetNextToken();
1840  jj_ntk = -1;
1841  if (token.kind == kind)
1842  {
1843  jj_gen++;
1844  if (++jj_gc > 100)
1845  {
1846  jj_gc = 0;
1847  for (int i = 0; i < jj_2_rtns.Length; i++)
1848  {
1849  JJCalls c = jj_2_rtns[i];
1850  while (c != null)
1851  {
1852  if (c.gen < jj_gen) c.first = null;
1853  c = c.next;
1854  }
1855  }
1856  }
1857  return token;
1858  }
1859  token = oldToken;
1860  jj_kind = kind;
1861  throw GenerateParseException();
1862  }
1863 
1864  [Serializable]
1865  private sealed class LookaheadSuccess : System.Exception
1866  {
1867  }
1868 
1869  private LookaheadSuccess jj_ls = new LookaheadSuccess();
1870  private bool jj_scan_token(int kind)
1871  {
1872  if (jj_scanpos == jj_lastpos)
1873  {
1874  jj_la--;
1875  if (jj_scanpos.next == null)
1876  {
1877  jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.GetNextToken();
1878  }
1879  else
1880  {
1881  jj_lastpos = jj_scanpos = jj_scanpos.next;
1882  }
1883  }
1884  else
1885  {
1886  jj_scanpos = jj_scanpos.next;
1887  }
1888  if (jj_rescan)
1889  {
1890  int i = 0;
1891  Token tok = token;
1892  while (tok != null && tok != jj_scanpos)
1893  {
1894  i++;
1895  tok = tok.next;
1896  }
1897  if (tok != null) Jj_add_error_token(kind, i);
1898  }
1899  if (jj_scanpos.kind != kind) return true;
1900  if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
1901  return false;
1902  }
1903 
1904  /// <summary>Get the next Token. </summary>
1905  public Token GetNextToken()
1906  {
1907  if (token.next != null) token = token.next;
1908  else token = token.next = token_source.GetNextToken();
1909  jj_ntk = -1;
1910  jj_gen++;
1911  return token;
1912  }
1913 
1914  /// <summary>Get the specific Token. </summary>
1915  public Token getToken(int index)
1916  {
1917  Token t = token;
1918  for (int i = 0; i < index; i++)
1919  {
1920  if (t.next != null) t = t.next;
1921  else t = t.next = token_source.GetNextToken();
1922  }
1923  return t;
1924  }
1925 
1926  private int Jj_ntk()
1927  {
1928  if ((jj_nt = token.next) == null)
1929  return (jj_ntk = (token.next = token_source.GetNextToken()).kind);
1930  else
1931  return (jj_ntk = jj_nt.kind);
1932  }
1933 
1934  private List<int[]> jj_expentries = new List<int[]>();
1935  private int[] jj_expentry;
1936  private int jj_kind = -1;
1937  private int[] jj_lasttokens = new int[100];
1938  private int jj_endpos;
1939 
1940  private void Jj_add_error_token(int kind, int pos)
1941  {
1942  if (pos >= 100) return;
1943  if (pos == jj_endpos + 1)
1944  {
1945  jj_lasttokens[jj_endpos++] = kind;
1946  }
1947  else if (jj_endpos != 0)
1948  {
1949  jj_expentry = new int[jj_endpos];
1950  for (int i = 0; i < jj_endpos; i++)
1951  {
1952  jj_expentry[i] = jj_lasttokens[i];
1953  }
1954 
1955  foreach (var oldentry in jj_expentries)
1956  {
1957  if (oldentry.Length == jj_expentry.Length)
1958  {
1959  for (int i = 0; i < jj_expentry.Length; i++)
1960  {
1961  if (oldentry[i] != jj_expentry[i])
1962  {
1963  continue;
1964  }
1965  }
1966  jj_expentries.Add(jj_expentry);
1967  break;
1968  }
1969  }
1970  if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
1971  }
1972  }
1973 
1974  /// <summary>Generate ParseException. </summary>
1975  public virtual ParseException GenerateParseException()
1976  {
1977  jj_expentries.Clear();
1978  bool[] la1tokens = new bool[34];
1979  if (jj_kind >= 0)
1980  {
1981  la1tokens[jj_kind] = true;
1982  jj_kind = -1;
1983  }
1984  for (int i = 0; i < 23; i++)
1985  {
1986  if (jj_la1[i] == jj_gen)
1987  {
1988  for (int j = 0; j < 32; j++)
1989  {
1990  if ((jj_la1_0[i] & (1 << j)) != 0)
1991  {
1992  la1tokens[j] = true;
1993  }
1994  if ((jj_la1_1[i] & (1 << j)) != 0)
1995  {
1996  la1tokens[32 + j] = true;
1997  }
1998  }
1999  }
2000  }
2001  for (int i = 0; i < 34; i++)
2002  {
2003  if (la1tokens[i])
2004  {
2005  jj_expentry = new int[1];
2006  jj_expentry[0] = i;
2007  jj_expentries.Add(jj_expentry);
2008  }
2009  }
2010  jj_endpos = 0;
2011  Jj_rescan_token();
2012  Jj_add_error_token(0, 0);
2013  int[][] exptokseq = new int[jj_expentries.Count][];
2014  for (int i = 0; i < jj_expentries.Count; i++)
2015  {
2016  exptokseq[i] = jj_expentries[i];
2017  }
2018  return new ParseException(token, exptokseq, tokenImage);
2019  }
2020 
2021  /// <summary>Enable tracing. </summary>
2022  public void Enable_tracing()
2023  {
2024  }
2025 
2026  /// <summary>Disable tracing. </summary>
2027  public void Disable_tracing()
2028  {
2029  }
2030 
2031  private void Jj_rescan_token()
2032  {
2033  jj_rescan = true;
2034  for (int i = 0; i < 1; i++)
2035  {
2036  try
2037  {
2038  JJCalls p = jj_2_rtns[i];
2039  do
2040  {
2041  if (p.gen > jj_gen)
2042  {
2043  jj_la = p.arg;
2044  jj_lastpos = jj_scanpos = p.first;
2045  switch (i)
2046  {
2047  case 0:
2048  Jj_3_1();
2049  break;
2050  }
2051  }
2052  p = p.next;
2053  } while (p != null);
2054  }
2055  catch (LookaheadSuccess)
2056  {
2057  }
2058  }
2059  jj_rescan = false;
2060  }
2061 
2062  private void Jj_save(int index, int xla)
2063  {
2064  JJCalls p = jj_2_rtns[index];
2065  while (p.gen > jj_gen)
2066  {
2067  if (p.next == null)
2068  {
2069  p = p.next = new JJCalls();
2070  break;
2071  }
2072  p = p.next;
2073  }
2074  p.gen = jj_gen + xla - jj_la;
2075  p.first = token;
2076  p.arg = xla;
2077  }
2078 
2079  internal sealed class JJCalls
2080  {
2081  internal int gen;
2082  internal Token first;
2083  internal int arg;
2084  internal JJCalls next;
2085  }
2086 
2087  static QueryParser()
2088  {
2089  {
2090  Jj_la1_init_0();
2091  Jj_la1_init_1();
2092  }
2093  }
2094  }
2095 }