Logo Search packages:      
Sourcecode: aspectj version File versions

PatternParser.java

/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 *               2005 Contributors
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation
 *     Adrian Colyer many updates since.... 
 * ******************************************************************/

package org.aspectj.weaver.patterns;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.MemberKind;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.internal.tools.PointcutDesignatorHandlerBasedPointcut;
import org.aspectj.weaver.tools.ContextBasedMatcher;
import org.aspectj.weaver.tools.PointcutDesignatorHandler;

//XXX doesn't handle errors for extra tokens very well (sometimes ignores)
public class PatternParser {

      private ITokenSource tokenSource;
      private ISourceContext sourceContext;

      /** not thread-safe, but this class is not intended to be... */
      private boolean allowHasTypePatterns = false;

      /** extension handlers used in weaver tools API only */
      private Set pointcutDesignatorHandlers = Collections.EMPTY_SET;
      private World world;

      /**
       * Constructor for PatternParser.
       */
      public PatternParser(ITokenSource tokenSource) {
            super();
            this.tokenSource = tokenSource;
            this.sourceContext = tokenSource.getSourceContext();
      }

      /** only used by weaver tools API */
      public void setPointcutDesignatorHandlers(Set handlers, World world) {
            this.pointcutDesignatorHandlers = handlers;
            this.world = world;
      }

      public PerClause maybeParsePerClause() {
            IToken tok = tokenSource.peek();
            if (tok == IToken.EOF)
                  return null;
            if (tok.isIdentifier()) {
                  String name = tok.getString();
                  if (name.equals("issingleton")) {
                        return parsePerSingleton();
                  } else if (name.equals("perthis")) {
                        return parsePerObject(true);
                  } else if (name.equals("pertarget")) {
                        return parsePerObject(false);
                  } else if (name.equals("percflow")) {
                        return parsePerCflow(false);
                  } else if (name.equals("percflowbelow")) {
                        return parsePerCflow(true);
                  } else if (name.equals("pertypewithin")) { // PTWIMPL Parse the pertypewithin clause
                        return parsePerTypeWithin();
                  } else {
                        return null;
                  }
            }
            return null;
      }

      private PerClause parsePerCflow(boolean isBelow) {
            parseIdentifier();
            eat("(");
            Pointcut entry = parsePointcut();
            eat(")");
            return new PerCflow(entry, isBelow);
      }

      private PerClause parsePerObject(boolean isThis) {
            parseIdentifier();
            eat("(");
            Pointcut entry = parsePointcut();
            eat(")");
            return new PerObject(entry, isThis);
      }

      private PerClause parsePerTypeWithin() {
            parseIdentifier();
            eat("(");
            TypePattern withinTypePattern = parseTypePattern();
            eat(")");
            return new PerTypeWithin(withinTypePattern);
      }

      private PerClause parsePerSingleton() {
            parseIdentifier();
            eat("(");
            eat(")");
            return new PerSingleton();
      }

      public Declare parseDeclare() {
            int startPos = tokenSource.peek().getStart();

            eatIdentifier("declare");
            String kind = parseIdentifier();
            Declare ret;
            if (kind.equals("error")) {
                  eat(":");
                  ret = parseErrorOrWarning(true);
            } else if (kind.equals("warning")) {
                  eat(":");
                  ret = parseErrorOrWarning(false);
            } else if (kind.equals("precedence")) {
                  eat(":");
                  ret = parseDominates();
            } else if (kind.equals("dominates")) {
                  throw new ParserException("name changed to declare precedence", tokenSource.peek(-2));
            } else if (kind.equals("parents")) {
                  ret = parseParents();
            } else if (kind.equals("soft")) {
                  eat(":");
                  ret = parseSoft();
            } else {
                  throw new ParserException(
                              "expected one of error, warning, parents, soft, precedence, @type, @method, @constructor, @field", tokenSource
                                          .peek(-1));
            }
            int endPos = tokenSource.peek(-1).getEnd();
            ret.setLocation(sourceContext, startPos, endPos);
            return ret;
      }

      public Declare parseDeclareAnnotation() {
            int startPos = tokenSource.peek().getStart();

            eatIdentifier("declare");
            eat("@");
            String kind = parseIdentifier();
            eat(":");
            Declare ret;
            if (kind.equals("type")) {
                  ret = parseDeclareAtType();
            } else if (kind.equals("method")) {
                  ret = parseDeclareAtMethod(true);
            } else if (kind.equals("field")) {
                  ret = parseDeclareAtField();
            } else if (kind.equals("constructor")) {
                  ret = parseDeclareAtMethod(false);
            } else {
                  throw new ParserException("one of type, method, field, constructor", tokenSource.peek(-1));
            }
            eat(";");
            int endPos = tokenSource.peek(-1).getEnd();
            ret.setLocation(sourceContext, startPos, endPos);
            return ret;

      }

      public DeclareAnnotation parseDeclareAtType() {
            allowHasTypePatterns = true;
            TypePattern p = parseTypePattern();
            allowHasTypePatterns = false;
            return new DeclareAnnotation(DeclareAnnotation.AT_TYPE, p);
      }

      public DeclareAnnotation parseDeclareAtMethod(boolean isMethod) {
            if (maybeEat("(")) {
                  DeclareAnnotation da = parseDeclareAtMethod(isMethod);
                  eat(")", "missing ')' - unbalanced parentheses around signature pattern in declare @"
                              + (isMethod ? "method" : "constructor"));
                  return da;
            }
            SignaturePattern sp = parseMethodOrConstructorSignaturePattern();
            boolean isConstructorPattern = (sp.getKind() == Member.CONSTRUCTOR);
            if (isMethod && isConstructorPattern) {
                  throw new ParserException("method signature pattern", tokenSource.peek(-1));
            }
            if (!isMethod && !isConstructorPattern) {
                  throw new ParserException("constructor signature pattern", tokenSource.peek(-1));
            }
            if (isConstructorPattern)
                  return new DeclareAnnotation(DeclareAnnotation.AT_CONSTRUCTOR, sp);
            else
                  return new DeclareAnnotation(DeclareAnnotation.AT_METHOD, sp);
      }

      public DeclareAnnotation parseDeclareAtField() {
            if (maybeEat("(")) {
                  DeclareAnnotation da = parseDeclareAtField();
                  eat(")", "missing ')' - unbalanced parentheses around field signature pattern in declare @field");
                  return da;
            }
            SignaturePattern fieldSigPattern = parseFieldSignaturePattern();
            return new DeclareAnnotation(DeclareAnnotation.AT_FIELD, fieldSigPattern);
      }

      public DeclarePrecedence parseDominates() {
            List l = new ArrayList();
            do {
                  l.add(parseTypePattern());
            } while (maybeEat(","));

            return new DeclarePrecedence(l);
      }

      private Declare parseParents() {
            /*
             * simplified design requires use of raw types for declare parents, no generic spec. allowed String[] typeParameters =
             * maybeParseSimpleTypeVariableList();
             */
            eat(":");
            allowHasTypePatterns = true;
            TypePattern p = parseTypePattern(false, false);
            allowHasTypePatterns = false;
            IToken t = tokenSource.next();
            if (!(t.getString().equals("extends") || t.getString().equals("implements"))) {
                  throw new ParserException("extends or implements", t);
            }
            boolean isExtends = t.getString().equals("extends");

            List l = new ArrayList();
            do {
                  l.add(parseTypePattern());
            } while (maybeEat(","));

            // XXX somewhere in the chain we need to enforce that we have only ExactTypePatterns

            DeclareParents decp = new DeclareParents(p, l, isExtends);
            return decp;
      }

      private Declare parseSoft() {
            TypePattern p = parseTypePattern();
            eat(":");
            Pointcut pointcut = parsePointcut();
            return new DeclareSoft(p, pointcut);
      }

      private Declare parseErrorOrWarning(boolean isError) {
            Pointcut pointcut = parsePointcut();
            eat(":");
            String message = parsePossibleStringSequence(true);
            return new DeclareErrorOrWarning(isError, pointcut, message);
      }

      public Pointcut parsePointcut() {
            Pointcut p = parseAtomicPointcut();
            if (maybeEat("&&")) {
                  p = new AndPointcut(p, parseNotOrPointcut());
            }

            if (maybeEat("||")) {
                  p = new OrPointcut(p, parsePointcut());
            }

            return p;
      }

      private Pointcut parseNotOrPointcut() {
            Pointcut p = parseAtomicPointcut();
            if (maybeEat("&&")) {
                  p = new AndPointcut(p, parsePointcut());
            }
            return p;
      }

      private Pointcut parseAtomicPointcut() {
            if (maybeEat("!")) {
                  int startPos = tokenSource.peek(-1).getStart();
                  Pointcut p = new NotPointcut(parseAtomicPointcut(), startPos);
                  return p;
            }
            if (maybeEat("(")) {
                  Pointcut p = parsePointcut();
                  eat(")");
                  return p;
            }
            if (maybeEat("@")) {
                  int startPos = tokenSource.peek().getStart();
                  Pointcut p = parseAnnotationPointcut();
                  int endPos = tokenSource.peek(-1).getEnd();
                  p.setLocation(sourceContext, startPos, endPos);
                  return p;
            }
            int startPos = tokenSource.peek().getStart();
            Pointcut p = parseSinglePointcut();
            int endPos = tokenSource.peek(-1).getEnd();
            p.setLocation(sourceContext, startPos, endPos);
            return p;
      }

      public Pointcut parseSinglePointcut() {
            int start = tokenSource.getIndex();
            IToken t = tokenSource.peek();
            Pointcut p = t.maybeGetParsedPointcut();
            if (p != null) {
                  tokenSource.next();
                  return p;
            }

            String kind = parseIdentifier();
            // IToken possibleTypeVariableToken = tokenSource.peek();
            // String[] typeVariables = maybeParseSimpleTypeVariableList();
            if (kind.equals("execution") || kind.equals("call") || kind.equals("get") || kind.equals("set")) {
                  p = parseKindedPointcut(kind);
            } else if (kind.equals("args")) {
                  p = parseArgsPointcut();
            } else if (kind.equals("this")) {
                  p = parseThisOrTargetPointcut(kind);
            } else if (kind.equals("target")) {
                  p = parseThisOrTargetPointcut(kind);
            } else if (kind.equals("within")) {
                  p = parseWithinPointcut();
            } else if (kind.equals("withincode")) {
                  p = parseWithinCodePointcut();
            } else if (kind.equals("cflow")) {
                  p = parseCflowPointcut(false);
            } else if (kind.equals("cflowbelow")) {
                  p = parseCflowPointcut(true);
            } else if (kind.equals("adviceexecution")) {
                  eat("(");
                  eat(")");
                  p = new KindedPointcut(Shadow.AdviceExecution, new SignaturePattern(Member.ADVICE, ModifiersPattern.ANY,
                              TypePattern.ANY, TypePattern.ANY, NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY,
                              AnnotationTypePattern.ANY));
            } else if (kind.equals("handler")) {
                  eat("(");
                  TypePattern typePat = parseTypePattern(false, false);
                  eat(")");
                  p = new HandlerPointcut(typePat);
            } else if (kind.equals("lock") || kind.equals("unlock")) {
                  p = parseMonitorPointcut(kind);
            } else if (kind.equals("initialization")) {
                  eat("(");
                  SignaturePattern sig = parseConstructorSignaturePattern();
                  eat(")");
                  p = new KindedPointcut(Shadow.Initialization, sig);
            } else if (kind.equals("staticinitialization")) {
                  eat("(");
                  TypePattern typePat = parseTypePattern(false, false);
                  eat(")");
                  p = new KindedPointcut(Shadow.StaticInitialization, new SignaturePattern(Member.STATIC_INITIALIZATION,
                              ModifiersPattern.ANY, TypePattern.ANY, typePat, NamePattern.ANY, TypePatternList.EMPTY, ThrowsPattern.ANY,
                              AnnotationTypePattern.ANY));
            } else if (kind.equals("preinitialization")) {
                  eat("(");
                  SignaturePattern sig = parseConstructorSignaturePattern();
                  eat(")");
                  p = new KindedPointcut(Shadow.PreInitialization, sig);
            } else if (kind.equals("if")) {
                  // - annotation style only allows if(), if(true) or if(false)
                  // - if() means the body of the annotated method represents the if expression
                  // - anything else is an error because code cannot be put into the if()
                  // - code style will already have been processed and the call to maybeGetParsedPointcut()
                  // at the top of this method will have succeeded.
                  eat("(");
                  if (maybeEatIdentifier("true")) {
                        eat(")");
                        p = new IfPointcut.IfTruePointcut();
                  } else if (maybeEatIdentifier("false")) {
                        eat(")");
                        p = new IfPointcut.IfFalsePointcut();
                  } else {
                        if (!maybeEat(")")) {
                              throw new ParserException(
                                          "in annotation style, if(...) pointcuts cannot contain code. Use if() and put the code in the annotated method",
                                          t);
                        }
                        // TODO - Alex has some token stuff going on here to get a readable name in place of ""...
                        p = new IfPointcut("");
                  }
            } else {
                  boolean matchedByExtensionDesignator = false;
                  // see if a registered handler wants to parse it, otherwise
                  // treat as a reference pointcut
                  for (Iterator iter = this.pointcutDesignatorHandlers.iterator(); iter.hasNext();) {
                        PointcutDesignatorHandler pcd = (PointcutDesignatorHandler) iter.next();
                        if (pcd.getDesignatorName().equals(kind)) {
                              p = parseDesignatorPointcut(pcd);
                              matchedByExtensionDesignator = true;
                        }

                  }
                  if (!matchedByExtensionDesignator) {
                        tokenSource.setIndex(start);
                        p = parseReferencePointcut();
                  }
            }
            return p;
      }

      private void assertNoTypeVariables(String[] tvs, String errorMessage, IToken token) {
            if (tvs != null)
                  throw new ParserException(errorMessage, token);
      }

      public Pointcut parseAnnotationPointcut() {
            int start = tokenSource.getIndex();
            IToken t = tokenSource.peek();
            String kind = parseIdentifier();
            IToken possibleTypeVariableToken = tokenSource.peek();
            String[] typeVariables = maybeParseSimpleTypeVariableList();
            if (typeVariables != null) {
                  String message = "(";
                  assertNoTypeVariables(typeVariables, message, possibleTypeVariableToken);
            }
            tokenSource.setIndex(start);
            if (kind.equals("annotation")) {
                  return parseAtAnnotationPointcut();
            } else if (kind.equals("args")) {
                  return parseArgsAnnotationPointcut();
            } else if (kind.equals("this") || kind.equals("target")) {
                  return parseThisOrTargetAnnotationPointcut();
            } else if (kind.equals("within")) {
                  return parseWithinAnnotationPointcut();
            } else if (kind.equals("withincode")) {
                  return parseWithinCodeAnnotationPointcut();
            }
            throw new ParserException("pointcut name", t);
      }

      private Pointcut parseAtAnnotationPointcut() {
            parseIdentifier();
            eat("(");
            if (maybeEat(")")) {
                  throw new ParserException("@AnnotationName or parameter", tokenSource.peek());
            }
            ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
            eat(")");
            return new AnnotationPointcut(type);
      }

      private SignaturePattern parseConstructorSignaturePattern() {
            SignaturePattern ret = parseMethodOrConstructorSignaturePattern();
            if (ret.getKind() == Member.CONSTRUCTOR)
                  return ret;

            throw new ParserException("constructor pattern required, found method pattern", ret);
      }

      private Pointcut parseWithinCodePointcut() {
            // parseIdentifier();
            eat("(");
            SignaturePattern sig = parseMethodOrConstructorSignaturePattern();
            eat(")");
            return new WithincodePointcut(sig);
      }

      private Pointcut parseCflowPointcut(boolean isBelow) {
            // parseIdentifier();
            eat("(");
            Pointcut entry = parsePointcut();
            eat(")");
            return new CflowPointcut(entry, isBelow, null);
      }

      /**
       * Method parseWithinPointcut.
       * 
       * @return Pointcut
       */
      private Pointcut parseWithinPointcut() {
            // parseIdentifier();
            eat("(");
            TypePattern type = parseTypePattern();
            eat(")");
            return new WithinPointcut(type);
      }

      /**
       * Method parseThisOrTargetPointcut.
       * 
       * @return Pointcut
       */
      private Pointcut parseThisOrTargetPointcut(String kind) {
            eat("(");
            TypePattern type = parseTypePattern();
            eat(")");
            return new ThisOrTargetPointcut(kind.equals("this"), type);
      }

      private Pointcut parseThisOrTargetAnnotationPointcut() {
            String kind = parseIdentifier();
            eat("(");
            if (maybeEat(")")) {
                  throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
            }
            ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
            eat(")");
            return new ThisOrTargetAnnotationPointcut(kind.equals("this"), type);
      }

      private Pointcut parseWithinAnnotationPointcut() {
            /* String kind = */parseIdentifier();
            eat("(");
            if (maybeEat(")")) {
                  throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
            }
            AnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
            eat(")");
            return new WithinAnnotationPointcut(type);
      }

      private Pointcut parseWithinCodeAnnotationPointcut() {
            /* String kind = */parseIdentifier();
            eat("(");
            if (maybeEat(")")) {
                  throw new ParserException("expecting @AnnotationName or parameter, but found ')'", tokenSource.peek());
            }
            ExactAnnotationTypePattern type = parseAnnotationNameOrVarTypePattern();
            eat(")");
            return new WithinCodeAnnotationPointcut(type);
      }

      /**
       * Method parseArgsPointcut.
       * 
       * @return Pointcut
       */
      private Pointcut parseArgsPointcut() {
            // parseIdentifier();
            TypePatternList arguments = parseArgumentsPattern(false);
            return new ArgsPointcut(arguments);
      }

      private Pointcut parseArgsAnnotationPointcut() {
            parseIdentifier();
            AnnotationPatternList arguments = parseArgumentsAnnotationPattern();
            return new ArgsAnnotationPointcut(arguments);
      }

      private Pointcut parseReferencePointcut() {
            TypePattern onType = parseTypePattern();
            NamePattern name = null;
            if (onType.typeParameters.size() > 0) {
                  eat(".");
                  name = parseNamePattern();
            } else {
                  name = tryToExtractName(onType);
            }
            if (name == null) {
                  throw new ParserException("name pattern", tokenSource.peek());
            }
            if (onType.toString().equals("")) {
                  onType = null;
            }

            String simpleName = name.maybeGetSimpleName();
            if (simpleName == null) {
                  throw new ParserException("(", tokenSource.peek(-1));
            }

            TypePatternList arguments = parseArgumentsPattern(false);
            return new ReferencePointcut(onType, simpleName, arguments);
      }

      private Pointcut parseDesignatorPointcut(PointcutDesignatorHandler pcdHandler) {
            eat("(");
            int parenCount = 1;
            StringBuffer pointcutBody = new StringBuffer();
            while (parenCount > 0) {
                  if (maybeEat("(")) {
                        parenCount++;
                        pointcutBody.append("(");
                  } else if (maybeEat(")")) {
                        parenCount--;
                        if (parenCount > 0) {
                              pointcutBody.append(")");
                        }
                  } else {
                        pointcutBody.append(nextToken().getString());
                  }
            }
            ContextBasedMatcher pcExpr = pcdHandler.parse(pointcutBody.toString());
            return new PointcutDesignatorHandlerBasedPointcut(pcExpr, world);
      }

      public List parseDottedIdentifier() {
            List ret = new ArrayList();
            ret.add(parseIdentifier());
            while (maybeEat(".")) {
                  ret.add(parseIdentifier());
            }
            return ret;
      }

      private KindedPointcut parseKindedPointcut(String kind) {
            eat("(");
            SignaturePattern sig;

            Shadow.Kind shadowKind = null;
            if (kind.equals("execution")) {
                  sig = parseMethodOrConstructorSignaturePattern();
                  if (sig.getKind() == Member.METHOD) {
                        shadowKind = Shadow.MethodExecution;
                  } else if (sig.getKind() == Member.CONSTRUCTOR) {
                        shadowKind = Shadow.ConstructorExecution;
                  }
            } else if (kind.equals("call")) {
                  sig = parseMethodOrConstructorSignaturePattern();
                  if (sig.getKind() == Member.METHOD) {
                        shadowKind = Shadow.MethodCall;
                  } else if (sig.getKind() == Member.CONSTRUCTOR) {
                        shadowKind = Shadow.ConstructorCall;
                  }
            } else if (kind.equals("get")) {
                  sig = parseFieldSignaturePattern();
                  shadowKind = Shadow.FieldGet;
            } else if (kind.equals("set")) {
                  sig = parseFieldSignaturePattern();
                  shadowKind = Shadow.FieldSet;
            } else {
                  throw new ParserException("bad kind: " + kind, tokenSource.peek());
            }
            eat(")");
            return new KindedPointcut(shadowKind, sig);
      }

      /** Covers the 'lock()' and 'unlock()' pointcuts */
      private KindedPointcut parseMonitorPointcut(String kind) {
            eat("(");
            // TypePattern type = TypePattern.ANY;
            eat(")");

            if (kind.equals("lock")) {
                  return new KindedPointcut(Shadow.SynchronizationLock, new SignaturePattern(Member.MONITORENTER, ModifiersPattern.ANY,
                              TypePattern.ANY, TypePattern.ANY,
                              // type,
                              NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY, AnnotationTypePattern.ANY));
            } else {
                  return new KindedPointcut(Shadow.SynchronizationUnlock, new SignaturePattern(Member.MONITORENTER, ModifiersPattern.ANY,
                              TypePattern.ANY, TypePattern.ANY,
                              // type,
                              NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY, AnnotationTypePattern.ANY));
            }
      }

      public TypePattern parseTypePattern() {
            return parseTypePattern(false, false);
      }

      public TypePattern parseTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
            TypePattern p = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
            if (maybeEat("&&")) {
                  p = new AndTypePattern(p, parseNotOrTypePattern(insideTypeParameters, parameterAnnotationsPossible));
            }

            if (maybeEat("||")) {
                  p = new OrTypePattern(p, parseTypePattern(insideTypeParameters, parameterAnnotationsPossible));
            }
            return p;
      }

      private TypePattern parseNotOrTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
            TypePattern p = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
            if (maybeEat("&&")) {
                  p = new AndTypePattern(p, parseTypePattern(insideTypeParameters, parameterAnnotationsPossible));
            }
            return p;
      }

      // Need to differentiate in here between two kinds of annotation pattern - depending on where the ( is

      private TypePattern parseAtomicTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
            AnnotationTypePattern ap = maybeParseAnnotationPattern(); // might be parameter annotation pattern or type annotation
            // pattern
            if (maybeEat("!")) {
                  // int startPos = tokenSource.peek(-1).getStart();
                  // ??? we lose source location for true start of !type

                  // An annotation, if processed, is outside of the Not - so here we have to build
                  // an And pattern containing the annotation and the not as left and right children
                  // *unless* the annotation pattern was just 'Any' then we can skip building the
                  // And and just return the Not directly (pr228980)
                  TypePattern p = null;
                  TypePattern tp = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
                  if (!(ap instanceof AnyAnnotationTypePattern)) {
                        p = new NotTypePattern(tp);
                        p = new AndTypePattern(setAnnotationPatternForTypePattern(TypePattern.ANY, ap, false), p);
                  } else {
                        p = new NotTypePattern(tp);
                  }
                  return p;
            }
            if (maybeEat("(")) {
                  TypePattern p = parseTypePattern(insideTypeParameters, false);
                  if ((p instanceof NotTypePattern) && !(ap instanceof AnyAnnotationTypePattern)) {
                        // dont set the annotation on it, we don't want the annotation to be
                        // considered as part of the not, it is outside the not (pr228980)
                        TypePattern tp = setAnnotationPatternForTypePattern(TypePattern.ANY, ap, parameterAnnotationsPossible);
                        p = new AndTypePattern(tp, p);
                  } else {
                        p = setAnnotationPatternForTypePattern(p, ap, parameterAnnotationsPossible);
                  }
                  eat(")");
                  boolean isVarArgs = maybeEat("...");
                  if (isVarArgs)
                        p.setIsVarArgs(isVarArgs);
                  boolean isIncludeSubtypes = maybeEat("+");
                  if (isIncludeSubtypes)
                        p.includeSubtypes = true; // need the test because (A+) should not set subtypes to false!
                  return p;
            }
            int startPos = tokenSource.peek().getStart();
            TypePattern p = parseSingleTypePattern(insideTypeParameters);
            int endPos = tokenSource.peek(-1).getEnd();
            p = setAnnotationPatternForTypePattern(p, ap, false);
            p.setLocation(sourceContext, startPos, endPos);
            return p;
      }

      private TypePattern setAnnotationPatternForTypePattern(TypePattern t, AnnotationTypePattern ap,
                  boolean parameterAnnotationsPattern) {
            TypePattern ret = t;
            if (parameterAnnotationsPattern)
                  ap.setForParameterAnnotationMatch();
            if (ap != AnnotationTypePattern.ANY) {
                  if (t == TypePattern.ANY) {
                        ret = new WildTypePattern(new NamePattern[] { NamePattern.ANY }, false, 0, false, null);
                  }
                  if (t.annotationPattern == AnnotationTypePattern.ANY) {
                        ret.setAnnotationTypePattern(ap);
                  } else {
                        ret.setAnnotationTypePattern(new AndAnnotationTypePattern(ap, t.annotationPattern)); // ???
                  }
            }
            return ret;
      }

      public AnnotationTypePattern maybeParseAnnotationPattern() {
            AnnotationTypePattern ret = AnnotationTypePattern.ANY;
            AnnotationTypePattern nextPattern = null;
            while ((nextPattern = maybeParseSingleAnnotationPattern()) != null) {
                  if (ret == AnnotationTypePattern.ANY) {
                        ret = nextPattern;
                  } else {
                        ret = new AndAnnotationTypePattern(ret, nextPattern);
                  }
            }
            return ret;
      }

      // PVAL cope with annotation values at other places in this code
      public AnnotationTypePattern maybeParseSingleAnnotationPattern() {
            AnnotationTypePattern ret = null;
            Map values = null;
            // LALR(2) - fix by making "!@" a single token
            int startIndex = tokenSource.getIndex();
            if (maybeEat("!")) {
                  if (maybeEat("@")) {
                        if (maybeEat("(")) {
                              TypePattern p = parseTypePattern();
                              ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
                              eat(")");
                              return ret;
                        } else {
                              TypePattern p = parseSingleTypePattern();
                              if (maybeEatAdjacent("(")) {
                                    values = parseAnnotationValues();
                                    eat(")");
                                    ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p, values));
                              } else {
                                    ret = new NotAnnotationTypePattern(new WildAnnotationTypePattern(p));
                              }
                              return ret;
                        }
                  } else {
                        tokenSource.setIndex(startIndex); // not for us!
                        return ret;
                  }
            }
            if (maybeEat("@")) {
                  if (maybeEat("(")) {
                        TypePattern p = parseTypePattern();
                        ret = new WildAnnotationTypePattern(p);
                        eat(")");
                        return ret;
                  } else {
                        TypePattern p = parseSingleTypePattern();
                        if (maybeEatAdjacent("(")) {
                              values = parseAnnotationValues();
                              eat(")");
                              ret = new WildAnnotationTypePattern(p, values);
                        } else {
                              ret = new WildAnnotationTypePattern(p);
                        }
                        return ret;
                  }
            } else {
                  tokenSource.setIndex(startIndex); // not for us!
                  return ret;
            }
      }

      // Parse annotation values. In an expression in @A(a=b,c=d) this method will be
      // parsing the a=b,c=d.)
      public Map/* String,String */parseAnnotationValues() {
            Map values = new HashMap();
            boolean seenDefaultValue = false;
            do {
                  String possibleKeyString = parseAnnotationNameValuePattern();
                  if (possibleKeyString == null) {
                        throw new ParserException("expecting simple literal ", tokenSource.peek(-1));
                  }
                  // did they specify just a single entry 'v' or a keyvalue pair 'k=v'
                  if (maybeEat("=")) {
                        // it was a key!
                        String valueString = parseAnnotationNameValuePattern();
                        if (valueString == null) {
                              throw new ParserException("expecting simple literal ", tokenSource.peek(-1));
                        }
                        values.put(possibleKeyString, valueString);
                  } else {
                        if (seenDefaultValue) {
                              throw new ParserException("cannot specify two default values", tokenSource.peek(-1));
                        }
                        seenDefaultValue = true;
                        values.put("value", possibleKeyString);
                  }
            } while (maybeEat(",")); // keep going whilst there are ','
            return values;
      }

      public TypePattern parseSingleTypePattern() {
            return parseSingleTypePattern(false);
      }

      public TypePattern parseSingleTypePattern(boolean insideTypeParameters) {
            if (insideTypeParameters && maybeEat("?"))
                  return parseGenericsWildcardTypePattern();
            if (allowHasTypePatterns) {
                  if (maybeEatIdentifier("hasmethod"))
                        return parseHasMethodTypePattern();
                  if (maybeEatIdentifier("hasfield"))
                        return parseHasFieldTypePattern();
            }

            List names = parseDottedNamePattern();

            int dim = 0;
            while (maybeEat("[")) {
                  eat("]");
                  dim++;
            }

            TypePatternList typeParameters = maybeParseTypeParameterList();
            int endPos = tokenSource.peek(-1).getEnd();

            boolean includeSubtypes = maybeEat("+");

            // TODO do we need to associate the + with either the type or the array?
            while (maybeEat("[")) {
                  eat("]");
                  dim++;
            }

            boolean isVarArgs = maybeEat("...");

            // ??? what about the source location of any's????
            if (names.size() == 1 && ((NamePattern) names.get(0)).isAny() && dim == 0 && !isVarArgs && typeParameters == null)
                  return TypePattern.ANY;

            // Notice we increase the dimensions if varargs is set. this is to allow type matching to
            // succeed later: The actual signature at runtime of a method declared varargs is an array type of
            // the original declared type (so Integer... becomes Integer[] in the bytecode). So, here for the
            // pattern 'Integer...' we create a WildTypePattern 'Integer[]' with varargs set. If this matches
            // during shadow matching, we confirm that the varargs flags match up before calling it a successful
            // match.
            return new WildTypePattern(names, includeSubtypes, dim + (isVarArgs ? 1 : 0), endPos, isVarArgs, typeParameters);
      }

      public TypePattern parseHasMethodTypePattern() {
            int startPos = tokenSource.peek(-1).getStart();
            eat("(");
            SignaturePattern sp = parseMethodOrConstructorSignaturePattern();
            eat(")");
            int endPos = tokenSource.peek(-1).getEnd();
            HasMemberTypePattern ret = new HasMemberTypePattern(sp);
            ret.setLocation(sourceContext, startPos, endPos);
            return ret;
      }

      public TypePattern parseHasFieldTypePattern() {
            int startPos = tokenSource.peek(-1).getStart();
            eat("(");
            SignaturePattern sp = parseFieldSignaturePattern();
            eat(")");
            int endPos = tokenSource.peek(-1).getEnd();
            HasMemberTypePattern ret = new HasMemberTypePattern(sp);
            ret.setLocation(sourceContext, startPos, endPos);
            return ret;
      }

      public TypePattern parseGenericsWildcardTypePattern() {
            List names = new ArrayList();
            names.add(new NamePattern("?"));
            TypePattern upperBound = null;
            TypePattern[] additionalInterfaceBounds = new TypePattern[0];
            TypePattern lowerBound = null;
            if (maybeEatIdentifier("extends")) {
                  upperBound = parseTypePattern(false, false);
                  additionalInterfaceBounds = maybeParseAdditionalInterfaceBounds();
            }
            if (maybeEatIdentifier("super")) {
                  lowerBound = parseTypePattern(false, false);
            }
            int endPos = tokenSource.peek(-1).getEnd();
            return new WildTypePattern(names, false, 0, endPos, false, null, upperBound, additionalInterfaceBounds, lowerBound);
      }

      // private AnnotationTypePattern completeAnnotationPattern(AnnotationTypePattern p) {
      // if (maybeEat("&&")) {
      // return new AndAnnotationTypePattern(p,parseNotOrAnnotationPattern());
      // }
      // if (maybeEat("||")) {
      // return new OrAnnotationTypePattern(p,parseAnnotationTypePattern());
      // }
      // return p;
      // }
      //
      // protected AnnotationTypePattern parseAnnotationTypePattern() {
      // AnnotationTypePattern ap = parseAtomicAnnotationPattern();
      // if (maybeEat("&&")) {
      // ap = new AndAnnotationTypePattern(ap, parseNotOrAnnotationPattern());
      // }
      //          
      // if (maybeEat("||")) {
      // ap = new OrAnnotationTypePattern(ap, parseAnnotationTypePattern());
      // }
      // return ap;
      // }
      //
      // private AnnotationTypePattern parseNotOrAnnotationPattern() {
      // AnnotationTypePattern p = parseAtomicAnnotationPattern();
      // if (maybeEat("&&")) {
      // p = new AndAnnotationTypePattern(p,parseAnnotationTypePattern());
      // }
      // return p;
      // }

      protected ExactAnnotationTypePattern parseAnnotationNameOrVarTypePattern() {
            ExactAnnotationTypePattern p = null;
            int startPos = tokenSource.peek().getStart();
            if (maybeEat("@")) {
                  throw new ParserException("@Foo form was deprecated in AspectJ 5 M2: annotation name or var ", tokenSource.peek(-1));
            }
            p = parseSimpleAnnotationName();
            int endPos = tokenSource.peek(-1).getEnd();
            p.setLocation(sourceContext, startPos, endPos);
            // For optimized syntax that allows binding directly to annotation values (pr234943)
            if (maybeEat("(")) {
                  String formalName = parseIdentifier();
                  p = new ExactAnnotationFieldTypePattern(p, formalName);
                  eat(")");
            }
            return p;
      }

      /**
       * @return
       */
      private ExactAnnotationTypePattern parseSimpleAnnotationName() {
            // the @ has already been eaten...
            ExactAnnotationTypePattern p;
            StringBuffer annotationName = new StringBuffer();
            annotationName.append(parseIdentifier());
            while (maybeEat(".")) {
                  annotationName.append('.');
                  annotationName.append(parseIdentifier());
            }
            UnresolvedType type = UnresolvedType.forName(annotationName.toString());
            p = new ExactAnnotationTypePattern(type, null);
            return p;
      }

      // private AnnotationTypePattern parseAtomicAnnotationPattern() {
      // if (maybeEat("!")) {
      // //int startPos = tokenSource.peek(-1).getStart();
      // //??? we lose source location for true start of !type
      // AnnotationTypePattern p = new NotAnnotationTypePattern(parseAtomicAnnotationPattern());
      // return p;
      // }
      // if (maybeEat("(")) {
      // AnnotationTypePattern p = parseAnnotationTypePattern();
      // eat(")");
      // return p;
      // }
      // int startPos = tokenSource.peek().getStart();
      // eat("@");
      // StringBuffer annotationName = new StringBuffer();
      // annotationName.append(parseIdentifier());
      // while (maybeEat(".")) {
      // annotationName.append('.');
      // annotationName.append(parseIdentifier());
      // }
      // UnresolvedType type = UnresolvedType.forName(annotationName.toString());
      // AnnotationTypePattern p = new ExactAnnotationTypePattern(type);
      // int endPos = tokenSource.peek(-1).getEnd();
      // p.setLocation(sourceContext, startPos, endPos);
      // return p;
      // }

      public List parseDottedNamePattern() {
            List names = new ArrayList();
            StringBuffer buf = new StringBuffer();
            IToken previous = null;
            boolean justProcessedEllipsis = false; // Remember if we just dealt with an ellipsis (PR61536)
            boolean justProcessedDot = false;
            boolean onADot = false;

            while (true) {
                  IToken tok = null;
                  int startPos = tokenSource.peek().getStart();
                  String afterDot = null;
                  while (true) {
                        if (previous != null && previous.getString().equals("."))
                              justProcessedDot = true;
                        tok = tokenSource.peek();
                        onADot = (tok.getString().equals("."));
                        if (previous != null) {
                              if (!isAdjacent(previous, tok))
                                    break;
                        }
                        if (tok.getString() == "*" || (tok.isIdentifier() && tok.getString() != "...")) {
                              buf.append(tok.getString());
                        } else if (tok.getString() == "...") {
                              break;
                        } else if (tok.getLiteralKind() != null) {
                              // System.err.println("literal kind: " + tok.getString());
                              String s = tok.getString();
                              int dot = s.indexOf('.');
                              if (dot != -1) {
                                    buf.append(s.substring(0, dot));
                                    afterDot = s.substring(dot + 1);
                                    previous = tokenSource.next();
                                    break;
                              }
                              buf.append(s); // ??? so-so
                        } else {
                              break;
                        }
                        previous = tokenSource.next();
                        // XXX need to handle floats and other fun stuff
                  }
                  int endPos = tokenSource.peek(-1).getEnd();
                  if (buf.length() == 0 && names.isEmpty()) {
                        throw new ParserException("name pattern", tok);
                  }

                  if (buf.length() == 0 && justProcessedEllipsis) {
                        throw new ParserException("name pattern cannot finish with ..", tok);
                  }
                  if (buf.length() == 0 && justProcessedDot && !onADot) {
                        throw new ParserException("name pattern cannot finish with .", tok);
                  }

                  if (buf.length() == 0) {
                        names.add(NamePattern.ELLIPSIS);
                        justProcessedEllipsis = true;
                  } else {
                        checkLegalName(buf.toString(), previous);
                        NamePattern ret = new NamePattern(buf.toString());
                        ret.setLocation(sourceContext, startPos, endPos);
                        names.add(ret);
                        justProcessedEllipsis = false;
                  }

                  if (afterDot == null) {
                        buf.setLength(0);
                        // no elipsis or dotted name part
                        if (!maybeEat("."))
                              break;
                        // go on
                        else
                              previous = tokenSource.peek(-1);
                  } else {
                        buf.setLength(0);
                        buf.append(afterDot);
                        afterDot = null;
                  }
            }
            // System.err.println("parsed: " + names);
            return names;
      }

      // supported form 'a.b.c.d' or just 'a'
      public String parseAnnotationNameValuePattern() {
            StringBuffer buf = new StringBuffer();
            IToken tok;
            // int startPos =
            tokenSource.peek().getStart();
            boolean dotOK = false;
            int depth = 0;
            while (true) {
                  tok = tokenSource.peek();
                  // keep going until we hit ')' or '=' or ','
                  if (tok.getString() == ")" && depth == 0)
                        break;
                  if (tok.getString() == "=" && depth == 0)
                        break;
                  if (tok.getString() == "," && depth == 0)
                        break;

                  // keep track of nested brackets
                  if (tok.getString() == "(")
                        depth++;
                  if (tok.getString() == ")")
                        depth--;
                  if (tok.getString() == "{")
                        depth++;
                  if (tok.getString() == "}")
                        depth--;

                  if (tok.getString() == "." && !dotOK) {
                        throw new ParserException("dot not expected", tok);
                  }
                  buf.append(tok.getString());
                  tokenSource.next();
                  dotOK = true;
            }
            if (buf.length() == 0)
                  return null;
            else
                  return buf.toString();
      }

      public NamePattern parseNamePattern() {
            StringBuffer buf = new StringBuffer();
            IToken previous = null;
            IToken tok;
            int startPos = tokenSource.peek().getStart();
            while (true) {
                  tok = tokenSource.peek();
                  if (previous != null) {
                        if (!isAdjacent(previous, tok))
                              break;
                  }
                  if (tok.getString() == "*" || tok.isIdentifier()) {
                        buf.append(tok.getString());
                  } else if (tok.getLiteralKind() != null) {
                        // System.err.println("literal kind: " + tok.getString());
                        String s = tok.getString();
                        if (s.indexOf('.') != -1)
                              break;
                        buf.append(s); // ??? so-so
                  } else {
                        break;
                  }
                  previous = tokenSource.next();
                  // XXX need to handle floats and other fun stuff
            }
            int endPos = tokenSource.peek(-1).getEnd();
            if (buf.length() == 0) {
                  throw new ParserException("name pattern", tok);
            }

            checkLegalName(buf.toString(), previous);
            NamePattern ret = new NamePattern(buf.toString());
            ret.setLocation(sourceContext, startPos, endPos);
            return ret;
      }

      private void checkLegalName(String s, IToken tok) {
            char ch = s.charAt(0);
            if (!(ch == '*' || Character.isJavaIdentifierStart(ch))) {
                  throw new ParserException("illegal identifier start (" + ch + ")", tok);
            }

            for (int i = 1, len = s.length(); i < len; i++) {
                  ch = s.charAt(i);
                  if (!(ch == '*' || Character.isJavaIdentifierPart(ch))) {
                        throw new ParserException("illegal identifier character (" + ch + ")", tok);
                  }
            }

      }

      private boolean isAdjacent(IToken first, IToken second) {
            return first.getEnd() == second.getStart() - 1;
      }

      public ModifiersPattern parseModifiersPattern() {
            int requiredFlags = 0;
            int forbiddenFlags = 0;
            int start;
            while (true) {
                  start = tokenSource.getIndex();
                  boolean isForbidden = false;
                  isForbidden = maybeEat("!");
                  IToken t = tokenSource.next();
                  int flag = ModifiersPattern.getModifierFlag(t.getString());
                  if (flag == -1)
                        break;
                  if (isForbidden)
                        forbiddenFlags |= flag;
                  else
                        requiredFlags |= flag;
            }

            tokenSource.setIndex(start);
            if (requiredFlags == 0 && forbiddenFlags == 0) {
                  return ModifiersPattern.ANY;
            } else {
                  return new ModifiersPattern(requiredFlags, forbiddenFlags);
            }
      }

      public TypePatternList parseArgumentsPattern(boolean parameterAnnotationsPossible) {
            List patterns = new ArrayList();
            eat("(");

            // ()
            if (maybeEat(")")) {
                  return new TypePatternList();
            }

            do {
                  if (maybeEat(".")) { // ..
                        eat(".");
                        patterns.add(TypePattern.ELLIPSIS);
                  } else {
                        patterns.add(parseTypePattern(false, parameterAnnotationsPossible));
                  }
            } while (maybeEat(","));
            eat(")");
            return new TypePatternList(patterns);
      }

      public AnnotationPatternList parseArgumentsAnnotationPattern() {
            List patterns = new ArrayList();
            eat("(");
            if (maybeEat(")")) {
                  return new AnnotationPatternList();
            }

            do {
                  if (maybeEat(".")) {
                        eat(".");
                        patterns.add(AnnotationTypePattern.ELLIPSIS);
                  } else if (maybeEat("*")) {
                        patterns.add(AnnotationTypePattern.ANY);
                  } else {
                        patterns.add(parseAnnotationNameOrVarTypePattern());
                  }
            } while (maybeEat(","));
            eat(")");
            return new AnnotationPatternList(patterns);
      }

      public ThrowsPattern parseOptionalThrowsPattern() {
            IToken t = tokenSource.peek();
            if (t.isIdentifier() && t.getString().equals("throws")) {
                  tokenSource.next();
                  List required = new ArrayList();
                  List forbidden = new ArrayList();
                  do {
                        boolean isForbidden = maybeEat("!");
                        // ???might want an error for a second ! without a paren
                        TypePattern p = parseTypePattern();
                        if (isForbidden)
                              forbidden.add(p);
                        else
                              required.add(p);
                  } while (maybeEat(","));
                  return new ThrowsPattern(new TypePatternList(required), new TypePatternList(forbidden));
            }
            return ThrowsPattern.ANY;
      }

      public SignaturePattern parseMethodOrConstructorSignaturePattern() {
            int startPos = tokenSource.peek().getStart();
            AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
            ModifiersPattern modifiers = parseModifiersPattern();
            TypePattern returnType = parseTypePattern(false, false);

            TypePattern declaringType;
            NamePattern name = null;
            MemberKind kind;
            // here we can check for 'new'
            if (maybeEatNew(returnType)) {
                  kind = Member.CONSTRUCTOR;
                  if (returnType.toString().length() == 0) {
                        declaringType = TypePattern.ANY;
                  } else {
                        declaringType = returnType;
                  }
                  returnType = TypePattern.ANY;
                  name = NamePattern.ANY;
            } else {
                  kind = Member.METHOD;
                  IToken nameToken = tokenSource.peek();
                  declaringType = parseTypePattern(false, false);
                  if (maybeEat(".")) {
                        nameToken = tokenSource.peek();
                        name = parseNamePattern();
                  } else {
                        name = tryToExtractName(declaringType);
                        if (declaringType.toString().equals("")) {
                              declaringType = TypePattern.ANY;
                        }
                  }
                  if (name == null) {
                        throw new ParserException("name pattern", tokenSource.peek());
                  }
                  String simpleName = name.maybeGetSimpleName();
                  // XXX should add check for any Java keywords
                  if (simpleName != null && simpleName.equals("new")) {
                        throw new ParserException("method name (not constructor)", nameToken);
                  }
            }

            TypePatternList parameterTypes = parseArgumentsPattern(true);

            ThrowsPattern throwsPattern = parseOptionalThrowsPattern();
            SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
                        throwsPattern, annotationPattern);
            int endPos = tokenSource.peek(-1).getEnd();
            ret.setLocation(sourceContext, startPos, endPos);
            return ret;
      }

      private boolean maybeEatNew(TypePattern returnType) {
            if (returnType instanceof WildTypePattern) {
                  WildTypePattern p = (WildTypePattern) returnType;
                  if (p.maybeExtractName("new"))
                        return true;
            }
            int start = tokenSource.getIndex();
            if (maybeEat(".")) {
                  String id = maybeEatIdentifier();
                  if (id != null && id.equals("new"))
                        return true;
                  tokenSource.setIndex(start);
            }

            return false;
      }

      public SignaturePattern parseFieldSignaturePattern() {
            int startPos = tokenSource.peek().getStart();

            // TypePatternList followMe = TypePatternList.ANY;

            AnnotationTypePattern annotationPattern = maybeParseAnnotationPattern();
            ModifiersPattern modifiers = parseModifiersPattern();
            TypePattern returnType = parseTypePattern();
            TypePattern declaringType = parseTypePattern();
            NamePattern name;
            // System.err.println("parsed field: " + declaringType.toString());
            if (maybeEat(".")) {
                  name = parseNamePattern();
            } else {
                  name = tryToExtractName(declaringType);
                  if (name == null)
                        throw new ParserException("name pattern", tokenSource.peek());
                  if (declaringType.toString().equals("")) {
                        declaringType = TypePattern.ANY;
                  }
            }
            SignaturePattern ret = new SignaturePattern(Member.FIELD, modifiers, returnType, declaringType, name, TypePatternList.ANY,
                        ThrowsPattern.ANY, annotationPattern);

            int endPos = tokenSource.peek(-1).getEnd();
            ret.setLocation(sourceContext, startPos, endPos);
            return ret;
      }

      private NamePattern tryToExtractName(TypePattern nextType) {
            if (nextType == TypePattern.ANY) {
                  return NamePattern.ANY;
            } else if (nextType instanceof WildTypePattern) {
                  WildTypePattern p = (WildTypePattern) nextType;
                  return p.extractName();
            } else {
                  return null;
            }
      }

      /**
       * Parse type variable declarations for a generic method or at the start of a signature pointcut to identify type variable names
       * in a generic type.
       * 
       * @param includeParameterizedTypes
       * @return
       */
      public TypeVariablePatternList maybeParseTypeVariableList() {
            if (!maybeEat("<"))
                  return null;
            List typeVars = new ArrayList();
            TypeVariablePattern t = parseTypeVariable();
            typeVars.add(t);
            while (maybeEat(",")) {
                  TypeVariablePattern nextT = parseTypeVariable();
                  typeVars.add(nextT);
            }
            eat(">");
            TypeVariablePattern[] tvs = new TypeVariablePattern[typeVars.size()];
            typeVars.toArray(tvs);
            return new TypeVariablePatternList(tvs);
      }

      // of the form execution<T,S,V> - allows identifiers only
      public String[] maybeParseSimpleTypeVariableList() {
            if (!maybeEat("<"))
                  return null;
            List typeVarNames = new ArrayList();
            do {
                  typeVarNames.add(parseIdentifier());
            } while (maybeEat(","));
            eat(">", "',' or '>'");
            String[] tvs = new String[typeVarNames.size()];
            typeVarNames.toArray(tvs);
            return tvs;
      }

      public TypePatternList maybeParseTypeParameterList() {
            if (!maybeEat("<"))
                  return null;
            List typePats = new ArrayList();
            do {
                  TypePattern tp = parseTypePattern(true, false);
                  typePats.add(tp);
            } while (maybeEat(","));
            eat(">");
            TypePattern[] tps = new TypePattern[typePats.size()];
            typePats.toArray(tps);
            return new TypePatternList(tps);
      }

      public TypeVariablePattern parseTypeVariable() {
            TypePattern upperBound = null;
            TypePattern[] additionalInterfaceBounds = null;
            TypePattern lowerBound = null;
            String typeVariableName = parseIdentifier();
            if (maybeEatIdentifier("extends")) {
                  upperBound = parseTypePattern();
                  additionalInterfaceBounds = maybeParseAdditionalInterfaceBounds();
            } else if (maybeEatIdentifier("super")) {
                  lowerBound = parseTypePattern();
            }
            return new TypeVariablePattern(typeVariableName, upperBound, additionalInterfaceBounds, lowerBound);
      }

      private TypePattern[] maybeParseAdditionalInterfaceBounds() {
            List boundsList = new ArrayList();
            while (maybeEat("&")) {
                  TypePattern tp = parseTypePattern();
                  boundsList.add(tp);
            }
            if (boundsList.size() == 0)
                  return null;
            TypePattern[] ret = new TypePattern[boundsList.size()];
            boundsList.toArray(ret);
            return ret;
      }

      public String parsePossibleStringSequence(boolean shouldEnd) {
            StringBuffer result = new StringBuffer();

            IToken token = tokenSource.next();
            if (token.getLiteralKind() == null) {
                  throw new ParserException("string", token);
            }
            while (token.getLiteralKind().equals("string")) {
                  result.append(token.getString());
                  boolean plus = maybeEat("+");
                  if (!plus)
                        break;
                  token = tokenSource.next();
                  if (token.getLiteralKind() == null) {
                        throw new ParserException("string", token);
                  }
            }
            eatIdentifier(";");
            IToken t = tokenSource.next();
            if (shouldEnd && t != IToken.EOF) {
                  throw new ParserException("<string>;", token);
            }
            // bug 125027: since we've eaten the ";" we need to set the index
            // to be one less otherwise the end position isn't set correctly.
            int currentIndex = tokenSource.getIndex();
            tokenSource.setIndex(currentIndex - 1);

            return result.toString();

      }

      public String parseStringLiteral() {
            IToken token = tokenSource.next();
            String literalKind = token.getLiteralKind();
            if (literalKind == "string") {
                  return token.getString();
            }

            throw new ParserException("string", token);
      }

      public String parseIdentifier() {
            IToken token = tokenSource.next();
            if (token.isIdentifier())
                  return token.getString();
            throw new ParserException("identifier", token);
      }

      public void eatIdentifier(String expectedValue) {
            IToken next = tokenSource.next();
            if (!next.getString().equals(expectedValue)) {
                  throw new ParserException(expectedValue, next);
            }
      }

      public boolean maybeEatIdentifier(String expectedValue) {
            IToken next = tokenSource.peek();
            if (next.getString().equals(expectedValue)) {
                  tokenSource.next();
                  return true;
            } else {
                  return false;
            }
      }

      public void eat(String expectedValue) {
            eat(expectedValue, expectedValue);
      }

      private void eat(String expectedValue, String expectedMessage) {
            IToken next = nextToken();
            if (next.getString() != expectedValue) {
                  if (expectedValue.equals(">") && next.getString().startsWith(">")) {
                        // handle problem of >> and >>> being lexed as single tokens
                        pendingRightArrows = BasicToken.makeLiteral(next.getString().substring(1).intern(), "string", next.getStart() + 1,
                                    next.getEnd());
                        return;
                  }
                  throw new ParserException(expectedMessage, next);
            }
      }

      private IToken pendingRightArrows;

      private IToken nextToken() {
            if (pendingRightArrows != null) {
                  IToken ret = pendingRightArrows;
                  pendingRightArrows = null;
                  return ret;
            } else {
                  return tokenSource.next();
            }
      }

      public boolean maybeEatAdjacent(String token) {
            IToken next = tokenSource.peek();
            if (next.getString() == token) {
                  if (isAdjacent(tokenSource.peek(-1), next)) {
                        tokenSource.next();
                        return true;
                  }
            }
            return false;
      }

      public boolean maybeEat(String token) {
            IToken next = tokenSource.peek();
            if (next.getString() == token) {
                  tokenSource.next();
                  return true;
            } else {
                  return false;
            }
      }

      public String maybeEatIdentifier() {
            IToken next = tokenSource.peek();
            if (next.isIdentifier()) {
                  tokenSource.next();
                  return next.getString();
            } else {
                  return null;
            }
      }

      public boolean peek(String token) {
            IToken next = tokenSource.peek();
            return next.getString() == token;
      }

      public void checkEof() {
            IToken last = tokenSource.next();
            if (last != IToken.EOF) {
                  throw new ParserException("unexpected pointcut element: " + last.toString(), last);
            }
      }

      public PatternParser(String data) {
            this(BasicTokenSource.makeTokenSource(data, null));
      }

      public PatternParser(String data, ISourceContext context) {
            this(BasicTokenSource.makeTokenSource(data, context));
      }
}

Generated by  Doxygen 1.6.0   Back to index