1   /* Generated By:JavaCC: Do not edit this line. QueryParser.java */
2   package org.apache.lucene.queryParser;
3   
4   import java.io.IOException;
5   import java.io.StringReader;
6   import java.text.DateFormat;
7   import java.text.Collator;
8   import java.util.ArrayList;
9   import java.util.Calendar;
10  import java.util.Date;
11  import java.util.HashMap;
12  import java.util.List;
13  import java.util.Locale;
14  import java.util.Map;
15  import java.util.Vector;
16  
17  import org.apache.lucene.analysis.Analyzer;
18  import org.apache.lucene.analysis.TokenStream;
19  import org.apache.lucene.document.DateField;
20  import org.apache.lucene.document.DateTools;
21  import org.apache.lucene.index.Term;
22  import org.apache.lucene.search.BooleanClause;
23  import org.apache.lucene.search.BooleanQuery;
24  import org.apache.lucene.search.ConstantScoreRangeQuery;
25  import org.apache.lucene.search.FuzzyQuery;
26  import org.apache.lucene.search.MatchAllDocsQuery;
27  import org.apache.lucene.search.MultiPhraseQuery;
28  import org.apache.lucene.search.PhraseQuery;
29  import org.apache.lucene.search.PrefixQuery;
30  import org.apache.lucene.search.Query;
31  import org.apache.lucene.search.RangeQuery;
32  import org.apache.lucene.search.TermQuery;
33  import org.apache.lucene.search.WildcardQuery;
34  import org.apache.lucene.util.Parameter;
35  
36  /**
37   * This class is generated by JavaCC.  The most important method is
38   * {@link #parse(String)}.
39   *
40   * The syntax for query strings is as follows:
41   * A Query is a series of clauses.
42   * A clause may be prefixed by:
43   * <ul>
44   * <li> a plus (<code>+</code>) or a minus (<code>-</code>) sign, indicating
45   * that the clause is required or prohibited respectively; or
46   * <li> a term followed by a colon, indicating the field to be searched.
47   * This enables one to construct queries which search multiple fields.
48   * </ul>
49   *
50   * A clause may be either:
51   * <ul>
52   * <li> a term, indicating all the documents that contain this term; or
53   * <li> a nested query, enclosed in parentheses.  Note that this may be used
54   * with a <code>+</code>/<code>-</code> prefix to require any of a set of
55   * terms.
56   * </ul>
57   *
58   * Thus, in BNF, the query grammar is:
59   * <pre>
60   *   Query  ::= ( Clause )*
61   *   Clause ::= ["+", "-"] [&lt;TERM&gt; ":"] ( &lt;TERM&gt; | "(" Query ")" )
62   * </pre>
63   *
64   * <p>
65   * Examples of appropriately formatted queries can be found in the <a
66   * href="http://lucene.apache.org/java/docs/queryparsersyntax.html">query syntax
67   * documentation</a>.
68   * </p>
69   *
70   * <p>
71   * In {@link RangeQuery}s, QueryParser tries to detect date values, e.g.
72   * <tt>date:[6/1/2005 TO 6/4/2005]</tt> produces a range query that searches
73   * for "date" fields between 2005-06-01 and 2005-06-04. Note that the format
74   * of the accepted input depends on {@link #setLocale(Locale) the locale}.
75   * By default a date is converted into a search term using the deprecated
76   * {@link DateField} for compatibility reasons.
77   * To use the new {@link DateTools} to convert dates, a
78   * {@link org.apache.lucene.document.DateTools.Resolution} has to be set.
79   * </p>
80   * <p>
81   * The date resolution that shall be used for RangeQueries can be set
82   * using {@link #setDateResolution(DateTools.Resolution)}
83   * or {@link #setDateResolution(String, DateTools.Resolution)}. The former
84   * sets the default date resolution for all fields, whereas the latter can
85   * be used to set field specific date resolutions. Field specific date
86   * resolutions take, if set, precedence over the default date resolution.
87   * </p>
88   * <p>
89   * If you use neither {@link DateField} nor {@link DateTools} in your
90   * index, you can create your own
91   * query parser that inherits QueryParser and overwrites
92   * {@link #getRangeQuery(String, String, String, boolean)} to
93   * use a different method for date conversion.
94   * </p>
95   *
96   * <p>Note that QueryParser is <em>not</em> thread-safe.</p>
97   *
98   */
99  public class QueryParser implements QueryParserConstants {
100 
101   private static final int CONJ_NONE   = 0;
102   private static final int CONJ_AND    = 1;
103   private static final int CONJ_OR     = 2;
104 
105   private static final int MOD_NONE    = 0;
106   private static final int MOD_NOT     = 10;
107   private static final int MOD_REQ     = 11;
108 
109   // make it possible to call setDefaultOperator() without accessing 
110   // the nested class:
111   /** Alternative form of QueryParser.Operator.AND */
112   public static final Operator AND_OPERATOR = Operator.AND;
113   /** Alternative form of QueryParser.Operator.OR */
114   public static final Operator OR_OPERATOR = Operator.OR;
115 
116   /** The actual operator that parser uses to combine query terms */
117   private Operator operator = OR_OPERATOR;
118 
119   boolean lowercaseExpandedTerms = true;
120   boolean useOldRangeQuery= false;
121   boolean allowLeadingWildcard = false;
122   boolean enablePositionIncrements = false;
123 
124   Analyzer analyzer;
125   String field;
126   int phraseSlop = 0;
127   float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity;
128   int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
129   Locale locale = Locale.getDefault();
130 
131   // the default date resolution
132   DateTools.Resolution dateResolution = null;
133   // maps field names to date resolutions
134   Map fieldToDateResolution = null;
135 
136   // The collator to use when determining range inclusion,
137   // for use when constructing RangeQuerys and ConstantScoreRangeQuerys.
138   Collator rangeCollator = null;
139 
140   /** The default operator for parsing queries. 
141    * Use {@link QueryParser#setDefaultOperator} to change it.
142    */
143   static public final class Operator extends Parameter {
144     private Operator(String name) {
145       super(name);
146     }
147     static public final Operator OR = new Operator("OR");
148     static public final Operator AND = new Operator("AND");
149   }
150 
151 
152   /** Constructs a query parser.
153    *  @param f  the default field for query terms.
154    *  @param a   used to find terms in the query text.
155    */
156   public QueryParser(String f, Analyzer a) {
157     this(new FastCharStream(new StringReader("")));
158     analyzer = a;
159     field = f;
160   }
161 
162   /** Parses a query string, returning a {@link org.apache.lucene.search.Query}.
163    *  @param query  the query string to be parsed.
164    *  @throws ParseException if the parsing fails
165    */
166   public Query parse(String query) throws ParseException {
167     ReInit(new FastCharStream(new StringReader(query)));
168     try {
169       // TopLevelQuery is a Query followed by the end-of-input (EOF)
170       Query res = TopLevelQuery(field);
171       return res!=null ? res : newBooleanQuery(false);
172     }
173     catch (ParseException tme) {
174       // rethrow to include the original query:
175       throw new ParseException("Cannot parse '" +query+ "': " + tme.getMessage());
176     }
177     catch (TokenMgrError tme) {
178       throw new ParseException("Cannot parse '" +query+ "': " + tme.getMessage());
179     }
180     catch (BooleanQuery.TooManyClauses tmc) {
181       throw new ParseException("Cannot parse '" +query+ "': too many boolean clauses");
182     }
183   }
184 
185    /**
186    * @return Returns the analyzer.
187    */
188   public Analyzer getAnalyzer() {
189     return analyzer;
190   }
191 
192   /**
193    * @return Returns the field.
194    */
195   public String getField() {
196     return field;
197   }
198 
199    /**
200    * Get the minimal similarity for fuzzy queries.
201    */
202   public float getFuzzyMinSim() {
203       return fuzzyMinSim;
204   }
205 
206   /**
207    * Set the minimum similarity for fuzzy queries.
208    * Default is 0.5f.
209    */
210   public void setFuzzyMinSim(float fuzzyMinSim) {
211       this.fuzzyMinSim = fuzzyMinSim;
212   }
213 
214    /**
215    * Get the prefix length for fuzzy queries. 
216    * @return Returns the fuzzyPrefixLength.
217    */
218   public int getFuzzyPrefixLength() {
219     return fuzzyPrefixLength;
220   }
221 
222   /**
223    * Set the prefix length for fuzzy queries. Default is 0.
224    * @param fuzzyPrefixLength The fuzzyPrefixLength to set.
225    */
226   public void setFuzzyPrefixLength(int fuzzyPrefixLength) {
227     this.fuzzyPrefixLength = fuzzyPrefixLength;
228   }
229 
230   /**
231    * Sets the default slop for phrases.  If zero, then exact phrase matches
232    * are required.  Default value is zero.
233    */
234   public void setPhraseSlop(int phraseSlop) {
235     this.phraseSlop = phraseSlop;
236   }
237 
238   /**
239    * Gets the default slop for phrases.
240    */
241   public int getPhraseSlop() {
242     return phraseSlop;
243   }
244 
245 
246   /**
247    * Set to <code>true</code> to allow leading wildcard characters.
248    * <p>
249    * When set, <code>*</code> or <code>?</code> are allowed as 
250    * the first character of a PrefixQuery and WildcardQuery.
251    * Note that this can produce very slow
252    * queries on big indexes. 
253    * <p>
254    * Default: false.
255    */
256   public void setAllowLeadingWildcard(boolean allowLeadingWildcard) {
257     this.allowLeadingWildcard = allowLeadingWildcard;
258   }
259 
260   /**
261    * @see #setAllowLeadingWildcard(boolean)
262    */
263   public boolean getAllowLeadingWildcard() {
264     return allowLeadingWildcard;
265   }
266 
267   /**
268    * Set to <code>true</code> to enable position increments in result query.
269    * <p>
270    * When set, result phrase and multi-phrase queries will
271    * be aware of position increments.
272    * Useful when e.g. a StopFilter increases the position increment of
273    * the token that follows an omitted token.
274    * <p>
275    * Default: false.
276    */
277   public void setEnablePositionIncrements(boolean enable) {
278     this.enablePositionIncrements = enable;
279   }
280 
281   /**
282    * @see #setEnablePositionIncrements(boolean)
283    */
284   public boolean getEnablePositionIncrements() {
285     return enablePositionIncrements;
286   }
287 
288   /**
289    * Sets the boolean operator of the QueryParser.
290    * In default mode (<code>OR_OPERATOR</code>) terms without any modifiers
291    * are considered optional: for example <code>capital of Hungary</code> is equal to
292    * <code>capital OR of OR Hungary</code>.<br/>
293    * In <code>AND_OPERATOR</code> mode terms are considered to be in conjunction: the
294    * above mentioned query is parsed as <code>capital AND of AND Hungary</code>
295    */
296   public void setDefaultOperator(Operator op) {
297     this.operator = op;
298   }
299 
300 
301   /**
302    * Gets implicit operator setting, which will be either AND_OPERATOR
303    * or OR_OPERATOR.
304    */
305   public Operator getDefaultOperator() {
306     return operator;
307   }
308 
309 
310   /**
311    * Whether terms of wildcard, prefix, fuzzy and range queries are to be automatically
312    * lower-cased or not.  Default is <code>true</code>.
313    */
314   public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) {
315     this.lowercaseExpandedTerms = lowercaseExpandedTerms;
316   }
317 
318 
319   /**
320    * @see #setLowercaseExpandedTerms(boolean)
321    */
322   public boolean getLowercaseExpandedTerms() {
323     return lowercaseExpandedTerms;
324   }
325 
326   /**
327    * By default QueryParser uses new ConstantScoreRangeQuery in preference to RangeQuery
328    * for range queries. This implementation is generally preferable because it 
329    * a) Runs faster b) Does not have the scarcity of range terms unduly influence score 
330    * c) avoids any "TooManyBooleanClauses" exception.
331    * However, if your application really needs to use the old-fashioned RangeQuery and the above
332    * points are not required then set this option to <code>true</code>
333    * Default is <code>false</code>.
334    */
335   public void setUseOldRangeQuery(boolean useOldRangeQuery) {
336     this.useOldRangeQuery = useOldRangeQuery;
337   }
338 
339 
340   /**
341    * @see #setUseOldRangeQuery(boolean)
342    */
343   public boolean getUseOldRangeQuery() {
344     return useOldRangeQuery;
345   }
346 
347   /**
348    * Set locale used by date range parsing.
349    */
350   public void setLocale(Locale locale) {
351     this.locale = locale;
352   }
353 
354   /**
355    * Returns current locale, allowing access by subclasses.
356    */
357   public Locale getLocale() {
358     return locale;
359   }
360 
361   /**
362    * Sets the default date resolution used by RangeQueries for fields for which no
363    * specific date resolutions has been set. Field specific resolutions can be set
364    * with {@link #setDateResolution(String, DateTools.Resolution)}.
365    *  
366    * @param dateResolution the default date resolution to set
367    */
368   public void setDateResolution(DateTools.Resolution dateResolution) {
369     this.dateResolution = dateResolution;
370   }
371 
372   /**
373    * Sets the date resolution used by RangeQueries for a specific field.
374    *  
375    * @param fieldName field for which the date resolution is to be set 
376    * @param dateResolution date resolution to set
377    */
378   public void setDateResolution(String fieldName, DateTools.Resolution dateResolution) {
379     if (fieldName == null) {
380       throw new IllegalArgumentException("Field cannot be null.");
381     }
382 
383     if (fieldToDateResolution == null) {
384       // lazily initialize HashMap
385       fieldToDateResolution = new HashMap();
386     }
387 
388     fieldToDateResolution.put(fieldName, dateResolution);
389   }
390 
391   /**
392    * Returns the date resolution that is used by RangeQueries for the given field. 
393    * Returns null, if no default or field specific date resolution has been set
394    * for the given field.
395    *
396    */
397   public DateTools.Resolution getDateResolution(String fieldName) {
398     if (fieldName == null) {
399       throw new IllegalArgumentException("Field cannot be null.");
400     }
401 
402     if (fieldToDateResolution == null) {
403       // no field specific date resolutions set; return default date resolution instead
404       return this.dateResolution;
405     }
406 
407     DateTools.Resolution resolution = (DateTools.Resolution) fieldToDateResolution.get(fieldName);
408     if (resolution == null) {
409       // no date resolutions set for the given field; return default date resolution instead
410       resolution = this.dateResolution;
411     }
412 
413     return resolution;
414   }
415 
416   /** 
417    * Sets the collator used to determine index term inclusion in ranges
418    * specified either for ConstantScoreRangeQuerys or RangeQuerys (if
419    * {@link #setUseOldRangeQuery(boolean)} is called with a <code>true</code>
420    * value.)
421    * <p/>
422    * <strong>WARNING:</strong> Setting the rangeCollator to a non-null
423    * collator using this method will cause every single index Term in the
424    * Field referenced by lowerTerm and/or upperTerm to be examined.
425    * Depending on the number of index Terms in this Field, the operation could
426    * be very slow.
427    *
428    *  @param rc  the collator to use when constructing RangeQuerys
429    *             and ConstantScoreRangeQuerys
430    */
431   public void setRangeCollator(Collator rc) {
432     rangeCollator = rc;
433   }
434 
435   /**
436    * @return the collator used to determine index term inclusion in ranges
437    *  specified either for ConstantScoreRangeQuerys or RangeQuerys (if
438    *  {@link #setUseOldRangeQuery(boolean)} is called with a <code>true</code>
439    *  value.)
440    */
441   public Collator getRangeCollator() {
442     return rangeCollator;
443   }
444 
445   /**
446    * @deprecated use {@link #addClause(List, int, int, Query)} instead.
447    */
448   protected void addClause(Vector clauses, int conj, int mods, Query q) {
449     addClause((List) clauses, conj, mods, q);
450   }
451 
452   protected void addClause(List clauses, int conj, int mods, Query q) {
453     boolean required, prohibited;
454 
455     // If this term is introduced by AND, make the preceding term required,
456     // unless it's already prohibited
457     if (clauses.size() > 0 && conj == CONJ_AND) {
458       BooleanClause c = (BooleanClause) clauses.get(clauses.size()-1);
459       if (!c.isProhibited())
460         c.setOccur(BooleanClause.Occur.MUST);
461     }
462 
463     if (clauses.size() > 0 && operator == AND_OPERATOR && conj == CONJ_OR) {
464       // If this term is introduced by OR, make the preceding term optional,
465       // unless it's prohibited (that means we leave -a OR b but +a OR b-->a OR b)
466       // notice if the input is a OR b, first term is parsed as required; without
467       // this modification a OR b would parsed as +a OR b
468       BooleanClause c = (BooleanClause) clauses.get(clauses.size()-1);
469       if (!c.isProhibited())
470         c.setOccur(BooleanClause.Occur.SHOULD);
471     }
472 
473     // We might have been passed a null query; the term might have been
474     // filtered away by the analyzer.
475     if (q == null)
476       return;
477 
478     if (operator == OR_OPERATOR) {
479       // We set REQUIRED if we're introduced by AND or +; PROHIBITED if
480       // introduced by NOT or -; make sure not to set both.
481       prohibited = (mods == MOD_NOT);
482       required = (mods == MOD_REQ);
483       if (conj == CONJ_AND && !prohibited) {
484         required = true;
485       }
486     } else {
487       // We set PROHIBITED if we're introduced by NOT or -; We set REQUIRED
488       // if not PROHIBITED and not introduced by OR
489       prohibited = (mods == MOD_NOT);
490       required   = (!prohibited && conj != CONJ_OR);
491     }
492     if (required && !prohibited)
493       clauses.add(newBooleanClause(q, BooleanClause.Occur.MUST));
494     else if (!required && !prohibited)
495       clauses.add(newBooleanClause(q, BooleanClause.Occur.SHOULD));
496     else if (!required && prohibited)
497       clauses.add(newBooleanClause(q, BooleanClause.Occur.MUST_NOT));
498     else
499       throw new RuntimeException("Clause cannot be both required and prohibited");
500   }
501 
502 
503   /**
504    * @exception ParseException throw in overridden method to disallow
505    */
506   protected Query getFieldQuery(String field, String queryText)  throws ParseException {
507     // Use the analyzer to get all the tokens, and then build a TermQuery,
508     // PhraseQuery, or nothing based on the term count
509 
510     TokenStream source = analyzer.tokenStream(field, new StringReader(queryText));
511     List list = new ArrayList();
512     final org.apache.lucene.analysis.Token reusableToken = new org.apache.lucene.analysis.Token();
513     org.apache.lucene.analysis.Token nextToken;
514     int positionCount = 0;
515     boolean severalTokensAtSamePosition = false;
516 
517     while (true) {
518       try {
519         nextToken = source.next(reusableToken);
520       }
521       catch (IOException e) {
522         nextToken = null;
523       }
524       if (nextToken == null)
525         break;
526       list.add(nextToken.clone());
527       if (nextToken.getPositionIncrement() != 0)
528         positionCount += nextToken.getPositionIncrement();
529       else
530         severalTokensAtSamePosition = true;
531     }
532     try {
533       source.close();
534     }
535     catch (IOException e) {
536       // ignore
537     }
538 
539     if (list.size() == 0)
540       return null;
541     else if (list.size() == 1) {
542       nextToken = (org.apache.lucene.analysis.Token) list.get(0);
543       return newTermQuery(new Term(field, nextToken.term()));
544     } else {
545       if (severalTokensAtSamePosition) {
546         if (positionCount == 1) {
547           // no phrase query:
548           BooleanQuery q = newBooleanQuery(true);
549           for (int i = 0; i < list.size(); i++) {
550             nextToken = (org.apache.lucene.analysis.Token) list.get(i);
551             Query currentQuery = newTermQuery(
552                 new Term(field, nextToken.term()));
553             q.add(currentQuery, BooleanClause.Occur.SHOULD);
554           }
555           return q;
556         }
557         else {
558           // phrase query:
559           MultiPhraseQuery mpq = newMultiPhraseQuery();
560           mpq.setSlop(phraseSlop);
561           List multiTerms = new ArrayList();
562           int position = -1;
563           for (int i = 0; i < list.size(); i++) {
564             nextToken = (org.apache.lucene.analysis.Token) list.get(i);
565             if (nextToken.getPositionIncrement() > 0 && multiTerms.size() > 0) {
566               if (enablePositionIncrements) {
567                 mpq.add((Term[])multiTerms.toArray(new Term[0]),position);
568               } else {
569                 mpq.add((Term[])multiTerms.toArray(new Term[0]));
570               }
571               multiTerms.clear();
572             }
573             position += nextToken.getPositionIncrement();
574             multiTerms.add(new Term(field, nextToken.term()));
575           }
576           if (enablePositionIncrements) {
577             mpq.add((Term[])multiTerms.toArray(new Term[0]),position);
578           } else {
579             mpq.add((Term[])multiTerms.toArray(new Term[0]));
580           }
581           return mpq;
582         }
583       }
584       else {
585         PhraseQuery pq = newPhraseQuery();
586         pq.setSlop(phraseSlop);
587         int position = -1;
588         for (int i = 0; i < list.size(); i++) {
589           nextToken = (org.apache.lucene.analysis.Token) list.get(i);
590           if (enablePositionIncrements) {
591             position += nextToken.getPositionIncrement();
592             pq.add(new Term(field, nextToken.term()),position);
593           } else {
594             pq.add(new Term(field, nextToken.term()));
595           }
596         }
597         return pq;
598       }
599     }
600   }
601 
602 
603   /**
604    * Base implementation delegates to {@link #getFieldQuery(String,String)}.
605    * This method may be overridden, for example, to return
606    * a SpanNearQuery instead of a PhraseQuery.
607    *
608    * @exception ParseException throw in overridden method to disallow
609    */
610   protected Query getFieldQuery(String field, String queryText, int slop)
611         throws ParseException {
612     Query query = getFieldQuery(field, queryText);
613 
614     if (query instanceof PhraseQuery) {
615       ((PhraseQuery) query).setSlop(slop);
616     }
617     if (query instanceof MultiPhraseQuery) {
618       ((MultiPhraseQuery) query).setSlop(slop);
619     }
620 
621     return query;
622   }
623 
624 
625   /**
626    * @exception ParseException throw in overridden method to disallow
627    */
628   protected Query getRangeQuery(String field,
629                                 String part1,
630                                 String part2,
631                                 boolean inclusive) throws ParseException
632   {
633     if (lowercaseExpandedTerms) {
634       part1 = part1.toLowerCase();
635       part2 = part2.toLowerCase();
636     }
637     try {
638       DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
639       df.setLenient(true);
640       Date d1 = df.parse(part1);
641       Date d2 = df.parse(part2);
642       if (inclusive) {
643         // The user can only specify the date, not the time, so make sure
644         // the time is set to the latest possible time of that date to really
645         // include all documents:
646         Calendar cal = Calendar.getInstance(locale);
647         cal.setTime(d2);
648         cal.set(Calendar.HOUR_OF_DAY, 23);
649         cal.set(Calendar.MINUTE, 59);
650         cal.set(Calendar.SECOND, 59);
651         cal.set(Calendar.MILLISECOND, 999);
652         d2 = cal.getTime();
653       }
654       DateTools.Resolution resolution = getDateResolution(field);
655       if (resolution == null) {
656         // no default or field specific date resolution has been set,
657         // use deprecated DateField to maintain compatibilty with
658         // pre-1.9 Lucene versions.
659         part1 = DateField.dateToString(d1);
660         part2 = DateField.dateToString(d2);
661       } else {
662         part1 = DateTools.dateToString(d1, resolution);
663         part2 = DateTools.dateToString(d2, resolution);
664       }
665     }
666     catch (Exception e) { }
667 
668     return newRangeQuery(field, part1, part2, inclusive);
669   }
670 
671  /**
672   * Builds a new BooleanQuery instance
673   * @param disableCoord disable coord
674   * @return new BooleanQuery instance
675   */
676   protected BooleanQuery newBooleanQuery(boolean disableCoord) {
677     return new BooleanQuery(disableCoord);
678   }
679 
680  /**
681   * Builds a new BooleanClause instance
682   * @param q sub query
683   * @param occur how this clause should occur when matching documents
684   * @return new BooleanClause instance
685   */
686   protected BooleanClause newBooleanClause(Query q, BooleanClause.Occur occur) {
687     return new BooleanClause(q, occur);
688   }
689 
690   /**
691    * Builds a new TermQuery instance
692    * @param term term
693    * @return new TermQuery instance
694    */
695   protected Query newTermQuery(Term term){
696     return new TermQuery(term);
697   }
698 
699   /**
700    * Builds a new PhraseQuery instance
701    * @return new PhraseQuery instance
702    */
703   protected PhraseQuery newPhraseQuery(){
704     return new PhraseQuery();
705   }
706 
707   /**
708    * Builds a new MultiPhraseQuery instance
709    * @return new MultiPhraseQuery instance
710    */
711   protected MultiPhraseQuery newMultiPhraseQuery(){
712     return new MultiPhraseQuery();
713   }
714 
715   /**
716    * Builds a new PrefixQuery instance
717    * @param prefix Prefix term
718    * @return new PrefixQuery instance
719    */
720   protected Query newPrefixQuery(Term prefix){
721     return new PrefixQuery(prefix);
722   }
723 
724   /**
725    * Builds a new FuzzyQuery instance
726    * @param term Term
727    * @param minimumSimilarity minimum similarity
728    * @param prefixLength prefix length
729    * @return new FuzzyQuery Instance
730    */
731   protected Query newFuzzyQuery(Term term, float minimumSimilarity, int prefixLength) {
732     return new FuzzyQuery(term,minimumSimilarity,prefixLength);
733   }
734 
735   /**
736    * Builds a new RangeQuery instance
737    * @param field Field
738    * @param part1 min
739    * @param part2 max
740    * @param inclusive true if range is inclusive
741    * @return new RangeQuery instance
742    */
743   protected Query newRangeQuery(String field, String part1, String part2, boolean inclusive) {
744     if(useOldRangeQuery)
745     {
746       return new RangeQuery(new Term(field, part1),
747                             new Term(field, part2),
748                             inclusive, rangeCollator);
749     }
750     else
751     {
752       return new ConstantScoreRangeQuery
753         (field, part1, part2, inclusive, inclusive, rangeCollator);
754     }
755   }
756 
757   /**
758    * Builds a new MatchAllDocsQuery instance
759    * @return new MatchAllDocsQuery instance
760    */
761   protected Query newMatchAllDocsQuery() {
762     return new MatchAllDocsQuery();
763   }
764 
765   /**
766    * Builds a new WildcardQuery instance
767    * @param t wildcard term
768    * @return new WildcardQuery instance
769    */
770   protected Query newWildcardQuery(Term t) {
771     return new WildcardQuery(t);
772   }
773 
774   /**
775    * Factory method for generating query, given a set of clauses.
776    * By default creates a boolean query composed of clauses passed in.
777    *
778    * Can be overridden by extending classes, to modify query being
779    * returned.
780    *
781    * @param clauses List that contains {@link BooleanClause} instances
782    *    to join.
783    *
784    * @return Resulting {@link Query} object.
785    * @exception ParseException throw in overridden method to disallow
786    * @deprecated use {@link #getBooleanQuery(List)} instead
787    */
788   protected Query getBooleanQuery(Vector clauses) throws ParseException {
789     return getBooleanQuery((List) clauses, false);
790   }
791 
792   /**
793    * Factory method for generating query, given a set of clauses.
794    * By default creates a boolean query composed of clauses passed in.
795    *
796    * Can be overridden by extending classes, to modify query being
797    * returned.
798    *
799    * @param clauses List that contains {@link BooleanClause} instances
800    *    to join.
801    *
802    * @return Resulting {@link Query} object.
803    * @exception ParseException throw in overridden method to disallow
804    */
805   protected Query getBooleanQuery(List clauses) throws ParseException {
806     return getBooleanQuery(clauses, false);
807   }
808 
809   /**
810    * Factory method for generating query, given a set of clauses.
811    * By default creates a boolean query composed of clauses passed in.
812    *
813    * Can be overridden by extending classes, to modify query being
814    * returned.
815    *
816    * @param clauses List that contains {@link BooleanClause} instances
817    *    to join.
818    * @param disableCoord true if coord scoring should be disabled.
819    *
820    * @return Resulting {@link Query} object.
821    * @exception ParseException throw in overridden method to disallow
822    * @deprecated use {@link #getBooleanQuery(List, boolean)} instead
823    */
824   protected Query getBooleanQuery(Vector clauses, boolean disableCoord)
825     throws ParseException
826   {
827     return getBooleanQuery((List) clauses, disableCoord);
828   }
829 
830   /**
831    * Factory method for generating query, given a set of clauses.
832    * By default creates a boolean query composed of clauses passed in.
833    *
834    * Can be overridden by extending classes, to modify query being
835    * returned.
836    *
837    * @param clauses List that contains {@link BooleanClause} instances
838    *    to join.
839    * @param disableCoord true if coord scoring should be disabled.
840    *
841    * @return Resulting {@link Query} object.
842    * @exception ParseException throw in overridden method to disallow
843    */
844   protected Query getBooleanQuery(List clauses, boolean disableCoord)
845     throws ParseException
846   {
847     if (clauses.size()==0) {
848       return null; // all clause words were filtered away by the analyzer.
849     }
850     BooleanQuery query = newBooleanQuery(disableCoord);
851     for (int i = 0; i < clauses.size(); i++) {
852       query.add((BooleanClause)clauses.get(i));
853     }
854     return query;
855   }
856 
857   /**
858    * Factory method for generating a query. Called when parser
859    * parses an input term token that contains one or more wildcard
860    * characters (? and *), but is not a prefix term token (one
861    * that has just a single * character at the end)
862    *<p>
863    * Depending on settings, prefix term may be lower-cased
864    * automatically. It will not go through the default Analyzer,
865    * however, since normal Analyzers are unlikely to work properly
866    * with wildcard templates.
867    *<p>
868    * Can be overridden by extending classes, to provide custom handling for
869    * wildcard queries, which may be necessary due to missing analyzer calls.
870    *
871    * @param field Name of the field query will use.
872    * @param termStr Term token that contains one or more wild card
873    *   characters (? or *), but is not simple prefix term
874    *
875    * @return Resulting {@link Query} built for the term
876    * @exception ParseException throw in overridden method to disallow
877    */
878   protected Query getWildcardQuery(String field, String termStr) throws ParseException
879   {
880     if ("*".equals(field)) {
881       if ("*".equals(termStr)) return newMatchAllDocsQuery();
882     }
883     if (!allowLeadingWildcard && (termStr.startsWith("*") || termStr.startsWith("?")))
884       throw new ParseException("'*' or '?' not allowed as first character in WildcardQuery");
885     if (lowercaseExpandedTerms) {
886       termStr = termStr.toLowerCase();
887     }
888     Term t = new Term(field, termStr);
889     return newWildcardQuery(t);
890   }
891 
892   /**
893    * Factory method for generating a query (similar to
894    * {@link #getWildcardQuery}). Called when parser parses an input term
895    * token that uses prefix notation; that is, contains a single '*' wildcard
896    * character as its last character. Since this is a special case
897    * of generic wildcard term, and such a query can be optimized easily,
898    * this usually results in a different query object.
899    *<p>
900    * Depending on settings, a prefix term may be lower-cased
901    * automatically. It will not go through the default Analyzer,
902    * however, since normal Analyzers are unlikely to work properly
903    * with wildcard templates.
904    *<p>
905    * Can be overridden by extending classes, to provide custom handling for
906    * wild card queries, which may be necessary due to missing analyzer calls.
907    *
908    * @param field Name of the field query will use.
909    * @param termStr Term token to use for building term for the query
910    *    (<b>without</b> trailing '*' character!)
911    *
912    * @return Resulting {@link Query} built for the term
913    * @exception ParseException throw in overridden method to disallow
914    */
915   protected Query getPrefixQuery(String field, String termStr) throws ParseException
916   {
917     if (!allowLeadingWildcard && termStr.startsWith("*"))
918       throw new ParseException("'*' not allowed as first character in PrefixQuery");
919     if (lowercaseExpandedTerms) {
920       termStr = termStr.toLowerCase();
921     }
922     Term t = new Term(field, termStr);
923     return newPrefixQuery(t);
924   }
925 
926    /**
927    * Factory method for generating a query (similar to
928    * {@link #getWildcardQuery}). Called when parser parses
929    * an input term token that has the fuzzy suffix (~) appended.
930    *
931    * @param field Name of the field query will use.
932    * @param termStr Term token to use for building term for the query
933    *
934    * @return Resulting {@link Query} built for the term
935    * @exception ParseException throw in overridden method to disallow
936    */
937   protected Query getFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException
938   {
939     if (lowercaseExpandedTerms) {
940       termStr = termStr.toLowerCase();
941     }
942     Term t = new Term(field, termStr);
943     return newFuzzyQuery(t, minSimilarity, fuzzyPrefixLength);
944   }
945 
946   /**
947    * Returns a String where the escape char has been
948    * removed, or kept only once if there was a double escape.
949    * 
950    * Supports escaped unicode characters, e. g. translates
951    * <code>\\u0041</code> to <code>A</code>.
952    * 
953    */
954   private String discardEscapeChar(String input) throws ParseException {
955     // Create char array to hold unescaped char sequence
956     char[] output = new char[input.length()];
957 
958     // The length of the output can be less than the input
959     // due to discarded escape chars. This variable holds
960     // the actual length of the output
961     int length = 0;
962 
963     // We remember whether the last processed character was 
964     // an escape character
965     boolean lastCharWasEscapeChar = false;
966 
967     // The multiplier the current unicode digit must be multiplied with.
968     // E. g. the first digit must be multiplied with 16^3, the second with 16^2...
969     int codePointMultiplier = 0;
970 
971     // Used to calculate the codepoint of the escaped unicode character
972     int codePoint = 0;
973 
974     for (int i = 0; i < input.length(); i++) {
975       char curChar = input.charAt(i);
976       if (codePointMultiplier > 0) {
977         codePoint += hexToInt(curChar) * codePointMultiplier;
978         codePointMultiplier >>>= 4;
979         if (codePointMultiplier == 0) {
980           output[length++] = (char)codePoint;
981           codePoint = 0;
982         }
983       } else if (lastCharWasEscapeChar) {
984         if (curChar == 'u') {
985           // found an escaped unicode character
986           codePointMultiplier = 16 * 16 * 16;
987         } else {
988           // this character was escaped
989           output[length] = curChar;
990           length++;
991         }
992         lastCharWasEscapeChar = false;
993       } else {
994         if (curChar == '\\') {
995           lastCharWasEscapeChar = true;
996         } else {
997           output[length] = curChar;
998           length++;
999         }
1000      }
1001    }
1002
1003    if (codePointMultiplier > 0) {
1004      throw new ParseException("Truncated unicode escape sequence.");
1005    }
1006
1007    if (lastCharWasEscapeChar) {
1008      throw new ParseException("Term can not end with escape character.");
1009    }
1010
1011    return new String(output, 0, length);
1012  }
1013
1014  /** Returns the numeric value of the hexadecimal character */
1015  private static final int hexToInt(char c) throws ParseException {
1016    if ('0' <= c && c <= '9') {
1017      return c - '0';
1018    } else if ('a' <= c && c <= 'f'){
1019      return c - 'a' + 10;
1020    } else if ('A' <= c && c <= 'F') {
1021      return c - 'A' + 10;
1022    } else {
1023      throw new ParseException("None-hex character in unicode escape sequence: " + c);
1024    }
1025  }
1026
1027  /**
1028   * Returns a String where those characters that QueryParser
1029   * expects to be escaped are escaped by a preceding <code>\</code>.
1030   */
1031  public static String escape(String s) {
1032    StringBuffer sb = new StringBuffer();
1033    for (int i = 0; i < s.length(); i++) {
1034      char c = s.charAt(i);
1035      // These characters are part of the query syntax and must be escaped
1036      if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':'
1037        || c == '^' || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~'
1038        || c == '*' || c == '?' || c == '|' || c == '&') {
1039        sb.append('\\');
1040      }
1041      sb.append(c);
1042    }
1043    return sb.toString();
1044  }
1045
1046  /**
1047   * Command line tool to test QueryParser, using {@link org.apache.lucene.analysis.SimpleAnalyzer}.
1048   * Usage:<br>
1049   * <code>java org.apache.lucene.queryParser.QueryParser &lt;input&gt;</code>
1050   */
1051  public static void main(String[] args) throws Exception {
1052    if (args.length == 0) {
1053      System.out.println("Usage: java org.apache.lucene.queryParser.QueryParser <input>");
1054      System.exit(0);
1055    }
1056    QueryParser qp = new QueryParser("field",
1057                           new org.apache.lucene.analysis.SimpleAnalyzer());
1058    Query q = qp.parse(args[0]);
1059    System.out.println(q.toString("field"));
1060  }
1061
1062// *   Query  ::= ( Clause )*
1063// *   Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" )
1064  final public int Conjunction() throws ParseException {
1065  int ret = CONJ_NONE;
1066    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1067    case AND:
1068    case OR:
1069      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1070      case AND:
1071        jj_consume_token(AND);
1072            ret = CONJ_AND;
1073        break;
1074      case OR:
1075        jj_consume_token(OR);
1076              ret = CONJ_OR;
1077        break;
1078      default:
1079        jj_la1[0] = jj_gen;
1080        jj_consume_token(-1);
1081        throw new ParseException();
1082      }
1083      break;
1084    default:
1085      jj_la1[1] = jj_gen;
1086      ;
1087    }
1088    {if (true) return ret;}
1089    throw new Error("Missing return statement in function");
1090  }
1091
1092  final public int Modifiers() throws ParseException {
1093  int ret = MOD_NONE;
1094    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1095    case NOT:
1096    case PLUS:
1097    case MINUS:
1098      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1099      case PLUS:
1100        jj_consume_token(PLUS);
1101              ret = MOD_REQ;
1102        break;
1103      case MINUS:
1104        jj_consume_token(MINUS);
1105                 ret = MOD_NOT;
1106        break;
1107      case NOT:
1108        jj_consume_token(NOT);
1109               ret = MOD_NOT;
1110        break;
1111      default:
1112        jj_la1[2] = jj_gen;
1113        jj_consume_token(-1);
1114        throw new ParseException();
1115      }
1116      break;
1117    default:
1118      jj_la1[3] = jj_gen;
1119      ;
1120    }
1121    {if (true) return ret;}
1122    throw new Error("Missing return statement in function");
1123  }
1124
1125// This makes sure that there is no garbage after the query string
1126  final public Query TopLevelQuery(String field) throws ParseException {
1127        Query q;
1128    q = Query(field);
1129    jj_consume_token(0);
1130                {if (true) return q;}
1131    throw new Error("Missing return statement in function");
1132  }
1133
1134  final public Query Query(String field) throws ParseException {
1135  List clauses = new ArrayList();
1136  Query q, firstQuery=null;
1137  int conj, mods;
1138    mods = Modifiers();
1139    q = Clause(field);
1140    addClause(clauses, CONJ_NONE, mods, q);
1141    if (mods == MOD_NONE)
1142        firstQuery=q;
1143    label_1:
1144    while (true) {
1145      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1146      case AND:
1147      case OR:
1148      case NOT:
1149      case PLUS:
1150      case MINUS:
1151      case LPAREN:
1152      case STAR:
1153      case QUOTED:
1154      case TERM:
1155      case PREFIXTERM:
1156      case WILDTERM:
1157      case RANGEIN_START:
1158      case RANGEEX_START:
1159      case NUMBER:
1160        ;
1161        break;
1162      default:
1163        jj_la1[4] = jj_gen;
1164        break label_1;
1165      }
1166      conj = Conjunction();
1167      mods = Modifiers();
1168      q = Clause(field);
1169      addClause(clauses, conj, mods, q);
1170    }
1171      if (clauses.size() == 1 && firstQuery != null)
1172        {if (true) return firstQuery;}
1173      else {
1174  {if (true) return getBooleanQuery(clauses);}
1175      }
1176    throw new Error("Missing return statement in function");
1177  }
1178
1179  final public Query Clause(String field) throws ParseException {
1180  Query q;
1181  Token fieldToken=null, boost=null;
1182    if (jj_2_1(2)) {
1183      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1184      case TERM:
1185        fieldToken = jj_consume_token(TERM);
1186        jj_consume_token(COLON);
1187                               field=discardEscapeChar(fieldToken.image);
1188        break;
1189      case STAR:
1190        jj_consume_token(STAR);
1191        jj_consume_token(COLON);
1192                      field="*";
1193        break;
1194      default:
1195        jj_la1[5] = jj_gen;
1196        jj_consume_token(-1);
1197        throw new ParseException();
1198      }
1199    } else {
1200      ;
1201    }
1202    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1203    case STAR:
1204    case QUOTED:
1205    case TERM:
1206    case PREFIXTERM:
1207    case WILDTERM:
1208    case RANGEIN_START:
1209    case RANGEEX_START:
1210    case NUMBER:
1211      q = Term(field);
1212      break;
1213    case LPAREN:
1214      jj_consume_token(LPAREN);
1215      q = Query(field);
1216      jj_consume_token(RPAREN);
1217      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1218      case CARAT:
1219        jj_consume_token(CARAT);
1220        boost = jj_consume_token(NUMBER);
1221        break;
1222      default:
1223        jj_la1[6] = jj_gen;
1224        ;
1225      }
1226      break;
1227    default:
1228      jj_la1[7] = jj_gen;
1229      jj_consume_token(-1);
1230      throw new ParseException();
1231    }
1232      if (boost != null) {
1233        float f = (float)1.0;
1234  try {
1235    f = Float.valueOf(boost.image).floatValue();
1236          q.setBoost(f);
1237  } catch (Exception ignored) { }
1238      }
1239      {if (true) return q;}
1240    throw new Error("Missing return statement in function");
1241  }
1242
1243  final public Query Term(String field) throws ParseException {
1244  Token term, boost=null, fuzzySlop=null, goop1, goop2;
1245  boolean prefix = false;
1246  boolean wildcard = false;
1247  boolean fuzzy = false;
1248  boolean rangein = false;
1249  Query q;
1250    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1251    case STAR:
1252    case TERM:
1253    case PREFIXTERM:
1254    case WILDTERM:
1255    case NUMBER:
1256      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1257      case TERM:
1258        term = jj_consume_token(TERM);
1259        break;
1260      case STAR:
1261        term = jj_consume_token(STAR);
1262                       wildcard=true;
1263        break;
1264      case PREFIXTERM:
1265        term = jj_consume_token(PREFIXTERM);
1266                             prefix=true;
1267        break;
1268      case WILDTERM:
1269        term = jj_consume_token(WILDTERM);
1270                           wildcard=true;
1271        break;
1272      case NUMBER:
1273        term = jj_consume_token(NUMBER);
1274        break;
1275      default:
1276        jj_la1[8] = jj_gen;
1277        jj_consume_token(-1);
1278        throw new ParseException();
1279      }
1280      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1281      case FUZZY_SLOP:
1282        fuzzySlop = jj_consume_token(FUZZY_SLOP);
1283                                fuzzy=true;
1284        break;
1285      default:
1286        jj_la1[9] = jj_gen;
1287        ;
1288      }
1289      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1290      case CARAT:
1291        jj_consume_token(CARAT);
1292        boost = jj_consume_token(NUMBER);
1293        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1294        case FUZZY_SLOP:
1295          fuzzySlop = jj_consume_token(FUZZY_SLOP);
1296                                                         fuzzy=true;
1297          break;
1298        default:
1299          jj_la1[10] = jj_gen;
1300          ;
1301        }
1302        break;
1303      default:
1304        jj_la1[11] = jj_gen;
1305        ;
1306      }
1307       String termImage=discardEscapeChar(term.image);
1308       if (wildcard) {
1309       q = getWildcardQuery(field, termImage);
1310       } else if (prefix) {
1311         q = getPrefixQuery(field,
1312           discardEscapeChar(term.image.substring
1313          (0, term.image.length()-1)));
1314       } else if (fuzzy) {
1315          float fms = fuzzyMinSim;
1316          try {
1317            fms = Float.valueOf(fuzzySlop.image.substring(1)).floatValue();
1318          } catch (Exception ignored) { }
1319         if(fms < 0.0f || fms > 1.0f){
1320           {if (true) throw new ParseException("Minimum similarity for a FuzzyQuery has to be between 0.0f and 1.0f !");}
1321         }
1322         q = getFuzzyQuery(field, termImage,fms);
1323       } else {
1324         q = getFieldQuery(field, termImage);
1325       }
1326      break;
1327    case RANGEIN_START:
1328      jj_consume_token(RANGEIN_START);
1329      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1330      case RANGEIN_GOOP:
1331        goop1 = jj_consume_token(RANGEIN_GOOP);
1332        break;
1333      case RANGEIN_QUOTED:
1334        goop1 = jj_consume_token(RANGEIN_QUOTED);
1335        break;
1336      default:
1337        jj_la1[12] = jj_gen;
1338        jj_consume_token(-1);
1339        throw new ParseException();
1340      }
1341      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1342      case RANGEIN_TO:
1343        jj_consume_token(RANGEIN_TO);
1344        break;
1345      default:
1346        jj_la1[13] = jj_gen;
1347        ;
1348      }
1349      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1350      case RANGEIN_GOOP:
1351        goop2 = jj_consume_token(RANGEIN_GOOP);
1352        break;
1353      case RANGEIN_QUOTED:
1354        goop2 = jj_consume_token(RANGEIN_QUOTED);
1355        break;
1356      default:
1357        jj_la1[14] = jj_gen;
1358        jj_consume_token(-1);
1359        throw new ParseException();
1360      }
1361      jj_consume_token(RANGEIN_END);
1362      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1363      case CARAT:
1364        jj_consume_token(CARAT);
1365        boost = jj_consume_token(NUMBER);
1366        break;
1367      default:
1368        jj_la1[15] = jj_gen;
1369        ;
1370      }
1371          if (goop1.kind == RANGEIN_QUOTED) {
1372            goop1.image = goop1.image.substring(1, goop1.image.length()-1);
1373          }
1374          if (goop2.kind == RANGEIN_QUOTED) {
1375            goop2.image = goop2.image.substring(1, goop2.image.length()-1);
1376          }
1377          q = getRangeQuery(field, discardEscapeChar(goop1.image), discardEscapeChar(goop2.image), true);
1378      break;
1379    case RANGEEX_START:
1380      jj_consume_token(RANGEEX_START);
1381      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1382      case RANGEEX_GOOP:
1383        goop1 = jj_consume_token(RANGEEX_GOOP);
1384        break;
1385      case RANGEEX_QUOTED:
1386        goop1 = jj_consume_token(RANGEEX_QUOTED);
1387        break;
1388      default:
1389        jj_la1[16] = jj_gen;
1390        jj_consume_token(-1);
1391        throw new ParseException();
1392      }
1393      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1394      case RANGEEX_TO:
1395        jj_consume_token(RANGEEX_TO);
1396        break;
1397      default:
1398        jj_la1[17] = jj_gen;
1399        ;
1400      }
1401      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1402      case RANGEEX_GOOP:
1403        goop2 = jj_consume_token(RANGEEX_GOOP);
1404        break;
1405      case RANGEEX_QUOTED:
1406        goop2 = jj_consume_token(RANGEEX_QUOTED);
1407        break;
1408      default:
1409        jj_la1[18] = jj_gen;
1410        jj_consume_token(-1);
1411        throw new ParseException();
1412      }
1413      jj_consume_token(RANGEEX_END);
1414      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1415      case CARAT:
1416        jj_consume_token(CARAT);
1417        boost = jj_consume_token(NUMBER);
1418        break;
1419      default:
1420        jj_la1[19] = jj_gen;
1421        ;
1422      }
1423          if (goop1.kind == RANGEEX_QUOTED) {
1424            goop1.image = goop1.image.substring(1, goop1.image.length()-1);
1425          }
1426          if (goop2.kind == RANGEEX_QUOTED) {
1427            goop2.image = goop2.image.substring(1, goop2.image.length()-1);
1428          }
1429
1430          q = getRangeQuery(field, discardEscapeChar(goop1.image), discardEscapeChar(goop2.image), false);
1431      break;
1432    case QUOTED:
1433      term = jj_consume_token(QUOTED);
1434      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1435      case FUZZY_SLOP:
1436        fuzzySlop = jj_consume_token(FUZZY_SLOP);
1437        break;
1438      default:
1439        jj_la1[20] = jj_gen;
1440        ;
1441      }
1442      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
1443      case CARAT:
1444        jj_consume_token(CARAT);
1445        boost = jj_consume_token(NUMBER);
1446        break;
1447      default:
1448        jj_la1[21] = jj_gen;
1449        ;
1450      }
1451         int s = phraseSlop;
1452
1453         if (fuzzySlop != null) {
1454           try {
1455             s = Float.valueOf(fuzzySlop.image.substring(1)).intValue();
1456           }
1457           catch (Exception ignored) { }
1458         }
1459         q = getFieldQuery(field, discardEscapeChar(term.image.substring(1, term.image.length()-1)), s);
1460      break;
1461    default:
1462      jj_la1[22] = jj_gen;
1463      jj_consume_token(-1);
1464      throw new ParseException();
1465    }
1466    if (boost != null) {
1467      float f = (float) 1.0;
1468      try {
1469        f = Float.valueOf(boost.image).floatValue();
1470      }
1471      catch (Exception ignored) {
1472    /* Should this be handled somehow? (defaults to "no boost", if
1473     * boost number is invalid)
1474     */
1475      }
1476
1477      // avoid boosting null queries, such as those caused by stop words
1478      if (q != null) {
1479        q.setBoost(f);
1480      }
1481    }
1482    {if (true) return q;}
1483    throw new Error("Missing return statement in function");
1484  }
1485
1486  private boolean jj_2_1(int xla) {
1487    jj_la = xla; jj_lastpos = jj_scanpos = token;
1488    try { return !jj_3_1(); }
1489    catch(LookaheadSuccess ls) { return true; }
1490    finally { jj_save(0, xla); }
1491  }
1492
1493  private boolean jj_3R_3() {
1494    if (jj_scan_token(STAR)) return true;
1495    if (jj_scan_token(COLON)) return true;
1496    return false;
1497  }
1498
1499  private boolean jj_3R_2() {
1500    if (jj_scan_token(TERM)) return true;
1501    if (jj_scan_token(COLON)) return true;
1502    return false;
1503  }
1504
1505  private boolean jj_3_1() {
1506    Token xsp;
1507    xsp = jj_scanpos;
1508    if (jj_3R_2()) {
1509    jj_scanpos = xsp;
1510    if (jj_3R_3()) return true;
1511    }
1512    return false;
1513  }
1514
1515  /** Generated Token Manager. */
1516  public QueryParserTokenManager token_source;
1517  /** Current token. */
1518  public Token token;
1519  /** Next token. */
1520  public Token jj_nt;
1521  private int jj_ntk;
1522  private Token jj_scanpos, jj_lastpos;
1523  private int jj_la;
1524  private int jj_gen;
1525  final private int[] jj_la1 = new int[23];
1526  static private int[] jj_la1_0;
1527  static private int[] jj_la1_1;
1528  static {
1529      jj_la1_init_0();
1530      jj_la1_init_1();
1531   }
1532   private static void jj_la1_init_0() {
1533      jj_la1_0 = new int[] {0x300,0x300,0x1c00,0x1c00,0x3ed3f00,0x90000,0x20000,0x3ed2000,0x2690000,0x100000,0x100000,0x20000,0x30000000,0x4000000,0x30000000,0x20000,0x0,0x40000000,0x0,0x20000,0x100000,0x20000,0x3ed0000,};
1534   }
1535   private static void jj_la1_init_1() {
1536      jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x3,0x0,0x0,0x0,0x0,};
1537   }
1538  final private JJCalls[] jj_2_rtns = new JJCalls[1];
1539  private boolean jj_rescan = false;
1540  private int jj_gc = 0;
1541
1542  /** Constructor with user supplied CharStream. */
1543  public QueryParser(CharStream stream) {
1544    token_source = new QueryParserTokenManager(stream);
1545    token = new Token();
1546    jj_ntk = -1;
1547    jj_gen = 0;
1548    for (int i = 0; i < 23; i++) jj_la1[i] = -1;
1549    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
1550  }
1551
1552  /** Reinitialise. */
1553  public void ReInit(CharStream stream) {
1554    token_source.ReInit(stream);
1555    token = new Token();
1556    jj_ntk = -1;
1557    jj_gen = 0;
1558    for (int i = 0; i < 23; i++) jj_la1[i] = -1;
1559    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
1560  }
1561
1562  /** Constructor with generated Token Manager. */
1563  public QueryParser(QueryParserTokenManager tm) {
1564    token_source = tm;
1565    token = new Token();
1566    jj_ntk = -1;
1567    jj_gen = 0;
1568    for (int i = 0; i < 23; i++) jj_la1[i] = -1;
1569    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
1570  }
1571
1572  /** Reinitialise. */
1573  public void ReInit(QueryParserTokenManager tm) {
1574    token_source = tm;
1575    token = new Token();
1576    jj_ntk = -1;
1577    jj_gen = 0;
1578    for (int i = 0; i < 23; i++) jj_la1[i] = -1;
1579    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
1580  }
1581
1582  private Token jj_consume_token(int kind) throws ParseException {
1583    Token oldToken;
1584    if ((oldToken = token).next != null) token = token.next;
1585    else token = token.next = token_source.getNextToken();
1586    jj_ntk = -1;
1587    if (token.kind == kind) {
1588      jj_gen++;
1589      if (++jj_gc > 100) {
1590        jj_gc = 0;
1591        for (int i = 0; i < jj_2_rtns.length; i++) {
1592          JJCalls c = jj_2_rtns[i];
1593          while (c != null) {
1594            if (c.gen < jj_gen) c.first = null;
1595            c = c.next;
1596          }
1597        }
1598      }
1599      return token;
1600    }
1601    token = oldToken;
1602    jj_kind = kind;
1603    throw generateParseException();
1604  }
1605
1606  static private final class LookaheadSuccess extends java.lang.Error { }
1607  final private LookaheadSuccess jj_ls = new LookaheadSuccess();
1608  private boolean jj_scan_token(int kind) {
1609    if (jj_scanpos == jj_lastpos) {
1610      jj_la--;
1611      if (jj_scanpos.next == null) {
1612        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
1613      } else {
1614        jj_lastpos = jj_scanpos = jj_scanpos.next;
1615      }
1616    } else {
1617      jj_scanpos = jj_scanpos.next;
1618    }
1619    if (jj_rescan) {
1620      int i = 0; Token tok = token;
1621      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
1622      if (tok != null) jj_add_error_token(kind, i);
1623    }
1624    if (jj_scanpos.kind != kind) return true;
1625    if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
1626    return false;
1627  }
1628
1629
1630/** Get the next Token. */
1631  final public Token getNextToken() {
1632    if (token.next != null) token = token.next;
1633    else token = token.next = token_source.getNextToken();
1634    jj_ntk = -1;
1635    jj_gen++;
1636    return token;
1637  }
1638
1639/** Get the specific Token. */
1640  final public Token getToken(int index) {
1641    Token t = token;
1642    for (int i = 0; i < index; i++) {
1643      if (t.next != null) t = t.next;
1644      else t = t.next = token_source.getNextToken();
1645    }
1646    return t;
1647  }
1648
1649  private int jj_ntk() {
1650    if ((jj_nt=token.next) == null)
1651      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
1652    else
1653      return (jj_ntk = jj_nt.kind);
1654  }
1655
1656  private java.util.List jj_expentries = new java.util.ArrayList();
1657  private int[] jj_expentry;
1658  private int jj_kind = -1;
1659  private int[] jj_lasttokens = new int[100];
1660  private int jj_endpos;
1661
1662  private void jj_add_error_token(int kind, int pos) {
1663    if (pos >= 100) return;
1664    if (pos == jj_endpos + 1) {
1665      jj_lasttokens[jj_endpos++] = kind;
1666    } else if (jj_endpos != 0) {
1667      jj_expentry = new int[jj_endpos];
1668      for (int i = 0; i < jj_endpos; i++) {
1669        jj_expentry[i] = jj_lasttokens[i];
1670      }
1671      jj_entries_loop: for (java.util.Iterator it = jj_expentries.iterator(); it.hasNext();) {
1672        int[] oldentry = (int[])(it.next());
1673        if (oldentry.length == jj_expentry.length) {
1674          for (int i = 0; i < jj_expentry.length; i++) {
1675            if (oldentry[i] != jj_expentry[i]) {
1676              continue jj_entries_loop;
1677            }
1678          }
1679          jj_expentries.add(jj_expentry);
1680          break jj_entries_loop;
1681        }
1682      }
1683      if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
1684    }
1685  }
1686
1687  /** Generate ParseException. */
1688  public ParseException generateParseException() {
1689    jj_expentries.clear();
1690    boolean[] la1tokens = new boolean[34];
1691    if (jj_kind >= 0) {
1692      la1tokens[jj_kind] = true;
1693      jj_kind = -1;
1694    }
1695    for (int i = 0; i < 23; i++) {
1696      if (jj_la1[i] == jj_gen) {
1697        for (int j = 0; j < 32; j++) {
1698          if ((jj_la1_0[i] & (1<<j)) != 0) {
1699            la1tokens[j] = true;
1700          }
1701          if ((jj_la1_1[i] & (1<<j)) != 0) {
1702            la1tokens[32+j] = true;
1703          }
1704        }
1705      }
1706    }
1707    for (int i = 0; i < 34; i++) {
1708      if (la1tokens[i]) {
1709        jj_expentry = new int[1];
1710        jj_expentry[0] = i;
1711        jj_expentries.add(jj_expentry);
1712      }
1713    }
1714    jj_endpos = 0;
1715    jj_rescan_token();
1716    jj_add_error_token(0, 0);
1717    int[][] exptokseq = new int[jj_expentries.size()][];
1718    for (int i = 0; i < jj_expentries.size(); i++) {
1719      exptokseq[i] = (int[])jj_expentries.get(i);
1720    }
1721    return new ParseException(token, exptokseq, tokenImage);
1722  }
1723
1724  /** Enable tracing. */
1725  final public void enable_tracing() {
1726  }
1727
1728  /** Disable tracing. */
1729  final public void disable_tracing() {
1730  }
1731
1732  private void jj_rescan_token() {
1733    jj_rescan = true;
1734    for (int i = 0; i < 1; i++) {
1735    try {
1736      JJCalls p = jj_2_rtns[i];
1737      do {
1738        if (p.gen > jj_gen) {
1739          jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
1740          switch (i) {
1741            case 0: jj_3_1(); break;
1742          }
1743        }
1744        p = p.next;
1745      } while (p != null);
1746      } catch(LookaheadSuccess ls) { }
1747    }
1748    jj_rescan = false;
1749  }
1750
1751  private void jj_save(int index, int xla) {
1752    JJCalls p = jj_2_rtns[index];
1753    while (p.gen > jj_gen) {
1754      if (p.next == null) { p = p.next = new JJCalls(); break; }
1755      p = p.next;
1756    }
1757    p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
1758  }
1759
1760  static final class JJCalls {
1761    int gen;
1762    Token first;
1763    int arg;
1764    JJCalls next;
1765  }
1766
1767}
1768