Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

GenericSignatureParser.java 13KB

13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /* *******************************************************************
  2. * Copyright (c) 2005-2008 Contributors.
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://eclipse.org/legal/epl-v10.html
  8. *
  9. * ******************************************************************/
  10. package org.aspectj.util;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. import org.aspectj.util.GenericSignature.ArrayTypeSignature;
  14. import org.aspectj.util.GenericSignature.BaseTypeSignature;
  15. import org.aspectj.util.GenericSignature.ClassTypeSignature;
  16. import org.aspectj.util.GenericSignature.FieldTypeSignature;
  17. import org.aspectj.util.GenericSignature.FormalTypeParameter;
  18. import org.aspectj.util.GenericSignature.MethodTypeSignature;
  19. import org.aspectj.util.GenericSignature.SimpleClassTypeSignature;
  20. import org.aspectj.util.GenericSignature.TypeArgument;
  21. import org.aspectj.util.GenericSignature.TypeSignature;
  22. import org.aspectj.util.GenericSignature.TypeVariableSignature;
  23. /**
  24. * Parses the generic signature attribute as defined in the JVM spec.
  25. *
  26. * @author Adrian Colyer
  27. * @author Andy Clement
  28. */
  29. public class GenericSignatureParser {
  30. private String inputString;
  31. private String[] tokenStream; // for parse in flight
  32. private int tokenIndex = 0;
  33. /**
  34. * AMC. Parse the signature string interpreting it as a ClassSignature according to the grammar defined in Section 4.4.4 of the
  35. * JVM specification.
  36. */
  37. public GenericSignature.ClassSignature parseAsClassSignature(String sig) {
  38. this.inputString = sig;
  39. tokenStream = tokenize(sig);
  40. tokenIndex = 0;
  41. GenericSignature.ClassSignature classSig = new GenericSignature.ClassSignature();
  42. // FormalTypeParameters-opt
  43. if (maybeEat("<")) {
  44. List<FormalTypeParameter> formalTypeParametersList = new ArrayList<FormalTypeParameter>();
  45. do {
  46. formalTypeParametersList.add(parseFormalTypeParameter());
  47. } while (!maybeEat(">"));
  48. classSig.formalTypeParameters = new FormalTypeParameter[formalTypeParametersList.size()];
  49. formalTypeParametersList.toArray(classSig.formalTypeParameters);
  50. }
  51. classSig.superclassSignature = parseClassTypeSignature();
  52. List<ClassTypeSignature> superIntSigs = new ArrayList<ClassTypeSignature>();
  53. while (tokenIndex < tokenStream.length) {
  54. superIntSigs.add(parseClassTypeSignature());
  55. }
  56. classSig.superInterfaceSignatures = new ClassTypeSignature[superIntSigs.size()];
  57. superIntSigs.toArray(classSig.superInterfaceSignatures);
  58. return classSig;
  59. }
  60. /**
  61. * AMC. Parse the signature string interpreting it as a MethodTypeSignature according to the grammar defined in Section 4.4.4 of
  62. * the JVM specification.
  63. */
  64. public MethodTypeSignature parseAsMethodSignature(String sig) {
  65. this.inputString = sig;
  66. tokenStream = tokenize(sig);
  67. tokenIndex = 0;
  68. FormalTypeParameter[] formals = new FormalTypeParameter[0];
  69. TypeSignature returnType = null;
  70. // FormalTypeParameters-opt
  71. if (maybeEat("<")) {
  72. List<FormalTypeParameter> formalTypeParametersList = new ArrayList<FormalTypeParameter>();
  73. do {
  74. formalTypeParametersList.add(parseFormalTypeParameter());
  75. } while (!maybeEat(">"));
  76. formals = new FormalTypeParameter[formalTypeParametersList.size()];
  77. formalTypeParametersList.toArray(formals);
  78. }
  79. // Parameters
  80. eat("(");
  81. List<TypeSignature> paramList = new ArrayList<TypeSignature>();
  82. while (!maybeEat(")")) {
  83. FieldTypeSignature fsig = parseFieldTypeSignature(true);
  84. if (fsig != null) {
  85. paramList.add(fsig);
  86. } else {
  87. paramList.add(new GenericSignature.BaseTypeSignature(eatIdentifier()));
  88. }
  89. }
  90. TypeSignature[] params = new TypeSignature[paramList.size()];
  91. paramList.toArray(params);
  92. // return type
  93. returnType = parseFieldTypeSignature(true);
  94. if (returnType == null)
  95. returnType = new GenericSignature.BaseTypeSignature(eatIdentifier());
  96. // throws
  97. List<FieldTypeSignature> throwsList = new ArrayList<FieldTypeSignature>();
  98. while (maybeEat("^")) {
  99. FieldTypeSignature fsig = parseFieldTypeSignature(false);
  100. throwsList.add(fsig);
  101. }
  102. FieldTypeSignature[] throwsSigs = new FieldTypeSignature[throwsList.size()];
  103. throwsList.toArray(throwsSigs);
  104. return new GenericSignature.MethodTypeSignature(formals, params, returnType, throwsSigs);
  105. }
  106. /**
  107. * AMC. Parse the signature string interpreting it as a FieldTypeSignature according to the grammar defined in Section 4.4.4 of
  108. * the JVM specification.
  109. */
  110. public FieldTypeSignature parseAsFieldSignature(String sig) {
  111. this.inputString = sig;
  112. tokenStream = tokenize(sig);
  113. tokenIndex = 0;
  114. return parseFieldTypeSignature(false);
  115. }
  116. private FormalTypeParameter parseFormalTypeParameter() {
  117. FormalTypeParameter ftp = new FormalTypeParameter();
  118. // Identifier
  119. ftp.identifier = eatIdentifier();
  120. // ClassBound
  121. eat(":");
  122. ftp.classBound = parseFieldTypeSignature(true);
  123. if (ftp.classBound == null) {
  124. ftp.classBound = new ClassTypeSignature("Ljava/lang/Object;", "Ljava/lang/Object");
  125. }
  126. // Optional InterfaceBounds
  127. List<FieldTypeSignature> optionalBounds = new ArrayList<FieldTypeSignature>();
  128. while (maybeEat(":")) {
  129. optionalBounds.add(parseFieldTypeSignature(false));
  130. }
  131. ftp.interfaceBounds = new FieldTypeSignature[optionalBounds.size()];
  132. optionalBounds.toArray(ftp.interfaceBounds);
  133. return ftp;
  134. }
  135. private FieldTypeSignature parseFieldTypeSignature(boolean isOptional) {
  136. if (isOptional) {
  137. // anything other than 'L', 'T' or '[' and we're out of here
  138. if (!tokenStream[tokenIndex].startsWith("L") && !tokenStream[tokenIndex].startsWith("T")
  139. && !tokenStream[tokenIndex].startsWith("[")) {
  140. return null;
  141. }
  142. }
  143. if (maybeEat("[")) {
  144. return parseArrayTypeSignature();
  145. } else if (tokenStream[tokenIndex].startsWith("L")) {
  146. return parseClassTypeSignature();
  147. } else if (tokenStream[tokenIndex].startsWith("T")) {
  148. return parseTypeVariableSignature();
  149. } else {
  150. throw new IllegalStateException("Expecting [,L, or T, but found " + tokenStream[tokenIndex] + " while unpacking "
  151. + inputString);
  152. }
  153. }
  154. private ArrayTypeSignature parseArrayTypeSignature() {
  155. // opening [ already eaten
  156. FieldTypeSignature fieldType = parseFieldTypeSignature(true);
  157. if (fieldType != null) {
  158. return new ArrayTypeSignature(fieldType);
  159. } else {
  160. // must be BaseType array
  161. return new ArrayTypeSignature(new BaseTypeSignature(eatIdentifier()));
  162. }
  163. }
  164. // L PackageSpecifier* SimpleClassTypeSignature ClassTypeSignature* ;
  165. private ClassTypeSignature parseClassTypeSignature() {
  166. SimpleClassTypeSignature outerType = null;
  167. SimpleClassTypeSignature[] nestedTypes = new SimpleClassTypeSignature[0];
  168. StringBuffer ret = new StringBuffer();
  169. String identifier = eatIdentifier();
  170. ret.append(identifier);
  171. while (maybeEat("/")) {
  172. ret.append("/"); // dont forget this...
  173. ret.append(eatIdentifier());
  174. }
  175. identifier = ret.toString();
  176. // now we have either a "." indicating the start of a nested type,
  177. // or a "<" indication type arguments, or ";" and we are done.
  178. while (!maybeEat(";")) {
  179. if (maybeEat(".")) {
  180. // outer type completed
  181. outerType = new SimpleClassTypeSignature(identifier);
  182. List<SimpleClassTypeSignature> nestedTypeList = new ArrayList<SimpleClassTypeSignature>();
  183. do {
  184. ret.append(".");
  185. SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
  186. ret.append(sig.toString());
  187. nestedTypeList.add(sig);
  188. } while (maybeEat("."));
  189. nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
  190. nestedTypeList.toArray(nestedTypes);
  191. } else if (tokenStream[tokenIndex].equals("<")) {
  192. ret.append("<");
  193. TypeArgument[] tArgs = maybeParseTypeArguments();
  194. for (int i = 0; i < tArgs.length; i++) {
  195. ret.append(tArgs[i].toString());
  196. }
  197. ret.append(">");
  198. outerType = new SimpleClassTypeSignature(identifier, tArgs);
  199. // now parse possible nesteds...
  200. List<SimpleClassTypeSignature> nestedTypeList = new ArrayList<SimpleClassTypeSignature>();
  201. while (maybeEat(".")) {
  202. ret.append(".");
  203. SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
  204. ret.append(sig.toString());
  205. nestedTypeList.add(sig);
  206. }
  207. nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
  208. nestedTypeList.toArray(nestedTypes);
  209. } else {
  210. throw new IllegalStateException("Expecting .,<, or ;, but found " + tokenStream[tokenIndex] + " while unpacking "
  211. + inputString);
  212. }
  213. }
  214. ret.append(";");
  215. if (outerType == null)
  216. outerType = new SimpleClassTypeSignature(ret.toString());
  217. return new ClassTypeSignature(ret.toString(), outerType, nestedTypes);
  218. }
  219. private SimpleClassTypeSignature parseSimpleClassTypeSignature() {
  220. String identifier = eatIdentifier();
  221. TypeArgument[] tArgs = maybeParseTypeArguments();
  222. if (tArgs != null) {
  223. return new SimpleClassTypeSignature(identifier, tArgs);
  224. } else {
  225. return new SimpleClassTypeSignature(identifier);
  226. }
  227. }
  228. private TypeArgument parseTypeArgument() {
  229. boolean isPlus = false;
  230. boolean isMinus = false;
  231. if (maybeEat("*")) {
  232. return new TypeArgument();
  233. } else if (maybeEat("+")) {
  234. isPlus = true;
  235. } else if (maybeEat("-")) {
  236. isMinus = true;
  237. }
  238. FieldTypeSignature sig = parseFieldTypeSignature(false);
  239. return new TypeArgument(isPlus, isMinus, sig);
  240. }
  241. private TypeArgument[] maybeParseTypeArguments() {
  242. if (maybeEat("<")) {
  243. List<TypeArgument> typeArgs = new ArrayList<TypeArgument>();
  244. do {
  245. TypeArgument arg = parseTypeArgument();
  246. typeArgs.add(arg);
  247. } while (!maybeEat(">"));
  248. TypeArgument[] tArgs = new TypeArgument[typeArgs.size()];
  249. typeArgs.toArray(tArgs);
  250. return tArgs;
  251. } else {
  252. return null;
  253. }
  254. }
  255. private TypeVariableSignature parseTypeVariableSignature() {
  256. TypeVariableSignature tv = new TypeVariableSignature(eatIdentifier());
  257. eat(";");
  258. return tv;
  259. }
  260. private boolean maybeEat(String token) {
  261. if (tokenStream.length <= tokenIndex)
  262. return false;
  263. if (tokenStream[tokenIndex].equals(token)) {
  264. tokenIndex++;
  265. return true;
  266. }
  267. return false;
  268. }
  269. private void eat(String token) {
  270. if (!tokenStream[tokenIndex].equals(token)) {
  271. throw new IllegalStateException("Expecting " + token + " but found " + tokenStream[tokenIndex] + " while unpacking "
  272. + inputString);
  273. }
  274. tokenIndex++;
  275. }
  276. private String eatIdentifier() {
  277. return tokenStream[tokenIndex++];
  278. }
  279. /**
  280. * non-private for test visibility Splits a string containing a generic signature into tokens for consumption by the parser.
  281. */
  282. public String[] tokenize(String signatureString) {
  283. char[] chars = signatureString.toCharArray();
  284. int index = 0;
  285. List<String> tokens = new ArrayList<String>();
  286. StringBuffer identifier = new StringBuffer();
  287. boolean inParens = false;
  288. boolean inArray = false;
  289. boolean couldSeePrimitive = false;
  290. do {
  291. switch (chars[index]) {
  292. case '<':
  293. if (identifier.length() > 0)
  294. tokens.add(identifier.toString());
  295. identifier = new StringBuffer();
  296. tokens.add("<");
  297. break;
  298. case '>':
  299. if (identifier.length() > 0)
  300. tokens.add(identifier.toString());
  301. identifier = new StringBuffer();
  302. tokens.add(">");
  303. break;
  304. case ':':
  305. if (identifier.length() > 0)
  306. tokens.add(identifier.toString());
  307. identifier = new StringBuffer();
  308. tokens.add(":");
  309. break;
  310. case '/':
  311. if (identifier.length() > 0)
  312. tokens.add(identifier.toString());
  313. identifier = new StringBuffer();
  314. tokens.add("/");
  315. couldSeePrimitive = false;
  316. break;
  317. case ';':
  318. if (identifier.length() > 0)
  319. tokens.add(identifier.toString());
  320. identifier = new StringBuffer();
  321. tokens.add(";");
  322. couldSeePrimitive = true;
  323. inArray = false;
  324. break;
  325. case '^':
  326. if (identifier.length() > 0)
  327. tokens.add(identifier.toString());
  328. identifier = new StringBuffer();
  329. tokens.add("^");
  330. break;
  331. case '+':
  332. tokens.add("+");
  333. break;
  334. case '-':
  335. tokens.add("-");
  336. break;
  337. case '*':
  338. tokens.add("*");
  339. break;
  340. case '.':
  341. if (identifier.length() > 0)
  342. tokens.add(identifier.toString());
  343. identifier = new StringBuffer();
  344. couldSeePrimitive = false;
  345. tokens.add(".");
  346. break;
  347. case '(':
  348. tokens.add("(");
  349. inParens = true;
  350. couldSeePrimitive = true;
  351. break;
  352. case ')':
  353. tokens.add(")");
  354. inParens = false;
  355. break;
  356. case '[':
  357. tokens.add("[");
  358. couldSeePrimitive = true;
  359. inArray = true;
  360. break;
  361. case 'B':
  362. case 'C':
  363. case 'D':
  364. case 'F':
  365. case 'I':
  366. case 'J':
  367. case 'S':
  368. case 'V':
  369. case 'Z':
  370. if ((inParens || inArray) && couldSeePrimitive && identifier.length() == 0) {
  371. tokens.add(new String("" + chars[index]));
  372. } else {
  373. identifier.append(chars[index]);
  374. }
  375. inArray = false;
  376. break;
  377. case 'L':
  378. couldSeePrimitive = false;
  379. // deliberate fall-through
  380. default:
  381. identifier.append(chars[index]);
  382. }
  383. } while ((++index) < chars.length);
  384. if (identifier.length() > 0)
  385. tokens.add(identifier.toString());
  386. String[] tokenArray = new String[tokens.size()];
  387. tokens.toArray(tokenArray);
  388. return tokenArray;
  389. }
  390. }