/******************************************************************************* * Copyright (c) 2003, 2004 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ /* * Created on Nov 11, 2003 * * To change the template for this generated file go to * Window>Preferences>Java>Code Generation>Code and Comments */ package org.eclipse.jst.common.internal.annotations.core; /** * @author Pat Kelley * * To change the template for this generated type comment go to * Window>Preferences>Java>Code Generation>Code and Comments */ public class AnnotationTagParser { private TagParseEventHandler handler; private char[] input; int pos; int endOfLastGoodAttParse; private Object annotationLock = new Object(); public AnnotationTagParser(TagParseEventHandler tp) { if (tp == null) { throw new IllegalArgumentException(AnnotationsCoreResources.AnnotationTagParser_0); } handler = tp; } private boolean eos() { return pos >= input.length; } private boolean isWS(char c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t'; } private void skipWS() { while (pos < input.length && (isWS(input[pos]) || input[pos] == '*')) { pos++; } } // Caller is expected to make sure the eos has not been reached. private char peek() { return input[pos]; } // Caller is expected to check for EOS. private char nextChar() { return input[pos++]; } private boolean isNextChar(char c) { if (eos()) return false; return peek() == c; } private boolean isIDChar(char c) { return !isWS(c) && c != '=' && c != '@' && c != '\"'; } private Token collectID() { StringBuffer b = new StringBuffer(16); Token t = new Token(); t.setBeginning(pos); while (!eos() && isIDChar(peek())) { b.append(nextChar()); } t.setEnd(pos - 1); t.setText(b.toString()); return t; } private Token expectAttribName() { if (eos()) { return null; } int save = pos; Token retval = collectID(); if (retval.length() == 0) { pos = save; return null; } return retval; } private Token expectTag() { if (eos()) { return null; } int savePos = pos; if (nextChar() != '@') { return null; } if (eos() || isWS(peek())) { return null; } Token retval = expectAttribName(); if (retval.length() == 0) { pos = savePos + 1; } retval.setBeginning(savePos); // Save end of parse so we can pass it as the end of the parsed tag. endOfLastGoodAttParse = pos; return retval; } private Token expectQuotedValue() { skipWS(); if (eos()) { return null; } Token tok = new Token(); tok.setBeginning(pos); if (peek() != '\"') { return null; } nextChar(); if (eos()) { return null; } StringBuffer b = new StringBuffer(64); while (!eos() && peek() != '\"') { b.append(nextChar()); } if (!eos()) { nextChar(); } tok.setEnd(pos - 1); tok.setText(b.toString()); return tok; } private boolean expectAssign() { if (eos()) { return false; } if (nextChar() == '=') { return true; } pos--; return false; } private Token mkNullToken() { Token retval = new Token(); retval.setBeginning(pos); retval.setEnd(pos - 1); retval.setText(""); //$NON-NLS-1$ return retval; } private boolean parseNextAttribute() { skipWS(); if (eos()) { return false; } Token key = collectID(); if (key == null || key.length() == 0) { return false; } skipWS(); if (eos()) { // Go ahead and report it, even though it is a partial attribute. ( // we still fail here ) handler.attribute(key, -1, mkNullToken()); return false; } int eqPos = pos; if (!expectAssign()) { // Even though we won't parse this as a full attribute, go ahead and // call the handler with it. Some clients want to see partial // attributes. handler.attribute(key, -1, mkNullToken()); return false; } skipWS(); if (eos()) { // Same here - we fail on it, but we report it anyway handler.attribute(key, eqPos, mkNullToken()); return false; } Token value = expectQuotedValue(); if (value == null) { value = collectID(); if (isNextChar('=')) { pos = value.getBeginning(); value = mkNullToken(); } } endOfLastGoodAttParse = pos; handler.attribute(key, eqPos, value); return true; } private void parseAttributes() { while (!eos() && parseNextAttribute()) { // loop while not end of string } } private void skipToTagChar() { while (!eos() && peek() != '@') { nextChar(); } } public void setParserInput(char[] text) { synchronized(annotationLock) { input = text; pos = 0; endOfLastGoodAttParse = 0; } } public void setParserInput(String text) { setParserInput(text.toCharArray()); } public void parse() { synchronized (annotationLock) { while (!eos()) { skipToTagChar(); Token tag = expectTag(); if (tag == null) { break; } handler.annotationTag(tag); parseAttributes(); handler.endOfTag(endOfLastGoodAttParse); } } } }