Final js1.8 feature: sugar for object destructuring (404734, r=mrbkap).

This commit is contained in:
brendan%mozilla.org 2008-01-30 06:27:13 +00:00
Родитель ad19ea8cb7
Коммит 3928a49838
6 изменённых файлов: 94 добавлений и 15 удалений

Просмотреть файл

@ -303,3 +303,4 @@ MSG_DEF(JSMSG_BAD_DELETE_OPERAND, 220, 0, JSEXN_SYNTAXERR, "invalid delete o
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_NULL_OR_UNDEFINED, 222, 2, JSEXN_TYPEERR, "{0} is {1}")
MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK, 223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block")
MSG_DEF(JSMSG_BAD_OBJECT_INIT, 224, 0, JSEXN_SYNTAXERR, "invalid object initializer")

Просмотреть файл

@ -230,7 +230,7 @@
#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */
#define JS_HAS_GENERATORS 1 /* has yield in generator function */
#define JS_HAS_BLOCK_SCOPE 1 /* has block scope via let/arraycomp */
#define JS_HAS_DESTRUCTURING 1 /* has [a,b] = ... or {p:a,q:b} = ... */
#define JS_HAS_DESTRUCTURING 2 /* has [a,b] = ... or {p:a,q:b} = ... */
#define JS_HAS_GENERATOR_EXPRS 1 /* has (expr for (lhs in iterable)) */
#define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */
@ -244,3 +244,5 @@
#define JS_HAS_RESERVED_JAVA_KEYWORDS 1
#define JS_HAS_RESERVED_ECMA_KEYWORDS 1
/* Feature-test macro for evolving destructuring support. */
#define JS_HAS_DESTRUCTURING_SHORTHAND (JS_HAS_DESTRUCTURING == 2)

Просмотреть файл

@ -6141,6 +6141,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
break;
case TOK_RC:
#if JS_HAS_DESTRUCTURING_SHORTHAND
if (pn->pn_extra & PNX_SHORTHAND) {
js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR,
JSMSG_BAD_OBJECT_INIT);
return JS_FALSE;
}
#endif
/*
* Emit code for {p:a, '%q':b, 2:c} of the form:
* t = new Object; t.p = a; t['%q'] = b; t[2] = c; t;

Просмотреть файл

@ -1307,7 +1307,7 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
static jsbytecode *
DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc)
{
ptrdiff_t head, todo;
ptrdiff_t head;
JSContext *cx;
JSPrinter *jp;
JSOp op, saveop;
@ -1341,6 +1341,10 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc)
lasti = -1;
while (pc < endpc) {
#if JS_HAS_DESTRUCTURING_SHORTHAND
ptrdiff_t nameoff = -1;
#endif
LOAD_OP_DATA(pc);
saveop = op;
@ -1393,6 +1397,9 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc)
*OFF2STR(&ss->sprinter, head) = '{';
GET_ATOM_FROM_BYTECODE(jp->script, pc, 0, atom);
str = ATOM_TO_STRING(atom);
#if JS_HAS_DESTRUCTURING_SHORTHAND
nameoff = ss->sprinter.offset;
#endif
if (!QuoteString(&ss->sprinter, str,
js_IsIdentifier(str) ? 0 : (jschar)'\'')) {
return NULL;
@ -1417,6 +1424,37 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc)
pc = DecompileDestructuringLHS(ss, pc, endpc, &hole);
if (!pc)
return NULL;
#if JS_HAS_DESTRUCTURING_SHORTHAND
if (nameoff >= 0) {
ptrdiff_t offset, initlen;
offset = ss->sprinter.offset;
LOCAL_ASSERT(*OFF2STR(&ss->sprinter, offset) == '\0');
initlen = offset - nameoff;
LOCAL_ASSERT(initlen >= 4);
/* Early check to rule out odd "name: lval" length. */
if (((size_t)initlen & 1) == 0) {
size_t namelen;
const char *name;
/*
* Even "name: lval" string length: check for "x: x" and the
* like, and apply the shorthand if we can.
*/
namelen = (size_t)(initlen - 2) >> 1;
name = OFF2STR(&ss->sprinter, nameoff);
if (!strncmp(name + namelen, ": ", 2) &&
!strncmp(name, name + namelen + 2, namelen)) {
offset -= namelen + 2;
*OFF2STR(&ss->sprinter, offset) = '\0';
ss->sprinter.offset = offset;
}
}
}
#endif
if (pc == endpc || *pc != JSOP_DUP)
break;
@ -1437,8 +1475,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc)
out:
lval = OFF2STR(&ss->sprinter, head);
todo = SprintPut(&ss->sprinter, (*lval == '[') ? "]" : "}", 1);
if (todo < 0)
if (SprintPut(&ss->sprinter, (*lval == '[') ? "]" : "}", 1) < 0)
return NULL;
return pc;
}
@ -3504,7 +3541,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
atom = GetSlotAtom(ss->printer, op == JSOP_GETARGPROP,
GET_UINT16(pc));
LOCAL_ASSERT(atom);
JS_ASSERT(ATOM_IS_STRING(atom));
LOCAL_ASSERT(ATOM_IS_STRING(atom));
lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
if (!lval || !PushOff(ss, STR2OFF(&ss->sprinter, lval), op))
return NULL;
@ -3669,7 +3706,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_DOUBLE:
LOAD_ATOM(0);
val = ATOM_KEY(atom);
JS_ASSERT(JSVAL_IS_DOUBLE(val));
LOCAL_ASSERT(JSVAL_IS_DOUBLE(val));
todo = SprintDoubleValue(&ss->sprinter, val, &saveop);
break;
@ -3820,7 +3857,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_OBJECT:
LOAD_OBJECT(0);
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
goto do_regexp;
case JSOP_REGEXP:
@ -4104,7 +4141,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_NEWINIT:
{
i = GET_INT8(pc);
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
LOCAL_ASSERT(i == JSProto_Array || i == JSProto_Object);
todo = ss->sprinter.offset;
#if JS_HAS_SHARP_VARS

Просмотреть файл

@ -5447,6 +5447,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
case TOK_LC:
{
JSBool afterComma;
JSParseNode *pnval;
pn = NewParseNode(cx, ts, PN_LIST, tc);
if (!pn)
@ -5535,13 +5536,38 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
return NULL;
}
#endif
if (tt != TOK_COLON) {
js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
JSMSG_COLON_AFTER_ID);
return NULL;
#if JS_HAS_DESTRUCTURING_SHORTHAND
if (tt != TOK_COMMA && tt != TOK_RC) {
#endif
js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
JSMSG_COLON_AFTER_ID);
return NULL;
#if JS_HAS_DESTRUCTURING_SHORTHAND
}
/*
* Support, e.g., |var {x, y} = o| as destructuring shorthand
* for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
*/
js_UngetToken(ts);
pn->pn_extra |= PNX_SHORTHAND;
pnval = pn3;
if (pnval->pn_type == TOK_NAME) {
pnval->pn_arity = PN_NAME;
pnval->pn_expr = NULL;
pnval->pn_slot = -1;
pnval->pn_const = JS_FALSE;
}
op = JSOP_NOP;
#endif
} else {
op = CURRENT_TOKEN(ts).t_op;
pnval = AssignExpr(cx, ts, tc);
}
op = CURRENT_TOKEN(ts).t_op;
pn2 = NewBinary(cx, TOK_COLON, op, pn3, AssignExpr(cx, ts, tc), tc);
pn2 = NewBinary(cx, TOK_COLON, op, pn3, pnval, tc);
#if JS_HAS_GETTER_SETTER
skip:
#endif

Просмотреть файл

@ -177,6 +177,9 @@ JS_BEGIN_EXTERN_C
* TOK_RC list pn_head: list of pn_count TOK_COLON nodes where
* each has pn_left: property id, pn_right: value
* #n={...} produces TOK_DEFSHARP at head of list
* var {x} = object destructuring shorthand shares
* PN_NAME node for x on left and right of TOK_COLON
* node in TOK_RC's list, has PNX_SHORTHAND flag
* TOK_DEFSHARP unary pn_num: jsint value of n in #n=
* pn_kid: null for #n=[...] and #n={...}, primary
* if #n=primary for function, paren, name, object
@ -309,7 +312,7 @@ struct JSParseNode {
JSAtom *atom; /* name or label atom, null if slot */
JSParseNode *expr; /* object or initializer */
jsint slot; /* -1 or arg or local var slot */
JSBool constslot; /* true for const names */
JSBool isconst; /* true for const names */
} name;
struct { /* lexical scope. */
JSParsedObjectBox *pob; /* block object */
@ -349,7 +352,7 @@ struct JSParseNode {
#define pn_atom pn_u.name.atom
#define pn_expr pn_u.name.expr
#define pn_slot pn_u.name.slot
#define pn_const pn_u.name.constslot
#define pn_const pn_u.name.isconst
#define pn_dval pn_u.dval
#define pn_atom2 pn_u.apair.atom2
#define pn_pob pn_u.object.pob
@ -366,6 +369,9 @@ struct JSParseNode {
#define PNX_NEEDBRACES 0x80 /* braces necessary due to closure */
#define PNX_FUNCDEFS 0x100 /* contains top-level function
statements */
#define PNX_SHORTHAND 0x200 /* shorthand syntax used, at present
object destructuring ({x,y}) only */
/*
* Move pn2 into pn, preserving pn->pn_pos and pn->pn_offset and handing off
* any kids in pn2->pn_u, by clearing pn2.