/*******************************************************************************
* Copyright (c) 2006 IBM Corporation.
* 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
*******************************************************************************/
package com.ibm.wala.types.generics;
import java.util.ArrayList;
import java.util.Iterator;
import com.ibm.wala.types.TypeReference;
/**
* UNDER CONSTRUCTION
*
* <verbatim> TypeArgument: WildcardIndicator? FieldTypeSignature *
*
* WildcardIndicator: + -
*
*
* </verbatim>
*
* @author sjfink
*
*/
public class TypeArgument extends Signature {
private final TypeSignature sig;
private final WildcardIndicator w;
private static enum WildcardIndicator {
PLUS, MINUS
}
private final static TypeArgument WILDCARD = new TypeArgument("*") {
@Override
public boolean isWildcard() {
return true;
}
@Override
public String toString() {
return "*";
}
};
private TypeArgument(String s) {
super(s);
sig = null;
w = null;
}
private TypeArgument(TypeSignature sig, WildcardIndicator w) {
super(sig.rawString());
this.sig = sig;
this.w = w;
}
public boolean isWildcard() {
return false;
}
public static TypeArgument[] make(String s) throws IllegalArgumentException {
if (s == null) {
throw new IllegalArgumentException("s is null");
}
if (s.length() == 0 || s.charAt(0) != '<') {
throw new IllegalArgumentException(s);
}
if (s.charAt(s.length() - 1) != '>') {
throw new IllegalArgumentException(s);
}
String[] args = parseForTypeArguments(s);
TypeArgument[] result = new TypeArgument[args.length];
for (int i = 0; i < result.length; i++) {
result[i] = makeTypeArgument(args[i]);
}
return result;
}
private static TypeArgument makeTypeArgument(String s) {
switch (s.charAt(0)) {
case '*':
return WILDCARD;
case '+': {
TypeSignature sig = TypeSignature.make(s.substring(1));
return new TypeArgument(sig, WildcardIndicator.PLUS);
}
case '-': {
TypeSignature sig = TypeSignature.make(s.substring(1));
return new TypeArgument(sig, WildcardIndicator.MINUS);
}
default:
TypeSignature sig = TypeSignature.make(s);
return new TypeArgument(sig, null);
}
}
/**
* @param typeSigs TypeSignature*
* @return tokenize it
*/
static String[] parseForTypeArguments(String typeArgs) {
ArrayList<String> args = new ArrayList<String>(10);
int i = 1;
while (true) {
switch (typeArgs.charAt(i++)) {
case TypeReference.ClassTypeCode: {
int off = i - 1;
int depth = 0;
while (typeArgs.charAt(i++) != ';' || depth > 0) {
if (typeArgs.charAt(i - 1) == '<') {
depth++;
}
if (typeArgs.charAt(i - 1) == '>') {
depth--;
}
}
args.add(typeArgs.substring(off, i));
continue;
}
case TypeReference.ArrayTypeCode: {
int off = i - 1;
while (typeArgs.charAt(i) == TypeReference.ArrayTypeCode) {
++i;
}
if (typeArgs.charAt(i++) == TypeReference.ClassTypeCode) {
while (typeArgs.charAt(i++) != ';')
;
args.add(typeArgs.substring(off, i - off - 1));
} else {
args.add(typeArgs.substring(off, i - off));
}
continue;
}
case (byte) '-':
case (byte) '+':
case (byte) 'T': { // type variable
int off = i - 1;
while (typeArgs.charAt(i++) != ';')
;
args.add(typeArgs.substring(off, i));
continue;
}
case (byte) '*': {
// a wildcard
args.add("*");
continue;
}
case (byte) '>': // end of argument list
int size = args.size();
if (size == 0) {
return null;
}
Iterator<String> it = args.iterator();
String[] result = new String[size];
for (int j = 0; j < size; j++) {
result[j] = it.next();
}
return result;
default:
assert false : "bad type argument list " + typeArgs;
}
}
}
public TypeSignature getFieldTypeSignature() {
return sig;
}
@Override
public String toString() {
if (w == null) {
return sig.toString();
} else if (w.equals(WildcardIndicator.PLUS)) {
return "+" + sig.toString();
} else {
return "-" + sig.toString();
}
}
}