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

Save This Page
Home » lucene-3.0.1-src » org.apache » lucene » queryParser » [javadoc | source]