Thu, 12 Oct 2017 19:44:07 +0800
merge
1 /*
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.codemodel.internal;
28 import java.util.HashSet;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
32 /**
33 * Utility methods that convert arbitrary strings into Java identifiers.
34 */
35 public class JJavaName {
38 /**
39 * Checks if a given string is usable as a Java identifier.
40 */
41 public static boolean isJavaIdentifier(String s) {
42 if(s.length()==0) return false;
43 if( reservedKeywords.contains(s) ) return false;
45 if(!Character.isJavaIdentifierStart(s.charAt(0))) return false;
47 for (int i = 1; i < s.length(); i++)
48 if (!Character.isJavaIdentifierPart(s.charAt(i)))
49 return false;
51 return true;
52 }
54 /**
55 * Checks if the given string is a valid fully qualified name.
56 */
57 public static boolean isFullyQualifiedClassName(String s) {
58 return isJavaPackageName(s);
59 }
61 /**
62 * Checks if the given string is a valid Java package name.
63 */
64 public static boolean isJavaPackageName(String s) {
65 while(s.length()!=0) {
66 int idx = s.indexOf('.');
67 if(idx==-1) idx=s.length();
68 if( !isJavaIdentifier(s.substring(0,idx)) )
69 return false;
71 s = s.substring(idx);
72 if(s.length()!=0) s = s.substring(1); // remove '.'
73 }
74 return true;
75 }
77 /**
78 * <b>Experimental API:</b> converts an English word into a plural form.
79 *
80 * @param word
81 * a word, such as "child", "apple". Must not be null.
82 * It accepts word concatanation forms
83 * that are common in programming languages, such as "my_child", "MyChild",
84 * "myChild", "MY-CHILD", "CODE003-child", etc, and mostly tries to do the right thing.
85 * ("my_children","MyChildren","myChildren", and "MY-CHILDREN", "CODE003-children" respectively)
86 * <p>
87 * Although this method only works for English words, it handles non-English
88 * words gracefully (by just returning it as-is.) For example, 日本語
89 * will be returned as-is without modified, not "日本語s"
90 * <p>
91 * This method doesn't handle suffixes very well. For example, passing
92 * "person56" will return "person56s", not "people56".
93 *
94 * @return
95 * always non-null.
96 */
97 public static String getPluralForm(String word) {
98 // remember the casing of the word
99 boolean allUpper = true;
101 // check if the word looks like an English word.
102 // if we see non-ASCII characters, abort
103 for(int i=0; i<word.length(); i++ ) {
104 char ch = word.charAt(i);
105 if(ch >=0x80)
106 return word;
108 // note that this isn't the same as allUpper &= Character.isUpperCase(ch);
109 allUpper &= !Character.isLowerCase(ch);
110 }
112 for (Entry e : TABLE) {
113 String r = e.apply(word);
114 if(r!=null) {
115 if(allUpper) r=r.toUpperCase();
116 return r;
117 }
118 }
120 // failed
121 return word;
122 }
125 /** All reserved keywords of Java. */
126 private static HashSet<String> reservedKeywords = new HashSet<String>();
128 static {
129 // see http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html
130 String[] words = new String[]{
131 "abstract",
132 "boolean",
133 "break",
134 "byte",
135 "case",
136 "catch",
137 "char",
138 "class",
139 "const",
140 "continue",
141 "default",
142 "do",
143 "double",
144 "else",
145 "extends",
146 "final",
147 "finally",
148 "float",
149 "for",
150 "goto",
151 "if",
152 "implements",
153 "import",
154 "instanceof",
155 "int",
156 "interface",
157 "long",
158 "native",
159 "new",
160 "package",
161 "private",
162 "protected",
163 "public",
164 "return",
165 "short",
166 "static",
167 "strictfp",
168 "super",
169 "switch",
170 "synchronized",
171 "this",
172 "throw",
173 "throws",
174 "transient",
175 "try",
176 "void",
177 "volatile",
178 "while",
180 // technically these are not reserved words but they cannot be used as identifiers.
181 "true",
182 "false",
183 "null",
185 // and I believe assert is also a new keyword
186 "assert",
188 // and 5.0 keywords
189 "enum"
190 };
191 for (String w : words)
192 reservedKeywords.add(w);
193 }
196 private static class Entry {
197 private final Pattern pattern;
198 private final String replacement;
200 public Entry(String pattern, String replacement) {
201 this.pattern = Pattern.compile(pattern,Pattern.CASE_INSENSITIVE);
202 this.replacement = replacement;
203 }
205 String apply(String word) {
206 Matcher m = pattern.matcher(word);
207 if(m.matches()) {
208 StringBuffer buf = new StringBuffer();
209 m.appendReplacement(buf,replacement);
210 return buf.toString();
211 } else {
212 return null;
213 }
214 }
215 }
217 private static final Entry[] TABLE;
219 static {
220 String[] source = {
221 "(.*)child","$1children",
222 "(.+)fe","$1ves",
223 "(.*)mouse","$1mise",
224 "(.+)f","$1ves",
225 "(.+)ch","$1ches",
226 "(.+)sh","$1shes",
227 "(.*)tooth","$1teeth",
228 "(.+)um","$1a",
229 "(.+)an","$1en",
230 "(.+)ato","$1atoes",
231 "(.*)basis","$1bases",
232 "(.*)axis","$1axes",
233 "(.+)is","$1ises",
234 "(.+)ss","$1sses",
235 "(.+)us","$1uses",
236 "(.+)s","$1s",
237 "(.*)foot","$1feet",
238 "(.+)ix","$1ixes",
239 "(.+)ex","$1ices",
240 "(.+)nx","$1nxes",
241 "(.+)x","$1xes",
242 "(.+)y","$1ies",
243 "(.+)","$1s",
244 };
246 TABLE = new Entry[source.length/2];
248 for( int i=0; i<source.length; i+=2 ) {
249 TABLE[i/2] = new Entry(source[i],source[i+1]);
250 }
251 }
252 }