mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Fixes for LC3 regression tests, including:
- check static members of instances in JavaMembers.put - do not unwrap Wrappers before calling NativeJavaMethod.findFunction or NativeJavaObject.coerceType; both methods may need extra information provided by the wrapper. - separate Java signatures for resolving overloaded methods and script signatures for error messages, so we can distinguish primitive types from classes. - separate Java signatures for resolving overloaded methods and script signatures for error messages, so we can distinguish primitive types from classes. - prevent a NativeJavaClass from being treated as a wrapped instance of java.lang.Class - correct bug which preferred the *less* specific of two classes in NativeJavaMethod.preferSignature - add new LC3 conversion rules to NativeJavaObject.coerceTypes. - coerce JS numbers to Java numbers or chars only if the JS number is in range.
This commit is contained in:
parent
52424b1aea
commit
a66a71b8d7
@ -166,6 +166,10 @@ class JavaMembers {
|
||||
{
|
||||
Hashtable ht = isStatic ? staticMembers : members;
|
||||
Object member = ht.get(name);
|
||||
if (!isStatic && member == null) {
|
||||
// Try to get static member from instance (LC3)
|
||||
member = staticMembers.get(name);
|
||||
}
|
||||
if (member == null)
|
||||
throw reportMemberNotFound(name);
|
||||
if (member instanceof FieldAndMethods) {
|
||||
@ -174,9 +178,6 @@ class JavaMembers {
|
||||
Field field = null;
|
||||
try {
|
||||
field = (Field) member;
|
||||
// XXX what was this for?
|
||||
//if (obj instanceof Wrapper)
|
||||
// obj = ((Wrapper)obj).unwrap();
|
||||
field.set(javaObject, NativeJavaObject.coerceType(field.getType(),
|
||||
value));
|
||||
} catch (ClassCastException e) {
|
||||
|
@ -82,8 +82,6 @@ public class NativeJavaArray extends NativeJavaObject {
|
||||
|
||||
public void put(int index, Scriptable start, Object value) {
|
||||
if (0 <= index && index < length) {
|
||||
if (value instanceof Wrapper)
|
||||
value = ((Wrapper)value).unwrap();
|
||||
Array.set(array, index, NativeJavaObject.coerceType(cls, value));
|
||||
return;
|
||||
}
|
||||
|
@ -129,16 +129,11 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
if (! (Modifier.isInterface(modifiers) ||
|
||||
Modifier.isAbstract(modifiers)))
|
||||
{
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] instanceof Wrapper)
|
||||
args[i] = ((Wrapper)args[i]).unwrap();
|
||||
}
|
||||
|
||||
Constructor[] ctors = members.getConstructors();
|
||||
Member member = NativeJavaMethod.findFunction(ctors, args);
|
||||
Constructor ctor = (Constructor) member;
|
||||
if (ctor == null) {
|
||||
String sig = NativeJavaMethod.signature(args);
|
||||
String sig = NativeJavaMethod.scriptSignature(args);
|
||||
Object errArgs[] = { classObject.getName(), sig };
|
||||
throw Context.reportRuntimeError(Context.getMessage(
|
||||
"msg.no.java.ctor", errArgs));
|
||||
@ -187,8 +182,8 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
args[i] = NativeJavaObject.coerceType(paramTypes[i], args[i]);
|
||||
}
|
||||
try {
|
||||
/* we need to force this to be wrapped, because construct _has_
|
||||
* to return a scriptable */
|
||||
// we need to force this to be wrapped, because construct _has_
|
||||
// to return a scriptable
|
||||
return
|
||||
(Scriptable) NativeJavaObject.wrap(topLevel,
|
||||
ctor.newInstance(args),
|
||||
@ -201,7 +196,7 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
("msg.cant.instantiate",
|
||||
errArgs));
|
||||
} catch (IllegalArgumentException argEx) {
|
||||
String signature = NativeJavaMethod.signature(args);
|
||||
String signature = NativeJavaMethod.scriptSignature(args);
|
||||
String ctorString = ctor.toString();
|
||||
Object[] errArgs = { argEx.getMessage(),ctorString,signature };
|
||||
throw Context.reportRuntimeError(Context.getMessage
|
||||
@ -222,11 +217,16 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
|
||||
/**
|
||||
* Determines if prototype is a wrapped Java object and performs
|
||||
* a Java "instanceof"
|
||||
* a Java "instanceof".
|
||||
* Exception: if value is an instance of NativeJavaClass, it isn't
|
||||
* considered an instance of the Java class; this forestalls any
|
||||
* name conflicts between java.lang.Class's methods and the
|
||||
* static methods exposed by a JavaNativeClass.
|
||||
*/
|
||||
public boolean hasInstance(Scriptable value) {
|
||||
|
||||
if (value instanceof NativeJavaObject) {
|
||||
if (value instanceof NativeJavaObject &&
|
||||
!(value instanceof NativeJavaClass)) {
|
||||
Object instance = ((NativeJavaObject)value).unwrap();
|
||||
|
||||
return getClassObject().isInstance(instance);
|
||||
|
@ -67,55 +67,58 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
methods = newMeths;
|
||||
}
|
||||
|
||||
static String signature(Class type) {
|
||||
if (type == null)
|
||||
static String scriptSignature(Object value) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
if (type == ScriptRuntime.BooleanClass)
|
||||
return "boolean";
|
||||
if (type == ScriptRuntime.ByteClass)
|
||||
return "byte";
|
||||
if (type == ScriptRuntime.ShortClass)
|
||||
return "short";
|
||||
if (type == ScriptRuntime.IntegerClass)
|
||||
return "int";
|
||||
if (type == ScriptRuntime.LongClass)
|
||||
return "long";
|
||||
if (type == ScriptRuntime.FloatClass)
|
||||
return "float";
|
||||
if (type == ScriptRuntime.DoubleClass)
|
||||
return "double";
|
||||
if (type == ScriptRuntime.StringClass)
|
||||
return "string";
|
||||
if (ScriptRuntime.ScriptableClass.isAssignableFrom(type)) {
|
||||
if (ScriptRuntime.FunctionClass.isAssignableFrom(type))
|
||||
return "function";
|
||||
}
|
||||
else {
|
||||
Class type = value.getClass();
|
||||
if (type == ScriptRuntime.UndefinedClass)
|
||||
return "undefined";
|
||||
return "object";
|
||||
if (type == ScriptRuntime.BooleanClass)
|
||||
return "boolean";
|
||||
if (type == ScriptRuntime.StringClass)
|
||||
return "string";
|
||||
if (ScriptRuntime.NumberClass.isAssignableFrom(type))
|
||||
return "number";
|
||||
if (value instanceof NativeJavaObject) {
|
||||
return ((NativeJavaObject)value).unwrap().getClass().getName();
|
||||
}
|
||||
if (value instanceof Scriptable) {
|
||||
if (value instanceof Function)
|
||||
return "function";
|
||||
return "object";
|
||||
}
|
||||
return javaSignature(type);
|
||||
}
|
||||
if (type.isArray()) {
|
||||
return signature(type.getComponentType()) + "[]";
|
||||
}
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
static String signature(Object[] values) {
|
||||
static String scriptSignature(Object[] values) {
|
||||
StringBuffer sig = new StringBuffer();
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (i != 0)
|
||||
sig.append(',');
|
||||
sig.append(values[i] == null ? "null"
|
||||
: signature(values[i].getClass()));
|
||||
sig.append(scriptSignature(values[i]));
|
||||
}
|
||||
return sig.toString();
|
||||
}
|
||||
|
||||
static String signature(Class[] types) {
|
||||
static String javaSignature(Class type) {
|
||||
if (type == null) {
|
||||
return "null";
|
||||
}
|
||||
else if (type.isArray()) {
|
||||
return javaSignature(type.getComponentType()) + "[]";
|
||||
}
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
static String javaSignature(Class[] types) {
|
||||
StringBuffer sig = new StringBuffer();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (i != 0)
|
||||
sig.append(',');
|
||||
sig.append(signature(types[i]));
|
||||
sig.append(javaSignature(types[i]));
|
||||
}
|
||||
return sig.toString();
|
||||
}
|
||||
@ -125,11 +128,11 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
|
||||
if (member instanceof Method) {
|
||||
paramTypes = ((Method) member).getParameterTypes();
|
||||
return member.getName() + "(" + signature(paramTypes) + ")";
|
||||
return member.getName() + "(" + javaSignature(paramTypes) + ")";
|
||||
}
|
||||
else {
|
||||
paramTypes = ((Constructor) member).getParameterTypes();
|
||||
return "(" + signature(paramTypes) + ")";
|
||||
return "(" + javaSignature(paramTypes) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,16 +145,11 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
throw new RuntimeException("No methods defined for call");
|
||||
}
|
||||
|
||||
// Eliminate useless args[0] and unwrap if required
|
||||
for (int i = 0; i < args.length; i++)
|
||||
if (args[i] instanceof Wrapper)
|
||||
args[i] = ((Wrapper)args[i]).unwrap();
|
||||
|
||||
Method meth = (Method) findFunction(methods, args);
|
||||
if (meth == null) {
|
||||
Class c = methods[0].getDeclaringClass();
|
||||
String sig = c.getName() + "." + names[0] + "(" +
|
||||
signature(args) + ")";
|
||||
scriptSignature(args) + ")";
|
||||
Object errArgs[] = { sig };
|
||||
throw Context.reportRuntimeError(
|
||||
Context.getMessage("msg.java.no_such_method", errArgs));
|
||||
@ -179,9 +177,28 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (debug) {
|
||||
printDebug("Calling", meth, args);
|
||||
}
|
||||
|
||||
Object retval = meth.invoke(javaObject, args);
|
||||
Class staticType = meth.getReturnType();
|
||||
|
||||
if (debug) {
|
||||
Class actualType = (retval == null) ? null : retval.getClass();
|
||||
System.err.println(" ----- Returned " + retval +
|
||||
" actual = " + actualType +
|
||||
" expect = " + staticType);
|
||||
}
|
||||
|
||||
Object wrapped = NativeJavaObject.wrap(scope, retval, staticType);
|
||||
|
||||
if (debug) {
|
||||
Class actualType = (wrapped == null) ? null : wrapped.getClass();
|
||||
System.err.println(" ----- Wrapped as " + wrapped +
|
||||
" class = " + actualType);
|
||||
}
|
||||
|
||||
// XXX set prototype && parent
|
||||
if (wrapped == Undefined.instance)
|
||||
return wrapped;
|
||||
@ -202,12 +219,6 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public Object getDefaultValue(Class hint) {
|
||||
return this;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find the correct function to call given the set of methods
|
||||
* or constructors and the arguments.
|
||||
@ -339,7 +350,7 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
if (isCtor) {
|
||||
Object errArgs[] = {
|
||||
bestFit.getName(),
|
||||
NativeJavaMethod.signature(args),
|
||||
NativeJavaMethod.scriptSignature(args),
|
||||
buf.toString()
|
||||
};
|
||||
errMsg =
|
||||
@ -349,7 +360,7 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
Object errArgs[] = {
|
||||
bestFit.getDeclaringClass().getName(),
|
||||
bestFit.getName(),
|
||||
NativeJavaMethod.signature(args),
|
||||
NativeJavaMethod.scriptSignature(args),
|
||||
buf.toString()
|
||||
};
|
||||
errMsg = Context.getMessage("msg.method.ambiguous", errArgs);
|
||||
@ -417,10 +428,10 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
rank2 == NativeJavaObject.CONVERSION_NONTRIVIAL) {
|
||||
|
||||
if (toClass1.isAssignableFrom(toClass2)) {
|
||||
return PREFERENCE_FIRST_ARG;
|
||||
return PREFERENCE_SECOND_ARG;
|
||||
}
|
||||
else if (toClass2.isAssignableFrom(toClass1)) {
|
||||
return PREFERENCE_SECOND_ARG;
|
||||
return PREFERENCE_FIRST_ARG;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -445,7 +456,7 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
System.err.println(" ----- " + msg +
|
||||
member.getDeclaringClass().getName() +
|
||||
"." + signature(member) +
|
||||
" for arguments (" + signature(args) + ")");
|
||||
" for arguments (" + scriptSignature(args) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
public static boolean canConvert(Object fromObj, Class to) {
|
||||
int weight = NativeJavaObject.getConversionWeight(fromObj, to);
|
||||
|
||||
return (weight != CONVERSION_NONE);
|
||||
return (weight < CONVERSION_NONE);
|
||||
}
|
||||
|
||||
static final int JSTYPE_UNDEFINED = 0; // undefined type
|
||||
@ -286,10 +286,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
if (to == Double.TYPE) {
|
||||
result = 1;
|
||||
}
|
||||
else if (to == Boolean.TYPE) {
|
||||
result = CONVERSION_NONE;
|
||||
}
|
||||
else {
|
||||
else if (to != Boolean.TYPE) {
|
||||
result = 1 + NativeJavaObject.getSizeRank(to);
|
||||
}
|
||||
}
|
||||
@ -315,7 +312,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
else if (to == ScriptRuntime.ObjectClass) {
|
||||
result = 2;
|
||||
}
|
||||
else if (to.isPrimitive()) {
|
||||
else if (to.isPrimitive() && to != Boolean.TYPE) {
|
||||
if (to == Character.TYPE) {
|
||||
result = 3;
|
||||
}
|
||||
@ -329,7 +326,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
if (to == ScriptRuntime.ClassClass) {
|
||||
result = 1;
|
||||
}
|
||||
if (Context.useJSObject && jsObjectClass != null &&
|
||||
else if (Context.useJSObject && jsObjectClass != null &&
|
||||
jsObjectClass.isAssignableFrom(to)) {
|
||||
result = 2;
|
||||
}
|
||||
@ -346,7 +343,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
if (to == ScriptRuntime.StringClass) {
|
||||
result = 2;
|
||||
}
|
||||
else if (to.isPrimitive()) {
|
||||
else if (to.isPrimitive() && to != Boolean.TYPE) {
|
||||
result =
|
||||
(fromCode == JSTYPE_JAVA_ARRAY) ?
|
||||
CONVERSION_NONTRIVIAL :
|
||||
@ -375,7 +372,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
else if (to == ScriptRuntime.StringClass) {
|
||||
result = 3;
|
||||
}
|
||||
else if (to.isPrimitive()) {
|
||||
else if (to.isPrimitive() || to != Boolean.TYPE) {
|
||||
result = 3 + NativeJavaObject.getSizeRank(to);
|
||||
}
|
||||
break;
|
||||
@ -407,6 +404,9 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
else if (aType == Byte.TYPE) {
|
||||
return 7;
|
||||
}
|
||||
else if (aType == Boolean.TYPE) {
|
||||
return CONVERSION_NONE;
|
||||
}
|
||||
else {
|
||||
return 8;
|
||||
}
|
||||
@ -426,6 +426,9 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
else if (value instanceof NativeJavaArray) {
|
||||
return JSTYPE_JAVA_ARRAY;
|
||||
}
|
||||
else if (value instanceof NativeString) {
|
||||
return JSTYPE_STRING;
|
||||
}
|
||||
else if (value instanceof NativeJavaObject) {
|
||||
return JSTYPE_JAVA_OBJECT;
|
||||
}
|
||||
@ -459,14 +462,41 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
|
||||
/**
|
||||
* Type-munging for field setting and method invocation.
|
||||
* Conforms to LC3 specification
|
||||
*/
|
||||
public static Object coerceType(Class type, Object value) {
|
||||
// Don't coerce null to a string (or other object)
|
||||
if (value == null) {
|
||||
// raise error if type.isPrimitive()
|
||||
if (type.isPrimitive()) {
|
||||
reportConversionError(value, type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (value == Undefined.instance) {
|
||||
if (type == ScriptRuntime.StringClass ||
|
||||
type == ScriptRuntime.ObjectClass) {
|
||||
return "undefined";
|
||||
}
|
||||
else {
|
||||
// report conversion error
|
||||
reportConversionError("undefined", type);
|
||||
}
|
||||
}
|
||||
|
||||
// For ScriptRuntime.finalClasses we can compare valueClass to ScriptRuntime.aClass object
|
||||
// Special case: converting JS numbers to Objects
|
||||
// Done before we unwrap, to distinguish from a
|
||||
// wrapped java.lang.Number.
|
||||
if (type == ScriptRuntime.ObjectClass && value instanceof Number) {
|
||||
return new Double(((Number)value).doubleValue());
|
||||
}
|
||||
|
||||
// Unwrap at this point; callers do not need to unwrap
|
||||
if (value instanceof Wrapper) {
|
||||
value = ((Wrapper)value).unwrap();
|
||||
}
|
||||
|
||||
// For final classes we can compare valueClass to a Class object
|
||||
// rather than using instanceof
|
||||
Class valueClass = value.getClass();
|
||||
|
||||
@ -479,29 +509,43 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
return ScriptRuntime.toString(value);
|
||||
|
||||
// Boolean
|
||||
if (type == Boolean.TYPE || type == ScriptRuntime.BooleanClass)
|
||||
return new Boolean(ScriptRuntime.toBoolean(value));
|
||||
if (type == Boolean.TYPE || type == ScriptRuntime.BooleanClass) {
|
||||
// Under LC3, only JS Booleans can be coerced into a Boolean value
|
||||
if (valueClass == ScriptRuntime.BooleanClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
reportConversionError(value, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Character
|
||||
if (type == Character.TYPE || type == ScriptRuntime.CharacterClass) {
|
||||
// Special case for converting a single char string to a character
|
||||
if (valueClass == ScriptRuntime.StringClass && ((String) value).length() == 1)
|
||||
return new Character(((String) value).charAt(0));
|
||||
return new Character((char)ScriptRuntime.toInteger(value));
|
||||
/*
|
||||
if (valueClass == ScriptRuntime.StringClass) {
|
||||
String string = (String)value;
|
||||
if (string.length() == 1) {
|
||||
char ch = string.charAt(0);
|
||||
// XXX: Next test not in LC3 spec, but is backwardly
|
||||
// compatible and satisfies regression tests
|
||||
if (!Character.isDigit(ch)) {
|
||||
return new Character(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (valueClass == ScriptRuntime.CharacterClass) {
|
||||
return value;
|
||||
}
|
||||
return new Character((char)toInteger(value,
|
||||
ScriptRuntime.CharacterClass,
|
||||
Character.MIN_VALUE,
|
||||
Character.MAX_VALUE));
|
||||
}
|
||||
|
||||
// Integer, Long, Char, Byte
|
||||
if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE)
|
||||
return new Integer((int)ScriptRuntime.toInteger(value));
|
||||
|
||||
if (type == ScriptRuntime.LongClass || type == Long.TYPE)
|
||||
return new Long((long)ScriptRuntime.toInteger(value));
|
||||
|
||||
if (type == ScriptRuntime.ByteClass || type == Byte.TYPE)
|
||||
return new Byte((byte)ScriptRuntime.toInteger(value));
|
||||
|
||||
if (type == ScriptRuntime.ShortClass || type == Short.TYPE)
|
||||
return new Short((short)ScriptRuntime.toInteger(value));
|
||||
|
||||
// Double, Float
|
||||
if (type == ScriptRuntime.DoubleClass || type == Double.TYPE) {
|
||||
return valueClass == ScriptRuntime.DoubleClass
|
||||
@ -510,14 +554,81 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
}
|
||||
|
||||
if (type == ScriptRuntime.FloatClass || type == Float.TYPE) {
|
||||
return valueClass == ScriptRuntime.FloatClass
|
||||
? value
|
||||
: new Float(ScriptRuntime.toNumber(value));
|
||||
if (valueClass == ScriptRuntime.FloatClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
double number = ScriptRuntime.toNumber(value);
|
||||
if (Double.isInfinite(number) || Double.isNaN(number)
|
||||
|| number == 0.0) {
|
||||
return new Float((float)number);
|
||||
}
|
||||
else {
|
||||
double absNumber = Math.abs(number);
|
||||
if (absNumber < (double)Float.MIN_VALUE) {
|
||||
return new Float((number > 0.0) ? +0.0 : -0.0);
|
||||
}
|
||||
else if (absNumber > (double)Float.MAX_VALUE) {
|
||||
return new Float((number > 0.0) ?
|
||||
Float.POSITIVE_INFINITY :
|
||||
Float.NEGATIVE_INFINITY);
|
||||
}
|
||||
else {
|
||||
return new Float((float)number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Integer, Long, Short, Byte
|
||||
if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE) {
|
||||
if (valueClass == ScriptRuntime.IntegerClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return new Integer((int)toInteger(value,
|
||||
ScriptRuntime.IntegerClass,
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ScriptRuntime.LongClass || type == Long.TYPE) {
|
||||
if (valueClass == ScriptRuntime.LongClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return new Long(toInteger(value,
|
||||
ScriptRuntime.LongClass,
|
||||
Long.MIN_VALUE,
|
||||
Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ScriptRuntime.ShortClass || type == Short.TYPE) {
|
||||
if (valueClass == ScriptRuntime.ShortClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return new Short((short)toInteger(value,
|
||||
ScriptRuntime.ShortClass,
|
||||
Short.MIN_VALUE,
|
||||
Short.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ScriptRuntime.ByteClass || type == Byte.TYPE) {
|
||||
if (valueClass == ScriptRuntime.ByteClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return new Byte((byte)toInteger(value,
|
||||
ScriptRuntime.ByteClass,
|
||||
Byte.MIN_VALUE,
|
||||
Byte.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
if (valueClass == ScriptRuntime.DoubleClass)
|
||||
return value;
|
||||
|
||||
// If JSObject compatibility is enabled, and the method wants it,
|
||||
// wrap the Scriptable value in a JSObject.
|
||||
if (Context.useJSObject && jsObjectClass != null &&
|
||||
@ -540,12 +651,50 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
}
|
||||
}
|
||||
|
||||
if (ScriptRuntime.NumberClass.isInstance(value))
|
||||
return new Double(((Number) value).doubleValue());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static long toInteger(Object value, Class type, long min, long max) {
|
||||
double d;
|
||||
|
||||
if (value instanceof Number) {
|
||||
d = ((Number)value).doubleValue();
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
d = ScriptRuntime.toNumber((String)value);
|
||||
}
|
||||
else if (value instanceof Scriptable) {
|
||||
d = ScriptRuntime.toNumber(value);
|
||||
}
|
||||
else {
|
||||
// XXX: is this correct?
|
||||
d = ScriptRuntime.toNumber(value.toString());
|
||||
}
|
||||
|
||||
if (Double.isInfinite(d) || Double.isNaN(d)) {
|
||||
// Convert to string first, for more readable message
|
||||
reportConversionError(value.toString(), type);
|
||||
}
|
||||
|
||||
if (d > 0.0) {
|
||||
d = Math.floor(d);
|
||||
}
|
||||
else {
|
||||
d = Math.ceil(d);
|
||||
}
|
||||
|
||||
if (d < (double)min || d > (double)max) {
|
||||
// Convert to string first, for more readable message
|
||||
reportConversionError(value.toString(), type);
|
||||
}
|
||||
return (long)d;
|
||||
}
|
||||
|
||||
static void reportConversionError(Object value, Class type) {
|
||||
Object[] args = {value, type};
|
||||
throw Context.reportRuntimeError(Context.getMessage("msg.conversion.not.allowed", args));
|
||||
}
|
||||
|
||||
public static void initJSObject() {
|
||||
if (!Context.useJSObject)
|
||||
return;
|
||||
|
@ -138,6 +138,10 @@ msg.constructor.ambiguous =\
|
||||
The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; \
|
||||
candidate constructors are: {2}
|
||||
|
||||
# NativeJavaObject
|
||||
msg.conversion.not.allowed =\
|
||||
Cannot convert {0} to {1}
|
||||
|
||||
# NativeRegExp
|
||||
msg.bad.quant =\
|
||||
Invalid quantifier {0}
|
||||
|
@ -166,6 +166,10 @@ class JavaMembers {
|
||||
{
|
||||
Hashtable ht = isStatic ? staticMembers : members;
|
||||
Object member = ht.get(name);
|
||||
if (!isStatic && member == null) {
|
||||
// Try to get static member from instance (LC3)
|
||||
member = staticMembers.get(name);
|
||||
}
|
||||
if (member == null)
|
||||
throw reportMemberNotFound(name);
|
||||
if (member instanceof FieldAndMethods) {
|
||||
@ -174,9 +178,6 @@ class JavaMembers {
|
||||
Field field = null;
|
||||
try {
|
||||
field = (Field) member;
|
||||
// XXX what was this for?
|
||||
//if (obj instanceof Wrapper)
|
||||
// obj = ((Wrapper)obj).unwrap();
|
||||
field.set(javaObject, NativeJavaObject.coerceType(field.getType(),
|
||||
value));
|
||||
} catch (ClassCastException e) {
|
||||
|
@ -82,8 +82,6 @@ public class NativeJavaArray extends NativeJavaObject {
|
||||
|
||||
public void put(int index, Scriptable start, Object value) {
|
||||
if (0 <= index && index < length) {
|
||||
if (value instanceof Wrapper)
|
||||
value = ((Wrapper)value).unwrap();
|
||||
Array.set(array, index, NativeJavaObject.coerceType(cls, value));
|
||||
return;
|
||||
}
|
||||
|
@ -129,16 +129,11 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
if (! (Modifier.isInterface(modifiers) ||
|
||||
Modifier.isAbstract(modifiers)))
|
||||
{
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] instanceof Wrapper)
|
||||
args[i] = ((Wrapper)args[i]).unwrap();
|
||||
}
|
||||
|
||||
Constructor[] ctors = members.getConstructors();
|
||||
Member member = NativeJavaMethod.findFunction(ctors, args);
|
||||
Constructor ctor = (Constructor) member;
|
||||
if (ctor == null) {
|
||||
String sig = NativeJavaMethod.signature(args);
|
||||
String sig = NativeJavaMethod.scriptSignature(args);
|
||||
Object errArgs[] = { classObject.getName(), sig };
|
||||
throw Context.reportRuntimeError(Context.getMessage(
|
||||
"msg.no.java.ctor", errArgs));
|
||||
@ -187,8 +182,8 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
args[i] = NativeJavaObject.coerceType(paramTypes[i], args[i]);
|
||||
}
|
||||
try {
|
||||
/* we need to force this to be wrapped, because construct _has_
|
||||
* to return a scriptable */
|
||||
// we need to force this to be wrapped, because construct _has_
|
||||
// to return a scriptable
|
||||
return
|
||||
(Scriptable) NativeJavaObject.wrap(topLevel,
|
||||
ctor.newInstance(args),
|
||||
@ -201,7 +196,7 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
("msg.cant.instantiate",
|
||||
errArgs));
|
||||
} catch (IllegalArgumentException argEx) {
|
||||
String signature = NativeJavaMethod.signature(args);
|
||||
String signature = NativeJavaMethod.scriptSignature(args);
|
||||
String ctorString = ctor.toString();
|
||||
Object[] errArgs = { argEx.getMessage(),ctorString,signature };
|
||||
throw Context.reportRuntimeError(Context.getMessage
|
||||
@ -222,11 +217,16 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
||||
|
||||
/**
|
||||
* Determines if prototype is a wrapped Java object and performs
|
||||
* a Java "instanceof"
|
||||
* a Java "instanceof".
|
||||
* Exception: if value is an instance of NativeJavaClass, it isn't
|
||||
* considered an instance of the Java class; this forestalls any
|
||||
* name conflicts between java.lang.Class's methods and the
|
||||
* static methods exposed by a JavaNativeClass.
|
||||
*/
|
||||
public boolean hasInstance(Scriptable value) {
|
||||
|
||||
if (value instanceof NativeJavaObject) {
|
||||
if (value instanceof NativeJavaObject &&
|
||||
!(value instanceof NativeJavaClass)) {
|
||||
Object instance = ((NativeJavaObject)value).unwrap();
|
||||
|
||||
return getClassObject().isInstance(instance);
|
||||
|
@ -67,55 +67,58 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
methods = newMeths;
|
||||
}
|
||||
|
||||
static String signature(Class type) {
|
||||
if (type == null)
|
||||
static String scriptSignature(Object value) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
if (type == ScriptRuntime.BooleanClass)
|
||||
return "boolean";
|
||||
if (type == ScriptRuntime.ByteClass)
|
||||
return "byte";
|
||||
if (type == ScriptRuntime.ShortClass)
|
||||
return "short";
|
||||
if (type == ScriptRuntime.IntegerClass)
|
||||
return "int";
|
||||
if (type == ScriptRuntime.LongClass)
|
||||
return "long";
|
||||
if (type == ScriptRuntime.FloatClass)
|
||||
return "float";
|
||||
if (type == ScriptRuntime.DoubleClass)
|
||||
return "double";
|
||||
if (type == ScriptRuntime.StringClass)
|
||||
return "string";
|
||||
if (ScriptRuntime.ScriptableClass.isAssignableFrom(type)) {
|
||||
if (ScriptRuntime.FunctionClass.isAssignableFrom(type))
|
||||
return "function";
|
||||
}
|
||||
else {
|
||||
Class type = value.getClass();
|
||||
if (type == ScriptRuntime.UndefinedClass)
|
||||
return "undefined";
|
||||
return "object";
|
||||
if (type == ScriptRuntime.BooleanClass)
|
||||
return "boolean";
|
||||
if (type == ScriptRuntime.StringClass)
|
||||
return "string";
|
||||
if (ScriptRuntime.NumberClass.isAssignableFrom(type))
|
||||
return "number";
|
||||
if (value instanceof NativeJavaObject) {
|
||||
return ((NativeJavaObject)value).unwrap().getClass().getName();
|
||||
}
|
||||
if (value instanceof Scriptable) {
|
||||
if (value instanceof Function)
|
||||
return "function";
|
||||
return "object";
|
||||
}
|
||||
return javaSignature(type);
|
||||
}
|
||||
if (type.isArray()) {
|
||||
return signature(type.getComponentType()) + "[]";
|
||||
}
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
static String signature(Object[] values) {
|
||||
static String scriptSignature(Object[] values) {
|
||||
StringBuffer sig = new StringBuffer();
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (i != 0)
|
||||
sig.append(',');
|
||||
sig.append(values[i] == null ? "null"
|
||||
: signature(values[i].getClass()));
|
||||
sig.append(scriptSignature(values[i]));
|
||||
}
|
||||
return sig.toString();
|
||||
}
|
||||
|
||||
static String signature(Class[] types) {
|
||||
static String javaSignature(Class type) {
|
||||
if (type == null) {
|
||||
return "null";
|
||||
}
|
||||
else if (type.isArray()) {
|
||||
return javaSignature(type.getComponentType()) + "[]";
|
||||
}
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
static String javaSignature(Class[] types) {
|
||||
StringBuffer sig = new StringBuffer();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (i != 0)
|
||||
sig.append(',');
|
||||
sig.append(signature(types[i]));
|
||||
sig.append(javaSignature(types[i]));
|
||||
}
|
||||
return sig.toString();
|
||||
}
|
||||
@ -125,11 +128,11 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
|
||||
if (member instanceof Method) {
|
||||
paramTypes = ((Method) member).getParameterTypes();
|
||||
return member.getName() + "(" + signature(paramTypes) + ")";
|
||||
return member.getName() + "(" + javaSignature(paramTypes) + ")";
|
||||
}
|
||||
else {
|
||||
paramTypes = ((Constructor) member).getParameterTypes();
|
||||
return "(" + signature(paramTypes) + ")";
|
||||
return "(" + javaSignature(paramTypes) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,16 +145,11 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
throw new RuntimeException("No methods defined for call");
|
||||
}
|
||||
|
||||
// Eliminate useless args[0] and unwrap if required
|
||||
for (int i = 0; i < args.length; i++)
|
||||
if (args[i] instanceof Wrapper)
|
||||
args[i] = ((Wrapper)args[i]).unwrap();
|
||||
|
||||
Method meth = (Method) findFunction(methods, args);
|
||||
if (meth == null) {
|
||||
Class c = methods[0].getDeclaringClass();
|
||||
String sig = c.getName() + "." + names[0] + "(" +
|
||||
signature(args) + ")";
|
||||
scriptSignature(args) + ")";
|
||||
Object errArgs[] = { sig };
|
||||
throw Context.reportRuntimeError(
|
||||
Context.getMessage("msg.java.no_such_method", errArgs));
|
||||
@ -179,9 +177,28 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (debug) {
|
||||
printDebug("Calling", meth, args);
|
||||
}
|
||||
|
||||
Object retval = meth.invoke(javaObject, args);
|
||||
Class staticType = meth.getReturnType();
|
||||
|
||||
if (debug) {
|
||||
Class actualType = (retval == null) ? null : retval.getClass();
|
||||
System.err.println(" ----- Returned " + retval +
|
||||
" actual = " + actualType +
|
||||
" expect = " + staticType);
|
||||
}
|
||||
|
||||
Object wrapped = NativeJavaObject.wrap(scope, retval, staticType);
|
||||
|
||||
if (debug) {
|
||||
Class actualType = (wrapped == null) ? null : wrapped.getClass();
|
||||
System.err.println(" ----- Wrapped as " + wrapped +
|
||||
" class = " + actualType);
|
||||
}
|
||||
|
||||
// XXX set prototype && parent
|
||||
if (wrapped == Undefined.instance)
|
||||
return wrapped;
|
||||
@ -202,12 +219,6 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public Object getDefaultValue(Class hint) {
|
||||
return this;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find the correct function to call given the set of methods
|
||||
* or constructors and the arguments.
|
||||
@ -339,7 +350,7 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
if (isCtor) {
|
||||
Object errArgs[] = {
|
||||
bestFit.getName(),
|
||||
NativeJavaMethod.signature(args),
|
||||
NativeJavaMethod.scriptSignature(args),
|
||||
buf.toString()
|
||||
};
|
||||
errMsg =
|
||||
@ -349,7 +360,7 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
Object errArgs[] = {
|
||||
bestFit.getDeclaringClass().getName(),
|
||||
bestFit.getName(),
|
||||
NativeJavaMethod.signature(args),
|
||||
NativeJavaMethod.scriptSignature(args),
|
||||
buf.toString()
|
||||
};
|
||||
errMsg = Context.getMessage("msg.method.ambiguous", errArgs);
|
||||
@ -417,10 +428,10 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
rank2 == NativeJavaObject.CONVERSION_NONTRIVIAL) {
|
||||
|
||||
if (toClass1.isAssignableFrom(toClass2)) {
|
||||
return PREFERENCE_FIRST_ARG;
|
||||
return PREFERENCE_SECOND_ARG;
|
||||
}
|
||||
else if (toClass2.isAssignableFrom(toClass1)) {
|
||||
return PREFERENCE_SECOND_ARG;
|
||||
return PREFERENCE_FIRST_ARG;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -445,7 +456,7 @@ public class NativeJavaMethod extends NativeFunction implements Function {
|
||||
System.err.println(" ----- " + msg +
|
||||
member.getDeclaringClass().getName() +
|
||||
"." + signature(member) +
|
||||
" for arguments (" + signature(args) + ")");
|
||||
" for arguments (" + scriptSignature(args) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
public static boolean canConvert(Object fromObj, Class to) {
|
||||
int weight = NativeJavaObject.getConversionWeight(fromObj, to);
|
||||
|
||||
return (weight != CONVERSION_NONE);
|
||||
return (weight < CONVERSION_NONE);
|
||||
}
|
||||
|
||||
static final int JSTYPE_UNDEFINED = 0; // undefined type
|
||||
@ -286,10 +286,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
if (to == Double.TYPE) {
|
||||
result = 1;
|
||||
}
|
||||
else if (to == Boolean.TYPE) {
|
||||
result = CONVERSION_NONE;
|
||||
}
|
||||
else {
|
||||
else if (to != Boolean.TYPE) {
|
||||
result = 1 + NativeJavaObject.getSizeRank(to);
|
||||
}
|
||||
}
|
||||
@ -315,7 +312,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
else if (to == ScriptRuntime.ObjectClass) {
|
||||
result = 2;
|
||||
}
|
||||
else if (to.isPrimitive()) {
|
||||
else if (to.isPrimitive() && to != Boolean.TYPE) {
|
||||
if (to == Character.TYPE) {
|
||||
result = 3;
|
||||
}
|
||||
@ -329,7 +326,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
if (to == ScriptRuntime.ClassClass) {
|
||||
result = 1;
|
||||
}
|
||||
if (Context.useJSObject && jsObjectClass != null &&
|
||||
else if (Context.useJSObject && jsObjectClass != null &&
|
||||
jsObjectClass.isAssignableFrom(to)) {
|
||||
result = 2;
|
||||
}
|
||||
@ -346,7 +343,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
if (to == ScriptRuntime.StringClass) {
|
||||
result = 2;
|
||||
}
|
||||
else if (to.isPrimitive()) {
|
||||
else if (to.isPrimitive() && to != Boolean.TYPE) {
|
||||
result =
|
||||
(fromCode == JSTYPE_JAVA_ARRAY) ?
|
||||
CONVERSION_NONTRIVIAL :
|
||||
@ -375,7 +372,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
else if (to == ScriptRuntime.StringClass) {
|
||||
result = 3;
|
||||
}
|
||||
else if (to.isPrimitive()) {
|
||||
else if (to.isPrimitive() || to != Boolean.TYPE) {
|
||||
result = 3 + NativeJavaObject.getSizeRank(to);
|
||||
}
|
||||
break;
|
||||
@ -407,6 +404,9 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
else if (aType == Byte.TYPE) {
|
||||
return 7;
|
||||
}
|
||||
else if (aType == Boolean.TYPE) {
|
||||
return CONVERSION_NONE;
|
||||
}
|
||||
else {
|
||||
return 8;
|
||||
}
|
||||
@ -426,6 +426,9 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
else if (value instanceof NativeJavaArray) {
|
||||
return JSTYPE_JAVA_ARRAY;
|
||||
}
|
||||
else if (value instanceof NativeString) {
|
||||
return JSTYPE_STRING;
|
||||
}
|
||||
else if (value instanceof NativeJavaObject) {
|
||||
return JSTYPE_JAVA_OBJECT;
|
||||
}
|
||||
@ -459,14 +462,41 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
|
||||
/**
|
||||
* Type-munging for field setting and method invocation.
|
||||
* Conforms to LC3 specification
|
||||
*/
|
||||
public static Object coerceType(Class type, Object value) {
|
||||
// Don't coerce null to a string (or other object)
|
||||
if (value == null) {
|
||||
// raise error if type.isPrimitive()
|
||||
if (type.isPrimitive()) {
|
||||
reportConversionError(value, type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (value == Undefined.instance) {
|
||||
if (type == ScriptRuntime.StringClass ||
|
||||
type == ScriptRuntime.ObjectClass) {
|
||||
return "undefined";
|
||||
}
|
||||
else {
|
||||
// report conversion error
|
||||
reportConversionError("undefined", type);
|
||||
}
|
||||
}
|
||||
|
||||
// For ScriptRuntime.finalClasses we can compare valueClass to ScriptRuntime.aClass object
|
||||
// Special case: converting JS numbers to Objects
|
||||
// Done before we unwrap, to distinguish from a
|
||||
// wrapped java.lang.Number.
|
||||
if (type == ScriptRuntime.ObjectClass && value instanceof Number) {
|
||||
return new Double(((Number)value).doubleValue());
|
||||
}
|
||||
|
||||
// Unwrap at this point; callers do not need to unwrap
|
||||
if (value instanceof Wrapper) {
|
||||
value = ((Wrapper)value).unwrap();
|
||||
}
|
||||
|
||||
// For final classes we can compare valueClass to a Class object
|
||||
// rather than using instanceof
|
||||
Class valueClass = value.getClass();
|
||||
|
||||
@ -479,29 +509,43 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
return ScriptRuntime.toString(value);
|
||||
|
||||
// Boolean
|
||||
if (type == Boolean.TYPE || type == ScriptRuntime.BooleanClass)
|
||||
return new Boolean(ScriptRuntime.toBoolean(value));
|
||||
if (type == Boolean.TYPE || type == ScriptRuntime.BooleanClass) {
|
||||
// Under LC3, only JS Booleans can be coerced into a Boolean value
|
||||
if (valueClass == ScriptRuntime.BooleanClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
reportConversionError(value, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Character
|
||||
if (type == Character.TYPE || type == ScriptRuntime.CharacterClass) {
|
||||
// Special case for converting a single char string to a character
|
||||
if (valueClass == ScriptRuntime.StringClass && ((String) value).length() == 1)
|
||||
return new Character(((String) value).charAt(0));
|
||||
return new Character((char)ScriptRuntime.toInteger(value));
|
||||
/*
|
||||
if (valueClass == ScriptRuntime.StringClass) {
|
||||
String string = (String)value;
|
||||
if (string.length() == 1) {
|
||||
char ch = string.charAt(0);
|
||||
// XXX: Next test not in LC3 spec, but is backwardly
|
||||
// compatible and satisfies regression tests
|
||||
if (!Character.isDigit(ch)) {
|
||||
return new Character(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (valueClass == ScriptRuntime.CharacterClass) {
|
||||
return value;
|
||||
}
|
||||
return new Character((char)toInteger(value,
|
||||
ScriptRuntime.CharacterClass,
|
||||
Character.MIN_VALUE,
|
||||
Character.MAX_VALUE));
|
||||
}
|
||||
|
||||
// Integer, Long, Char, Byte
|
||||
if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE)
|
||||
return new Integer((int)ScriptRuntime.toInteger(value));
|
||||
|
||||
if (type == ScriptRuntime.LongClass || type == Long.TYPE)
|
||||
return new Long((long)ScriptRuntime.toInteger(value));
|
||||
|
||||
if (type == ScriptRuntime.ByteClass || type == Byte.TYPE)
|
||||
return new Byte((byte)ScriptRuntime.toInteger(value));
|
||||
|
||||
if (type == ScriptRuntime.ShortClass || type == Short.TYPE)
|
||||
return new Short((short)ScriptRuntime.toInteger(value));
|
||||
|
||||
// Double, Float
|
||||
if (type == ScriptRuntime.DoubleClass || type == Double.TYPE) {
|
||||
return valueClass == ScriptRuntime.DoubleClass
|
||||
@ -510,14 +554,81 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
}
|
||||
|
||||
if (type == ScriptRuntime.FloatClass || type == Float.TYPE) {
|
||||
return valueClass == ScriptRuntime.FloatClass
|
||||
? value
|
||||
: new Float(ScriptRuntime.toNumber(value));
|
||||
if (valueClass == ScriptRuntime.FloatClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
double number = ScriptRuntime.toNumber(value);
|
||||
if (Double.isInfinite(number) || Double.isNaN(number)
|
||||
|| number == 0.0) {
|
||||
return new Float((float)number);
|
||||
}
|
||||
else {
|
||||
double absNumber = Math.abs(number);
|
||||
if (absNumber < (double)Float.MIN_VALUE) {
|
||||
return new Float((number > 0.0) ? +0.0 : -0.0);
|
||||
}
|
||||
else if (absNumber > (double)Float.MAX_VALUE) {
|
||||
return new Float((number > 0.0) ?
|
||||
Float.POSITIVE_INFINITY :
|
||||
Float.NEGATIVE_INFINITY);
|
||||
}
|
||||
else {
|
||||
return new Float((float)number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Integer, Long, Short, Byte
|
||||
if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE) {
|
||||
if (valueClass == ScriptRuntime.IntegerClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return new Integer((int)toInteger(value,
|
||||
ScriptRuntime.IntegerClass,
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ScriptRuntime.LongClass || type == Long.TYPE) {
|
||||
if (valueClass == ScriptRuntime.LongClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return new Long(toInteger(value,
|
||||
ScriptRuntime.LongClass,
|
||||
Long.MIN_VALUE,
|
||||
Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ScriptRuntime.ShortClass || type == Short.TYPE) {
|
||||
if (valueClass == ScriptRuntime.ShortClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return new Short((short)toInteger(value,
|
||||
ScriptRuntime.ShortClass,
|
||||
Short.MIN_VALUE,
|
||||
Short.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ScriptRuntime.ByteClass || type == Byte.TYPE) {
|
||||
if (valueClass == ScriptRuntime.ByteClass) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return new Byte((byte)toInteger(value,
|
||||
ScriptRuntime.ByteClass,
|
||||
Byte.MIN_VALUE,
|
||||
Byte.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
if (valueClass == ScriptRuntime.DoubleClass)
|
||||
return value;
|
||||
|
||||
// If JSObject compatibility is enabled, and the method wants it,
|
||||
// wrap the Scriptable value in a JSObject.
|
||||
if (Context.useJSObject && jsObjectClass != null &&
|
||||
@ -540,12 +651,50 @@ public class NativeJavaObject implements Scriptable, Wrapper {
|
||||
}
|
||||
}
|
||||
|
||||
if (ScriptRuntime.NumberClass.isInstance(value))
|
||||
return new Double(((Number) value).doubleValue());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static long toInteger(Object value, Class type, long min, long max) {
|
||||
double d;
|
||||
|
||||
if (value instanceof Number) {
|
||||
d = ((Number)value).doubleValue();
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
d = ScriptRuntime.toNumber((String)value);
|
||||
}
|
||||
else if (value instanceof Scriptable) {
|
||||
d = ScriptRuntime.toNumber(value);
|
||||
}
|
||||
else {
|
||||
// XXX: is this correct?
|
||||
d = ScriptRuntime.toNumber(value.toString());
|
||||
}
|
||||
|
||||
if (Double.isInfinite(d) || Double.isNaN(d)) {
|
||||
// Convert to string first, for more readable message
|
||||
reportConversionError(value.toString(), type);
|
||||
}
|
||||
|
||||
if (d > 0.0) {
|
||||
d = Math.floor(d);
|
||||
}
|
||||
else {
|
||||
d = Math.ceil(d);
|
||||
}
|
||||
|
||||
if (d < (double)min || d > (double)max) {
|
||||
// Convert to string first, for more readable message
|
||||
reportConversionError(value.toString(), type);
|
||||
}
|
||||
return (long)d;
|
||||
}
|
||||
|
||||
static void reportConversionError(Object value, Class type) {
|
||||
Object[] args = {value, type};
|
||||
throw Context.reportRuntimeError(Context.getMessage("msg.conversion.not.allowed", args));
|
||||
}
|
||||
|
||||
public static void initJSObject() {
|
||||
if (!Context.useJSObject)
|
||||
return;
|
||||
|
@ -138,6 +138,10 @@ msg.constructor.ambiguous =\
|
||||
The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; \
|
||||
candidate constructors are: {2}
|
||||
|
||||
# NativeJavaObject
|
||||
msg.conversion.not.allowed =\
|
||||
Cannot convert {0} to {1}
|
||||
|
||||
# NativeRegExp
|
||||
msg.bad.quant =\
|
||||
Invalid quantifier {0}
|
||||
|
Loading…
Reference in New Issue
Block a user