You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PatternParser.java 59KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900
  1. /* *******************************************************************
  2. * Copyright (c) 2002,2010
  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://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * Adrian Colyer, IBM
  12. * Andy Clement, IBM, SpringSource
  13. * ******************************************************************/
  14. package org.aspectj.weaver.patterns;
  15. import java.util.ArrayList;
  16. import java.util.Collections;
  17. import java.util.HashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Set;
  21. import org.aspectj.weaver.ISourceContext;
  22. import org.aspectj.weaver.Member;
  23. import org.aspectj.weaver.MemberKind;
  24. import org.aspectj.weaver.Shadow;
  25. import org.aspectj.weaver.UnresolvedType;
  26. import org.aspectj.weaver.World;
  27. import org.aspectj.weaver.internal.tools.PointcutDesignatorHandlerBasedPointcut;
  28. import org.aspectj.weaver.tools.ContextBasedMatcher;
  29. import org.aspectj.weaver.tools.PointcutDesignatorHandler;
  30. /**
  31. * @author PARC
  32. * @author Adrian Colyer
  33. * @author Andy Clement
  34. */
  35. // XXX doesn't handle errors for extra tokens very well (sometimes ignores)
  36. public class PatternParser {
  37. private ITokenSource tokenSource;
  38. private ISourceContext sourceContext;
  39. /** not thread-safe, but this class is not intended to be... */
  40. private boolean allowHasTypePatterns = false;
  41. /** extension handlers used in weaver tools API only */
  42. private Set<PointcutDesignatorHandler> pointcutDesignatorHandlers = Collections.emptySet();
  43. private World world;
  44. /**
  45. * Constructor for PatternParser.
  46. */
  47. public PatternParser(ITokenSource tokenSource) {
  48. super();
  49. this.tokenSource = tokenSource;
  50. this.sourceContext = tokenSource.getSourceContext();
  51. }
  52. /** only used by weaver tools API */
  53. public void setPointcutDesignatorHandlers(Set<PointcutDesignatorHandler> handlers, World world) {
  54. this.pointcutDesignatorHandlers = handlers;
  55. this.world = world;
  56. }
  57. public PerClause maybeParsePerClause() {
  58. IToken tok = tokenSource.peek();
  59. if (tok == IToken.EOF) {
  60. return null;
  61. }
  62. if (tok.isIdentifier()) {
  63. String name = tok.getString();
  64. if (name.equals("issingleton")) {
  65. return parsePerSingleton();
  66. } else if (name.equals("perthis")) {
  67. return parsePerObject(true);
  68. } else if (name.equals("pertarget")) {
  69. return parsePerObject(false);
  70. } else if (name.equals("percflow")) {
  71. return parsePerCflow(false);
  72. } else if (name.equals("percflowbelow")) {
  73. return parsePerCflow(true);
  74. } else if (name.equals("pertypewithin")) { // PTWIMPL Parse the pertypewithin clause
  75. return parsePerTypeWithin();
  76. } else {
  77. return null;
  78. }
  79. }
  80. return null;
  81. }
  82. private PerClause parsePerCflow(boolean isBelow) {
  83. parseIdentifier();
  84. eat("(");
  85. Pointcut entry = parsePointcut();
  86. eat(")");
  87. return new PerCflow(entry, isBelow);
  88. }
  89. private PerClause parsePerObject(boolean isThis) {
  90. parseIdentifier();
  91. eat("(");
  92. Pointcut entry = parsePointcut();
  93. eat(")");
  94. return new PerObject(entry, isThis);
  95. }
  96. private PerClause parsePerTypeWithin() {
  97. parseIdentifier();
  98. eat("(");
  99. TypePattern withinTypePattern = parseTypePattern();
  100. eat(")");
  101. return new PerTypeWithin(withinTypePattern);
  102. }
  103. private PerClause parsePerSingleton() {
  104. parseIdentifier();
  105. eat("(");
  106. eat(")");
  107. return new PerSingleton();
  108. }
  109. public Declare parseDeclare() {
  110. int startPos = tokenSource.peek().getStart();
  111. eatIdentifier("declare");
  112. String kind = parseIdentifier();
  113. Declare ret;
  114. if (kind.equals("error")) {
  115. eat(":");
  116. ret = parseErrorOrWarning(true);
  117. } else if (kind.equals("warning")) {
  118. eat(":");
  119. ret = parseErrorOrWarning(false);
  120. } else if (kind.equals("precedence")) {
  121. eat(":");
  122. ret = parseDominates();
  123. } else if (kind.equals("dominates")) {
  124. throw new ParserException("name changed to declare precedence", tokenSource.peek(-2));
  125. } else if (kind.equals("parents")) {
  126. ret = parseParents();
  127. } else if (kind.equals("soft")) {
  128. eat(":");
  129. ret = parseSoft();
  130. } else {
  131. throw new ParserException(
  132. "expected one of error, warning, parents, soft, precedence, @type, @method, @constructor, @field",
  133. tokenSource.peek(-1));
  134. }
  135. int endPos = tokenSource.peek(-1).getEnd();
  136. ret.setLocation(sourceContext, startPos, endPos);
  137. return ret;
  138. }
  139. public Declare parseDeclareAnnotation() {
  140. int startPos = tokenSource.peek().getStart();
  141. eatIdentifier("declare");
  142. eat("@");
  143. String kind = parseIdentifier();
  144. eat(":");
  145. Declare ret;
  146. if (kind.equals("type")) {
  147. ret = parseDeclareAtType();
  148. } else if (kind.equals("method")) {
  149. ret = parseDeclareAtMethod(true);
  150. } else if (kind.equals("field")) {
  151. ret = parseDeclareAtField();
  152. } else if (kind.equals("constructor")) {
  153. ret = parseDeclareAtMethod(false);
  154. } else {
  155. throw new ParserException("one of type, method, field, constructor", tokenSource.peek(-1));
  156. }
  157. eat(";");
  158. int endPos = tokenSource.peek(-1).getEnd();
  159. ret.setLocation(sourceContext, startPos, endPos);
  160. return ret;
  161. }
  162. public DeclareAnnotation parseDeclareAtType() {
  163. allowHasTypePatterns = true;
  164. TypePattern p = parseTypePattern();
  165. allowHasTypePatterns = false;
  166. return new DeclareAnnotation(DeclareAnnotation.AT_TYPE, p);
  167. }
  168. public DeclareAnnotation parseDeclareAtMethod(boolean isMethod) {
  169. ISignaturePattern sp = parseCompoundMethodOrConstructorSignaturePattern(isMethod);// parseMethodOrConstructorSignaturePattern();
  170. if (!isMethod) {
  171. return new DeclareAnnotation(DeclareAnnotation.AT_CONSTRUCTOR, sp);
  172. } else {
  173. return new DeclareAnnotation(DeclareAnnotation.AT_METHOD, sp);
  174. }
  175. }
  176. public DeclareAnnotation parseDeclareAtField() {
  177. ISignaturePattern compoundFieldSignaturePattern = parseCompoundFieldSignaturePattern();
  178. DeclareAnnotation da = new DeclareAnnotation(DeclareAnnotation.AT_FIELD, compoundFieldSignaturePattern);
  179. return da;
  180. }
  181. public ISignaturePattern parseCompoundFieldSignaturePattern() {
  182. int index = tokenSource.getIndex();
  183. try {
  184. ISignaturePattern atomicFieldSignaturePattern = parseMaybeParenthesizedFieldSignaturePattern();
  185. while (isEitherAndOrOr()) {
  186. if (maybeEat("&&")) {
  187. atomicFieldSignaturePattern = new AndSignaturePattern(atomicFieldSignaturePattern,
  188. parseMaybeParenthesizedFieldSignaturePattern());
  189. }
  190. if (maybeEat("||")) {
  191. atomicFieldSignaturePattern = new OrSignaturePattern(atomicFieldSignaturePattern,
  192. parseMaybeParenthesizedFieldSignaturePattern());
  193. }
  194. }
  195. return atomicFieldSignaturePattern;
  196. } catch (ParserException e) {
  197. // fallback in the case of a regular single field signature pattern that just happened to start with '('
  198. int nowAt = tokenSource.getIndex();
  199. tokenSource.setIndex(index);
  200. try {
  201. ISignaturePattern fsp = parseFieldSignaturePattern();
  202. return fsp;
  203. } catch (Exception e2) {
  204. tokenSource.setIndex(nowAt);
  205. // throw the original
  206. throw e;
  207. }
  208. }
  209. }
  210. private boolean isEitherAndOrOr() {
  211. String tokenstring = tokenSource.peek().getString();
  212. return tokenstring.equals("&&") || tokenstring.equals("||");
  213. }
  214. public ISignaturePattern parseCompoundMethodOrConstructorSignaturePattern(boolean isMethod) {
  215. ISignaturePattern atomicMethodCtorSignaturePattern = parseMaybeParenthesizedMethodOrConstructorSignaturePattern(isMethod);
  216. while (isEitherAndOrOr()) {
  217. if (maybeEat("&&")) {
  218. atomicMethodCtorSignaturePattern = new AndSignaturePattern(atomicMethodCtorSignaturePattern,
  219. parseMaybeParenthesizedMethodOrConstructorSignaturePattern(isMethod));
  220. }
  221. if (maybeEat("||")) {
  222. atomicMethodCtorSignaturePattern = new OrSignaturePattern(atomicMethodCtorSignaturePattern,
  223. parseMaybeParenthesizedMethodOrConstructorSignaturePattern(isMethod));
  224. }
  225. }
  226. return atomicMethodCtorSignaturePattern;
  227. }
  228. public DeclarePrecedence parseDominates() {
  229. List<TypePattern> l = new ArrayList<TypePattern>();
  230. do {
  231. l.add(parseTypePattern());
  232. } while (maybeEat(","));
  233. return new DeclarePrecedence(l);
  234. }
  235. private Declare parseParents() {
  236. /*
  237. * simplified design requires use of raw types for declare parents, no generic spec. allowed String[] typeParameters =
  238. * maybeParseSimpleTypeVariableList();
  239. */
  240. eat(":");
  241. allowHasTypePatterns = true;
  242. TypePattern p = parseTypePattern(false, false);
  243. allowHasTypePatterns = false;
  244. IToken t = tokenSource.next();
  245. if (!(t.getString().equals("extends") || t.getString().equals("implements"))) {
  246. throw new ParserException("extends or implements", t);
  247. }
  248. boolean isExtends = t.getString().equals("extends");
  249. List<TypePattern> l = new ArrayList<TypePattern>();
  250. do {
  251. l.add(parseTypePattern());
  252. } while (maybeEat(","));
  253. // XXX somewhere in the chain we need to enforce that we have only ExactTypePatterns
  254. DeclareParents decp = new DeclareParents(p, l, isExtends);
  255. return decp;
  256. }
  257. private Declare parseSoft() {
  258. TypePattern p = parseTypePattern();
  259. eat(":");
  260. Pointcut pointcut = parsePointcut();
  261. return new DeclareSoft(p, pointcut);
  262. }
  263. /**
  264. * Attempt to parse a pointcut, if that fails then try again for a type pattern.
  265. *
  266. * @param isError true if it is declare error rather than declare warning
  267. * @return the new declare
  268. */
  269. private Declare parseErrorOrWarning(boolean isError) {
  270. Pointcut pointcut = null;
  271. int index = tokenSource.getIndex();
  272. try {
  273. pointcut = parsePointcut();
  274. } catch (ParserException pe) {
  275. try {
  276. tokenSource.setIndex(index);
  277. boolean oldValue = allowHasTypePatterns;
  278. TypePattern typePattern = null;
  279. try {
  280. allowHasTypePatterns = true;
  281. typePattern = parseTypePattern();
  282. } finally {
  283. allowHasTypePatterns = oldValue;
  284. }
  285. eat(":");
  286. String message = parsePossibleStringSequence(true);
  287. return new DeclareTypeErrorOrWarning(isError, typePattern, message);
  288. } catch (ParserException pe2) {
  289. // deliberately throw the original problem
  290. throw pe;
  291. }
  292. }
  293. eat(":");
  294. String message = parsePossibleStringSequence(true);
  295. return new DeclareErrorOrWarning(isError, pointcut, message);
  296. }
  297. public Pointcut parsePointcut() {
  298. Pointcut p = parseAtomicPointcut();
  299. if (maybeEat("&&")) {
  300. p = new AndPointcut(p, parseNotOrPointcut());
  301. }
  302. if (maybeEat("||")) {
  303. p = new OrPointcut(p, parsePointcut());
  304. }
  305. return p;
  306. }
  307. private Pointcut parseNotOrPointcut() {
  308. Pointcut p = parseAtomicPointcut();
  309. if (maybeEat("&&")) {
  310. p = new AndPointcut(p, parseNotOrPointcut());
  311. }
  312. return p;
  313. }
  314. private Pointcut parseAtomicPointcut() {
  315. if (maybeEat("!")) {
  316. int startPos = tokenSource.peek(-1).getStart();
  317. Pointcut p = new NotPointcut(parseAtomicPointcut(), startPos);
  318. return p;
  319. }
  320. if (maybeEat("(")) {
  321. Pointcut p = parsePointcut();
  322. eat(")");
  323. return p;
  324. }
  325. if (maybeEat("@")) {
  326. int startPos = tokenSource.peek().getStart();
  327. Pointcut p = parseAnnotationPointcut();
  328. int endPos = tokenSource.peek(-1).getEnd();
  329. p.setLocation(sourceContext, startPos, endPos);
  330. return p;
  331. }
  332. int startPos = tokenSource.peek().getStart();
  333. Pointcut p = parseSinglePointcut();
  334. int endPos = tokenSource.peek(-1).getEnd();
  335. p.setLocation(sourceContext, startPos, endPos);
  336. return p;
  337. }
  338. public Pointcut parseSinglePointcut() {
  339. int start = tokenSource.getIndex();
  340. IToken t = tokenSource.peek();
  341. Pointcut p = t.maybeGetParsedPointcut();
  342. if (p != null) {
  343. tokenSource.next();
  344. return p;
  345. }
  346. String kind = parseIdentifier();
  347. // IToken possibleTypeVariableToken = tokenSource.peek();
  348. // String[] typeVariables = maybeParseSimpleTypeVariableList();
  349. if (kind.equals("execution") || kind.equals("call") || kind.equals("get") || kind.equals("set")) {
  350. p = parseKindedPointcut(kind);
  351. } else if (kind.equals("args")) {
  352. p = parseArgsPointcut();
  353. } else if (kind.equals("this")) {
  354. p = parseThisOrTargetPointcut(kind);
  355. } else if (kind.equals("target")) {
  356. p = parseThisOrTargetPointcut(kind);
  357. } else if (kind.equals("within")) {
  358. p = parseWithinPointcut();
  359. } else if (kind.equals("withincode")) {
  360. p = parseWithinCodePointcut();
  361. } else if (kind.equals("cflow")) {
  362. p = parseCflowPointcut(false);
  363. } else if (kind.equals("cflowbelow")) {
  364. p = parseCflowPointcut(true);
  365. } else if (kind.equals("adviceexecution")) {
  366. eat("(");
  367. eat(")");
  368. p = new KindedPointcut(Shadow.AdviceExecution, new SignaturePattern(Member.ADVICE, ModifiersPattern.ANY,
  369. TypePattern.ANY, TypePattern.ANY, NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY,
  370. AnnotationTypePattern.ANY));
  371. } else if (kind.equals("handler")) {
  372. eat("(");
  373. TypePattern typePat = parseTypePattern(false, false);
  374. eat(")");
  375. p = new HandlerPointcut(typePat);
  376. } else if (kind.equals("lock") || kind.equals("unlock")) {
  377. p = parseMonitorPointcut(kind);
  378. } else if (kind.equals("initialization")) {
  379. eat("(");
  380. SignaturePattern sig = parseConstructorSignaturePattern();
  381. eat(")");
  382. p = new KindedPointcut(Shadow.Initialization, sig);
  383. } else if (kind.equals("staticinitialization")) {
  384. eat("(");
  385. TypePattern typePat = parseTypePattern(false, false);
  386. eat(")");
  387. p = new KindedPointcut(Shadow.StaticInitialization, new SignaturePattern(Member.STATIC_INITIALIZATION,
  388. ModifiersPattern.ANY, TypePattern.ANY, typePat, NamePattern.ANY, TypePatternList.EMPTY, ThrowsPattern.ANY,
  389. AnnotationTypePattern.ANY));
  390. } else if (kind.equals("preinitialization")) {
  391. eat("(");
  392. SignaturePattern sig = parseConstructorSignaturePattern();
  393. eat(")");
  394. p = new KindedPointcut(Shadow.PreInitialization, sig);
  395. } else if (kind.equals("if")) {
  396. // - annotation style only allows if(), if(true) or if(false)
  397. // - if() means the body of the annotated method represents the if expression
  398. // - anything else is an error because code cannot be put into the if()
  399. // - code style will already have been processed and the call to maybeGetParsedPointcut()
  400. // at the top of this method will have succeeded.
  401. eat("(");
  402. if (maybeEatIdentifier("true")) {
  403. eat(")");
  404. p = new IfPointcut.IfTruePointcut();
  405. } else if (maybeEatIdentifier("false")) {
  406. eat(")");
  407. p = new IfPointcut.IfFalsePointcut();
  408. } else {
  409. if (!maybeEat(")")) {
  410. throw new ParserException(
  411. "in annotation style, if(...) pointcuts cannot contain code. Use if() and put the code in the annotated method",
  412. t);
  413. }
  414. // TODO - Alex has some token stuff going on here to get a readable name in place of ""...
  415. p = new IfPointcut("");
  416. }
  417. } else {
  418. boolean matchedByExtensionDesignator = false;
  419. // see if a registered handler wants to parse it, otherwise
  420. // treat as a reference pointcut
  421. for (PointcutDesignatorHandler pcd : pointcutDesignatorHandlers) {
  422. if (pcd.getDesignatorName().equals(kind)) {
  423. p = parseDesignatorPointcut(pcd);
  424. matchedByExtensionDesignator = true;
  425. }
  426. }
  427. if (!matchedByExtensionDesignator) {
  428. tokenSource.setIndex(start);
  429. p = parseReferencePointcut();
  430. }
  431. }
  432. return p;
  433. }
  434. private void assertNoTypeVariables(String[] tvs, String errorMessage, IToken token) {
  435. if (tvs != null) {
  436. throw new ParserException(errorMessage, token);
  437. }
  438. }
  439. public Pointcut parseAnnotationPointcut() {
  440. int start = tokenSource.getIndex();
  441. IToken t = tokenSource.peek();
  442. String kind = parseIdentifier();
  443. IToken possibleTypeVariableToken = tokenSource.peek();
  444. String[] typeVariables = maybeParseSimpleTypeVariableList();
  445. if (typeVariables != null) {
  446. String message = "(";
  447. assertNoTypeVariables(typeVariables, message, possibleTypeVariableToken);
  448. }
  449. tokenSource.setIndex(start);
  450. if (kind.equals("annotation")) {
  451. return parseAtAnnotationPointcut();
  452. } else if (kind.equals("args")) {
  453. return parseArgsAnnotationPointcut();
  454. } else if (kind.equals("this") || kind.equals("target")) {
  455. return parseThisOrTargetAnnotationPointcut();
  456. } else if (kind.equals("within")) {
  457. return parseWithinAnnotationPointcut();
  458. } else if (kind.equals("withincode")) {
  459. return parseWithinCodeAnnotationPointcut();
  460. }
  461. throw new ParserException("pointcut name", t);
  462. }
  463. private Pointcut parseAtAnnotationPointcut() {
  464. parseIdentifier();
  465. eat("(");
  466. if (maybeEat(")")) {
  467. throw new ParserException("@AnnotationName or parameter", tokenSource.peek());
  468. }
  469. ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
  470. eat(")");
  471. return new AnnotationPointcut(type);
  472. }
  473. private SignaturePattern parseConstructorSignaturePattern() {
  474. SignaturePattern ret = parseMethodOrConstructorSignaturePattern();
  475. if (ret.getKind() == Member.CONSTRUCTOR) {
  476. return ret;
  477. }
  478. throw new ParserException("constructor pattern required, found method pattern", ret);
  479. }
  480. private Pointcut parseWithinCodePointcut() {
  481. // parseIdentifier();
  482. eat("(");
  483. SignaturePattern sig = parseMethodOrConstructorSignaturePattern();
  484. eat(")");
  485. return new WithincodePointcut(sig);
  486. }
  487. private Pointcut parseCflowPointcut(boolean isBelow) {
  488. // parseIdentifier();
  489. eat("(");
  490. Pointcut entry = parsePointcut();
  491. eat(")");
  492. return new CflowPointcut(entry, isBelow, null);
  493. }
  494. /**
  495. * Method parseWithinPointcut.
  496. *
  497. * @return Pointcut
  498. */
  499. private Pointcut parseWithinPointcut() {
  500. // parseIdentifier();
  501. eat("(");
  502. TypePattern type = parseTypePattern();
  503. eat(")");
  504. return new WithinPointcut(type);
  505. }
  506. /**
  507. * Method parseThisOrTargetPointcut.
  508. *
  509. * @return Pointcut
  510. */
  511. private Pointcut parseThisOrTargetPointcut(String kind) {
  512. boolean optional = false;
  513. if (maybeEat("?")) {
  514. optional = true;
  515. }
  516. eat("(");
  517. TypePattern type = parseTypePattern();
  518. eat(")");
  519. return new ThisOrTargetPointcut(kind.equals("this"), type,optional);
  520. }
  521. private Pointcut parseThisOrTargetAnnotationPointcut() {
  522. String kind = parseIdentifier();
  523. eat("(");
  524. if (maybeEat(")")) {
  525. throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
  526. }
  527. ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
  528. eat(")");
  529. return new ThisOrTargetAnnotationPointcut(kind.equals("this"), type);
  530. }
  531. private Pointcut parseWithinAnnotationPointcut() {
  532. /* String kind = */parseIdentifier();
  533. eat("(");
  534. if (maybeEat(")")) {
  535. throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
  536. }
  537. AnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
  538. eat(")");
  539. return new WithinAnnotationPointcut(type);
  540. }
  541. private Pointcut parseWithinCodeAnnotationPointcut() {
  542. /* String kind = */parseIdentifier();
  543. eat("(");
  544. if (maybeEat(")")) {
  545. throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
  546. }
  547. ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
  548. eat(")");
  549. return new WithinCodeAnnotationPointcut(type);
  550. }
  551. /**
  552. * Method parseArgsPointcut.
  553. *
  554. * @return Pointcut
  555. */
  556. private Pointcut parseArgsPointcut() {
  557. // parseIdentifier();
  558. TypePatternList arguments = parseArgumentsPattern(false);
  559. return new ArgsPointcut(arguments);
  560. }
  561. private Pointcut parseArgsAnnotationPointcut() {
  562. parseIdentifier();
  563. AnnotationPatternList arguments = parseArgumentsAnnotationPattern();
  564. return new ArgsAnnotationPointcut(arguments);
  565. }
  566. private Pointcut parseReferencePointcut() {
  567. TypePattern onType = parseTypePattern();
  568. NamePattern name = null;
  569. if (onType.typeParameters.size() > 0) {
  570. eat(".");
  571. name = parseNamePattern();
  572. } else {
  573. name = tryToExtractName(onType);
  574. }
  575. if (name == null) {
  576. throw new ParserException("name pattern", tokenSource.peek());
  577. }
  578. if (onType.toString().equals("")) {
  579. onType = null;
  580. }
  581. String simpleName = name.maybeGetSimpleName();
  582. if (simpleName == null) {
  583. throw new ParserException("(", tokenSource.peek(-1));
  584. }
  585. TypePatternList arguments = parseArgumentsPattern(false);
  586. return new ReferencePointcut(onType, simpleName, arguments);
  587. }
  588. private Pointcut parseDesignatorPointcut(PointcutDesignatorHandler pcdHandler) {
  589. eat("(");
  590. int parenCount = 1;
  591. StringBuffer pointcutBody = new StringBuffer();
  592. while (parenCount > 0) {
  593. if (maybeEat("(")) {
  594. parenCount++;
  595. pointcutBody.append("(");
  596. } else if (maybeEat(")")) {
  597. parenCount--;
  598. if (parenCount > 0) {
  599. pointcutBody.append(")");
  600. }
  601. } else {
  602. pointcutBody.append(nextToken().getString());
  603. }
  604. }
  605. ContextBasedMatcher pcExpr = pcdHandler.parse(pointcutBody.toString());
  606. return new PointcutDesignatorHandlerBasedPointcut(pcExpr, world);
  607. }
  608. public List<String> parseDottedIdentifier() {
  609. List<String> ret = new ArrayList<String>();
  610. ret.add(parseIdentifier());
  611. while (maybeEat(".")) {
  612. ret.add(parseIdentifier());
  613. }
  614. return ret;
  615. }
  616. private KindedPointcut parseKindedPointcut(String kind) {
  617. eat("(");
  618. SignaturePattern sig;
  619. Shadow.Kind shadowKind = null;
  620. if (kind.equals("execution")) {
  621. sig = parseMethodOrConstructorSignaturePattern();
  622. if (sig.getKind() == Member.METHOD) {
  623. shadowKind = Shadow.MethodExecution;
  624. } else if (sig.getKind() == Member.CONSTRUCTOR) {
  625. shadowKind = Shadow.ConstructorExecution;
  626. }
  627. } else if (kind.equals("call")) {
  628. sig = parseMethodOrConstructorSignaturePattern();
  629. if (sig.getKind() == Member.METHOD) {
  630. shadowKind = Shadow.MethodCall;
  631. } else if (sig.getKind() == Member.CONSTRUCTOR) {
  632. shadowKind = Shadow.ConstructorCall;
  633. }
  634. } else if (kind.equals("get")) {
  635. sig = parseFieldSignaturePattern();
  636. shadowKind = Shadow.FieldGet;
  637. } else if (kind.equals("set")) {
  638. sig = parseFieldSignaturePattern();
  639. shadowKind = Shadow.FieldSet;
  640. } else {
  641. throw new ParserException("bad kind: " + kind, tokenSource.peek());
  642. }
  643. eat(")");
  644. return new KindedPointcut(shadowKind, sig);
  645. }
  646. /** Covers the 'lock()' and 'unlock()' pointcuts */
  647. private KindedPointcut parseMonitorPointcut(String kind) {
  648. eat("(");
  649. // TypePattern type = TypePattern.ANY;
  650. eat(")");
  651. if (kind.equals("lock")) {
  652. return new KindedPointcut(Shadow.SynchronizationLock, new SignaturePattern(Member.MONITORENTER, ModifiersPattern.ANY,
  653. TypePattern.ANY, TypePattern.ANY,
  654. // type,
  655. NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY, AnnotationTypePattern.ANY));
  656. } else {
  657. return new KindedPointcut(Shadow.SynchronizationUnlock, new SignaturePattern(Member.MONITORENTER, ModifiersPattern.ANY,
  658. TypePattern.ANY, TypePattern.ANY,
  659. // type,
  660. NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY, AnnotationTypePattern.ANY));
  661. }
  662. }
  663. public TypePattern parseTypePattern() {
  664. return parseTypePattern(false, false);
  665. }
  666. public TypePattern parseTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
  667. TypePattern p = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
  668. if (maybeEat("&&")) {
  669. p = new AndTypePattern(p, parseNotOrTypePattern(insideTypeParameters, parameterAnnotationsPossible));
  670. }
  671. if (maybeEat("||")) {
  672. p = new OrTypePattern(p, parseTypePattern(insideTypeParameters, parameterAnnotationsPossible));
  673. }
  674. return p;
  675. }
  676. private TypePattern parseNotOrTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
  677. TypePattern p = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
  678. if (maybeEat("&&")) {
  679. p = new AndTypePattern(p, parseTypePattern(insideTypeParameters, parameterAnnotationsPossible));
  680. }
  681. return p;
  682. }
  683. // Need to differentiate in here between two kinds of annotation pattern - depending on where the ( is
  684. private TypePattern parseAtomicTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
  685. AnnotationTypePattern ap = maybeParseAnnotationPattern(); // might be parameter annotation pattern or type annotation
  686. // pattern
  687. if (maybeEat("!")) {
  688. // int startPos = tokenSource.peek(-1).getStart();
  689. // ??? we lose source location for true start of !type
  690. // An annotation, if processed, is outside of the Not - so here we have to build
  691. // an And pattern containing the annotation and the not as left and right children
  692. // *unless* the annotation pattern was just 'Any' then we can skip building the
  693. // And and just return the Not directly (pr228980)
  694. TypePattern p = null;
  695. TypePattern tp = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
  696. if (!(ap instanceof AnyAnnotationTypePattern)) {
  697. p = new NotTypePattern(tp);
  698. p = new AndTypePattern(setAnnotationPatternForTypePattern(TypePattern.ANY, ap, false), p);
  699. } else {
  700. p = new NotTypePattern(tp);
  701. }
  702. return p;
  703. }
  704. if (maybeEat("(")) {
  705. int openParenPos = tokenSource.peek(-1).getStart();
  706. TypePattern p = parseTypePattern(insideTypeParameters, false);
  707. if ((p instanceof NotTypePattern) && !(ap instanceof AnyAnnotationTypePattern)) {
  708. // dont set the annotation on it, we don't want the annotation to be
  709. // considered as part of the not, it is outside the not (pr228980)
  710. TypePattern tp = setAnnotationPatternForTypePattern(TypePattern.ANY, ap, parameterAnnotationsPossible);
  711. p = new AndTypePattern(tp, p);
  712. } else {
  713. p = setAnnotationPatternForTypePattern(p, ap, parameterAnnotationsPossible);
  714. }
  715. eat(")");
  716. int closeParenPos = tokenSource.peek(-1).getStart();
  717. boolean isVarArgs = maybeEat("...");
  718. if (isVarArgs) {
  719. p.setIsVarArgs(isVarArgs);
  720. }
  721. boolean isIncludeSubtypes = maybeEat("+");
  722. if (isIncludeSubtypes) {
  723. p.includeSubtypes = true; // need the test because (A+) should not set subtypes to false!
  724. }
  725. p.start = openParenPos;
  726. p.end = closeParenPos;
  727. return p;
  728. }
  729. int startPos = tokenSource.peek().getStart();
  730. if (ap.start != -1) {
  731. startPos = ap.start;
  732. }
  733. TypePattern p = parseSingleTypePattern(insideTypeParameters);
  734. int endPos = tokenSource.peek(-1).getEnd();
  735. p = setAnnotationPatternForTypePattern(p, ap, false);
  736. p.setLocation(sourceContext, startPos, endPos);
  737. return p;
  738. }
  739. private TypePattern setAnnotationPatternForTypePattern(TypePattern t, AnnotationTypePattern ap,
  740. boolean parameterAnnotationsPattern) {
  741. TypePattern ret = t;
  742. if (parameterAnnotationsPattern) {
  743. ap.setForParameterAnnotationMatch();
  744. }
  745. if (ap != AnnotationTypePattern.ANY) {
  746. if (t == TypePattern.ANY) {
  747. if (t.annotationPattern == AnnotationTypePattern.ANY) {
  748. return new AnyWithAnnotationTypePattern(ap);
  749. } else {
  750. return new AnyWithAnnotationTypePattern(new AndAnnotationTypePattern(ap, t.annotationPattern));
  751. }
  752. // ret = new WildTypePattern(new NamePattern[] { NamePattern.ANY }, false, 0, false, null);
  753. }
  754. if (t.annotationPattern == AnnotationTypePattern.ANY) {
  755. ret.setAnnotationTypePattern(ap);
  756. } else {
  757. ret.setAnnotationTypePattern(new AndAnnotationTypePattern(ap, t.annotationPattern)); // ???
  758. }
  759. }
  760. return ret;
  761. }
  762. public AnnotationTypePattern maybeParseAnnotationPattern() {
  763. AnnotationTypePattern ret = AnnotationTypePattern.ANY;
  764. AnnotationTypePattern nextPattern = null;
  765. while ((nextPattern = maybeParseSingleAnnotationPattern()) != null) {
  766. if (ret == AnnotationTypePattern.ANY) {
  767. ret = nextPattern;
  768. } else {
  769. ret = new AndAnnotationTypePattern(ret, nextPattern);
  770. }
  771. }
  772. return ret;
  773. }
  774. // PVAL cope with annotation values at other places in this code
  775. public AnnotationTypePattern maybeParseSingleAnnotationPattern() {
  776. AnnotationTypePattern ret = null;
  777. Map<String, String> values = null;
  778. // LALR(2) - fix by making "!@" a single token
  779. int startIndex = tokenSource.getIndex();
  780. if (maybeEat("!")) {
  781. if (maybeEat("@")) {
  782. if (maybeEat("(")) {
  783. TypePattern p = parseTypePattern();
  784. ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
  785. eat(")");
  786. return ret;
  787. } else {
  788. TypePattern p = parseSingleTypePattern();
  789. if (maybeEatAdjacent("(")) {
  790. values = parseAnnotationValues();
  791. eat(")");
  792. ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p, values));
  793. } else {
  794. ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
  795. }
  796. return ret;
  797. }
  798. } else {
  799. tokenSource.setIndex(startIndex); // not for us!
  800. return ret;
  801. }
  802. }
  803. if (maybeEat("@")) {
  804. if (maybeEat("(")) {
  805. TypePattern p = parseTypePattern();
  806. ret = new WildAnnotationTypePattern(p);
  807. eat(")");
  808. return ret;
  809. } else {
  810. int atPos = tokenSource.peek(-1).getStart();
  811. TypePattern p = parseSingleTypePattern();
  812. if (maybeEatAdjacent("(")) {
  813. values = parseAnnotationValues();
  814. eat(")");
  815. ret = new WildAnnotationTypePattern(p, values);
  816. } else {
  817. ret = new WildAnnotationTypePattern(p);
  818. }
  819. ret.start = atPos;
  820. return ret;
  821. }
  822. } else {
  823. tokenSource.setIndex(startIndex); // not for us!
  824. return ret;
  825. }
  826. }
  827. // Parse annotation values. In an expression in @A(a=b,c=d) this method will be
  828. // parsing the a=b,c=d.)
  829. public Map<String, String> parseAnnotationValues() {
  830. Map<String, String> values = new HashMap<String, String>();
  831. boolean seenDefaultValue = false;
  832. do {
  833. String possibleKeyString = parseAnnotationNameValuePattern();
  834. if (possibleKeyString == null) {
  835. throw new ParserException("expecting simple literal ", tokenSource.peek(-1));
  836. }
  837. // did they specify just a single entry 'v' or a keyvalue pair 'k=v'
  838. if (maybeEat("=")) {
  839. // it was a key!
  840. String valueString = parseAnnotationNameValuePattern();
  841. if (valueString == null) {
  842. throw new ParserException("expecting simple literal ", tokenSource.peek(-1));
  843. }
  844. values.put(possibleKeyString, valueString);
  845. } else if (maybeEat("!=")) {
  846. // it was a key, with a !=
  847. String valueString = parseAnnotationNameValuePattern();
  848. if (valueString == null) {
  849. throw new ParserException("expecting simple literal ", tokenSource.peek(-1));
  850. }
  851. // negation is captured by adding a trailing ! to the key name
  852. values.put(possibleKeyString + "!", valueString);
  853. } else {
  854. if (seenDefaultValue) {
  855. throw new ParserException("cannot specify two default values", tokenSource.peek(-1));
  856. }
  857. seenDefaultValue = true;
  858. values.put("value", possibleKeyString);
  859. }
  860. } while (maybeEat(",")); // keep going whilst there are ','
  861. return values;
  862. }
  863. public TypePattern parseSingleTypePattern() {
  864. return parseSingleTypePattern(false);
  865. }
  866. public TypePattern parseSingleTypePattern(boolean insideTypeParameters) {
  867. if (insideTypeParameters && maybeEat("?")) {
  868. return parseGenericsWildcardTypePattern();
  869. }
  870. if (allowHasTypePatterns) {
  871. if (maybeEatIdentifier("hasmethod")) {
  872. return parseHasMethodTypePattern();
  873. }
  874. if (maybeEatIdentifier("hasfield")) {
  875. return parseHasFieldTypePattern();
  876. }
  877. }
  878. // // Check for a type category
  879. // IToken token = tokenSource.peek();
  880. // if (token.isIdentifier()) {
  881. // String category = token.getString();
  882. // TypeCategoryTypePattern typeIsPattern = null;
  883. // if (category.equals("isClass")) {
  884. // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.CLASS);
  885. // } else if (category.equals("isAspect")) {
  886. // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ASPECT);
  887. // } else if (category.equals("isInterface")) {
  888. // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INTERFACE);
  889. // } else if (category.equals("isInner")) {
  890. // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INNER);
  891. // } else if (category.equals("isAnonymous")) {
  892. // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANONYMOUS);
  893. // } else if (category.equals("isEnum")) {
  894. // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ENUM);
  895. // } else if (category.equals("isAnnotation")) {
  896. // typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION);
  897. // }
  898. // if (typeIsPattern != null) {
  899. // tokenSource.next();
  900. // typeIsPattern.setLocation(tokenSource.getSourceContext(), token.getStart(), token.getEnd());
  901. // return typeIsPattern;
  902. // }
  903. // }
  904. if (maybeEatIdentifier("is")) {
  905. int pos = tokenSource.getIndex() - 1;
  906. TypePattern typeIsPattern = parseIsTypePattern();
  907. if (typeIsPattern != null) {
  908. return typeIsPattern;
  909. }
  910. // rewind as if we never tried to parse it as a typeIs
  911. tokenSource.setIndex(pos);
  912. }
  913. List<NamePattern> names = parseDottedNamePattern();
  914. int dim = 0;
  915. while (maybeEat("[")) {
  916. eat("]");
  917. dim++;
  918. }
  919. TypePatternList typeParameters = maybeParseTypeParameterList();
  920. int endPos = tokenSource.peek(-1).getEnd();
  921. boolean includeSubtypes = maybeEat("+");
  922. // TODO do we need to associate the + with either the type or the array?
  923. while (maybeEat("[")) {
  924. eat("]");
  925. dim++;
  926. }
  927. boolean isVarArgs = maybeEat("...");
  928. // ??? what about the source location of any's????
  929. if (names.size() == 1 && names.get(0).isAny() && dim == 0 && !isVarArgs && typeParameters == null) {
  930. return TypePattern.ANY;
  931. }
  932. // Notice we increase the dimensions if varargs is set. this is to allow type matching to
  933. // succeed later: The actual signature at runtime of a method declared varargs is an array type of
  934. // the original declared type (so Integer... becomes Integer[] in the bytecode). So, here for the
  935. // pattern 'Integer...' we create a WildTypePattern 'Integer[]' with varargs set. If this matches
  936. // during shadow matching, we confirm that the varargs flags match up before calling it a successful
  937. // match.
  938. return new WildTypePattern(names, includeSubtypes, dim + (isVarArgs ? 1 : 0), endPos, isVarArgs, typeParameters);
  939. }
  940. public TypePattern parseHasMethodTypePattern() {
  941. int startPos = tokenSource.peek(-1).getStart();
  942. eat("(");
  943. SignaturePattern sp = parseMethodOrConstructorSignaturePattern();
  944. eat(")");
  945. int endPos = tokenSource.peek(-1).getEnd();
  946. HasMemberTypePattern ret = new HasMemberTypePattern(sp);
  947. ret.setLocation(sourceContext, startPos, endPos);
  948. return ret;
  949. }
  950. /**
  951. * Attempt to parse a typeIs(<category>) construct. If it cannot be parsed we just return null and that should cause the caller
  952. * to reset their position and attempt to consume it in another way. This means we won't have problems here: execution(*
  953. * typeIs(..)) because someone has decided to call a method the same as our construct.
  954. *
  955. * @return a TypeIsTypePattern or null if could not be parsed
  956. */
  957. public TypePattern parseIsTypePattern() {
  958. int startPos = tokenSource.peek(-1).getStart(); // that will be the start of the 'typeIs'
  959. if (!maybeEatAdjacent("(")) {
  960. return null;
  961. }
  962. IToken token = tokenSource.next();
  963. TypeCategoryTypePattern typeIsPattern = null;
  964. if (token.isIdentifier()) {
  965. String category = token.getString();
  966. if (category.equals("ClassType")) {
  967. typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.CLASS);
  968. } else if (category.equals("AspectType")) {
  969. typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ASPECT);
  970. } else if (category.equals("InterfaceType")) {
  971. typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INTERFACE);
  972. } else if (category.equals("InnerType")) {
  973. typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.INNER);
  974. } else if (category.equals("AnonymousType")) {
  975. typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANONYMOUS);
  976. } else if (category.equals("EnumType")) {
  977. typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ENUM);
  978. } else if (category.equals("AnnotationType")) {
  979. typeIsPattern = new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION);
  980. }
  981. }
  982. if (typeIsPattern == null) {
  983. return null;
  984. }
  985. if (!maybeEat(")")) {
  986. throw new ParserException(")", tokenSource.peek());
  987. }
  988. int endPos = tokenSource.peek(-1).getEnd();
  989. typeIsPattern.setLocation(tokenSource.getSourceContext(), startPos, endPos);
  990. return typeIsPattern;
  991. }
  992. // if (names.size() == 1 && !names.get(0).isAny()) {
  993. // if (maybeEatAdjacent("(")) {
  994. // if (maybeEat(")")) {
  995. // // likely to be one of isClass()/isInterface()/isInner()/isAnonymous()/isAspect()
  996. // if (names.size() == 1) {
  997. // NamePattern np = names.get(0);
  998. // String simpleName = np.maybeGetSimpleName();
  999. // if (simpleName != null) {
  1000. // return new TypeCategoryTypePattern(TypeCategoryTypePattern.ANNOTATION, np);
  1001. // } else {
  1002. // throw new ParserException(
  1003. // "not a supported type category, supported are isClass/isInterface/isEnum/isAnnotation/isInner/isAnonymous",
  1004. // tokenSource.peek(-3));
  1005. // }
  1006. // }
  1007. // int stop = 1;
  1008. // // return new WildTypePattern(names, includeSubtypes, dim + (isVarArgs ? 1 : 0), endPos, isVarArgs,
  1009. // // typeParameters);
  1010. // }
  1011. // } else {
  1012. // throw new ParserException("category type pattern is missing closing parentheses", tokenSource.peek(-2));
  1013. // }
  1014. // }
  1015. // }
  1016. public TypePattern parseHasFieldTypePattern() {
  1017. int startPos = tokenSource.peek(-1).getStart();
  1018. eat("(");
  1019. SignaturePattern sp = parseFieldSignaturePattern();
  1020. eat(")");
  1021. int endPos = tokenSource.peek(-1).getEnd();
  1022. HasMemberTypePattern ret = new HasMemberTypePattern(sp);
  1023. ret.setLocation(sourceContext, startPos, endPos);
  1024. return ret;
  1025. }
  1026. public TypePattern parseGenericsWildcardTypePattern() {
  1027. List<NamePattern> names = new ArrayList<NamePattern>();
  1028. names.add(new NamePattern("?"));
  1029. TypePattern upperBound = null;
  1030. TypePattern[] additionalInterfaceBounds = new TypePattern[0];
  1031. TypePattern lowerBound = null;
  1032. if (maybeEatIdentifier("extends")) {
  1033. upperBound = parseTypePattern(false, false);
  1034. additionalInterfaceBounds = maybeParseAdditionalInterfaceBounds();
  1035. }
  1036. if (maybeEatIdentifier("super")) {
  1037. lowerBound = parseTypePattern(false, false);
  1038. }
  1039. int endPos = tokenSource.peek(-1).getEnd();
  1040. return new WildTypePattern(names, false, 0, endPos, false, null, upperBound, additionalInterfaceBounds, lowerBound);
  1041. }
  1042. // private AnnotationTypePattern completeAnnotationPattern(AnnotationTypePattern p) {
  1043. // if (maybeEat("&&")) {
  1044. // return new AndAnnotationTypePattern(p,parseNotOrAnnotationPattern());
  1045. // }
  1046. // if (maybeEat("||")) {
  1047. // return new OrAnnotationTypePattern(p,parseAnnotationTypePattern());
  1048. // }
  1049. // return p;
  1050. // }
  1051. //
  1052. // protected AnnotationTypePattern parseAnnotationTypePattern() {
  1053. // AnnotationTypePattern ap = parseAtomicAnnotationPattern();
  1054. // if (maybeEat("&&")) {
  1055. // ap = new AndAnnotationTypePattern(ap, parseNotOrAnnotationPattern());
  1056. // }
  1057. //
  1058. // if (maybeEat("||")) {
  1059. // ap = new OrAnnotationTypePattern(ap, parseAnnotationTypePattern());
  1060. // }
  1061. // return ap;
  1062. // }
  1063. //
  1064. // private AnnotationTypePattern parseNotOrAnnotationPattern() {
  1065. // AnnotationTypePattern p = parseAtomicAnnotationPattern();
  1066. // if (maybeEat("&&")) {
  1067. // p = new AndAnnotationTypePattern(p,parseAnnotationTypePattern());
  1068. // }
  1069. // return p;
  1070. // }
  1071. protected ExactAnnotationTypePattern parseAnnotationNameOrVarTypePattern() {
  1072. ExactAnnotationTypePattern p = null;
  1073. int startPos = tokenSource.peek().getStart();
  1074. if (maybeEat("@")) {
  1075. throw new ParserException("@Foo form was deprecated in AspectJ 5 M2: annotation name or var ", tokenSource.peek(-1));
  1076. }
  1077. p = parseSimpleAnnotationName();
  1078. int endPos = tokenSource.peek(-1).getEnd();
  1079. p.setLocation(sourceContext, startPos, endPos);
  1080. // For optimized syntax that allows binding directly to annotation values (pr234943)
  1081. if (maybeEat("(")) {
  1082. String formalName = parseIdentifier();
  1083. p = new ExactAnnotationFieldTypePattern(p, formalName);
  1084. eat(")");
  1085. }
  1086. return p;
  1087. }
  1088. /**
  1089. * @return
  1090. */
  1091. private ExactAnnotationTypePattern parseSimpleAnnotationName() {
  1092. // the @ has already been eaten...
  1093. ExactAnnotationTypePattern p;
  1094. StringBuffer annotationName = new StringBuffer();
  1095. annotationName.append(parseIdentifier());
  1096. while (maybeEat(".")) {
  1097. annotationName.append('.');
  1098. annotationName.append(parseIdentifier());
  1099. }
  1100. UnresolvedType type = UnresolvedType.forName(annotationName.toString());
  1101. p = new ExactAnnotationTypePattern(type, null);
  1102. return p;
  1103. }
  1104. // private AnnotationTypePattern parseAtomicAnnotationPattern() {
  1105. // if (maybeEat("!")) {
  1106. // //int startPos = tokenSource.peek(-1).getStart();
  1107. // //??? we lose source location for true start of !type
  1108. // AnnotationTypePattern p = new NotAnnotationTypePattern(parseAtomicAnnotationPattern());
  1109. // return p;
  1110. // }
  1111. // if (maybeEat("(")) {
  1112. // AnnotationTypePattern p = parseAnnotationTypePattern();
  1113. // eat(")");
  1114. // return p;
  1115. // }
  1116. // int startPos = tokenSource.peek().getStart();
  1117. // eat("@");
  1118. // StringBuffer annotationName = new StringBuffer();
  1119. // annotationName.append(parseIdentifier());
  1120. // while (maybeEat(".")) {
  1121. // annotationName.append('.');
  1122. // annotationName.append(parseIdentifier());
  1123. // }
  1124. // UnresolvedType type = UnresolvedType.forName(annotationName.toString());
  1125. // AnnotationTypePattern p = new ExactAnnotationTypePattern(type);
  1126. // int endPos = tokenSource.peek(-1).getEnd();
  1127. // p.setLocation(sourceContext, startPos, endPos);
  1128. // return p;
  1129. // }
  1130. public List<NamePattern> parseDottedNamePattern() {
  1131. List<NamePattern> names = new ArrayList<NamePattern>();
  1132. StringBuffer buf = new StringBuffer();
  1133. IToken previous = null;
  1134. boolean justProcessedEllipsis = false; // Remember if we just dealt with an ellipsis (PR61536)
  1135. boolean justProcessedDot = false;
  1136. boolean onADot = false;
  1137. while (true) {
  1138. IToken tok = null;
  1139. int startPos = tokenSource.peek().getStart();
  1140. String afterDot = null;
  1141. while (true) {
  1142. if (previous != null && previous.getString().equals(".")) {
  1143. justProcessedDot = true;
  1144. }
  1145. tok = tokenSource.peek();
  1146. onADot = (tok.getString().equals("."));
  1147. if (previous != null) {
  1148. if (!isAdjacent(previous, tok)) {
  1149. break;
  1150. }
  1151. }
  1152. if (tok.getString() == "*" || (tok.isIdentifier() && tok.getString() != "...")) {
  1153. buf.append(tok.getString());
  1154. } else if (tok.getString() == "...") {
  1155. break;
  1156. } else if (tok.getLiteralKind() != null) {
  1157. // System.err.println("literal kind: " + tok.getString());
  1158. String s = tok.getString();
  1159. int dot = s.indexOf('.');
  1160. if (dot != -1) {
  1161. buf.append(s.substring(0, dot));
  1162. afterDot = s.substring(dot + 1);
  1163. previous = tokenSource.next();
  1164. break;
  1165. }
  1166. buf.append(s); // ??? so-so
  1167. } else {
  1168. break;
  1169. }
  1170. previous = tokenSource.next();
  1171. // XXX need to handle floats and other fun stuff
  1172. }
  1173. int endPos = tokenSource.peek(-1).getEnd();
  1174. if (buf.length() == 0 && names.isEmpty()) {
  1175. throw new ParserException("name pattern", tok);
  1176. }
  1177. if (buf.length() == 0 && justProcessedEllipsis) {
  1178. throw new ParserException("name pattern cannot finish with ..", tok);
  1179. }
  1180. if (buf.length() == 0 && justProcessedDot && !onADot) {
  1181. throw new ParserException("name pattern cannot finish with .", tok);
  1182. }
  1183. if (buf.length() == 0) {
  1184. names.add(NamePattern.ELLIPSIS);
  1185. justProcessedEllipsis = true;
  1186. } else {
  1187. checkLegalName(buf.toString(), previous);
  1188. NamePattern ret = new NamePattern(buf.toString());
  1189. ret.setLocation(sourceContext, startPos, endPos);
  1190. names.add(ret);
  1191. justProcessedEllipsis = false;
  1192. }
  1193. if (afterDot == null) {
  1194. buf.setLength(0);
  1195. // no elipsis or dotted name part
  1196. if (!maybeEat(".")) {
  1197. break;
  1198. // go on
  1199. } else {
  1200. previous = tokenSource.peek(-1);
  1201. }
  1202. } else {
  1203. buf.setLength(0);
  1204. buf.append(afterDot);
  1205. afterDot = null;
  1206. }
  1207. }
  1208. // System.err.println("parsed: " + names);
  1209. return names;
  1210. }
  1211. // supported form 'a.b.c.d' or just 'a'
  1212. public String parseAnnotationNameValuePattern() {
  1213. StringBuffer buf = new StringBuffer();
  1214. IToken tok;
  1215. // int startPos =
  1216. tokenSource.peek().getStart();
  1217. boolean dotOK = false;
  1218. int depth = 0;
  1219. while (true) {
  1220. tok = tokenSource.peek();
  1221. // keep going until we hit ')' or '=' or ','
  1222. if (tok.getString() == ")" && depth == 0) {
  1223. break;
  1224. }
  1225. if (tok.getString() == "!=" && depth == 0) {
  1226. break;
  1227. }
  1228. if (tok.getString() == "=" && depth == 0) {
  1229. break;
  1230. }
  1231. if (tok.getString() == "," && depth == 0) {
  1232. break;
  1233. }
  1234. if (tok == IToken.EOF) {
  1235. throw new ParserException("eof", tokenSource.peek());
  1236. }
  1237. // keep track of nested brackets
  1238. if (tok.getString() == "(") {
  1239. depth++;
  1240. }
  1241. if (tok.getString() == ")") {
  1242. depth--;
  1243. }
  1244. if (tok.getString() == "{") {
  1245. depth++;
  1246. }
  1247. if (tok.getString() == "}") {
  1248. depth--;
  1249. }
  1250. if (tok.getString() == "." && !dotOK) {
  1251. throw new ParserException("dot not expected", tok);
  1252. }
  1253. buf.append(tok.getString());
  1254. tokenSource.next();
  1255. dotOK = true;
  1256. }
  1257. return buf.toString();
  1258. }
  1259. public NamePattern parseNamePattern() {
  1260. StringBuffer buf = new StringBuffer();
  1261. IToken previous = null;
  1262. IToken tok;
  1263. int startPos = tokenSource.peek().getStart();
  1264. while (true) {
  1265. tok = tokenSource.peek();
  1266. if (previous != null) {
  1267. if (!isAdjacent(previous, tok)) {
  1268. break;
  1269. }
  1270. }
  1271. if (tok.getString() == "*" || tok.isIdentifier()) {
  1272. buf.append(tok.getString());
  1273. } else if (tok.getLiteralKind() != null) {
  1274. // System.err.println("literal kind: " + tok.getString());
  1275. String s = tok.getString();
  1276. if (s.indexOf('.') != -1) {
  1277. break;
  1278. }
  1279. buf.append(s); // ??? so-so
  1280. } else {
  1281. break;
  1282. }
  1283. previous = tokenSource.next();
  1284. // XXX need to handle floats and other fun stuff
  1285. }
  1286. int endPos = tokenSource.peek(-1).getEnd();
  1287. if (buf.length() == 0) {
  1288. throw new ParserException("name pattern", tok);
  1289. }
  1290. checkLegalName(buf.toString(), previous);
  1291. NamePattern ret = new NamePattern(buf.toString());
  1292. ret.setLocation(sourceContext, startPos, endPos);
  1293. return ret;
  1294. }
  1295. private void checkLegalName(String s, IToken tok) {
  1296. char ch = s.charAt(0);
  1297. if (!(ch == '*' || Character.isJavaIdentifierStart(ch))) {
  1298. throw new ParserException("illegal identifier start (" + ch + ")", tok);
  1299. }
  1300. for (int i = 1, len = s.length(); i < len; i++) {
  1301. ch = s.charAt(i);
  1302. if (!(ch == '*' || Character.isJavaIdentifierPart(ch))) {
  1303. throw new ParserException("illegal identifier character (" + ch + ")", tok);
  1304. }
  1305. }
  1306. }
  1307. private boolean isAdjacent(IToken first, IToken second) {
  1308. return first.getEnd() == second.getStart() - 1;
  1309. }
  1310. public ModifiersPattern parseModifiersPattern() {
  1311. int requiredFlags = 0;
  1312. int forbiddenFlags = 0;
  1313. int start;
  1314. while (true) {
  1315. start = tokenSource.getIndex();
  1316. boolean isForbidden = false;
  1317. isForbidden = maybeEat("!");
  1318. IToken t = tokenSource.next();
  1319. int flag = ModifiersPattern.getModifierFlag(t.getString());
  1320. if (flag == -1) {
  1321. break;
  1322. }
  1323. if (isForbidden) {
  1324. forbiddenFlags |= flag;
  1325. } else {
  1326. requiredFlags |= flag;
  1327. }
  1328. }
  1329. tokenSource.setIndex(start);
  1330. if (requiredFlags == 0 && forbiddenFlags == 0) {
  1331. return ModifiersPattern.ANY;
  1332. } else {
  1333. return new ModifiersPattern(requiredFlags, forbiddenFlags);
  1334. }
  1335. }
  1336. public TypePatternList parseArgumentsPattern(boolean parameterAnnotationsPossible) {
  1337. List<TypePattern> patterns = new ArrayList<TypePattern>();
  1338. eat("(");
  1339. // ()
  1340. if (maybeEat(")")) {
  1341. return new TypePatternList();
  1342. }
  1343. do {
  1344. if (maybeEat(".")) { // ..
  1345. eat(".");
  1346. patterns.add(TypePattern.ELLIPSIS);
  1347. } else {
  1348. patterns.add(parseTypePattern(false, parameterAnnotationsPossible));
  1349. }
  1350. } while (maybeEat(","));
  1351. eat(")");
  1352. return new TypePatternList(patterns);
  1353. }
  1354. public AnnotationPatternList parseArgumentsAnnotationPattern() {
  1355. List<AnnotationTypePattern> patterns = new ArrayList<AnnotationTypePattern>();
  1356. eat("(");
  1357. if (maybeEat(")")) {
  1358. return new AnnotationPatternList();
  1359. }
  1360. do {
  1361. if (maybeEat(".")) {
  1362. eat(".");
  1363. patterns.add(AnnotationTypePattern.ELLIPSIS);
  1364. } else if (maybeEat("*")) {
  1365. patterns.add(AnnotationTypePattern.ANY);
  1366. } else {
  1367. patterns.add(parseAnnotationNameOrVarTypePattern());
  1368. }
  1369. } while (maybeEat(","));
  1370. eat(")");
  1371. return new AnnotationPatternList(patterns);
  1372. }
  1373. public ThrowsPattern parseOptionalThrowsPattern() {
  1374. IToken t = tokenSource.peek();
  1375. if (t.isIdentifier() && t.getString().equals("throws")) {
  1376. tokenSource.next();
  1377. List<TypePattern> required = new ArrayList<TypePattern>();
  1378. List<TypePattern> forbidden = new ArrayList<TypePattern>();
  1379. do {
  1380. boolean isForbidden = maybeEat("!");
  1381. // ???might want an error for a second ! without a paren
  1382. TypePattern p = parseTypePattern();
  1383. if (isForbidden) {
  1384. forbidden.add(p);
  1385. } else {
  1386. required.add(p);
  1387. }
  1388. } while (maybeEat(","));
  1389. return new ThrowsPattern(new TypePatternList(required), new TypePatternList(forbidden));
  1390. }
  1391. return ThrowsPattern.ANY;
  1392. }
  1393. public SignaturePattern parseMethodOrConstructorSignaturePattern() {
  1394. int startPos = tokenSource.peek().getStart();
  1395. AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
  1396. ModifiersPattern modifiers = parseModifiersPattern();
  1397. TypePattern returnType = parseTypePattern(false, false);
  1398. TypePattern declaringType;
  1399. NamePattern name = null;
  1400. MemberKind kind;
  1401. // here we can check for 'new'
  1402. if (maybeEatNew(returnType)) {
  1403. kind = Member.CONSTRUCTOR;
  1404. if (returnType.toString().length() == 0) {
  1405. declaringType = TypePattern.ANY;
  1406. } else {
  1407. declaringType = returnType;
  1408. }
  1409. returnType = TypePattern.ANY;
  1410. name = NamePattern.ANY;
  1411. } else {
  1412. kind = Member.METHOD;
  1413. IToken nameToken = tokenSource.peek();
  1414. declaringType = parseTypePattern(false, false);
  1415. if (maybeEat(".")) {
  1416. nameToken = tokenSource.peek();
  1417. name = parseNamePattern();
  1418. } else {
  1419. name = tryToExtractName(declaringType);
  1420. if (declaringType.toString().equals("")) {
  1421. declaringType = TypePattern.ANY;
  1422. }
  1423. }
  1424. if (name == null) {
  1425. throw new ParserException("name pattern", tokenSource.peek());
  1426. }
  1427. String simpleName = name.maybeGetSimpleName();
  1428. // XXX should add check for any Java keywords
  1429. if (simpleName != null && simpleName.equals("new")) {
  1430. throw new ParserException("method name (not constructor)", nameToken);
  1431. }
  1432. }
  1433. TypePatternList parameterTypes = parseArgumentsPattern(true);
  1434. ThrowsPattern throwsPattern = parseOptionalThrowsPattern();
  1435. SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
  1436. throwsPattern, annotationPattern);
  1437. int endPos = tokenSource.peek(-1).getEnd();
  1438. ret.setLocation(sourceContext, startPos, endPos);
  1439. return ret;
  1440. }
  1441. private boolean maybeEatNew(TypePattern returnType) {
  1442. if (returnType instanceof WildTypePattern) {
  1443. WildTypePattern p = (WildTypePattern) returnType;
  1444. if (p.maybeExtractName("new")) {
  1445. return true;
  1446. }
  1447. }
  1448. int start = tokenSource.getIndex();
  1449. if (maybeEat(".")) {
  1450. String id = maybeEatIdentifier();
  1451. if (id != null && id.equals("new")) {
  1452. return true;
  1453. }
  1454. tokenSource.setIndex(start);
  1455. }
  1456. return false;
  1457. }
  1458. public ISignaturePattern parseMaybeParenthesizedFieldSignaturePattern() {
  1459. boolean negated = tokenSource.peek().getString().equals("!") && tokenSource.peek(1).getString().equals("(");
  1460. if (negated) {
  1461. eat("!");
  1462. }
  1463. ISignaturePattern result = null;
  1464. if (maybeEat("(")) {
  1465. result = parseCompoundFieldSignaturePattern();
  1466. eat(")", "missing ')' - unbalanced parentheses around field signature pattern in declare @field");
  1467. if (negated) {
  1468. result = new NotSignaturePattern(result);
  1469. }
  1470. } else {
  1471. result = parseFieldSignaturePattern();
  1472. }
  1473. return result;
  1474. }
  1475. public ISignaturePattern parseMaybeParenthesizedMethodOrConstructorSignaturePattern(boolean isMethod) {
  1476. boolean negated = tokenSource.peek().getString().equals("!") && tokenSource.peek(1).getString().equals("(");
  1477. if (negated) {
  1478. eat("!");
  1479. }
  1480. ISignaturePattern result = null;
  1481. if (maybeEat("(")) {
  1482. result = parseCompoundMethodOrConstructorSignaturePattern(isMethod);
  1483. eat(")", "missing ')' - unbalanced parentheses around method/ctor signature pattern in declare annotation");
  1484. if (negated) {
  1485. result = new NotSignaturePattern(result);
  1486. }
  1487. } else {
  1488. SignaturePattern sp = parseMethodOrConstructorSignaturePattern();
  1489. boolean isConstructorPattern = (sp.getKind() == Member.CONSTRUCTOR);
  1490. if (isMethod && isConstructorPattern) {
  1491. throw new ParserException("method signature pattern", tokenSource.peek(-1));
  1492. }
  1493. if (!isMethod && !isConstructorPattern) {
  1494. throw new ParserException("constructor signature pattern", tokenSource.peek(-1));
  1495. }
  1496. result = sp;
  1497. }
  1498. return result;
  1499. }
  1500. public SignaturePattern parseFieldSignaturePattern() {
  1501. int startPos = tokenSource.peek().getStart();
  1502. // TypePatternList followMe = TypePatternList.ANY;
  1503. AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
  1504. ModifiersPattern modifiers = parseModifiersPattern();
  1505. TypePattern returnType = parseTypePattern();
  1506. TypePattern declaringType = parseTypePattern();
  1507. NamePattern name;
  1508. // System.err.println("parsed field: " + declaringType.toString());
  1509. if (maybeEat(".")) {
  1510. name = parseNamePattern();
  1511. } else {
  1512. name = tryToExtractName(declaringType);
  1513. if (name == null) {
  1514. throw new ParserException("name pattern", tokenSource.peek());
  1515. }
  1516. if (declaringType.toString().equals("")) {
  1517. declaringType = TypePattern.ANY;
  1518. }
  1519. }
  1520. SignaturePattern ret = new SignaturePattern(Member.FIELD, modifiers, returnType, declaringType, name, TypePatternList.ANY,
  1521. ThrowsPattern.ANY, annotationPattern);
  1522. int endPos = tokenSource.peek(-1).getEnd();
  1523. ret.setLocation(sourceContext, startPos, endPos);
  1524. return ret;
  1525. }
  1526. private NamePattern tryToExtractName(TypePattern nextType) {
  1527. if (nextType == TypePattern.ANY) {
  1528. return NamePattern.ANY;
  1529. } else if (nextType instanceof WildTypePattern) {
  1530. WildTypePattern p = (WildTypePattern) nextType;
  1531. return p.extractName();
  1532. } else {
  1533. return null;
  1534. }
  1535. }
  1536. /**
  1537. * Parse type variable declarations for a generic method or at the start of a signature pointcut to identify type variable names
  1538. * in a generic type.
  1539. *
  1540. * @param includeParameterizedTypes
  1541. * @return
  1542. */
  1543. public TypeVariablePatternList maybeParseTypeVariableList() {
  1544. if (!maybeEat("<")) {
  1545. return null;
  1546. }
  1547. List<TypeVariablePattern> typeVars = new ArrayList<TypeVariablePattern>();
  1548. TypeVariablePattern t = parseTypeVariable();
  1549. typeVars.add(t);
  1550. while (maybeEat(",")) {
  1551. TypeVariablePattern nextT = parseTypeVariable();
  1552. typeVars.add(nextT);
  1553. }
  1554. eat(">");
  1555. TypeVariablePattern[] tvs = new TypeVariablePattern[typeVars.size()];
  1556. typeVars.toArray(tvs);
  1557. return new TypeVariablePatternList(tvs);
  1558. }
  1559. // of the form execution<T,S,V> - allows identifiers only
  1560. public String[] maybeParseSimpleTypeVariableList() {
  1561. if (!maybeEat("<")) {
  1562. return null;
  1563. }
  1564. List<String> typeVarNames = new ArrayList<String>();
  1565. do {
  1566. typeVarNames.add(parseIdentifier());
  1567. } while (maybeEat(","));
  1568. eat(">", "',' or '>'");
  1569. String[] tvs = new String[typeVarNames.size()];
  1570. typeVarNames.toArray(tvs);
  1571. return tvs;
  1572. }
  1573. public TypePatternList maybeParseTypeParameterList() {
  1574. if (!maybeEat("<")) {
  1575. return null;
  1576. }
  1577. List<TypePattern> typePats = new ArrayList<TypePattern>();
  1578. do {
  1579. TypePattern tp = parseTypePattern(true, false);
  1580. typePats.add(tp);
  1581. } while (maybeEat(","));
  1582. eat(">");
  1583. TypePattern[] tps = new TypePattern[typePats.size()];
  1584. typePats.toArray(tps);
  1585. return new TypePatternList(tps);
  1586. }
  1587. public TypeVariablePattern parseTypeVariable() {
  1588. TypePattern upperBound = null;
  1589. TypePattern[] additionalInterfaceBounds = null;
  1590. TypePattern lowerBound = null;
  1591. String typeVariableName = parseIdentifier();
  1592. if (maybeEatIdentifier("extends")) {
  1593. upperBound = parseTypePattern();
  1594. additionalInterfaceBounds = maybeParseAdditionalInterfaceBounds();
  1595. } else if (maybeEatIdentifier("super")) {
  1596. lowerBound = parseTypePattern();
  1597. }
  1598. return new TypeVariablePattern(typeVariableName, upperBound, additionalInterfaceBounds, lowerBound);
  1599. }
  1600. private TypePattern[] maybeParseAdditionalInterfaceBounds() {
  1601. List<TypePattern> boundsList = new ArrayList<TypePattern>();
  1602. while (maybeEat("&")) {
  1603. TypePattern tp = parseTypePattern();
  1604. boundsList.add(tp);
  1605. }
  1606. if (boundsList.size() == 0) {
  1607. return null;
  1608. }
  1609. TypePattern[] ret = new TypePattern[boundsList.size()];
  1610. boundsList.toArray(ret);
  1611. return ret;
  1612. }
  1613. public String parsePossibleStringSequence(boolean shouldEnd) {
  1614. StringBuffer result = new StringBuffer();
  1615. IToken token = tokenSource.next();
  1616. if (token.getLiteralKind() == null) {
  1617. throw new ParserException("string", token);
  1618. }
  1619. while (token.getLiteralKind().equals("string")) {
  1620. result.append(token.getString());
  1621. boolean plus = maybeEat("+");
  1622. if (!plus) {
  1623. break;
  1624. }
  1625. token = tokenSource.next();
  1626. if (token.getLiteralKind() == null) {
  1627. throw new ParserException("string", token);
  1628. }
  1629. }
  1630. eatIdentifier(";");
  1631. IToken t = tokenSource.next();
  1632. if (shouldEnd && t != IToken.EOF) {
  1633. throw new ParserException("<string>;", token);
  1634. }
  1635. // bug 125027: since we've eaten the ";" we need to set the index
  1636. // to be one less otherwise the end position isn't set correctly.
  1637. int currentIndex = tokenSource.getIndex();
  1638. tokenSource.setIndex(currentIndex - 1);
  1639. return result.toString();
  1640. }
  1641. public String parseStringLiteral() {
  1642. IToken token = tokenSource.next();
  1643. String literalKind = token.getLiteralKind();
  1644. if (literalKind == "string") {
  1645. return token.getString();
  1646. }
  1647. throw new ParserException("string", token);
  1648. }
  1649. public String parseIdentifier() {
  1650. IToken token = tokenSource.next();
  1651. if (token.isIdentifier()) {
  1652. return token.getString();
  1653. }
  1654. throw new ParserException("identifier", token);
  1655. }
  1656. public void eatIdentifier(String expectedValue) {
  1657. IToken next = tokenSource.next();
  1658. if (!next.getString().equals(expectedValue)) {
  1659. throw new ParserException(expectedValue, next);
  1660. }
  1661. }
  1662. public boolean maybeEatIdentifier(String expectedValue) {
  1663. IToken next = tokenSource.peek();
  1664. if (next.getString().equals(expectedValue)) {
  1665. tokenSource.next();
  1666. return true;
  1667. } else {
  1668. return false;
  1669. }
  1670. }
  1671. public void eat(String expectedValue) {
  1672. eat(expectedValue, expectedValue);
  1673. }
  1674. private void eat(String expectedValue, String expectedMessage) {
  1675. IToken next = nextToken();
  1676. if (next.getString() != expectedValue) {
  1677. if (expectedValue.equals(">") && next.getString().startsWith(">")) {
  1678. // handle problem of >> and >>> being lexed as single tokens
  1679. pendingRightArrows = BasicToken.makeLiteral(next.getString().substring(1).intern(), "string", next.getStart() + 1,
  1680. next.getEnd());
  1681. return;
  1682. }
  1683. throw new ParserException(expectedMessage, next);
  1684. }
  1685. }
  1686. private IToken pendingRightArrows;
  1687. private IToken nextToken() {
  1688. if (pendingRightArrows != null) {
  1689. IToken ret = pendingRightArrows;
  1690. pendingRightArrows = null;
  1691. return ret;
  1692. } else {
  1693. return tokenSource.next();
  1694. }
  1695. }
  1696. public boolean maybeEatAdjacent(String token) {
  1697. IToken next = tokenSource.peek();
  1698. if (next.getString() == token) {
  1699. if (isAdjacent(tokenSource.peek(-1), next)) {
  1700. tokenSource.next();
  1701. return true;
  1702. }
  1703. }
  1704. return false;
  1705. }
  1706. public boolean maybeEat(String token) {
  1707. IToken next = tokenSource.peek();
  1708. if (next.getString() == token) {
  1709. tokenSource.next();
  1710. return true;
  1711. } else {
  1712. return false;
  1713. }
  1714. }
  1715. public String maybeEatIdentifier() {
  1716. IToken next = tokenSource.peek();
  1717. if (next.isIdentifier()) {
  1718. tokenSource.next();
  1719. return next.getString();
  1720. } else {
  1721. return null;
  1722. }
  1723. }
  1724. public boolean peek(String token) {
  1725. IToken next = tokenSource.peek();
  1726. return next.getString() == token;
  1727. }
  1728. public void checkEof() {
  1729. IToken last = tokenSource.next();
  1730. if (last != IToken.EOF) {
  1731. throw new ParserException("unexpected pointcut element: " + last.toString(), last);
  1732. }
  1733. }
  1734. public PatternParser(String data) {
  1735. this(BasicTokenSource.makeTokenSource(data, null));
  1736. }
  1737. public PatternParser(String data, ISourceContext context) {
  1738. this(BasicTokenSource.makeTokenSource(data, context));
  1739. }
  1740. }