/* * Copyright 2008 Google Inc. * * 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. */ package com.google.gwt.dev.util; import com.google.gwt.core.ext.typeinfo.JniConstants; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * A parsed Java reference from within a JSNI method. */ public class JsniRef { /** * Special field name for referring to a class literal. */ public static final String CLASS = "class"; /** * Special method name for a class constructor. */ public static final String NEW = "new"; /** * A parameter list indicating a match to any overload. */ public static final String WILDCARD_PARAM_LIST = "*"; /** * A regex pattern for a Java reference in JSNI code. Its groups are: * <ol> * <li>the class name * <li>the field or method name * <li>the method parameter types, including the surrounding parentheses * <li>the method parameter types, excluding the parentheses * </ol> */ private static Pattern JsniRefPattern = Pattern.compile("@?([^:]+)::([^(]+)(\\((.*)\\))?"); /** * Parse a Java reference from JSNI code. This parser is forgiving; it does * not always detect invalid references. If the refString is improperly * formatted, returns null. */ public static JsniRef parse(String refString) { Matcher matcher = JsniRefPattern.matcher(refString); if (!matcher.matches()) { return null; } String className = matcher.group(1); String memberName = matcher.group(2); String paramTypesString = null; String[] paramTypes = null; if (matcher.group(3) != null) { paramTypesString = matcher.group(4); if (!paramTypesString.equals(WILDCARD_PARAM_LIST)) { paramTypes = computeParamTypes(paramTypesString); if (paramTypes == null) { return null; } } } return new JsniRef(className, memberName, paramTypesString, paramTypes); } private static String[] computeParamTypes(String paramTypesString) { ArrayList<String> types = new ArrayList<String>(); StringBuilder nextType = new StringBuilder(); boolean inRef = false; for (char c : paramTypesString.toCharArray()) { nextType.append(c); if (inRef) { if (c == JniConstants.DESC_REF_END) { types.add(nextType.toString()); nextType.setLength(0); inRef = false; } } else { switch (c) { case JniConstants.DESC_BOOLEAN: case JniConstants.DESC_BYTE: case JniConstants.DESC_CHAR: case JniConstants.DESC_DOUBLE: case JniConstants.DESC_FLOAT: case JniConstants.DESC_INT: case JniConstants.DESC_LONG: case JniConstants.DESC_SHORT: case JniConstants.DESC_VOID: types.add(nextType.toString()); nextType.setLength(0); break; case JniConstants.DESC_ARRAY: // Nothing special to do. break; case JniConstants.DESC_REF: inRef = true; break; default: // Bad input. return null; } } } return types.toArray(Empty.STRINGS); } private final String className; private final String memberName; private final String[] paramTypes; private final String paramTypesString; protected JsniRef(String className, String memberName, String paramTypesString, String[] paramTypes) { this.className = className; this.memberName = memberName; this.paramTypesString = paramTypesString; this.paramTypes = paramTypes; } public String className() { return className; } @Override public boolean equals(Object obj) { return (obj instanceof JsniRef) && toString().equals(obj.toString()); } @Override public int hashCode() { return toString().hashCode(); } public boolean isField() { return paramTypesString == null; } public boolean isMethod() { return paramTypesString != null; } /** * Whether this method reference matches all overloads of the specified class * and method name. Only valid for method references. */ public boolean matchesAnyOverload() { return paramTypesString.equals(WILDCARD_PARAM_LIST); } public String memberName() { return memberName; } public String memberSignature() { String ret = memberName; if (isMethod()) { ret += "(" + paramTypesString + ")"; } return ret; } /** * Return the list of parameter types for the method referred to by this * reference. Only valid for method references where * {@link #matchesAnyOverload()} is false. */ public String[] paramTypes() { assert !matchesAnyOverload(); return paramTypes; } public String paramTypesString() { return paramTypesString; } @Override public String toString() { return "@" + className + "::" + memberSignature(); } }