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 33KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.patterns;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. import org.aspectj.weaver.ISourceContext;
  16. import org.aspectj.weaver.Member;
  17. import org.aspectj.weaver.Shadow;
  18. import org.aspectj.weaver.TypeX;
  19. //XXX doesn't handle errors for extra tokens very well (sometimes ignores)
  20. public class PatternParser {
  21. private ITokenSource tokenSource;
  22. private ISourceContext sourceContext;
  23. /**
  24. * Constructor for PatternParser.
  25. */
  26. public PatternParser(ITokenSource tokenSource) {
  27. super();
  28. this.tokenSource = tokenSource;
  29. this.sourceContext = tokenSource.getSourceContext();
  30. }
  31. public PerClause maybeParsePerClause() {
  32. IToken tok = tokenSource.peek();
  33. if (tok == IToken.EOF) return null;
  34. if (tok.isIdentifier()) {
  35. String name = tok.getString();
  36. if (name.equals("issingleton")) {
  37. return parsePerSingleton();
  38. } else if (name.equals("perthis")) {
  39. return parsePerObject(true);
  40. } else if (name.equals("pertarget")) {
  41. return parsePerObject(false);
  42. } else if (name.equals("percflow")) {
  43. return parsePerCflow(false);
  44. } else if (name.equals("percflowbelow")) {
  45. return parsePerCflow(true);
  46. } else if (name.equals("pertypewithin")) { // PTWIMPL Parse the pertypewithin clause
  47. return parsePerTypeWithin();
  48. } else {
  49. return null;
  50. }
  51. }
  52. return null;
  53. }
  54. private PerClause parsePerCflow(boolean isBelow) {
  55. parseIdentifier();
  56. eat("(");
  57. Pointcut entry = parsePointcut();
  58. eat(")");
  59. return new PerCflow(entry, isBelow);
  60. }
  61. private PerClause parsePerObject(boolean isThis) {
  62. parseIdentifier();
  63. eat("(");
  64. Pointcut entry = parsePointcut();
  65. eat(")");
  66. return new PerObject(entry, isThis);
  67. }
  68. private PerClause parsePerTypeWithin() {
  69. parseIdentifier();
  70. eat("(");
  71. TypePattern withinTypePattern = parseTypePattern();
  72. eat(")");
  73. return new PerTypeWithin(withinTypePattern);
  74. }
  75. private PerClause parsePerSingleton() {
  76. parseIdentifier();
  77. eat("(");
  78. eat(")");
  79. return new PerSingleton();
  80. }
  81. public Declare parseDeclare() {
  82. int startPos = tokenSource.peek().getStart();
  83. eatIdentifier("declare");
  84. String kind = parseIdentifier();
  85. eat(":");
  86. Declare ret;
  87. if (kind.equals("error")) {
  88. ret = parseErrorOrWarning(true);
  89. } else if (kind.equals("warning")) {
  90. ret = parseErrorOrWarning(false);
  91. } else if (kind.equals("precedence")) {
  92. ret = parseDominates();
  93. } else if (kind.equals("dominates")) {
  94. throw new ParserException("name changed to declare precedence", tokenSource.peek(-2));
  95. } else if (kind.equals("parents")) {
  96. ret = parseParents();
  97. } else if (kind.equals("soft")) {
  98. ret = parseSoft();
  99. } else {
  100. throw new ParserException("expected one of error, warning, parents, soft, dominates",
  101. tokenSource.peek(-1));
  102. }
  103. int endPos = tokenSource.peek(-1).getEnd();
  104. ret.setLocation(sourceContext, startPos, endPos);
  105. return ret;
  106. }
  107. public Declare parseDeclareAnnotation() {
  108. int startPos = tokenSource.peek().getStart();
  109. eatIdentifier("declare");
  110. eat("@");
  111. String kind = parseIdentifier();
  112. eat(":");
  113. Declare ret;
  114. if (kind.equals("type")) {
  115. ret = parseDeclareAtType();
  116. } else if (kind.equals("method")) {
  117. ret = parseDeclareAtMethod(true);
  118. } else if (kind.equals("field")) {
  119. ret = parseDeclareAtField();
  120. } else if (kind.equals("constructor")) {
  121. ret = parseDeclareAtMethod(false);
  122. } else {
  123. throw new ParserException("expected one of type, method, field, constructor",
  124. tokenSource.peek(-1));
  125. }
  126. eat(";");
  127. int endPos = tokenSource.peek(-1).getEnd();
  128. ret.setLocation(sourceContext, startPos, endPos);
  129. return ret;
  130. }
  131. public DeclareAnnotation parseDeclareAtType() {
  132. return new DeclareAnnotation("type",parseTypePattern());
  133. }
  134. public DeclareAnnotation parseDeclareAtMethod(boolean isMethod) {
  135. SignaturePattern sp = parseMethodOrConstructorSignaturePattern();
  136. boolean isConstructorPattern = (sp.getKind() == Member.CONSTRUCTOR);
  137. if (isMethod && isConstructorPattern) {
  138. throw new ParserException("method signature pattern",tokenSource.peek(-1));
  139. }
  140. if (!isMethod && !isConstructorPattern) {
  141. throw new ParserException("constructor signature pattern",tokenSource.peek(-1));
  142. }
  143. return new DeclareAnnotation("method",sp); // sp itself differentiates...
  144. }
  145. public DeclareAnnotation parseDeclareAtField() {
  146. return new DeclareAnnotation("field",parseFieldSignaturePattern());
  147. }
  148. public DeclarePrecedence parseDominates() {
  149. List l = new ArrayList();
  150. do {
  151. l.add(parseTypePattern());
  152. } while (maybeEat(","));
  153. return new DeclarePrecedence(l);
  154. }
  155. private Declare parseParents() {
  156. TypePattern p = parseTypePattern();
  157. IToken t = tokenSource.next();
  158. if (!(t.getString().equals("extends") || t.getString().equals("implements"))) {
  159. throw new ParserException("extends or implements", t);
  160. }
  161. List l = new ArrayList();
  162. do {
  163. l.add(parseTypePattern());
  164. } while (maybeEat(","));
  165. //XXX somewhere in the chain we need to enforce that we have only ExactTypePatterns
  166. return new DeclareParents(p, l);
  167. }
  168. private Declare parseSoft() {
  169. TypePattern p = parseTypePattern();
  170. eat(":");
  171. Pointcut pointcut = parsePointcut();
  172. return new DeclareSoft(p, pointcut);
  173. }
  174. private Declare parseErrorOrWarning(boolean isError) {
  175. Pointcut pointcut = parsePointcut();
  176. eat(":");
  177. String message = parsePossibleStringSequence(true);
  178. return new DeclareErrorOrWarning(isError, pointcut, message);
  179. }
  180. public Pointcut parsePointcut() {
  181. Pointcut p = parseAtomicPointcut();
  182. if (maybeEat("&&")) {
  183. p = new AndPointcut(p, parseNotOrPointcut());
  184. }
  185. if (maybeEat("||")) {
  186. p = new OrPointcut(p, parsePointcut());
  187. }
  188. return p;
  189. }
  190. private Pointcut parseNotOrPointcut() {
  191. Pointcut p = parseAtomicPointcut();
  192. if (maybeEat("&&")) {
  193. p = new AndPointcut(p, parsePointcut());
  194. }
  195. return p;
  196. }
  197. private Pointcut parseAtomicPointcut() {
  198. if (maybeEat("!")) {
  199. int startPos = tokenSource.peek(-1).getStart();
  200. Pointcut p = new NotPointcut(parseAtomicPointcut(), startPos);
  201. return p;
  202. }
  203. if (maybeEat("(")) {
  204. Pointcut p = parsePointcut();
  205. eat(")");
  206. return p;
  207. }
  208. if (maybeEat("@")) {
  209. int startPos = tokenSource.peek().getStart();
  210. Pointcut p = parseAnnotationPointcut();
  211. int endPos = tokenSource.peek(-1).getEnd();
  212. p.setLocation(sourceContext, startPos, endPos);
  213. return p;
  214. }
  215. int startPos = tokenSource.peek().getStart();
  216. Pointcut p = parseSinglePointcut();
  217. int endPos = tokenSource.peek(-1).getEnd();
  218. p.setLocation(sourceContext, startPos, endPos);
  219. return p;
  220. }
  221. public Pointcut parseSinglePointcut() {
  222. int start = tokenSource.getIndex();
  223. IToken t = tokenSource.peek();
  224. Pointcut p = t.maybeGetParsedPointcut();
  225. if (p != null) {
  226. tokenSource.next();
  227. return p;
  228. }
  229. String kind = parseIdentifier();
  230. tokenSource.setIndex(start);
  231. if (kind.equals("execution") || kind.equals("call") ||
  232. kind.equals("get") || kind.equals("set")) {
  233. return parseKindedPointcut();
  234. } else if (kind.equals("args")) {
  235. return parseArgsPointcut();
  236. } else if (kind.equals("this") || kind.equals("target")) {
  237. return parseThisOrTargetPointcut();
  238. } else if (kind.equals("within")) {
  239. return parseWithinPointcut();
  240. } else if (kind.equals("withincode")) {
  241. return parseWithinCodePointcut();
  242. } else if (kind.equals("cflow")) {
  243. return parseCflowPointcut(false);
  244. } else if (kind.equals("cflowbelow")) {
  245. return parseCflowPointcut(true);
  246. } else if (kind.equals("adviceexecution")) {
  247. parseIdentifier(); eat("(");
  248. eat(")");
  249. return new KindedPointcut(Shadow.AdviceExecution,
  250. new SignaturePattern(Member.ADVICE, ModifiersPattern.ANY,
  251. TypePattern.ANY, TypePattern.ANY, NamePattern.ANY,
  252. TypePatternList.ANY,
  253. ThrowsPattern.ANY,
  254. AnnotationTypePattern.ANY));
  255. } else if (kind.equals("handler")) {
  256. parseIdentifier(); eat("(");
  257. TypePattern typePat = parseTypePattern();
  258. eat(")");
  259. return new HandlerPointcut(typePat);
  260. } else if (kind.equals("initialization")) {
  261. parseIdentifier(); eat("(");
  262. SignaturePattern sig = parseConstructorSignaturePattern();
  263. eat(")");
  264. return new KindedPointcut(Shadow.Initialization, sig);
  265. } else if (kind.equals("staticinitialization")) {
  266. parseIdentifier(); eat("(");
  267. TypePattern typePat = parseTypePattern();
  268. eat(")");
  269. return new KindedPointcut(Shadow.StaticInitialization,
  270. new SignaturePattern(Member.STATIC_INITIALIZATION, ModifiersPattern.ANY,
  271. TypePattern.ANY, typePat, NamePattern.ANY, TypePatternList.EMPTY,
  272. ThrowsPattern.ANY,AnnotationTypePattern.ANY));
  273. } else if (kind.equals("preinitialization")) {
  274. parseIdentifier(); eat("(");
  275. SignaturePattern sig = parseConstructorSignaturePattern();
  276. eat(")");
  277. return new KindedPointcut(Shadow.PreInitialization, sig);
  278. } else {
  279. return parseReferencePointcut();
  280. }
  281. }
  282. public Pointcut parseAnnotationPointcut() {
  283. int start = tokenSource.getIndex();
  284. IToken t = tokenSource.peek();
  285. String kind = parseIdentifier();
  286. tokenSource.setIndex(start);
  287. if (kind.equals("annotation")) {
  288. return parseAtAnnotationPointcut();
  289. } else if (kind.equals("args")) {
  290. return parseArgsAnnotationPointcut();
  291. } else if (kind.equals("this") || kind.equals("target")) {
  292. return parseThisOrTargetAnnotationPointcut();
  293. } else if (kind.equals("within")) {
  294. return parseWithinAnnotationPointcut();
  295. } else if (kind.equals("withincode")) {
  296. return parseWithinCodeAnnotationPointcut();
  297. } throw new ParserException("@pointcut name expected, but found " + kind, t);
  298. }
  299. private Pointcut parseAtAnnotationPointcut() {
  300. parseIdentifier();
  301. eat("(");
  302. if (maybeEat(")")) {
  303. throw new ParserException("@AnnotationName or parameter", tokenSource.peek());
  304. }
  305. ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
  306. eat(")");
  307. return new AnnotationPointcut(type);
  308. }
  309. private SignaturePattern parseConstructorSignaturePattern() {
  310. SignaturePattern ret = parseMethodOrConstructorSignaturePattern();
  311. if (ret.getKind() == Member.CONSTRUCTOR) return ret;
  312. throw new ParserException("constructor pattern required, found method pattern",
  313. ret);
  314. }
  315. private Pointcut parseWithinCodePointcut() {
  316. parseIdentifier();
  317. eat("(");
  318. SignaturePattern sig = parseMethodOrConstructorSignaturePattern();
  319. eat(")");
  320. return new WithincodePointcut(sig);
  321. }
  322. private Pointcut parseCflowPointcut(boolean isBelow) {
  323. parseIdentifier();
  324. eat("(");
  325. Pointcut entry = parsePointcut();
  326. eat(")");
  327. return new CflowPointcut(entry, isBelow, null);
  328. }
  329. /**
  330. * Method parseWithinPointcut.
  331. * @return Pointcut
  332. */
  333. private Pointcut parseWithinPointcut() {
  334. parseIdentifier();
  335. eat("(");
  336. TypePattern type = parseTypePattern();
  337. eat(")");
  338. return new WithinPointcut(type);
  339. }
  340. /**
  341. * Method parseThisOrTargetPointcut.
  342. * @return Pointcut
  343. */
  344. private Pointcut parseThisOrTargetPointcut() {
  345. String kind = parseIdentifier();
  346. eat("(");
  347. TypePattern type = parseTypePattern();
  348. eat(")");
  349. return new ThisOrTargetPointcut(kind.equals("this"), type);
  350. }
  351. private Pointcut parseThisOrTargetAnnotationPointcut() {
  352. String kind = parseIdentifier();
  353. eat("(");
  354. if (maybeEat(")")) {
  355. throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
  356. }
  357. ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
  358. eat(")");
  359. return new ThisOrTargetAnnotationPointcut(kind.equals("this"),type);
  360. }
  361. private Pointcut parseWithinAnnotationPointcut() {
  362. String kind = parseIdentifier();
  363. eat("(");
  364. if (maybeEat(")")) {
  365. throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
  366. }
  367. AnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
  368. eat(")");
  369. return new WithinAnnotationPointcut(type);
  370. }
  371. private Pointcut parseWithinCodeAnnotationPointcut() {
  372. String kind = parseIdentifier();
  373. eat("(");
  374. if (maybeEat(")")) {
  375. throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
  376. }
  377. ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
  378. eat(")");
  379. return new WithinCodeAnnotationPointcut(type);
  380. }
  381. /**
  382. * Method parseArgsPointcut.
  383. * @return Pointcut
  384. */
  385. private Pointcut parseArgsPointcut() {
  386. parseIdentifier();
  387. TypePatternList arguments = parseArgumentsPattern();
  388. return new ArgsPointcut(arguments);
  389. }
  390. private Pointcut parseArgsAnnotationPointcut() {
  391. parseIdentifier();
  392. AnnotationPatternList arguments = parseArgumentsAnnotationPattern();
  393. return new ArgsAnnotationPointcut(arguments);
  394. }
  395. private Pointcut parseReferencePointcut() {
  396. TypePattern onType = parseTypePattern();
  397. NamePattern name = tryToExtractName(onType);
  398. if (name == null) {
  399. throw new ParserException("name pattern", tokenSource.peek());
  400. }
  401. if (onType.toString().equals("")) {
  402. onType = null;
  403. }
  404. TypePatternList arguments = parseArgumentsPattern();
  405. return new ReferencePointcut(onType, name.maybeGetSimpleName(), arguments);
  406. }
  407. public List parseDottedIdentifier() {
  408. List ret = new ArrayList();
  409. ret.add(parseIdentifier());
  410. while (maybeEat(".")) {
  411. ret.add(parseIdentifier());
  412. }
  413. return ret;
  414. }
  415. private KindedPointcut parseKindedPointcut() {
  416. String kind = parseIdentifier();
  417. eat("(");
  418. SignaturePattern sig;
  419. Shadow.Kind shadowKind = null;
  420. if (kind.equals("execution")) {
  421. sig = parseMethodOrConstructorSignaturePattern();
  422. if (sig.getKind() == Member.METHOD) {
  423. shadowKind = Shadow.MethodExecution;
  424. } else if (sig.getKind() == Member.CONSTRUCTOR) {
  425. shadowKind = Shadow.ConstructorExecution;
  426. }
  427. } else if (kind.equals("call")) {
  428. sig = parseMethodOrConstructorSignaturePattern();
  429. if (sig.getKind() == Member.METHOD) {
  430. shadowKind = Shadow.MethodCall;
  431. } else if (sig.getKind() == Member.CONSTRUCTOR) {
  432. shadowKind = Shadow.ConstructorCall;
  433. }
  434. } else if (kind.equals("get")) {
  435. sig = parseFieldSignaturePattern();
  436. shadowKind = Shadow.FieldGet;
  437. } else if (kind.equals("set")) {
  438. sig = parseFieldSignaturePattern();
  439. shadowKind = Shadow.FieldSet;
  440. } else {
  441. throw new ParserException("bad kind: " + kind, tokenSource.peek());
  442. }
  443. eat(")");
  444. return new KindedPointcut(shadowKind, sig);
  445. }
  446. public TypePattern parseTypePattern() {
  447. TypePattern p = parseAtomicTypePattern();
  448. if (maybeEat("&&")) {
  449. p = new AndTypePattern(p, parseNotOrTypePattern());
  450. }
  451. if (maybeEat("||")) {
  452. p = new OrTypePattern(p, parseTypePattern());
  453. }
  454. return p;
  455. }
  456. private TypePattern parseNotOrTypePattern() {
  457. TypePattern p = parseAtomicTypePattern();
  458. if (maybeEat("&&")) {
  459. p = new AndTypePattern(p, parseTypePattern());
  460. }
  461. return p;
  462. }
  463. private TypePattern parseAtomicTypePattern() {
  464. AnnotationTypePattern ap = maybeParseAnnotationPattern();
  465. if (maybeEat("!")) {
  466. //int startPos = tokenSource.peek(-1).getStart();
  467. //??? we lose source location for true start of !type
  468. TypePattern p = new NotTypePattern(parseAtomicTypePattern());
  469. p = setAnnotationPatternForTypePattern(p,ap);
  470. return p;
  471. }
  472. if (maybeEat("(")) {
  473. TypePattern p = parseTypePattern();
  474. p = setAnnotationPatternForTypePattern(p,ap);
  475. eat(")");
  476. return p;
  477. }
  478. int startPos = tokenSource.peek().getStart();
  479. TypePattern p = parseSingleTypePattern();
  480. int endPos = tokenSource.peek(-1).getEnd();
  481. p = setAnnotationPatternForTypePattern(p,ap);
  482. p.setLocation(sourceContext, startPos, endPos);
  483. return p;
  484. }
  485. private TypePattern setAnnotationPatternForTypePattern(TypePattern t, AnnotationTypePattern ap) {
  486. TypePattern ret = t;
  487. if (ap != AnnotationTypePattern.ANY) {
  488. if (t == TypePattern.ANY) {
  489. ret = new WildTypePattern(new NamePattern[] {NamePattern.ANY},false,0,false);
  490. }
  491. if (t.annotationPattern == AnnotationTypePattern.ANY) {
  492. ret.setAnnotationTypePattern(ap);
  493. } else {
  494. ret.setAnnotationTypePattern(new AndAnnotationTypePattern(ap,t.annotationPattern)); //???
  495. }
  496. }
  497. return ret;
  498. }
  499. public AnnotationTypePattern maybeParseAnnotationPattern() {
  500. AnnotationTypePattern ret = AnnotationTypePattern.ANY;
  501. AnnotationTypePattern nextPattern = null;
  502. while ((nextPattern = maybeParseSingleAnnotationPattern()) != null) {
  503. if (ret == AnnotationTypePattern.ANY) {
  504. ret = nextPattern;
  505. } else {
  506. ret = new AndAnnotationTypePattern(ret,nextPattern);
  507. }
  508. }
  509. return ret;
  510. }
  511. public AnnotationTypePattern maybeParseSingleAnnotationPattern() {
  512. AnnotationTypePattern ret = null;
  513. // LALR(2) - fix by making "!@" a single token
  514. int startIndex = tokenSource.getIndex();
  515. if (maybeEat("!")) {
  516. if (maybeEat("@")) {
  517. if (maybeEat("(")) {
  518. TypePattern p = parseTypePattern();
  519. ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
  520. eat(")");
  521. return ret;
  522. } else {
  523. TypePattern p = parseSingleTypePattern();
  524. ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
  525. return ret;
  526. }
  527. } else {
  528. tokenSource.setIndex(startIndex); // not for us!
  529. return ret;
  530. }
  531. }
  532. if (maybeEat("@")) {
  533. if (maybeEat("(")) {
  534. TypePattern p = parseTypePattern();
  535. ret = new WildAnnotationTypePattern(p);
  536. eat(")");
  537. return ret;
  538. } else {
  539. TypePattern p = parseSingleTypePattern();
  540. ret = new WildAnnotationTypePattern(p);
  541. return ret;
  542. }
  543. } else {
  544. tokenSource.setIndex(startIndex); // not for us!
  545. return ret;
  546. }
  547. }
  548. public TypePattern parseSingleTypePattern() {
  549. List names = parseDottedNamePattern();
  550. // new ArrayList();
  551. // NamePattern p1 = parseNamePattern();
  552. // names.add(p1);
  553. // while (maybeEat(".")) {
  554. // if (maybeEat(".")) {
  555. // names.add(NamePattern.ELLIPSIS);
  556. // }
  557. // NamePattern p2 = parseNamePattern();
  558. // names.add(p2);
  559. // }
  560. int dim = 0;
  561. while (maybeEat("[")) {
  562. eat("]");
  563. dim++;
  564. }
  565. boolean isVarArgs = maybeEat("...");
  566. boolean includeSubtypes = maybeEat("+");
  567. int endPos = tokenSource.peek(-1).getEnd();
  568. //??? what about the source location of any's????
  569. if (names.size() == 1 && ((NamePattern)names.get(0)).isAny() && dim == 0) return TypePattern.ANY;
  570. // Notice we increase the dimensions if varargs is set. this is to allow type matching to
  571. // succeed later: The actual signature at runtime of a method declared varargs is an array type of
  572. // the original declared type (so Integer... becomes Integer[] in the bytecode). So, here for the
  573. // pattern 'Integer...' we create a WildTypePattern 'Integer[]' with varargs set. If this matches
  574. // during shadow matching, we confirm that the varargs flags match up before calling it a successful
  575. // match.
  576. return new WildTypePattern(names, includeSubtypes, dim+(isVarArgs?1:0), endPos,isVarArgs);
  577. }
  578. // private AnnotationTypePattern completeAnnotationPattern(AnnotationTypePattern p) {
  579. // if (maybeEat("&&")) {
  580. // return new AndAnnotationTypePattern(p,parseNotOrAnnotationPattern());
  581. // }
  582. // if (maybeEat("||")) {
  583. // return new OrAnnotationTypePattern(p,parseAnnotationTypePattern());
  584. // }
  585. // return p;
  586. // }
  587. //
  588. // protected AnnotationTypePattern parseAnnotationTypePattern() {
  589. // AnnotationTypePattern ap = parseAtomicAnnotationPattern();
  590. // if (maybeEat("&&")) {
  591. // ap = new AndAnnotationTypePattern(ap, parseNotOrAnnotationPattern());
  592. // }
  593. //
  594. // if (maybeEat("||")) {
  595. // ap = new OrAnnotationTypePattern(ap, parseAnnotationTypePattern());
  596. // }
  597. // return ap;
  598. // }
  599. //
  600. // private AnnotationTypePattern parseNotOrAnnotationPattern() {
  601. // AnnotationTypePattern p = parseAtomicAnnotationPattern();
  602. // if (maybeEat("&&")) {
  603. // p = new AndAnnotationTypePattern(p,parseAnnotationTypePattern());
  604. // }
  605. // return p;
  606. // }
  607. protected ExactAnnotationTypePattern parseAnnotationNameOrVarTypePattern() {
  608. ExactAnnotationTypePattern p = null;
  609. int startPos = tokenSource.peek().getStart();
  610. if (maybeEat("@")) {
  611. p = parseSimpleAnnotationName();
  612. } else {
  613. String formal = parseIdentifier();
  614. p = new ExactAnnotationTypePattern(formal); // will get replaced when bindings resolved
  615. }
  616. int endPos = tokenSource.peek(-1).getEnd();
  617. p.setLocation(sourceContext,startPos,endPos);
  618. return p;
  619. }
  620. /**
  621. * @return
  622. */
  623. private ExactAnnotationTypePattern parseSimpleAnnotationName() {
  624. // the @ has already been eaten...
  625. ExactAnnotationTypePattern p;
  626. StringBuffer annotationName = new StringBuffer();
  627. annotationName.append(parseIdentifier());
  628. while (maybeEat(".")) {
  629. annotationName.append('.');
  630. annotationName.append(parseIdentifier());
  631. }
  632. TypeX type = TypeX.forName(annotationName.toString());
  633. p = new ExactAnnotationTypePattern(type);
  634. return p;
  635. }
  636. // private AnnotationTypePattern parseAtomicAnnotationPattern() {
  637. // if (maybeEat("!")) {
  638. // //int startPos = tokenSource.peek(-1).getStart();
  639. // //??? we lose source location for true start of !type
  640. // AnnotationTypePattern p = new NotAnnotationTypePattern(parseAtomicAnnotationPattern());
  641. // return p;
  642. // }
  643. // if (maybeEat("(")) {
  644. // AnnotationTypePattern p = parseAnnotationTypePattern();
  645. // eat(")");
  646. // return p;
  647. // }
  648. // int startPos = tokenSource.peek().getStart();
  649. // eat("@");
  650. // StringBuffer annotationName = new StringBuffer();
  651. // annotationName.append(parseIdentifier());
  652. // while (maybeEat(".")) {
  653. // annotationName.append('.');
  654. // annotationName.append(parseIdentifier());
  655. // }
  656. // TypeX type = TypeX.forName(annotationName.toString());
  657. // AnnotationTypePattern p = new ExactAnnotationTypePattern(type);
  658. // int endPos = tokenSource.peek(-1).getEnd();
  659. // p.setLocation(sourceContext, startPos, endPos);
  660. // return p;
  661. // }
  662. private boolean isAnnotationPattern(PatternNode p) {
  663. return (p instanceof AnnotationTypePattern);
  664. }
  665. public List parseDottedNamePattern() {
  666. List names = new ArrayList();
  667. StringBuffer buf = new StringBuffer();
  668. IToken previous = null;
  669. boolean justProcessedEllipsis = false; // Remember if we just dealt with an ellipsis (PR61536)
  670. boolean justProcessedDot = false;
  671. boolean onADot = false;
  672. while (true) {
  673. IToken tok = null;
  674. int startPos = tokenSource.peek().getStart();
  675. String afterDot = null;
  676. while (true) {
  677. if (previous !=null && previous.getString().equals(".")) justProcessedDot = true;
  678. tok = tokenSource.peek();
  679. onADot = (tok.getString().equals("."));
  680. if (previous != null) {
  681. if (!isAdjacent(previous, tok)) break;
  682. }
  683. if (tok.getString() == "*" || tok.isIdentifier()) {
  684. buf.append(tok.getString());
  685. } else if (tok.getLiteralKind() != null) {
  686. //System.err.println("literal kind: " + tok.getString());
  687. String s = tok.getString();
  688. int dot = s.indexOf('.');
  689. if (dot != -1) {
  690. buf.append(s.substring(0, dot));
  691. afterDot = s.substring(dot+1);
  692. previous = tokenSource.next();
  693. break;
  694. }
  695. buf.append(s); // ??? so-so
  696. } else {
  697. break;
  698. }
  699. previous = tokenSource.next();
  700. //XXX need to handle floats and other fun stuff
  701. }
  702. int endPos = tokenSource.peek(-1).getEnd();
  703. if (buf.length() == 0 && names.isEmpty()) {
  704. throw new ParserException("name pattern", tok);
  705. }
  706. if (buf.length() == 0 && justProcessedEllipsis) {
  707. throw new ParserException("name pattern cannot finish with ..", tok);
  708. }
  709. if (buf.length() == 0 && justProcessedDot && !onADot) {
  710. throw new ParserException("name pattern cannot finish with .", tok);
  711. }
  712. if (buf.length() == 0) {
  713. names.add(NamePattern.ELLIPSIS);
  714. justProcessedEllipsis = true;
  715. } else {
  716. checkLegalName(buf.toString(), previous);
  717. NamePattern ret = new NamePattern(buf.toString());
  718. ret.setLocation(sourceContext, startPos, endPos);
  719. names.add(ret);
  720. justProcessedEllipsis = false;
  721. }
  722. if (afterDot == null) {
  723. buf.setLength(0);
  724. if (!maybeEat(".")) break;
  725. else previous = tokenSource.peek(-1);
  726. } else {
  727. buf.setLength(0);
  728. buf.append(afterDot);
  729. afterDot = null;
  730. }
  731. }
  732. //System.err.println("parsed: " + names);
  733. return names;
  734. }
  735. public NamePattern parseNamePattern() {
  736. StringBuffer buf = new StringBuffer();
  737. IToken previous = null;
  738. IToken tok;
  739. int startPos = tokenSource.peek().getStart();
  740. while (true) {
  741. tok = tokenSource.peek();
  742. if (previous != null) {
  743. if (!isAdjacent(previous, tok)) break;
  744. }
  745. if (tok.getString() == "*" || tok.isIdentifier()) {
  746. buf.append(tok.getString());
  747. } else if (tok.getLiteralKind() != null) {
  748. //System.err.println("literal kind: " + tok.getString());
  749. String s = tok.getString();
  750. if (s.indexOf('.') != -1) break;
  751. buf.append(s); // ??? so-so
  752. } else {
  753. break;
  754. }
  755. previous = tokenSource.next();
  756. //XXX need to handle floats and other fun stuff
  757. }
  758. int endPos = tokenSource.peek(-1).getEnd();
  759. if (buf.length() == 0) {
  760. throw new ParserException("name pattern", tok);
  761. }
  762. checkLegalName(buf.toString(), previous);
  763. NamePattern ret = new NamePattern(buf.toString());
  764. ret.setLocation(sourceContext, startPos, endPos);
  765. return ret;
  766. }
  767. private void checkLegalName(String s, IToken tok) {
  768. char ch = s.charAt(0);
  769. if (!(ch == '*' || Character.isJavaIdentifierStart(ch))) {
  770. throw new ParserException("illegal identifier start (" + ch + ")", tok);
  771. }
  772. for (int i=1, len=s.length(); i < len; i++) {
  773. ch = s.charAt(i);
  774. if (!(ch == '*' || Character.isJavaIdentifierPart(ch))) {
  775. throw new ParserException("illegal identifier character (" + ch + ")", tok);
  776. }
  777. }
  778. }
  779. private boolean isAdjacent(IToken first, IToken second) {
  780. return first.getEnd() == second.getStart()-1;
  781. }
  782. public ModifiersPattern parseModifiersPattern() {
  783. int requiredFlags = 0;
  784. int forbiddenFlags = 0;
  785. int start;
  786. while (true) {
  787. start = tokenSource.getIndex();
  788. boolean isForbidden = false;
  789. isForbidden = maybeEat("!");
  790. IToken t = tokenSource.next();
  791. int flag = ModifiersPattern.getModifierFlag(t.getString());
  792. if (flag == -1) break;
  793. if (isForbidden) forbiddenFlags |= flag;
  794. else requiredFlags |= flag;
  795. }
  796. tokenSource.setIndex(start);
  797. if (requiredFlags == 0 && forbiddenFlags == 0) {
  798. return ModifiersPattern.ANY;
  799. } else {
  800. return new ModifiersPattern(requiredFlags, forbiddenFlags);
  801. }
  802. }
  803. public TypePatternList parseArgumentsPattern() {
  804. List patterns = new ArrayList();
  805. eat("(");
  806. if (maybeEat(")")) {
  807. return new TypePatternList();
  808. }
  809. do {
  810. if (maybeEat(".")) {
  811. eat(".");
  812. patterns.add(TypePattern.ELLIPSIS);
  813. } else {
  814. patterns.add(parseTypePattern());
  815. }
  816. } while (maybeEat(","));
  817. eat(")");
  818. return new TypePatternList(patterns);
  819. }
  820. public AnnotationPatternList parseArgumentsAnnotationPattern() {
  821. List patterns = new ArrayList();
  822. eat("(");
  823. if (maybeEat(")")) {
  824. return new AnnotationPatternList();
  825. }
  826. do {
  827. if (maybeEat(".")) {
  828. eat(".");
  829. patterns.add(AnnotationTypePattern.ELLIPSIS);
  830. } else if (maybeEat("*")) {
  831. patterns.add(AnnotationTypePattern.ANY);
  832. } else {
  833. patterns.add(parseAnnotationNameOrVarTypePattern());
  834. }
  835. } while (maybeEat(","));
  836. eat(")");
  837. return new AnnotationPatternList(patterns);
  838. }
  839. public ThrowsPattern parseOptionalThrowsPattern() {
  840. IToken t = tokenSource.peek();
  841. if (t.isIdentifier() && t.getString().equals("throws")) {
  842. tokenSource.next();
  843. List required = new ArrayList();
  844. List forbidden = new ArrayList();
  845. do {
  846. boolean isForbidden = maybeEat("!");
  847. //???might want an error for a second ! without a paren
  848. TypePattern p = parseTypePattern();
  849. if (isForbidden) forbidden.add(p);
  850. else required.add(p);
  851. } while (maybeEat(","));
  852. return new ThrowsPattern(new TypePatternList(required), new TypePatternList(forbidden));
  853. }
  854. return ThrowsPattern.ANY;
  855. }
  856. public SignaturePattern parseMethodOrConstructorSignaturePattern() {
  857. int startPos = tokenSource.peek().getStart();
  858. AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
  859. ModifiersPattern modifiers = parseModifiersPattern();
  860. TypePattern returnType = parseTypePattern();
  861. TypePattern declaringType;
  862. NamePattern name = null;
  863. Member.Kind kind;
  864. // here we can check for 'new'
  865. if (maybeEatNew(returnType)) {
  866. kind = Member.CONSTRUCTOR;
  867. if (returnType.toString().length() == 0) {
  868. declaringType = TypePattern.ANY;
  869. } else {
  870. declaringType = returnType;
  871. }
  872. returnType = TypePattern.ANY;
  873. name = NamePattern.ANY;
  874. } else {
  875. kind = Member.METHOD;
  876. declaringType = parseTypePattern();
  877. if (maybeEat(".")) {
  878. name = parseNamePattern();
  879. } else {
  880. name = tryToExtractName(declaringType);
  881. if (name == null) {
  882. throw new ParserException("name pattern", tokenSource.peek());
  883. }
  884. String simpleName = name.maybeGetSimpleName();
  885. //XXX should add check for any Java keywords
  886. if (simpleName != null && simpleName.equals("new")) {
  887. throw new ParserException("constructor patterns have no return type",
  888. tokenSource.peek());
  889. }
  890. if (declaringType.toString().equals("")) {
  891. declaringType = TypePattern.ANY;
  892. }
  893. }
  894. }
  895. TypePatternList parameterTypes = parseArgumentsPattern();
  896. ThrowsPattern throwsPattern = parseOptionalThrowsPattern();
  897. SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes, throwsPattern, annotationPattern);
  898. int endPos = tokenSource.peek(-1).getEnd();
  899. ret.setLocation(sourceContext, startPos, endPos);
  900. return ret;
  901. }
  902. private boolean maybeEatNew(TypePattern returnType) {
  903. if (returnType instanceof WildTypePattern) {
  904. WildTypePattern p = (WildTypePattern)returnType;
  905. if (p.maybeExtractName("new")) return true;
  906. }
  907. int start = tokenSource.getIndex();
  908. if (maybeEat(".")) {
  909. String id = maybeEatIdentifier();
  910. if (id != null && id.equals("new")) return true;
  911. tokenSource.setIndex(start);
  912. }
  913. return false;
  914. }
  915. public SignaturePattern parseFieldSignaturePattern() {
  916. int startPos = tokenSource.peek().getStart();
  917. AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
  918. ModifiersPattern modifiers = parseModifiersPattern();
  919. TypePattern returnType = parseTypePattern();
  920. TypePattern declaringType = parseTypePattern();
  921. NamePattern name;
  922. //System.err.println("parsed field: " + declaringType.toString());
  923. if (maybeEat(".")) {
  924. name = parseNamePattern();
  925. } else {
  926. name = tryToExtractName(declaringType);
  927. if (declaringType.toString().equals("")) {
  928. declaringType = TypePattern.ANY;
  929. }
  930. }
  931. SignaturePattern ret = new SignaturePattern(Member.FIELD, modifiers, returnType,
  932. declaringType, name, TypePatternList.ANY, ThrowsPattern.ANY,annotationPattern);
  933. int endPos = tokenSource.peek(-1).getEnd();
  934. ret.setLocation(sourceContext, startPos, endPos);
  935. return ret;
  936. }
  937. private NamePattern tryToExtractName(TypePattern nextType) {
  938. if (nextType == TypePattern.ANY) {
  939. return NamePattern.ANY;
  940. } else if (nextType instanceof WildTypePattern) {
  941. WildTypePattern p = (WildTypePattern)nextType;
  942. return p.extractName();
  943. } else {
  944. return null;
  945. }
  946. }
  947. public String parsePossibleStringSequence(boolean shouldEnd) {
  948. StringBuffer result = new StringBuffer();
  949. IToken token = tokenSource.next();
  950. if (token.getLiteralKind()==null) {
  951. throw new ParserException("string",token);
  952. }
  953. while (token.getLiteralKind().equals("string")) {
  954. result.append(token.getString());
  955. boolean plus = maybeEat("+");
  956. if (!plus) break;
  957. token = tokenSource.next();
  958. if (token.getLiteralKind()==null) {
  959. throw new ParserException("string",token);
  960. }
  961. }
  962. eatIdentifier(";");
  963. IToken t = tokenSource.next();
  964. if (shouldEnd && t!=IToken.EOF) {
  965. throw new ParserException("<string>;",token);
  966. }
  967. return result.toString();
  968. }
  969. public String parseStringLiteral() {
  970. IToken token = tokenSource.next();
  971. String literalKind = token.getLiteralKind();
  972. if (literalKind == "string") {
  973. return token.getString();
  974. }
  975. throw new ParserException("string", token);
  976. }
  977. public String parseIdentifier() {
  978. IToken token = tokenSource.next();
  979. if (token.isIdentifier()) return token.getString();
  980. throw new ParserException("identifier", token);
  981. }
  982. public void eatIdentifier(String expectedValue) {
  983. IToken next = tokenSource.next();
  984. if (!next.getString().equals(expectedValue)) {
  985. throw new ParserException(expectedValue, next);
  986. }
  987. }
  988. public boolean maybeEatIdentifier(String expectedValue) {
  989. IToken next = tokenSource.peek();
  990. if (next.getString().equals(expectedValue)) {
  991. tokenSource.next();
  992. return true;
  993. } else {
  994. return false;
  995. }
  996. }
  997. public void eat(String expectedValue) {
  998. IToken next = tokenSource.next();
  999. if (next.getString() != expectedValue) {
  1000. throw new ParserException(expectedValue, next);
  1001. }
  1002. }
  1003. public boolean maybeEat(String token) {
  1004. IToken next = tokenSource.peek();
  1005. if (next.getString() == token) {
  1006. tokenSource.next();
  1007. return true;
  1008. } else {
  1009. return false;
  1010. }
  1011. }
  1012. public String maybeEatIdentifier() {
  1013. IToken next = tokenSource.peek();
  1014. if (next.isIdentifier()) {
  1015. tokenSource.next();
  1016. return next.getString();
  1017. } else {
  1018. return null;
  1019. }
  1020. }
  1021. public boolean peek(String token) {
  1022. IToken next = tokenSource.peek();
  1023. return next.getString() == token;
  1024. }
  1025. public PatternParser(String data) {
  1026. this(BasicTokenSource.makeTokenSource(data));
  1027. }
  1028. }