org.caesarj.compiler.aspectj.CaesarWrapperPatternParser.java Source code

Java tutorial

Introduction

Here is the source code for org.caesarj.compiler.aspectj.CaesarWrapperPatternParser.java

Source

/*
 * This source file is part of CaesarJ 
 * For the latest info, see http://caesarj.org/
 * 
 * Copyright  2003-2005 
 * Darmstadt University of Technology, Software Technology Group
 * Also see acknowledgements in readme.txt
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 */
package org.caesarj.compiler.aspectj;

import java.util.ArrayList;
import java.util.List;

import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.patterns.AndPointcut;
import org.aspectj.weaver.patterns.ArgsPointcut;
import org.aspectj.weaver.patterns.CflowPointcut;
import org.aspectj.weaver.patterns.HandlerPointcut;
import org.aspectj.weaver.patterns.IToken;
import org.aspectj.weaver.patterns.ITokenSource;
import org.aspectj.weaver.patterns.IfPointcut;
import org.aspectj.weaver.patterns.ModifiersPattern;
import org.aspectj.weaver.patterns.NamePattern;
import org.aspectj.weaver.patterns.NotPointcut;
import org.aspectj.weaver.patterns.OrPointcut;
import org.aspectj.weaver.patterns.ParserException;
import org.aspectj.weaver.patterns.PatternParser;
import org.aspectj.weaver.patterns.Pointcut;
import org.aspectj.weaver.patterns.ReferencePointcut;
import org.aspectj.weaver.patterns.SignaturePattern;
import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
import org.aspectj.weaver.patterns.ThrowsPattern;
import org.aspectj.weaver.patterns.TypePattern;
import org.aspectj.weaver.patterns.TypePatternList;
import org.aspectj.weaver.patterns.WildTypePattern;
import org.aspectj.weaver.patterns.WithinPointcut;
import org.aspectj.weaver.patterns.WithincodePointcut;

/**
 * Extends the PatternParser to generate Wrappers for Pointcut objects
 * instead of the objects themselves. It also performs the registration
 * of parsed pointcuts to the CaesarPointcutScope class, so that more 
 * information about the pointcut can be used when resolving them.
 *
 * @author Thiago Tonelli Bartolomei <thiagobart@gmail.com>
 *
 */
public class CaesarWrapperPatternParser extends PatternParser {

    /**
     * Store the tokenSource too
     */
    private ITokenSource tokenSource = null;

    private ISourceContext sourceContext;

    /**
     * Constructor for PatterParserWrapper.
     * Just calls super.
     * 
     * @param tokenSource the tokensource object
     */
    public CaesarWrapperPatternParser(ITokenSource tokenSource) {
        super(tokenSource);
        this.tokenSource = tokenSource;
        this.sourceContext = tokenSource.getSourceContext();
    }

    // ----------------------------------------------------------------------
    // CODE COPIED FROM ASPECTJ'S PatternParser AND MODIFIED TO GENERATE WRAPPERS
    // ----------------------------------------------------------------------

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

        String kind = parseIdentifier();
        tokenSource.setIndex(start);
        if (kind.equals("if")) {
            return parseIfPointcut();
        } else if (kind.equals("super")) {
            return parseSuperPointcut();
        } else if (kind.equals("execution") || kind.equals("call") || kind.equals("get") || kind.equals("set")) {
            return parseKindedPointcut();
        } else if (kind.equals("args")) {
            return parseArgsPointcut();
        } else if (kind.equals("this") || kind.equals("target")) {
            return parseThisOrTargetPointcut();
        } else if (kind.equals("within")) {
            return parseWithinPointcut();
        } else if (kind.equals("withincode")) {
            return parseWithinCodePointcut();
        } else if (kind.equals("cflow")) {
            return parseCflowPointcut(false);
        } else if (kind.equals("cflowbelow")) {
            return parseCflowPointcut(true);
        } else if (kind.equals("adviceexecution")) {
            parseIdentifier();
            eat("(");
            eat(")");

            // Creates the wrapper 
            CaesarKindedPointcut pointcut = new CaesarKindedPointcut(Shadow.AdviceExecution,
                    new SignaturePattern(Member.ADVICE, ModifiersPattern.ANY, TypePattern.ANY, TypePattern.ANY,
                            NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY));
            CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(pointcut);
            return wrapper;

        } else if (kind.equals("handler")) {
            parseIdentifier();
            eat("(");
            TypePattern typePat = parseTypePattern();
            eat(")");

            // Creates the wrapper 
            HandlerPointcut pointcut = new HandlerPointcut(typePat);
            CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(pointcut);
            wrapper.setExceptionType(typePat);
            return wrapper;

        } else if (kind.equals("initialization")) {
            parseIdentifier();
            eat("(");
            SignaturePattern sig = parseConstructorSignaturePattern();
            eat(")");

            // Creates the wrapper
            CaesarKindedPointcut regular = new CaesarKindedPointcut(Shadow.Initialization, sig);

            return new CaesarPointcutWrapper(regular);

        } else if (kind.equals("staticinitialization")) {
            parseIdentifier();
            eat("(");
            TypePattern typePat = parseTypePattern();
            eat(")");
            SignaturePattern sig = new SignaturePattern(Member.STATIC_INITIALIZATION, ModifiersPattern.ANY,
                    TypePattern.ANY, typePat, NamePattern.ANY, TypePatternList.EMPTY, ThrowsPattern.ANY);

            // Creates the wrapper and register it
            CaesarKindedPointcut pt = new CaesarKindedPointcut(Shadow.StaticInitialization, sig);
            CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(pt);
            registerPointcut(wrapper);

            // Append something like || get(public * Classname_Impl_Mixin_*.field)
            TypePattern mixinType = createMixinType(sig.getDeclaringType());
            SignaturePattern mixinSignature = createMixinSignature(sig, mixinType);

            CaesarKindedPointcut mixin = new CaesarKindedPointcut(Shadow.StaticInitialization, mixinSignature);

            // Register the mixin
            wrapper = new CaesarPointcutWrapper(mixin, sig.getDeclaringType());
            wrapper.setDeclaringType(mixinType);
            registerPointcut(wrapper);

            // Creates an orPointcut for both the type and the mixin
            Pointcut orPointcut = new OrPointcut(pt, mixin);

            return new CaesarPointcutWrapper(orPointcut);

        } else if (kind.equals("preinitialization")) {
            parseIdentifier();
            eat("(");
            SignaturePattern sig = parseConstructorSignaturePattern();
            eat(")");

            CaesarCloner c = CaesarCloner.instance();

            SignaturePattern cclassSig = new SignaturePattern(Member.CONSTRUCTOR, sig.getModifiers(),
                    c.clone(sig.getReturnType()), c.clone(sig.getDeclaringType()), c.clone(sig.getName()),
                    createObjectTypeList(), c.clone(sig.getThrowsPattern()));

            CaesarKindedPointcut regular = new CaesarKindedPointcut(Shadow.PreInitialization, sig);

            CaesarKindedPointcut cclass = new CaesarKindedPointcut(Shadow.PreInitialization, cclassSig);

            registerPointcut(new CaesarPointcutWrapper(regular));
            registerPointcut(new CaesarPointcutWrapper(cclass));

            // Creates an orPointcut for both the regular java and cclass constructors
            Pointcut orPointcut = new OrPointcut(regular, cclass);

            return new CaesarPointcutWrapper(orPointcut);

        } else {
            return parseReferencePointcut();
        }
    }

    private CaesarPointcutWrapper parseKindedPointcut() {
        String kind = parseIdentifier();
        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(")");

        // Creates the wrapper

        if (Shadow.MethodCall.equals(shadowKind) || Shadow.MethodExecution.equals(shadowKind)) {

            // Method call and execution are wrapped in an "and pointcut" to avoid getting constructors
            CaesarKindedPointcut p = new CaesarKindedPointcut(shadowKind, sig);
            registerPointcut(new CaesarPointcutWrapper(p));

            Pointcut andPointcut = new AndPointcut(p,
                    new NotPointcut(new CaesarKindedPointcut(shadowKind, this.createConstructorSignature()),
                            tokenSource.peek().getStart()));

            return new CaesarPointcutWrapper(andPointcut);
        } else if (Shadow.ConstructorCall.equals(shadowKind) || Shadow.ConstructorExecution.equals(shadowKind)) {

            Shadow.Kind cclassShadowKind = null;

            // Transform the constructor call/execution to a method call/execution, 
            // using $constructor and the same parameters
            if (Shadow.ConstructorCall.equals(shadowKind)) {
                cclassShadowKind = Shadow.MethodCall;
            } else {
                cclassShadowKind = Shadow.MethodExecution;
            }

            CaesarCloner c = CaesarCloner.instance();

            SignaturePattern cclassSig = new SignaturePattern(Member.METHOD, sig.getModifiers(),
                    createCaesarObjectPattern(), c.clone(sig.getDeclaringType()), new NamePattern("$constructor"),
                    c.clone(sig.getParameterTypes()), c.clone(sig.getThrowsPattern()));

            CaesarKindedPointcut regular = new CaesarKindedPointcut(shadowKind, sig);

            CaesarKindedPointcut cclass = new CaesarKindedPointcut(cclassShadowKind, cclassSig);

            registerPointcut(new CaesarPointcutWrapper(regular));
            registerPointcut(new CaesarPointcutWrapper(cclass));

            // Creates an orPointcut for both the regular java and cclass constructors
            Pointcut orPointcut = new OrPointcut(regular, cclass);

            return new CaesarPointcutWrapper(orPointcut);
        }

        if (Shadow.FieldGet.equals(shadowKind) || Shadow.FieldSet.equals(shadowKind)) {

            // Creates the wrapper and register it
            CaesarKindedPointcut p = new CaesarKindedPointcut(shadowKind, sig);
            CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(p);
            registerPointcut(wrapper);

            // Append something like || get(public * Classname_Impl_Mixin_*.field)
            TypePattern mixinType = createMixinType(sig.getDeclaringType());
            SignaturePattern mixinSignature = createMixinSignature(sig, mixinType);

            CaesarKindedPointcut mixin = new CaesarKindedPointcut(shadowKind, mixinSignature);

            // Register the mixin
            wrapper = new CaesarPointcutWrapper(mixin, sig.getDeclaringType());
            wrapper.setDeclaringType(mixinType);
            registerPointcut(wrapper);

            // Creates an orPointcut for both the type and the mixin
            Pointcut orPointcut = new OrPointcut(p, mixin);

            return new CaesarPointcutWrapper(orPointcut);

        }
        CaesarKindedPointcut p = new CaesarKindedPointcut(shadowKind, sig);
        return new CaesarPointcutWrapper(p);
    }

    /**
     * Method parseArgsPointcut.
     * @return Pointcut
     */
    private CaesarPointcutWrapper parseArgsPointcut() {
        parseIdentifier();
        TypePatternList arguments = parseArgumentsPattern();

        // Creates the wrapper 
        ArgsPointcut p = new ArgsPointcut(arguments);
        CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(p);
        return wrapper;

    }

    /**
     * Method parseThisOrTargetPointcut.
     * @return Pointcut
     */
    private CaesarPointcutWrapper parseThisOrTargetPointcut() {
        String kind = parseIdentifier();
        eat("(");
        TypePattern type = parseTypePattern();
        eat(")");

        // Creates the wrapper 
        ThisOrTargetPointcut p = new ThisOrTargetPointcut(kind.equals("this"), type);
        CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(p);
        return wrapper;
    }

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

        // Creates the wrapper and register it
        WithinPointcut p = new WithinPointcut(type);
        CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(p);
        wrapper.setTypePattern(type);
        registerPointcut(wrapper);

        // Creates something like || within(Classname_Impl_Mixin_*)
        TypePattern mixinType = createMixinType(type);

        WithinPointcut mixin = new WithinPointcut(mixinType);

        // Register the mixin
        wrapper = new CaesarPointcutWrapper(mixin, type);
        wrapper.setTypePattern(mixinType);
        registerPointcut(wrapper);

        // Creates an orPointcut for both the type and the mixin
        Pointcut orPointcut = new OrPointcut(p, mixin);

        return new CaesarPointcutWrapper(orPointcut);
    }

    /**
     * Parses a Withincode Pointcut
     * 
     * @return
     */
    private CaesarPointcutWrapper parseWithinCodePointcut() {

        // Parses the signature pattern
        parseIdentifier();
        eat("(");
        SignaturePattern sig = parseMethodOrConstructorSignaturePattern();
        eat(")");

        // Gets the declaring type
        TypePattern type = sig.getDeclaringType();

        // Creates the wrapper and register it
        Pointcut p = new WithincodePointcut(sig);
        CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(p);
        wrapper.setDeclaringType(type);
        registerPointcut(wrapper);

        if (Member.CONSTRUCTOR.equals(sig.getKind())) {

            // Transform the constructor withincode to a method withincode, 
            // using $constructor and the same parameters (for cclasses)
            CaesarCloner c = CaesarCloner.instance();

            sig = new SignaturePattern(Member.METHOD, sig.getModifiers(), createCaesarObjectPattern(),
                    c.clone(type), new NamePattern("$constructor"), c.clone(sig.getParameterTypes()),
                    c.clone(sig.getThrowsPattern()));

            WithincodePointcut cclass = new WithincodePointcut(sig);
            wrapper = new CaesarPointcutWrapper(cclass);
            wrapper.setDeclaringType(sig.getDeclaringType());
            registerPointcut(wrapper);

            // Creates an orPointcut for both the regular java and cclass constructors
            p = new OrPointcut(p, cclass);
        }

        // Creates something like || withincode(* Classname_Impl_Mixin_*.m())
        TypePattern mixinType = createMixinType(type);
        SignaturePattern mixinSignature = createMixinSignature(sig, mixinType);

        WithincodePointcut mixin = new WithincodePointcut(mixinSignature);

        // Register the mixin
        wrapper = new CaesarPointcutWrapper(mixin, type);
        wrapper.setDeclaringType(mixinType);
        registerPointcut(wrapper);

        // Creates an orPointcut for both the type and the mixin
        Pointcut orPointcut = new OrPointcut(p, mixin);

        return new CaesarPointcutWrapper(orPointcut);
    }

    private CaesarPointcutWrapper parseCflowPointcut(boolean isBelow) {
        parseIdentifier();
        eat("(");
        Pointcut entry = parsePointcut();
        eat(")");

        // Creates the wrapper 
        CflowPointcut p = new CflowPointcut(entry, isBelow, null);
        CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(p);
        return wrapper;

    }

    /**
     * 
     * @return
     */
    private CaesarPointcutWrapper parseIfPointcut() {
        String kind = parseIdentifier();
        eat("(");
        CaesarPointcutWrapper w = null;
        if (maybeEatIdentifier("true")) {
            w = new CaesarPointcutWrapper(IfPointcut.makeIfTruePointcut(Pointcut.SYMBOLIC));
        }
        if (maybeEatIdentifier("false")) {
            w = new CaesarPointcutWrapper(IfPointcut.makeIfFalsePointcut(Pointcut.SYMBOLIC));
        }
        eat(")");
        if (w == null)
            throw new ParserException("If pointcuts currently accept only 'true' or 'false' as values",
                    tokenSource.peek());

        return w;
    }

    /**
     * When the token "super" is found in a pointcut, parse a super pointcut.
     * 
     * @return a wrapper to the super pointcut
     */
    private CaesarPointcutWrapper parseSuperPointcut() {
        String kind = parseIdentifier();
        eat(".");
        TypePattern onType = parseTypePattern();
        NamePattern name = tryToExtractName(onType);
        if (name == null) {
            throw new ParserException("Super pointcut must reference a named pointcut", tokenSource.peek());
        }

        TypePatternList arguments = parseArgumentsPattern();

        // Creates the wrapper 
        CaesarSuperPointcut p = new CaesarSuperPointcut(name.maybeGetSimpleName(), arguments);
        CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(p);
        return wrapper;
    }

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

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

    private CaesarPointcutWrapper parseReferencePointcut() {
        TypePattern onType = parseTypePattern();
        NamePattern name = tryToExtractName(onType);
        if (name == null) {
            throw new ParserException("name pattern", tokenSource.peek());
        }
        if (onType.toString().equals("")) {
            onType = null;
        }

        TypePatternList arguments = parseArgumentsPattern();

        // Creates the wrapper 
        ReferencePointcut p = new ReferencePointcut(onType, name.maybeGetSimpleName(), arguments);
        CaesarPointcutWrapper wrapper = new CaesarPointcutWrapper(p);
        wrapper.setOnTypeSymbolic(p.onTypeSymbolic);
        return wrapper;
    }

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

    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 CaesarModifiersPattern(requiredFlags, forbiddenFlags);
        }
    }

    //----------------------------------------------------------------------
    // COPIED JUST TO ADAPT FOR CaesarWildTypePatterns
    // ----------------------------------------------------------------------

    public TypePattern parseSingleTypePattern() {
        List<NamePattern> names = parseDottedNamePattern();
        //      new ArrayList();
        //      NamePattern p1 = parseNamePattern();
        //      names.add(p1);
        //      while (maybeEat(".")) {
        //         if (maybeEat(".")) {
        //            names.add(NamePattern.ELLIPSIS);
        //         }
        //         NamePattern p2 = parseNamePattern();
        //         names.add(p2);
        //      }
        int dim = 0;
        while (maybeEat("[")) {
            eat("]");
            dim++;
        }

        boolean includeSubtypes = maybeEat("+");
        int endPos = tokenSource.peek(-1).getEnd();

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

        return new CaesarWildTypePattern(names, includeSubtypes, dim, endPos);
    }

    public List<NamePattern> parseDottedNamePattern() {
        List<NamePattern> names = new ArrayList<NamePattern>();
        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()) {
                    buf.append(tok.getString());
                } 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("expected 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);
                if (!maybeEat("."))
                    break;
                else
                    previous = tokenSource.peek(-1);
            } else {
                buf.setLength(0);
                buf.append(afterDot);
                afterDot = null;
            }
        }
        //System.err.println("parsed: " + names);
        return names;
    }

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

    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 maybeEatNew(TypePattern returnType) {

        if (returnType instanceof CaesarWildTypePattern) {
            CaesarWildTypePattern p = (CaesarWildTypePattern) returnType;
            if (p.maybeExtractName("new"))
                return true;
        }
        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;
    }

    // ----------------------------------------------------------------------
    // CODE FOR REGISTRING THE GENERATED POINTCUTS
    // ----------------------------------------------------------------------

    /**
     * Extends PatterParser's parseSinglePointcut to register the
     * relation between the TypePattern with the Pointcut.
     */
    public Pointcut parseSinglePointcut() {

        // Parse the pointcut with PatterParser
        CaesarPointcutWrapper p = this.parsePointcutWrapper();

        // Store in the map
        registerPointcut(p);

        // Return the PatterParser result
        return p.getWrappee();
    }

    /**
     * Register the relation between the TypePattern in 
     * the Pointcut with the Pointcut itself. The map will 
     * be stored statically in the CaesarPointcutScope, 
     * where it will be used to lookup the correct type in pointcuts.
     * 
     * @param pointcut the pointcut to be registered
     */
    protected void registerPointcut(CaesarPointcutWrapper pointcut) {

        if (pointcut.isKinded()) {
            CaesarKindedPointcut p = (CaesarKindedPointcut) pointcut.getWrappee();

            CaesarPointcutScope.register(p.getSignature().getDeclaringType(), pointcut);
            return;
        }

        if (pointcut.isWithin()) {
            CaesarPointcutScope.register(pointcut.getTypePattern(), pointcut);
            return;
        }

        if (pointcut.isWithincode()) {
            CaesarPointcutScope.register(pointcut.getDeclaringType(), pointcut);
            return;
        }

        if (pointcut.isHandler()) {
            CaesarPointcutScope.register(pointcut.getExceptionType(), pointcut);
            return;
        }

        if (pointcut.isReference()) {
            CaesarPointcutScope.register(pointcut.getOnTypeSymbolic(), pointcut);
            return;
        }

        // No need to store information for these types
        if (pointcut.isArgs()) {
            return;
        }
        if (pointcut.isThisOrTarget()) {
            return;
        }
        if (pointcut.isCflow()) {
            return;
        }
    }

    // ----------------------------------------------------------------------
    // HELPERS
    // ----------------------------------------------------------------------

    /**
     * Creates a TypePatternList which contains only the CaesarWildTypePattern needed
     * to match the java.lang.Object name. This is used to create the parameters
     * list when matching the default contructor
     * 
     * @return a list with the pattern for Object
     */
    protected TypePatternList createObjectTypeList() {

        ArrayList<NamePattern> names = new ArrayList<NamePattern>();
        names.add(new NamePattern("java.lang.Object"));

        return new TypePatternList(new TypePattern[] { new CaesarWildTypePattern(names, false, 0) });
    }

    /**
     * Creates a type pattern (a CaesarWildTypePattern) which represents the CaesarObject
     * class. 
     * 
     * @return a type pattern for the CaesarObject class
     */
    protected TypePattern createCaesarObjectPattern() {

        ArrayList<NamePattern> names = new ArrayList<NamePattern>();
        names.add(new NamePattern("org.caesarj.runtime.CaesarObject"));

        return new CaesarWildTypePattern(names, false, 0);
    }

    /**
     * Creates a signator which select constructors:
     * 
     *   * $constructor(..)
     *   
     * @return
     */
    protected SignaturePattern createConstructorSignature() {

        return new SignaturePattern(Member.METHOD, ModifiersPattern.ANY, TypePattern.ANY, TypePattern.ANY,
                new NamePattern("$constructor"), new TypePatternList(new TypePattern[] { TypePattern.ELLIPSIS }),
                ThrowsPattern.ANY);
    }

    /**
     * Returns a clone of the name patterns this type pattern has
     *  
     * @param pattern
     * @return a list of name patterns, which is a clone of this pattern
     */
    protected List<NamePattern> createMixinNamePatterns(TypePattern pattern) {

        ArrayList<NamePattern> namePatterns = new ArrayList<NamePattern>();

        String[] names = pattern.toString().split("\\.");

        for (int i = 0; i < names.length; i++) {
            namePatterns.add(new NamePattern(names[i]));
        }

        return namePatterns;
    }

    /**
     * Creates a mixin type pattern (a CaesarWildTypePatter) for this type, using the 
     * createMixinNamePatterns method.
     * 
     * @param type the type
     * @return a mixin pattern to the type
     */
    protected TypePattern createMixinType(TypePattern type) {

        return new CaesarWildTypePattern(createMixinNamePatterns(type), type.isIncludeSubtypes(), 0);
    }

    /**
     * Creates a signature pattern which is a clone of this signature but has the mixinType 
     * as declaringType
     * 
     * @param sig
     * @param mixinType
     * @return
     */
    protected SignaturePattern createMixinSignature(SignaturePattern sig, TypePattern mixinType) {

        CaesarCloner c = CaesarCloner.instance();

        return new SignaturePattern(sig.getKind(), sig.getModifiers(), c.clone(sig.getReturnType()), mixinType,
                c.clone(sig.getName()), c.clone(sig.getParameterTypes()), c.clone(sig.getThrowsPattern()));
    }
}