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:
rogerl%netscape.com 1999-09-21 18:58:51 +00:00
parent 5f40481fce
commit fcc6869f54
5 changed files with 130 additions and 80 deletions

View File

@ -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")

View File

@ -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);
}

View File

@ -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. */

View File

@ -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___ */

View File

@ -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