зеркало из https://github.com/mozilla/gecko-dev.git
r=brendan,rginda
Added ECMA3 compliant getter/setter syntax. Fixed bugs - #28686, mishandling of \$ in replace() - #27902, eval not detected as heavyweight indicator for non ECMA context version.
This commit is contained in:
Родитель
b811298c4b
Коммит
429c1db8e9
|
@ -2239,10 +2239,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
op = JSOP_CALL;
|
||||
emit_call:
|
||||
pn2 = pn->pn_head;
|
||||
if (JSVERSION_IS_ECMA(cx->version) &&
|
||||
pn2->pn_op == JSOP_NAME &&
|
||||
if (pn2->pn_op == JSOP_NAME &&
|
||||
pn2->pn_atom == cx->runtime->atomState.evalAtom) {
|
||||
op = JSOP_EVAL;
|
||||
if (JSVERSION_IS_ECMA(cx->version))
|
||||
op = JSOP_EVAL;
|
||||
cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
|
||||
|
|
|
@ -516,15 +516,25 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
if (attrs & JSPROP_GETTER) {
|
||||
val[valcnt] = (jsval)
|
||||
SPROP_GETTER((JSScopeProperty *)prop, obj2);
|
||||
#ifdef OLD_GETTER_SETTER
|
||||
gsop[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
|
||||
#else
|
||||
gsop[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.getAtom);
|
||||
#endif
|
||||
valcnt++;
|
||||
}
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
val[valcnt] = (jsval)
|
||||
SPROP_SETTER((JSScopeProperty *)prop, obj2);
|
||||
#ifdef OLD_GETTER_SETTER
|
||||
gsop[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
|
||||
#else
|
||||
gsop[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.setAtom);
|
||||
#endif
|
||||
valcnt++;
|
||||
}
|
||||
} else {
|
||||
|
@ -572,6 +582,15 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
vchars = valstr->chars;
|
||||
vlength = valstr->length;
|
||||
|
||||
#ifndef OLD_GETTER_SETTER
|
||||
/* Remove 'function ' from beginning of valstr*/
|
||||
if (gsop[j]) {
|
||||
int n = strlen(js_function_str) + 1;
|
||||
vchars += n;
|
||||
vlength -= n;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If val[j] is a non-sharp object, consider sharpening it. */
|
||||
vsharp = NULL;
|
||||
vsharplength = 0;
|
||||
|
@ -619,6 +638,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
}
|
||||
comma = ", ";
|
||||
|
||||
#ifdef OLD_GETTER_SETTER
|
||||
js_strncpy(&chars[nchars], idstr->chars, idstr->length);
|
||||
nchars += idstr->length;
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
|
@ -629,7 +649,17 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
}
|
||||
#endif
|
||||
chars[nchars++] = ':';
|
||||
|
||||
#else
|
||||
if (gsop[j]) {
|
||||
js_strncpy(&chars[nchars], gsop[j]->chars, gsop[j]->length);
|
||||
nchars += gsop[j]->length;
|
||||
chars[nchars++] = ' ';
|
||||
}
|
||||
js_strncpy(&chars[nchars], idstr->chars, idstr->length);
|
||||
nchars += idstr->length;
|
||||
if (!gsop[j])
|
||||
chars[nchars++] = ':';
|
||||
#endif
|
||||
if (vsharplength) {
|
||||
js_strncpy(&chars[nchars], vsharp, vsharplength);
|
||||
nchars += vsharplength;
|
||||
|
@ -938,6 +968,55 @@ obj_propertyIsEnumerable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
}
|
||||
#endif /* JS_HAS_NEW_OBJ_METHODS */
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
static JSBool
|
||||
obj_defineGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
JSAtom *atom;
|
||||
jsval fval = argv[1];
|
||||
|
||||
if (JS_TypeOfValue(cx, fval) != JSTYPE_FUNCTION) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_GETTER_OR_SETTER,
|
||||
js_getter_str);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
atom = js_ValueToStringAtom(cx, argv[0]);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
|
||||
return OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID,
|
||||
(JSPropertyOp) JSVAL_TO_OBJECT(fval),
|
||||
NULL, JSPROP_GETTER, NULL);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
obj_defineSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
JSAtom *atom;
|
||||
jsval fval = argv[1];
|
||||
|
||||
if (JS_TypeOfValue(cx, argv[1]) != JSTYPE_FUNCTION) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_GETTER_OR_SETTER,
|
||||
js_setter_str);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
atom = js_ValueToStringAtom(cx, argv[0]);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
|
||||
return OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, NULL,
|
||||
(JSPropertyOp) JSVAL_TO_OBJECT(argv[1]),
|
||||
JSPROP_SETTER, NULL);
|
||||
}
|
||||
#endif /* JS_HAS_GETTER_SETTER */
|
||||
|
||||
|
||||
static JSFunctionSpec object_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
{js_toSource_str, js_obj_toSource, 0, 0, OBJ_TOSTRING_EXTRA},
|
||||
|
@ -953,6 +1032,10 @@ static JSFunctionSpec object_methods[] = {
|
|||
{"hasOwnProperty", obj_hasOwnProperty, 1,0,0},
|
||||
{"isPrototypeOf", obj_isPrototypeOf, 1,0,0},
|
||||
{"propertyIsEnumerable", obj_propertyIsEnumerable, 1,0,0},
|
||||
#endif
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
{"__defineGetter__", obj_defineGetter, 2,0,0},
|
||||
{"__defineSetter__", obj_defineSetter, 2,0,0},
|
||||
#endif
|
||||
{0,0,0,0,0}
|
||||
};
|
||||
|
|
|
@ -2041,16 +2041,34 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
xval = ATOM_BYTES(atom);
|
||||
lval = POP_STR();
|
||||
do_initprop:
|
||||
todo = Sprint(&ss->sprinter, "%s%s%s%s%s:%s",
|
||||
lval,
|
||||
#ifdef OLD_GETTER_SETTER
|
||||
todo = Sprint(&ss->sprinter, "%s%s%s%s%s:%s",
|
||||
lval,
|
||||
(lval[1] != '\0') ? ", " : "",
|
||||
xval,
|
||||
xval,
|
||||
(lastop == JSOP_GETTER || lastop == JSOP_SETTER)
|
||||
? " " : "",
|
||||
(lastop == JSOP_GETTER) ? js_getter_str :
|
||||
(lastop == JSOP_SETTER) ? js_setter_str :
|
||||
"",
|
||||
rval);
|
||||
#else
|
||||
if (lastop == JSOP_GETTER || lastop == JSOP_SETTER) {
|
||||
todo = Sprint(&ss->sprinter, "%s%s%s %s%s",
|
||||
lval,
|
||||
(lval[1] != '\0') ? ", " : "",
|
||||
(lastop == JSOP_GETTER)
|
||||
? js_get_str : js_set_str,
|
||||
xval,
|
||||
rval + strlen(js_function_str) + 1);
|
||||
} else {
|
||||
todo = Sprint(&ss->sprinter, "%s%s%s:%s",
|
||||
lval,
|
||||
(lval[1] != '\0') ? ", " : "",
|
||||
xval,
|
||||
rval);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case JSOP_INITELEM:
|
||||
|
|
|
@ -220,6 +220,13 @@ CheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt)
|
|||
return TOK_ERROR;
|
||||
}
|
||||
CURRENT_TOKEN(ts).t_op = op;
|
||||
if (!js_ReportCompileErrorNumber(cx, ts,
|
||||
JSREPORT_WARNING |
|
||||
JSREPORT_STRICT,
|
||||
JSMSG_DEPRECATED_USAGE,
|
||||
ATOM_BYTES(atom))) {
|
||||
return TOK_ERROR;
|
||||
}
|
||||
return tt;
|
||||
}
|
||||
#endif
|
||||
|
@ -2360,6 +2367,8 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
JSTokenType tt;
|
||||
JSParseNode *pn, *pn2, *pn3;
|
||||
char *badWord;
|
||||
JSAtom *atom;
|
||||
JSRuntime *rt;
|
||||
|
||||
#if JS_HAS_SHARP_VARS
|
||||
JSParseNode *defsharp;
|
||||
|
@ -2473,6 +2482,31 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
pn3->pn_dval = CURRENT_TOKEN(ts).t_dval;
|
||||
break;
|
||||
case TOK_NAME:
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
atom = CURRENT_TOKEN(ts).t_atom;
|
||||
rt = cx->runtime;
|
||||
if (atom == rt->atomState.getAtom ||
|
||||
atom == rt->atomState.setAtom) {
|
||||
op = (atom == rt->atomState.getAtom)
|
||||
? JSOP_GETTER
|
||||
: JSOP_SETTER;
|
||||
if (js_MatchToken(cx, ts, TOK_NAME)) {
|
||||
pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts),
|
||||
PN_NAME);
|
||||
if (!pn3)
|
||||
return NULL;
|
||||
pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;
|
||||
pn3->pn_expr = NULL;
|
||||
/* have to fake a 'function' token */
|
||||
CURRENT_TOKEN(ts).t_op = JSOP_NOP;
|
||||
CURRENT_TOKEN(ts).type = TOK_FUNCTION;
|
||||
pn2 = FunctionDef(cx, ts, tc, JS_TRUE);
|
||||
pn2 = NewBinary(cx, TOK_COLON, op, pn3, pn2);
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
/* else fall thru ... */
|
||||
#endif
|
||||
case TOK_STRING:
|
||||
pn3 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NULLARY);
|
||||
if (pn3)
|
||||
|
@ -2501,6 +2535,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
op = CURRENT_TOKEN(ts).t_op;
|
||||
pn2 = NewBinary(cx, TOK_COLON, op, pn3, AssignExpr(cx, ts, tc));
|
||||
skip:
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
PN_APPEND(pn, pn2);
|
||||
|
|
|
@ -146,7 +146,10 @@ struct JSScopeProperty {
|
|||
(((sprop)->attrs & JSPROP_SETTER) \
|
||||
? js_InternalCall(cx, obj, OBJECT_TO_JSVAL(SPROP_SETTER(sprop,obj2)), \
|
||||
1, vp, vp) \
|
||||
: SPROP_SETTER(sprop,obj2)(cx, OBJ_THIS_OBJECT(cx,obj), sprop->id, vp))
|
||||
: ((sprop)->attrs & JSPROP_GETTER) \
|
||||
? (JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, \
|
||||
JSMSG_GETTER_ONLY, NULL), JS_FALSE) \
|
||||
: SPROP_SETTER(sprop,obj2)(cx, OBJ_THIS_OBJECT(cx,obj), sprop->id, vp))
|
||||
|
||||
extern JSScope *
|
||||
js_GetMutableScope(JSContext *cx, JSObject *obj);
|
||||
|
|
|
@ -998,10 +998,16 @@ interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
|
|||
uintN num, tmp;
|
||||
JSString *str;
|
||||
|
||||
/* Allow a real backslash (literal "\\") to escape "$1" etc. */
|
||||
JS_ASSERT(*dp == '$');
|
||||
if (dp > rdata->repstr->chars && dp[-1] == '\\')
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Allow a real backslash (literal "\\") to escape "$1" etc.
|
||||
* Do this for versions less than 1.5 (ECMA 3) only
|
||||
*/
|
||||
if (cx->version != JSVERSION_DEFAULT &&
|
||||
cx->version <= JSVERSION_1_4)
|
||||
if (dp > rdata->repstr->chars && dp[-1] == '\\')
|
||||
return NULL;
|
||||
|
||||
/* Interpret all Perl match-induced dollar variables. */
|
||||
res = &cx->regExpStatics;
|
||||
|
|
Загрузка…
Ссылка в новой задаче