ECMA errors as exceptions changes - conformance to latest spec for
hierarchy and names etc. Added attempt to make the base exceptions be instanceof equal across contexts. git-svn-id: svn://10.0.0.236/trunk@48586 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
5f40481fce
commit
fcc6869f54
@ -64,25 +64,25 @@ MSG_DEF(JSMSG_BAD_CHAR, 4, 1, JSEXN_NONE, "invalid format charac
|
||||
MSG_DEF(JSMSG_BAD_TYPE, 5, 1, JSEXN_NONE, "unknown type {0}")
|
||||
MSG_DEF(JSMSG_CANT_LOCK, 6, 0, JSEXN_NONE, "can't lock memory")
|
||||
MSG_DEF(JSMSG_CANT_UNLOCK, 7, 0, JSEXN_NONE, "can't unlock memory")
|
||||
MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TARGETERR, "{0}.prototype.{1} called on incompatible {2}")
|
||||
MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
|
||||
MSG_DEF(JSMSG_NO_CONSTRUCTOR, 9, 1, JSEXN_NONE, "{0} has no constructor")
|
||||
MSG_DEF(JSMSG_CANT_ALIAS, 10, 3, JSEXN_NONE, "can't alias {0} to {1} in class {2}")
|
||||
MSG_DEF(JSMSG_NO_PROTO, 11, 1, JSEXN_INTERNALERR, "sorry, Array.prototype.{0} is not yet implemented")
|
||||
MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_ARRAYERR, "invalid Array.prototype.sort argument")
|
||||
MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
|
||||
MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER, 13, 1, JSEXN_INTERNALERR, "internal error: no index for atom {0}")
|
||||
MSG_DEF(JSMSG_TOO_MANY_LITERALS, 14, 0, JSEXN_INTERNALERR, "too many literals")
|
||||
MSG_DEF(JSMSG_CANT_WATCH, 15, 1, JSEXN_NONE, "can't watch non-native objects of class {0}")
|
||||
MSG_DEF(JSMSG_STACK_UNDERFLOW, 16, 2, JSEXN_INTERNALERR, "internal error compiling {0}: stack underflow at pc {1}")
|
||||
MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_SYNTAXERR, "{0} too large")
|
||||
MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_INTERNALERR, "{0} too large")
|
||||
MSG_DEF(JSMSG_BAD_CASE, 18, 2, JSEXN_SYNTAXERR, "{0}, line {1}: invalid case expression")
|
||||
MSG_DEF(JSMSG_READ_ONLY, 19, 1, JSEXN_ERR, "{0} is read-only")
|
||||
MSG_DEF(JSMSG_BAD_FORMAL, 20, 0, JSEXN_SYNTAXERR, "malformed formal parameter")
|
||||
MSG_DEF(JSMSG_SAME_FORMAL, 21, 1, JSEXN_NONE, "duplicate formal argument {0}")
|
||||
MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_CALLERR, "{0} is not a function")
|
||||
MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_CONSTRUCTORERR, "{0} is not a constructor")
|
||||
MSG_DEF(JSMSG_STACK_OVERFLOW, 24, 1, JSEXN_NONE, "stack overflow in {0}")
|
||||
MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_TYPEERR, "{0} is not a function")
|
||||
MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_TYPEERR, "{0} is not a constructor")
|
||||
MSG_DEF(JSMSG_STACK_OVERFLOW, 24, 1, JSEXN_INTERNALERR, "stack overflow in {0}")
|
||||
MSG_DEF(JSMSG_NOT_EXPORTED, 25, 1, JSEXN_NONE, "{0} is not exported")
|
||||
MSG_DEF(JSMSG_OVER_RECURSED, 26, 0, JSEXN_NONE, "too much recursion")
|
||||
MSG_DEF(JSMSG_OVER_RECURSED, 26, 0, JSEXN_INTERNALERR, "too much recursion")
|
||||
MSG_DEF(JSMSG_IN_NOT_OBJECT, 27, 0, JSEXN_ERR, "target of 'in' operator must be an object")
|
||||
MSG_DEF(JSMSG_BAD_NEW_RESULT, 28, 1, JSEXN_NONE, "invalid new expression result {0}")
|
||||
MSG_DEF(JSMSG_BAD_SHARP_DEF, 29, 1, JSEXN_ERR, "invalid sharp variable definition #{0}=")
|
||||
@ -91,11 +91,11 @@ MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 31, 1, JSEXN_ERR, "invalid instanceof ope
|
||||
MSG_DEF(JSMSG_BAD_BYTECODE, 32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
|
||||
MSG_DEF(JSMSG_BAD_RADIX, 33, 1, JSEXN_ERR, "illegal radix {0}")
|
||||
MSG_DEF(JSMSG_NAN, 34, 1, JSEXN_ERR, "{0} is not a number")
|
||||
MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_TOPRIMITIVEERR, "can't convert {0} to an integer")
|
||||
MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_NONE, "can't convert {0} to an integer")
|
||||
MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_ERR, "cyclic {0} value")
|
||||
MSG_DEF(JSMSG_PERMANENT, 37, 1, JSEXN_ERR, "{0} is permanent")
|
||||
MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_DEFAULTVALUEERR, "can't convert {0} to {1}")
|
||||
MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TOOBJECTERR, "{0} has no properties")
|
||||
MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}")
|
||||
MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TYPEERR, "{0} has no properties")
|
||||
MSG_DEF(JSMSG_CANT_FIND_CLASS, 40, 1, JSEXN_NONE, "can't find class id {0}")
|
||||
MSG_DEF(JSMSG_CANT_XDR_CLASS, 41, 1, JSEXN_NONE, "can't XDR class {0}")
|
||||
MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 42, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})")
|
||||
@ -202,9 +202,10 @@ MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 142, 0, JSEXN_SYNTAXERR, "invalid flag aft
|
||||
MSG_DEF(JSMSG_SHARPVAR_TOO_BIG, 143, 0, JSEXN_SYNTAXERR, "overlarge sharp variable number")
|
||||
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 144, 0, JSEXN_SYNTAXERR, "illegal character")
|
||||
MSG_DEF(JSMSG_BAD_OCTAL, 145, 1, JSEXN_NONE, "{0} is not a legal ECMA-262 numeric constant")
|
||||
MSG_DEF(JSMSG_BAD_INDIRECT_CALL, 146, 1, JSEXN_CALLERR, "function {0} must be called directly, and not by way of a function of another name.")
|
||||
MSG_DEF(JSMSG_BAD_INDIRECT_CALL, 146, 1, JSEXN_EVALERR, "function {0} must be called directly, and not by way of a function of another name.")
|
||||
MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 147, 1, JSEXN_NONE, "uncaught exception: {0}")
|
||||
MSG_DEF(JSMSG_INVALID_BACKREF, 148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference")
|
||||
MSG_DEF(JSMSG_BAD_BACKREF, 149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses")
|
||||
MSG_DEF(JSMSG_PRECISION_RANGE, 150, 1, JSEXN_RANGEERR, "precision {0} out of range")
|
||||
MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 151, 1, JSEXN_SYNTAXERR, "invalid {0} usage")
|
||||
MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 152, 0, JSEXN_RANGEERR, "Inappropriate array length")
|
||||
|
||||
@ -101,52 +101,37 @@ IdIsIndex(jsid id, jsuint *indexp)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static JSBool
|
||||
ValueIsLength(JSContext *cx, jsval v, jsuint *lengthp)
|
||||
{
|
||||
jsint i;
|
||||
|
||||
/*
|
||||
* It's only an array length if it's an int or a double. Some relevant
|
||||
* ECMA language is 15.4.2.2 - 'If the argument len is a number, then the
|
||||
* length property of the newly constructed object is set to ToUint32(len)
|
||||
* - I take 'is a number' to mean 'typeof len' returns 'number' in
|
||||
* javascript.
|
||||
*/
|
||||
if (JSVAL_IS_INT(v)) {
|
||||
i = JSVAL_TO_INT(v);
|
||||
/* jsuint cast does ToUint32 */
|
||||
if (i < 0) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_ARRAY_LENGTH);
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (lengthp)
|
||||
*lengthp = (jsuint) i;
|
||||
return JS_TRUE;
|
||||
}
|
||||
if (JSVAL_IS_DOUBLE(v)) {
|
||||
/*
|
||||
* XXXmccabe I'd love to add another check here, against
|
||||
* js_DoubleToInteger(d) != d), so that ValueIsLength matches
|
||||
* IdIsIndex, but it doesn't seem to follow from ECMA.
|
||||
* (seems to be appropriate for IdIsIndex, though).
|
||||
*/
|
||||
return js_ValueToECMAUint32(cx, v, (uint32 *)lengthp);
|
||||
}
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static JSBool
|
||||
ValueToIndex(JSContext *cx, jsval v, jsuint *lengthp)
|
||||
{
|
||||
jsint i;
|
||||
|
||||
if (JSVAL_IS_INT(v)) {
|
||||
i = JSVAL_TO_INT(v);
|
||||
/* jsuint cast does ToUint32. */
|
||||
if (lengthp)
|
||||
*lengthp = (jsuint)i;
|
||||
jsdouble d;
|
||||
/* mccabe gets his wish */
|
||||
if (!js_ValueToNumber(cx, v, &d))
|
||||
return JS_FALSE;
|
||||
if (!js_DoubleToECMAUint32(cx, d, (uint32 *)lengthp))
|
||||
return JS_FALSE;
|
||||
if (d != *(uint32 *)lengthp) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_ARRAY_LENGTH);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
return js_ValueToECMAUint32(cx, v, (uint32 *)lengthp);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
@ -250,7 +235,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
jsid id2;
|
||||
jsval junk;
|
||||
|
||||
if (!ValueToIndex(cx, *vp, &newlen))
|
||||
if (!ValueIsLength(cx, *vp, &newlen))
|
||||
return JS_FALSE;
|
||||
if (!js_GetLengthProperty(cx, obj, &oldlen))
|
||||
return JS_FALSE;
|
||||
@ -1320,17 +1305,23 @@ Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
if (argc == 0) {
|
||||
length = 0;
|
||||
vector = NULL;
|
||||
} else if (cx->version != JSVERSION_1_2 &&
|
||||
argc == 1 && ValueIsLength(cx, argv[0], &length))
|
||||
{
|
||||
/*
|
||||
* Only use 1 arg as first element for version 1.2; for any other
|
||||
* version (including 1.3), follow ECMA and use it as a length.
|
||||
*/
|
||||
vector = NULL;
|
||||
} else if (cx->version == JSVERSION_1_2) {
|
||||
if (argc == 1 && ValueIsLength(cx, argv[0], &length))
|
||||
vector = NULL;
|
||||
else {
|
||||
length = (jsuint) argc;
|
||||
vector = argv;
|
||||
}
|
||||
} else {
|
||||
length = (jsuint) argc;
|
||||
vector = argv;
|
||||
if (argc > 1) {
|
||||
length = (jsuint) argc;
|
||||
vector = argv;
|
||||
}
|
||||
else {
|
||||
if (!ValueIsLength(cx, argv[0], &length))
|
||||
return JS_FALSE;
|
||||
vector = NULL;
|
||||
}
|
||||
}
|
||||
return InitArrayObject(cx, obj, length, vector);
|
||||
}
|
||||
|
||||
@ -39,11 +39,13 @@
|
||||
/* Declaration to resolve circular reference of exn_class by Exception. */
|
||||
static JSBool
|
||||
Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
|
||||
JSBool
|
||||
js_exnHasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
|
||||
|
||||
static void
|
||||
exn_finalize(JSContext *cx, JSObject *obj);
|
||||
|
||||
static JSClass exn_class = {
|
||||
JSClass exn_class = {
|
||||
"Exception",
|
||||
JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
@ -209,20 +211,15 @@ js_ErrorFromException(JSContext *cx, jsval exn)
|
||||
/* This must be kept in synch with the exceptions array below. */
|
||||
typedef enum JSExnType {
|
||||
JSEXN_NONE = -1,
|
||||
JSEXN_EXCEPTION,
|
||||
JSEXN_ERR,
|
||||
JSEXN_INTERNALERR,
|
||||
JSEXN_SYNTAXERR,
|
||||
JSEXN_REFERENCEERR,
|
||||
JSEXN_CALLERR,
|
||||
JSEXN_TARGETERR,
|
||||
JSEXN_CONSTRUCTORERR,
|
||||
JSEXN_CONVERSIONERR,
|
||||
JSEXN_TOOBJECTERR,
|
||||
JSEXN_TOPRIMITIVEERR,
|
||||
JSEXN_DEFAULTVALUEERR,
|
||||
JSEXN_ARRAYERR,
|
||||
JSEXN_EVALERR,
|
||||
JSEXN_RANGEERR,
|
||||
JSEXN_REFERENCEERR,
|
||||
JSEXN_SYNTAXERR,
|
||||
JSEXN_TYPEERR,
|
||||
JSEXN_URIERR,
|
||||
JSEXN_LIMIT
|
||||
} JSExnType;
|
||||
|
||||
@ -232,20 +229,15 @@ struct JSExnSpec {
|
||||
};
|
||||
|
||||
static struct JSExnSpec exceptions[] = {
|
||||
{ JSEXN_NONE, "Exception" },
|
||||
{ JSEXN_EXCEPTION, "Error" },
|
||||
{ JSEXN_NONE, "Error" },
|
||||
{ JSEXN_ERR, "InternalError" },
|
||||
{ JSEXN_ERR, "SyntaxError" },
|
||||
{ JSEXN_ERR, "ReferenceError" },
|
||||
{ JSEXN_ERR, "CallError" },
|
||||
{ JSEXN_CALLERR, "TargetError" },
|
||||
{ JSEXN_ERR, "ConstructorError" },
|
||||
{ JSEXN_ERR, "ConversionError" },
|
||||
{ JSEXN_CONVERSIONERR, "ToObjectError" },
|
||||
{ JSEXN_CONVERSIONERR, "ToPrimitiveError" },
|
||||
{ JSEXN_CONVERSIONERR, "DefaultValueError" },
|
||||
{ JSEXN_ERR, "ArrayError" },
|
||||
{ JSEXN_ERR, "EvalError" },
|
||||
{ JSEXN_ERR, "RangeError" },
|
||||
{ JSEXN_ERR, "ReferenceError" },
|
||||
{ JSEXN_ERR, "SyntaxError" },
|
||||
{ JSEXN_ERR, "TypeError" },
|
||||
{ JSEXN_ERR, "URIError" },
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -285,6 +277,35 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by fun_hasInstance when 'obj' has exn_class, to see if
|
||||
* 'v' could be an instanceof an exception from some other context
|
||||
* - we'll know it is if it has that special 'something'
|
||||
*/
|
||||
|
||||
JSBool
|
||||
js_exnHasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
|
||||
{
|
||||
JSFunction *fun;
|
||||
JSAtom *functionName;
|
||||
jsval pval;
|
||||
|
||||
JSObject *obj2;
|
||||
*bp = JS_FALSE;
|
||||
|
||||
fun = (JSFunction *)JS_GetPrivate(cx, obj);
|
||||
functionName = fun->atom;
|
||||
|
||||
obj2 = JSVAL_TO_OBJECT(v);
|
||||
if (!OBJ_GET_PROPERTY(cx, obj2, (jsid)functionName, &pval))
|
||||
return JS_FALSE;
|
||||
|
||||
if (JSVAL_IS_INT(pval))
|
||||
*bp = JS_TRUE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert to string.
|
||||
*
|
||||
@ -416,6 +437,20 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
|
||||
|
||||
atom = js_Atomize(cx, exceptions[i].name, strlen(exceptions[i].name), 0);
|
||||
|
||||
/*
|
||||
Now add a property to this prototype that can be used to
|
||||
identify these kind of exceptions across multiple contexts.
|
||||
This is a little less than satisfying, since other proto
|
||||
chains may include objects with the same property but it'll
|
||||
pass for now.
|
||||
*/
|
||||
if (!JS_DefineProperty(cx, protos[i], exceptions[i].name,
|
||||
INT_TO_JSVAL(i),
|
||||
NULL, NULL,
|
||||
JSPROP_READONLY | JSPROP_PERMANENT))
|
||||
return NULL;
|
||||
|
||||
|
||||
/* Make a constructor function for the current name. */
|
||||
fun = js_DefineFunction(cx, obj, atom, Exception, 1, 0);
|
||||
if (!fun)
|
||||
@ -425,8 +460,9 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
|
||||
fun->clasp = &exn_class;
|
||||
|
||||
/* Make the prototype and constructor links. */
|
||||
if (!js_SetClassPrototype(cx, fun->object, protos[i],
|
||||
JSPROP_READONLY | JSPROP_PERMANENT))
|
||||
if (!js_SetClassPrototype(cx, fun->object,
|
||||
protos[i],
|
||||
JSPROP_READONLY | JSPROP_PERMANENT))
|
||||
return NULL;
|
||||
|
||||
/* proto bootstrap bit from JS_InitClass omitted. */
|
||||
|
||||
@ -61,6 +61,10 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp);
|
||||
extern JSBool
|
||||
js_ReportUncaughtException(JSContext *cx);
|
||||
|
||||
extern JSClass exn_class;
|
||||
extern JSBool
|
||||
js_exnHasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsexn_h___ */
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsstr.h"
|
||||
#include "jsexn.h"
|
||||
|
||||
enum {
|
||||
CALL_ARGUMENTS = -1, /* predefined arguments local variable */
|
||||
@ -1110,8 +1111,25 @@ fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
|
||||
&pval)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!JSVAL_IS_PRIMITIVE(pval))
|
||||
return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp);
|
||||
if (!JSVAL_IS_PRIMITIVE(pval)) {
|
||||
JSObject *protoObj = JSVAL_TO_OBJECT(pval);
|
||||
if (!js_IsDelegate(cx, protoObj, v, bp))
|
||||
return JS_FALSE;
|
||||
|
||||
#if JS_HAS_ERROR_EXCEPTIONS
|
||||
/*
|
||||
For exceptions, we want cross-context exceptions to be equal, i.e. a
|
||||
SyntaxError thrown from one context (another window) will still be a
|
||||
'instanceof SyntaxError' in another context (window). Here, if we're
|
||||
asking if an object is an instance of an exception, make a special
|
||||
call into js_exnHasInstance.
|
||||
*/
|
||||
if (*bp == JS_TRUE) return JS_TRUE;
|
||||
if (OBJ_GET_CLASS(cx, protoObj) == &exn_class)
|
||||
return js_exnHasInstance(cx, obj, v, bp);
|
||||
#endif /* JS_HAS_ERROR_EXCEPTIONS */
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Throw a runtime error if instanceof is called on a function
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user