All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.spricom.dessert.classfile.attribute.SignatureParser Maven / Gradle / Ivy

The newest version!
package de.spricom.dessert.classfile.attribute;

/*-
 * #%L
 * Dessert Dependency Assertion Library for Java
 * %%
 * Copyright (C) 2017 - 2023 Hans Jörg Heßmann
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.util.HashSet;
import java.util.Set;

public class SignatureParser {
	private final Set dependentClasses;
	private final String signature;
	private int position;

	public SignatureParser(String signature, Set dependentClasses) {
		this.dependentClasses = dependentClasses;
		this.signature = signature;
	}

	public SignatureParser(String signature) {
		this(signature, new HashSet());
	}

	public boolean parseClassSignature() {
		parseTypeParameters();
		ensure(parseSuperclassSignature());
		while (parseSuperInterfaceSignature());
		return true;
	}

	private boolean parseTypeParameters() {
		if ('<' != lookAhead()) {
			return false;
		}
		position++;
		parseTypeParameter();
		while (parseTypeParameter())
			;
		ensure('>' == lookAhead());
		position++;
		return true;
	}

	private boolean parseTypeParameter() {
		int lastIndex = position;
		parseIdentifier();
		if (!parseClassBound()) {
			position = lastIndex;
			return false;
		}
		while (parseInterfaceBound())
			;
		return true;
	}

	private boolean parseClassBound() {
		if (':' != lookAhead()) {
			return false;
		}
		position++;
		parseReferenceTypeSignature();
		return true;
	}

	private boolean parseInterfaceBound() {
		if (':' != lookAhead()) {
			return false;
		}
		position++;
		ensure(parseReferenceTypeSignature());
		return true;
	}

	private boolean parseSuperclassSignature() {
		ensure(parseClassTypeSignature());
		return true;
	}

	private boolean parseSuperInterfaceSignature() {
		return parseClassTypeSignature();
	}

	public boolean parseMethodSignature() {
		parseTypeParameters();
		ensure('(' == lookAhead());
		position++;
		while (parseJavaTypeSignature())
			;
		ensure(')' == lookAhead());
		position++;
		ensure(parseResult());
		while (parseThrowsSignature())
			;
		return true;
	}

	private boolean parseResult() {
		return parseVoidDescriptor() || parseJavaTypeSignature();
	}

	private boolean parseVoidDescriptor() {
		if ('V' != lookAhead()) {
			return false;
		}
		position++;
		return true;
	}

	private boolean parseThrowsSignature() {
		if ('^' != lookAhead()) {
			return false;
		}
		position++;
		ensure(parseClassTypeSignature() || parseTypeVariableSignature());
		return true;
	}

	public boolean parseFieldSignature() {
		ensure(parseReferenceTypeSignature());
		return true;
	}

	public boolean parseJavaTypeSignature() {
		return parseBaseType() || parseReferenceTypeSignature();
	}

	private boolean parseReferenceTypeSignature() {
		return parseClassTypeSignature() || parseTypeVariableSignature() || parseArrayTypeSignature();
	}

	private boolean parseClassTypeSignature() {
		if ('L' != lookAhead()) {
			return false;
		}
		position++;
		int start = position;
		parsePackageSpecifier();
		ensure(parseSimpleClassTypeSignature());
		while (parseClassTypeSignatureSuffix())
			;
		ensure(';' == lookAhead());
		
		String classname = signature.substring(start, position);
		int typeIndex = classname.indexOf('<');
		if (typeIndex == -1) typeIndex = classname.length();
		dependentClasses.add(classname.substring(0, typeIndex).replace('/', '.'));
		
		position++;
		return true;
	}

	private boolean parsePackageSpecifier() {
		int lastIndex = position;
		parseIdentifier();
		if ('/' != lookAhead()) {
			position = lastIndex;
			return false;
		}
		position++;
		parsePackageSpecifier();
		return true;
	}

	private boolean parseSimpleClassTypeSignature() {
		ensure(parseIdentifier());
		parseTypeArguments();
		return true;
	}

	private boolean parseTypeArguments() {
		if ('<' != lookAhead()) {
			return false;
		}
		position++;
		ensure(parseTypeArgument());
		while (parseTypeArgument())
			;
		ensure('>' == lookAhead());
		position++;
		return true;
	}

	private boolean parseTypeArgument() {
		if ('*' == lookAhead()) {
			position++;
			return true;
		}
		parseWildcardIndicator();
		return parseReferenceTypeSignature();
	}

	private boolean parseWildcardIndicator() {
		if ("+-".indexOf(lookAhead()) == -1) {
			return false;
		}
		position++;
		return true;
	}

	private boolean parseClassTypeSignatureSuffix() {
		if ('.' != lookAhead()) {
			return false;
		}
		position++;
		ensure(parseSimpleClassTypeSignature());
		return true;
	}

	private boolean parseTypeVariableSignature() {
		if ('T' != lookAhead()) {
			return false;
		}
		position++;
		ensure(parseIdentifier());
		ensure(';' == lookAhead());
		position++;
		return true;
	}

	private boolean parseArrayTypeSignature() {
		if ('[' != lookAhead()) {
			return false;
		}
		position++;
		ensure(parseJavaTypeSignature());
		return true;
	}

	private boolean parseIdentifier() {
		if (!Character.isJavaIdentifierStart(lookAhead())) {
			return false;
		}
		position++;
		while (Character.isJavaIdentifierPart(lookAhead())) {
			position++;
		}
		return true;
	}

	private boolean parseBaseType() {
		if ("BCDFIJSZ".indexOf(lookAhead()) == -1) {
			return false;
		}
		position++;
		return true;
	}

	private char lookAhead() {
		if (position >= signature.length()) {
			return 0;
		}
		return signature.charAt(position);
	}

	private void ensure(boolean parsed) {
		if (!parsed) {
			throw new IllegalArgumentException(
					signature + " is invalid at position " + position + ": " + signature.substring(position));
		}
	}

	public boolean isComplete() {
		return position == signature.length();
	}

	public Set getDependentClasses() {
		return dependentClasses;
	}

	public String getSignature() {
		return signature;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy