rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java
changeset 772 d382dacfd73f
parent 666 8338ab1991e6
child 1321 7a78a84ab583
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java	Tue Feb 26 16:54:16 2013 +0100
     1.3 @@ -0,0 +1,224 @@
     1.4 +/**
     1.5 + * Back 2 Browser Bytecode Translator
     1.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     1.7 + *
     1.8 + * This program is free software: you can redistribute it and/or modify
     1.9 + * it under the terms of the GNU General Public License as published by
    1.10 + * the Free Software Foundation, version 2 of the License.
    1.11 + *
    1.12 + * This program is distributed in the hope that it will be useful,
    1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 + * GNU General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU General Public License
    1.18 + * along with this program. Look for COPYING file in the top folder.
    1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    1.20 + */
    1.21 +package org.apidesign.bck2brwsr.emul.reflect;
    1.22 +
    1.23 +import java.lang.reflect.Array;
    1.24 +import java.lang.reflect.Method;
    1.25 +import java.util.Enumeration;
    1.26 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    1.27 +
    1.28 +/** Utilities to work on methods.
    1.29 + *
    1.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    1.31 + */
    1.32 +public abstract class MethodImpl {
    1.33 +    public static MethodImpl INSTANCE;
    1.34 +    static {
    1.35 +        try {
    1.36 +            Class.forName(Method.class.getName());
    1.37 +        } catch (ClassNotFoundException ex) {
    1.38 +            throw new IllegalStateException(ex);
    1.39 +        }
    1.40 +    }
    1.41 +
    1.42 +    protected abstract Method create(Class<?> declaringClass, String name, Object data, String sig);
    1.43 +    
    1.44 +    
    1.45 +    //
    1.46 +    // bck2brwsr implementation
    1.47 +    //
    1.48 +
    1.49 +    @JavaScriptBody(args = {"clazz", "prefix"},
    1.50 +        body = ""
    1.51 +        + "var c = clazz.cnstr.prototype;"
    1.52 +        + "var arr = new Array();\n"
    1.53 +        + "for (m in c) {\n"
    1.54 +        + "  if (m.indexOf(prefix) === 0) {\n"
    1.55 +        + "     if (!c[m].cls) continue;\n"
    1.56 +        + "     arr.push(m);\n"
    1.57 +        + "     arr.push(c[m]);\n"
    1.58 +        + "     arr.push(c[m].cls.$class);\n"
    1.59 +        + "  }"
    1.60 +        + "}\n"
    1.61 +        + "return arr;")
    1.62 +    private static native Object[] findMethodData(
    1.63 +        Class<?> clazz, String prefix);
    1.64 +
    1.65 +    public static Method findMethod(
    1.66 +        Class<?> clazz, String name, Class<?>... parameterTypes) {
    1.67 +        Object[] data = findMethodData(clazz, name + "__");
    1.68 +        BIG: for (int i = 0; i < data.length; i += 3) {
    1.69 +            String sig = ((String) data[i]).substring(name.length() + 2);
    1.70 +            Class<?> cls = (Class<?>) data[i + 2];
    1.71 +            Method tmp = INSTANCE.create(cls, name, data[i + 1], sig);
    1.72 +            Class<?>[] tmpParms = tmp.getParameterTypes();
    1.73 +            if (parameterTypes.length != tmpParms.length) {
    1.74 +                continue;
    1.75 +            }
    1.76 +            for (int j = 0; j < tmpParms.length; j++) {
    1.77 +                if (!parameterTypes[j].equals(tmpParms[j])) {
    1.78 +                    continue BIG;
    1.79 +                }
    1.80 +            }
    1.81 +            return tmp;
    1.82 +        }
    1.83 +        return null;
    1.84 +    }
    1.85 +
    1.86 +    public static Method[] findMethods(Class<?> clazz, int mask) {
    1.87 +        Object[] namesAndData = findMethodData(clazz, "");
    1.88 +        int cnt = 0;
    1.89 +        for (int i = 0; i < namesAndData.length; i += 3) {
    1.90 +            String sig = (String) namesAndData[i];
    1.91 +            Object data = namesAndData[i + 1];
    1.92 +            int middle = sig.indexOf("__");
    1.93 +            if (middle == -1) {
    1.94 +                continue;
    1.95 +            }
    1.96 +            String name = sig.substring(0, middle);
    1.97 +            sig = sig.substring(middle + 2);
    1.98 +            Class<?> cls = (Class<?>) namesAndData[i + 2];
    1.99 +            final Method m = INSTANCE.create(cls, name, data, sig);
   1.100 +            if ((m.getModifiers() & mask) == 0) {
   1.101 +                continue;
   1.102 +            }
   1.103 +            namesAndData[cnt++] = m;
   1.104 +        }
   1.105 +        Method[] arr = new Method[cnt];
   1.106 +        for (int i = 0; i < cnt; i++) {
   1.107 +            arr[i] = (Method) namesAndData[i];
   1.108 +        }
   1.109 +        return arr;
   1.110 +    }
   1.111 +    static String toSignature(Method m) {
   1.112 +        StringBuilder sb = new StringBuilder();
   1.113 +        sb.append(m.getName()).append("__");
   1.114 +        appendType(sb, m.getReturnType());
   1.115 +        Class<?>[] arr = m.getParameterTypes();
   1.116 +        for (int i = 0; i < arr.length; i++) {
   1.117 +            appendType(sb, arr[i]);
   1.118 +        }
   1.119 +        return sb.toString();
   1.120 +    }
   1.121 +    
   1.122 +    private static void appendType(StringBuilder sb, Class<?> type) {
   1.123 +        if (type == Integer.TYPE) {
   1.124 +            sb.append('I');
   1.125 +            return;
   1.126 +        }
   1.127 +        if (type == Long.TYPE) {
   1.128 +            sb.append('J');
   1.129 +            return;
   1.130 +        }
   1.131 +        if (type == Double.TYPE) {
   1.132 +            sb.append('D');
   1.133 +            return;
   1.134 +        }
   1.135 +        if (type == Float.TYPE) {
   1.136 +            sb.append('F');
   1.137 +            return;
   1.138 +        }
   1.139 +        if (type == Byte.TYPE) {
   1.140 +            sb.append('B');
   1.141 +            return;
   1.142 +        }
   1.143 +        if (type == Boolean.TYPE) {
   1.144 +            sb.append('Z');
   1.145 +            return;
   1.146 +        }
   1.147 +        if (type == Short.TYPE) {
   1.148 +            sb.append('S');
   1.149 +            return;
   1.150 +        }
   1.151 +        if (type == Void.TYPE) {
   1.152 +            sb.append('V');
   1.153 +            return;
   1.154 +        }
   1.155 +        if (type == Character.TYPE) {
   1.156 +            sb.append('C');
   1.157 +            return;
   1.158 +        }
   1.159 +        if (type.isArray()) {
   1.160 +            sb.append("_3");
   1.161 +            appendType(sb, type.getComponentType());
   1.162 +            return;
   1.163 +        }
   1.164 +        sb.append('L').append(type.getName().replace('.', '_'));
   1.165 +        sb.append("_2");
   1.166 +    }
   1.167 +
   1.168 +    public static int signatureElements(String sig) {
   1.169 +        Enumeration<Class> en = signatureParser(sig);
   1.170 +        int cnt = 0;
   1.171 +        while (en.hasMoreElements()) {
   1.172 +            en.nextElement();
   1.173 +            cnt++;
   1.174 +        }
   1.175 +        return cnt;
   1.176 +    }
   1.177 +    
   1.178 +    public static Enumeration<Class> signatureParser(final String sig) {
   1.179 +        class E implements Enumeration<Class> {
   1.180 +            int pos;
   1.181 +            
   1.182 +            public boolean hasMoreElements() {
   1.183 +                return pos < sig.length();
   1.184 +            }
   1.185 +
   1.186 +            public Class nextElement() {
   1.187 +                switch (sig.charAt(pos++)) {
   1.188 +                    case 'I':
   1.189 +                        return Integer.TYPE;
   1.190 +                    case 'J':
   1.191 +                        return Long.TYPE;
   1.192 +                    case 'D':
   1.193 +                        return Double.TYPE;
   1.194 +                    case 'F':
   1.195 +                        return Float.TYPE;
   1.196 +                    case 'B':
   1.197 +                        return Byte.TYPE;
   1.198 +                    case 'Z':
   1.199 +                        return Boolean.TYPE;
   1.200 +                    case 'S':
   1.201 +                        return Short.TYPE;
   1.202 +                    case 'V':
   1.203 +                        return Void.TYPE;
   1.204 +                    case 'C':
   1.205 +                        return Character.TYPE;
   1.206 +                    case 'L':
   1.207 +                        try {
   1.208 +                            int up = sig.indexOf("_2", pos);
   1.209 +                            String type = sig.substring(pos, up);
   1.210 +                            pos = up + 2;
   1.211 +                            return Class.forName(type.replace('_', '.'));
   1.212 +                        } catch (ClassNotFoundException ex) {
   1.213 +                            throw new IllegalStateException(ex);
   1.214 +                        }
   1.215 +                    case '_': {
   1.216 +                        char nch = sig.charAt(pos++);
   1.217 +                        assert nch == '3' : "Can't find '3' at " + sig.substring(pos - 1);
   1.218 +                        final Class compType = nextElement();
   1.219 +                        return Array.newInstance(compType, 0).getClass();
   1.220 +                    }
   1.221 +                }
   1.222 +                throw new UnsupportedOperationException(sig + " at " + pos);
   1.223 +            }
   1.224 +        }
   1.225 +        return new E();
   1.226 +    }
   1.227 +}