| /* gnu/regexp/RETokenNamedProperty.java | |
| Copyright (C) 2006 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package gnu.java.util.regex; | |
| import gnu.java.lang.CPStringBuilder; | |
| import java.lang.reflect.InvocationTargetException; | |
| import java.lang.reflect.Method; | |
| final class RETokenNamedProperty extends REToken | |
| { | |
| String name; | |
| boolean insens; | |
| boolean negate; | |
| Handler handler; | |
| // Grouped properties | |
| static final byte[] LETTER = new byte[]{ Character.LOWERCASE_LETTER, | |
| Character.UPPERCASE_LETTER, | |
| Character.TITLECASE_LETTER, | |
| Character.MODIFIER_LETTER, | |
| Character.OTHER_LETTER | |
| }; | |
| static final byte[] MARK = new byte[]{ Character.NON_SPACING_MARK, | |
| Character.COMBINING_SPACING_MARK, | |
| Character.ENCLOSING_MARK | |
| }; | |
| static final byte[] SEPARATOR = new byte[]{ Character.SPACE_SEPARATOR, | |
| Character.LINE_SEPARATOR, | |
| Character.PARAGRAPH_SEPARATOR | |
| }; | |
| static final byte[] SYMBOL = new byte[]{ Character.MATH_SYMBOL, | |
| Character.CURRENCY_SYMBOL, | |
| Character.MODIFIER_SYMBOL, | |
| Character.OTHER_SYMBOL | |
| }; | |
| static final byte[] NUMBER = new byte[]{ Character.DECIMAL_DIGIT_NUMBER, | |
| Character.LETTER_NUMBER, | |
| Character.OTHER_NUMBER | |
| }; | |
| static final byte[] PUNCTUATION = new byte[]{ Character.DASH_PUNCTUATION, | |
| Character.START_PUNCTUATION, | |
| Character.END_PUNCTUATION, | |
| Character.CONNECTOR_PUNCTUATION, | |
| Character.OTHER_PUNCTUATION, | |
| Character.INITIAL_QUOTE_PUNCTUATION, | |
| Character.FINAL_QUOTE_PUNCTUATION | |
| }; | |
| static final byte[] OTHER = new byte[]{ Character.CONTROL, | |
| Character.FORMAT, | |
| Character.PRIVATE_USE, | |
| Character.SURROGATE, | |
| Character.UNASSIGNED | |
| }; | |
| RETokenNamedProperty (int subIndex, String name, boolean insens, | |
| boolean negate) throws REException | |
| { | |
| super (subIndex); | |
| this.name = name; | |
| this.insens = insens; | |
| this.negate = negate; | |
| handler = getHandler (name); | |
| } | |
| int getMinimumLength () | |
| { | |
| return 1; | |
| } | |
| int getMaximumLength () | |
| { | |
| return 1; | |
| } | |
| REMatch matchThis (CharIndexed input, REMatch mymatch) | |
| { | |
| char ch = input.charAt (mymatch.index); | |
| boolean retval = matchOneChar (ch); | |
| if (retval) | |
| { | |
| ++mymatch.index; | |
| return mymatch; | |
| } | |
| return null; | |
| } | |
| private boolean matchOneChar (char ch) | |
| { | |
| if (ch == CharIndexed.OUT_OF_BOUNDS) | |
| return false; | |
| boolean retval = handler.includes (ch); | |
| if (insens) | |
| { | |
| retval = retval || | |
| handler.includes (toUpperCase (ch, unicodeAware)) || | |
| handler.includes (toLowerCase (ch, unicodeAware)); | |
| } | |
| if (negate) | |
| retval = !retval; | |
| return retval; | |
| } | |
| boolean returnsFixedLengthMatches () | |
| { | |
| return true; | |
| } | |
| int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) | |
| { | |
| int index = mymatch.index; | |
| int numRepeats = 0; | |
| while (true) | |
| { | |
| if (numRepeats >= max) | |
| break; | |
| char ch = input.charAt (index++); | |
| if (!matchOneChar (ch)) | |
| break; | |
| numRepeats++; | |
| } | |
| return numRepeats; | |
| } | |
| void dump (CPStringBuilder os) | |
| { | |
| os.append ("\\").append (negate ? "P" : "p").append ("{" + name + "}"); | |
| } | |
| private abstract static class Handler | |
| { | |
| public abstract boolean includes (char c); | |
| } | |
| private Handler getHandler (String name) throws REException | |
| { | |
| if (name.equals ("Lower") || name.equals ("Upper") || | |
| // name.equals("ASCII") || | |
| name.equals ("Alpha") || | |
| name.equals ("Digit") || | |
| name.equals ("Alnum") || | |
| name.equals ("Punct") || | |
| name.equals ("Graph") || | |
| name.equals ("Print") || | |
| name.equals ("Blank") || | |
| name.equals ("Cntrl") || | |
| name.equals ("XDigit") || name.equals ("Space")) | |
| { | |
| return new POSIXHandler (name); | |
| } | |
| if (name.startsWith ("In")) | |
| { | |
| try | |
| { | |
| name = name.substring (2); | |
| Character.UnicodeBlock block = | |
| Character.UnicodeBlock.forName (name); | |
| return new UnicodeBlockHandler (block); | |
| } | |
| catch (IllegalArgumentException e) | |
| { | |
| throw new REException ("Invalid Unicode block name: " + name, | |
| REException.REG_ESCAPE, 0); | |
| } | |
| } | |
| if (name.startsWith ("Is")) | |
| { | |
| name = name.substring (2); | |
| } | |
| // "grouped properties" | |
| if (name.equals ("L")) | |
| return new UnicodeCategoriesHandler (LETTER); | |
| if (name.equals ("M")) | |
| return new UnicodeCategoriesHandler (MARK); | |
| if (name.equals ("Z")) | |
| return new UnicodeCategoriesHandler (SEPARATOR); | |
| if (name.equals ("S")) | |
| return new UnicodeCategoriesHandler (SYMBOL); | |
| if (name.equals ("N")) | |
| return new UnicodeCategoriesHandler (NUMBER); | |
| if (name.equals ("P")) | |
| return new UnicodeCategoriesHandler (PUNCTUATION); | |
| if (name.equals ("C")) | |
| return new UnicodeCategoriesHandler (OTHER); | |
| if (name.equals ("Mc")) | |
| return new UnicodeCategoryHandler (Character.COMBINING_SPACING_MARK); | |
| if (name.equals ("Pc")) | |
| return new UnicodeCategoryHandler (Character.CONNECTOR_PUNCTUATION); | |
| if (name.equals ("Cc")) | |
| return new UnicodeCategoryHandler (Character.CONTROL); | |
| if (name.equals ("Sc")) | |
| return new UnicodeCategoryHandler (Character.CURRENCY_SYMBOL); | |
| if (name.equals ("Pd")) | |
| return new UnicodeCategoryHandler (Character.DASH_PUNCTUATION); | |
| if (name.equals ("Nd")) | |
| return new UnicodeCategoryHandler (Character.DECIMAL_DIGIT_NUMBER); | |
| if (name.equals ("Me")) | |
| return new UnicodeCategoryHandler (Character.ENCLOSING_MARK); | |
| if (name.equals ("Pe")) | |
| return new UnicodeCategoryHandler (Character.END_PUNCTUATION); | |
| if (name.equals ("Pf")) | |
| return new UnicodeCategoryHandler (Character.FINAL_QUOTE_PUNCTUATION); | |
| if (name.equals ("Cf")) | |
| return new UnicodeCategoryHandler (Character.FORMAT); | |
| if (name.equals ("Pi")) | |
| return new UnicodeCategoryHandler (Character.INITIAL_QUOTE_PUNCTUATION); | |
| if (name.equals ("Nl")) | |
| return new UnicodeCategoryHandler (Character.LETTER_NUMBER); | |
| if (name.equals ("Zl")) | |
| return new UnicodeCategoryHandler (Character.LINE_SEPARATOR); | |
| if (name.equals ("Ll")) | |
| return new UnicodeCategoryHandler (Character.LOWERCASE_LETTER); | |
| if (name.equals ("Sm")) | |
| return new UnicodeCategoryHandler (Character.MATH_SYMBOL); | |
| if (name.equals ("Lm")) | |
| return new UnicodeCategoryHandler (Character.MODIFIER_LETTER); | |
| if (name.equals ("Sk")) | |
| return new UnicodeCategoryHandler (Character.MODIFIER_SYMBOL); | |
| if (name.equals ("Mn")) | |
| return new UnicodeCategoryHandler (Character.NON_SPACING_MARK); | |
| if (name.equals ("Lo")) | |
| return new UnicodeCategoryHandler (Character.OTHER_LETTER); | |
| if (name.equals ("No")) | |
| return new UnicodeCategoryHandler (Character.OTHER_NUMBER); | |
| if (name.equals ("Po")) | |
| return new UnicodeCategoryHandler (Character.OTHER_PUNCTUATION); | |
| if (name.equals ("So")) | |
| return new UnicodeCategoryHandler (Character.OTHER_SYMBOL); | |
| if (name.equals ("Zp")) | |
| return new UnicodeCategoryHandler (Character.PARAGRAPH_SEPARATOR); | |
| if (name.equals ("Co")) | |
| return new UnicodeCategoryHandler (Character.PRIVATE_USE); | |
| if (name.equals ("Zs")) | |
| return new UnicodeCategoryHandler (Character.SPACE_SEPARATOR); | |
| if (name.equals ("Ps")) | |
| return new UnicodeCategoryHandler (Character.START_PUNCTUATION); | |
| if (name.equals ("Cs")) | |
| return new UnicodeCategoryHandler (Character.SURROGATE); | |
| if (name.equals ("Lt")) | |
| return new UnicodeCategoryHandler (Character.TITLECASE_LETTER); | |
| if (name.equals ("Cn")) | |
| return new UnicodeCategoryHandler (Character.UNASSIGNED); | |
| if (name.equals ("Lu")) | |
| return new UnicodeCategoryHandler (Character.UPPERCASE_LETTER); | |
| if (name.equals ("all")) | |
| return new Handler () | |
| { | |
| public boolean includes (char c) | |
| { | |
| return true; | |
| } | |
| }; | |
| if (name.startsWith ("java")) | |
| { | |
| try | |
| { | |
| Method m = Character.class.getMethod ("is" + name.substring (4), | |
| Character.TYPE); | |
| return new JavaCategoryHandler (m); | |
| } | |
| catch (NoSuchMethodException e) | |
| { | |
| throw new REException ("Unsupported Java handler: " + name, e, | |
| REException.REG_ESCAPE, 0); | |
| } | |
| } | |
| throw new REException ("unsupported name " + name, REException.REG_ESCAPE, | |
| 0); | |
| } | |
| private static class POSIXHandler extends Handler | |
| { | |
| private RETokenPOSIX retoken; | |
| public POSIXHandler (String name) | |
| { | |
| int posixId = RETokenPOSIX.intValue (name.toLowerCase ()); | |
| if (posixId != -1) | |
| retoken = new RETokenPOSIX (0, posixId, false, false); | |
| else | |
| throw new RuntimeException ("Unknown posix ID: " + name); | |
| } | |
| public boolean includes (char c) | |
| { | |
| return retoken.matchOneChar (c); | |
| } | |
| } | |
| private static class UnicodeCategoryHandler extends Handler | |
| { | |
| public UnicodeCategoryHandler (byte category) | |
| { | |
| this.category = (int) category; | |
| } | |
| private int category; | |
| public boolean includes (char c) | |
| { | |
| return Character.getType (c) == category; | |
| } | |
| } | |
| private static class UnicodeCategoriesHandler extends Handler | |
| { | |
| public UnicodeCategoriesHandler (byte[]categories) | |
| { | |
| this.categories = categories; | |
| } | |
| private byte[] categories; | |
| public boolean includes (char c) | |
| { | |
| int category = Character.getType (c); | |
| for (int i = 0; i < categories.length; i++) | |
| if (category == categories[i]) | |
| return true; | |
| return false; | |
| } | |
| } | |
| private static class UnicodeBlockHandler extends Handler | |
| { | |
| public UnicodeBlockHandler (Character.UnicodeBlock block) | |
| { | |
| this.block = block; | |
| } | |
| private Character.UnicodeBlock block; | |
| public boolean includes (char c) | |
| { | |
| Character.UnicodeBlock cblock = Character.UnicodeBlock.of (c); | |
| return (cblock != null && cblock.equals (block)); | |
| } | |
| } | |
| /** | |
| * Handle the Java-specific extensions \p{javaX} where X | |
| * is a method from Character of the form isX | |
| * | |
| * @author Andrew John Hughes (gnu_andrew@member.fsf.org) | |
| */ | |
| private static class JavaCategoryHandler extends Handler | |
| { | |
| private Method method; | |
| public JavaCategoryHandler (Method m) | |
| { | |
| this.method = m; | |
| } | |
| public boolean includes (char c) | |
| { | |
| try | |
| { | |
| return (Boolean) method.invoke (null, c); | |
| } | |
| catch (IllegalAccessException e) | |
| { | |
| throw new InternalError ("Unable to access method " + method); | |
| } | |
| catch (InvocationTargetException e) | |
| { | |
| throw new InternalError ("Error invoking " + method); | |
| } | |
| } | |
| } | |
| } |