/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2009 by Trifork
*
* 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 erjang.beam;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.objectweb.asm.Type;
import erjang.EAtom;
import erjang.EBinary;
import erjang.beam.repr.ExtFun;
/**
*
*/
public class EUtil {
static final Pattern SIMPLE_ID = Pattern
.compile("^([a-z]|[A-Z])\\p{Alnum}*$");
private static final String EOBJECT_DESC = CompilerVisitor.EOBJECT_TYPE
.getDescriptor();
private static final String EPROC_DESC = CompilerVisitor.EPROC_TYPE
.getDescriptor();
static Map<Integer, String> signatures = new HashMap<Integer, String>();
static Map<Integer, String> noproc_signatures = new HashMap<Integer, String>();
public static String getSignature(int arity, boolean withProc) {
Map<Integer, String> signatures = withProc ? noproc_signatures
: EUtil.signatures;
String res = signatures.get(arity);
if (res == null) {
StringBuffer sb = new StringBuffer("(");
if (withProc) {
sb.append(EPROC_DESC);
}
for (int i = 0; i < arity; i++) {
sb.append(EOBJECT_DESC);
}
sb.append(")");
sb.append(EOBJECT_DESC);
signatures.put(arity, res = sb.toString());
}
return res;
}
static String toJavaIdentifier(EAtom name) {
return toJavaIdentifier(name.getName());
}
/** encode any char sequence into a valid java identifier */
static String toJavaIdentifier(String name) {
if (SIMPLE_ID.matcher(name).matches())
return name;
StringBuilder sb = new StringBuilder();
for (char c : name.toCharArray()) {
if (c == '$') {
sb.append("$$");
continue;
} else if (sb.length() == 0) {
if (Character.isJavaIdentifierStart(c)) {
sb.append(c);
continue;
}
} else if (Character.isJavaIdentifierPart(c)) {
sb.append(c);
continue;
}
try {
sb.append('$');
ByteArrayOutputStream baro = new ByteArrayOutputStream(5);
DataOutputStream dao = new DataOutputStream(baro);
dao.writeUTF(new String(new char[] { c }));
dao.close();
byte[] data = baro.toByteArray();
writeHexByte(sb, 0xff & data[2]);
if (data.length > 3)
writeHexByte(sb, 0xff & data[3]);
if (data.length > 4)
writeHexByte(sb, 0xff & data[4]);
} catch (IOException ex) {
throw new Error();
}
}
return sb.toString();
}
private static void writeHexByte(StringBuilder sb, int b) {
if (b < 0x10) {
sb.append('0');
}
sb.append(Integer.toHexString(b).toUpperCase());
}
public static String plen(Object o) {
String s = String.valueOf(o);
StringBuilder sb = new StringBuilder("_");
writeHexByte(sb, s.length());
sb.append(s);
return s.toString();
}
public static String getJavaName(EAtom fun, int arity) {
String fname = fun.getName();
if (fname.indexOf("__") == -1) {
return toJavaIdentifier(fun.getName() + "__" + arity);
} else {
return toJavaIdentifier(plen(fun.getName()) + "__" + arity);
}
}
/**
* @param fun
* @return
*/
public static String getJavaName(ExtFun fun) {
return toJavaIdentifier(fun.mod) + "__" + getJavaName(fun.fun, fun.arity);
}
/**
* @param selfType
* @param efun
* @return
*/
public static String getFunClassName(Type self_type, ExtFun efun) {
return self_type.getInternalName() + "$FN_"
+ getJavaName(efun.fun, efun.arity);
}
public static String getFunClassName(Type self_type, ExtFun efun, int freevars) {
return self_type.getInternalName() + "$FN_"
+ getJavaName(efun.fun, efun.arity-freevars);
}
/**
* @param arity
* @param proc
* @param returnType
* @return
*/
public static String getSignature(int arity, boolean withProc,
Type returnType) {
StringBuffer sb = new StringBuffer("(");
if (withProc) {
sb.append(EPROC_DESC);
}
for (int i = 0; i < arity; i++) {
sb.append(EOBJECT_DESC);
}
sb.append(")");
sb.append(returnType.getDescriptor());
return sb.toString();
}
/**
* @param methodName
* @return
*/
public static String decodeJavaName(String methodName) {
int idx;
if ((idx = methodName.indexOf('$')) == -1)
return methodName;
StringBuilder sb = new StringBuilder();
int start = 0;
while (idx != -1) {
sb.append(methodName.substring(start, idx));
if (methodName.charAt(idx+1) == '$') {
sb.append('$');
start = idx + 2;
} else {
String hex = methodName.substring(idx + 1, idx + 3);
char chval;
try {
chval = (char) Integer.parseInt(hex, 16);
} catch (NumberFormatException e) {
chval = '?';
}
sb.append(chval);
start = idx + 3;
}
idx = methodName.indexOf('$', start);
}
sb.append(methodName.substring(start));
return sb.toString();
}
public static EBinary readFile(File file) throws IOException {
int length = (int) file.length();
byte[] data = new byte[length];
FileInputStream fi = new FileInputStream(file);
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
int read = 0;
while (read < length) {
read += fi.read(data, read, length-read);
}
} finally {
fi.close();
}
EBinary bin = new EBinary(data);
return bin;
}
}