package xtc.lang.blink.agent;
import static java.lang.String.format;
/**
* Blink's support for the convenience variables in Java. This class
* in particular represents a set of polymorphic
* convenience variables to hold both the java primitive and reference
* values.
*
* @author Byeongcheol Lee
*/
public class AgentVariable {
/** The unique identifier. */
private int id;
/** The value. */
private Object value;
/** A Java expression to read the value from the Java debugger. */
private String accessExpression;
/** The Java type representation. */
private String typeName;
/** Constructor. */
private AgentVariable(int id) {this.id = id;}
/** The Blink Java multi-typed variable array. */
private static AgentVariable[] jvars;
/** The next unique variable identifier. */
private static int nextVJIdentifier;
/** Perform initialization. */
public static void init() {
jvars = new AgentVariable[100];
nextVJIdentifier = 0;
}
/** Create a new instance of the convenience variable. */
private static AgentVariable createVariable() {
if (nextVJIdentifier < jvars.length) {
AgentVariable vj = new AgentVariable(nextVJIdentifier);
jvars[nextVJIdentifier] = vj;
nextVJIdentifier++;
return vj;
} else {
AgentVariable[] newJVars = new AgentVariable[jvars.length * 2];
System.arraycopy(jvars, 0, newJVars, 0, nextVJIdentifier);
jvars = newJVars;
return createVariable();
}
}
/** clean up the temp variables table. */
public static void cleanTempVars() {
for(int i = 0; i < jvars.length;i++) {
if( jvars[i] != null ) {
jvars[i] = null;
}
}
nextVJIdentifier = 0;
}
private static String genAccessExpression(int vid, String methodName, String typeName) {
return format("((%s)%s.%s(%d))",
typeName,
"xtc.lang.blink.agent.AgentVariable",
methodName, vid);
}
/**
* Take a class instance and return the fully qualified name of the
* type that the class instance represents.
*
* @param cls The class instance.
* @return The fully qualified name.
*/
private static String getFullyQualifiedName(Class<?> cls) {
String type = cls.getName();
int i = 0, dim = 0;
if (type.charAt(i) == '[') {
for(; type.charAt(i) == '[';i++) {
dim++;
}
}
StringBuilder type_rhs = new StringBuilder();
for(int d = 0; d < dim;d++) {
type_rhs.append('[');
}
for(int d = 0; d < dim;d++) {
type_rhs.append(']');
}
String type_lhs;
if (dim == 0) {
type_lhs = type;
} else {
switch(type.charAt(i)) {
case 'L':
type_lhs = type.substring(i+1, type.length() - 1);
break;
case 'Z':
type_lhs = "boolean";
break;
case 'B':
type_lhs = "byte";
break;
case 'C':
type_lhs = "char";
break;
case 'D':
type_lhs = "double";
break;
case 'F':
type_lhs = "float";
break;
case 'I':
type_lhs = "int";
break;
case 'J':
type_lhs = "long";
break;
case 'S':
type_lhs = "short";
break;
default:
type_lhs = "failure";
break;
}
}
return type_lhs + type_rhs.toString();
}
/**
* Take a boolean primitive value, create convenience variable, and
* assign the boolean value to the convenience variable.
*
* @param value
* @return The convenience variable identifier.
*/
public static int set(boolean value) {
AgentVariable vj = createVariable();
vj.value = new Boolean(value);
vj.typeName = "boolean";
vj.accessExpression = genAccessExpression(vj.id, "getAsBoolean", vj.typeName);
return vj.id;
}
/**
* Take an integer primitive value, create convenience variable, and
* assign the integer value to the convenience variable.
*
* @param value
* @return The convenience variable identifier.
*/
public static int set(int value) {
AgentVariable vj = createVariable();
vj.value = new Integer(value);
vj.typeName = "int";
vj.accessExpression = genAccessExpression(vj.id, "getAsInt", vj.typeName);
return vj.id;
}
/**
* Take an double primitive value, create convenience variable, and
* assign the double value to the convenience variable.
*
* @param value
* @return The convenience variable identifier.
*/
public static int set(double value) {
AgentVariable vj = createVariable();
vj.value = new Double(value);
vj.typeName = "double";
vj.accessExpression = genAccessExpression(vj.id, "getAsDouble", vj.typeName);
return vj.id;
}
/**
* Take a reference value, create convenience variable, and assign
* the reference value to the convenience variable.
*
* @param obj The reference.
* @return The convenience variable identifier.
*/
public static int set(Object obj) {
AgentVariable vj = createVariable();
if (obj != null) {
String fqname = getFullyQualifiedName(obj.getClass());
vj.value = obj;
vj.typeName = fqname;
vj.accessExpression = genAccessExpression(vj.id, "getAsObject", vj.typeName);
} else {
vj.value = null;
vj.typeName = "java.lang.Object";
vj.accessExpression="(null)";
}
return vj.id;
}
/**
* Create a Java expression so that the Java debugger will read the
* value of the convenience variable.
* @param vjid The convenience variable identifier.
* @return The Java expression.
*/
public static String getJavaExpression(int vjid) {
return jvars[vjid].accessExpression;
}
/**
* Get the Java type representation of a convenience variable.
* @param vjid The convenience variable identifier.
* @return The Java expression.
*/
public static String getTypeName(int vjid) {
return jvars[vjid].typeName;
}
/**
* Get the boolean value of the convience variable.
* @param vjid The convenience variable identifier.
* @return The boolean value.
*/
public static boolean getAsBoolean(int vjid) {
Object obj = jvars[vjid].value;
Boolean bobj = (Boolean)obj;
return bobj.booleanValue();
}
/**
* Get the integer value of the convience variable.
* @param vjid The convenience variable identifier.
* @return The integer value.
*/
public static int getAsInt(int vjid) {
Object obj = jvars[vjid].value;
Integer bobj = (Integer)obj;
return bobj.intValue();
}
/**
* Get the double value of the convience variable.
* @param vjid The convenience variable identifier.
* @return The double value.
*/
public static double getAsDouble(int vjid) {
Object obj = jvars[vjid].value;
Double bobj = (Double)obj;
return bobj.doubleValue();
}
/**
* Get the reference value of the convience variable.
* @param vjid The convenience variable identifier.
* @return The reference value.
*/
public static Object getAsObject(int vjid) {
Object obj = jvars[vjid].value;
Object bobj = (Object)obj;
return bobj;
}
}