Browse Source

Merge pull request #985 from svaarala/es6-computed-property-name-object-literal

Add ES6 computed property name support
pull/986/head
Sami Vaarala 8 years ago
committed by GitHub
parent
commit
6e4e914d28
  1. 3
      RELEASES.rst
  2. 34
      src-input/duk_js_compiler.c
  3. 4
      src-input/duk_js_executor.c
  4. 68
      tests/ecmascript/test-dev-object-literal-computed.js

3
RELEASES.rst

@ -1800,6 +1800,9 @@ Planned
won't backtrack on e.g. an invalid hex escape and treat it literally
(GH-926)
* Add support for ES6 computed property names in object literals, e.g.
"{ [1+2]: 'three' }" (GH-985)
* Remove no longer needed platform wrappers in duk_config.h: DUK_ABORT(),
DUK_EXIT(), DUK_PRINTF(), DUK_FPRINTF(), DUK_FOPEN(), DUK_FCLOSE(),
DUK_FREAD(), DUK_FWRITE(), DUK_FSEEK(), DUK_FTELL(), DUK_FFLUSH(),

34
src-input/duk_js_compiler.c

@ -3074,30 +3074,44 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
DUK__SETTEMP(comp_ctx, temp_start);
} else {
duk_bool_t skip_key_load = 0;
reg_temp = DUK__ALLOCTEMP(comp_ctx);
/* normal key/value */
if (comp_ctx->prev_token.t_nores == DUK_TOK_IDENTIFIER ||
comp_ctx->prev_token.t_nores == DUK_TOK_STRING) {
/* same handling for identifiers and strings */
/* Same handling for identifiers and strings. */
DUK_ASSERT(comp_ctx->prev_token.str1 != NULL);
duk_push_hstring(ctx, comp_ctx->prev_token.str1);
} else if (comp_ctx->prev_token.t == DUK_TOK_NUMBER) {
duk_push_number(ctx, comp_ctx->prev_token.num);
duk_to_string(ctx, -1);
} else if (comp_ctx->prev_token.t == DUK_TOK_LBRACKET) {
/* ES6 computed property name. Executor ToPropertyKey()
* coerces the key at runtime.
*/
duk__expr_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR, reg_temp);
DUK__SETTEMP(comp_ctx, reg_temp + 1);
duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
skip_key_load = 1;
} else {
goto syntax_error;
}
DUK_ASSERT(duk_is_string(ctx, -1));
if (duk__nud_object_literal_key_check(comp_ctx, DUK__OBJ_LIT_KEY_PLAIN)) {
goto syntax_error;
if (!skip_key_load) {
DUK_ASSERT(duk_is_string(ctx, -1));
if (duk__nud_object_literal_key_check(comp_ctx, DUK__OBJ_LIT_KEY_PLAIN)) {
goto syntax_error;
}
reg_key = duk__getconst(comp_ctx);
duk__emit_a_bc(comp_ctx,
DUK_OP_LDCONST,
(duk_regconst_t) reg_temp,
(duk_regconst_t) reg_key);
}
reg_key = duk__getconst(comp_ctx);
reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__emit_a_bc(comp_ctx,
DUK_OP_LDCONST,
(duk_regconst_t) reg_temp,
(duk_regconst_t) reg_key);
duk__advance_expect(comp_ctx, DUK_TOK_COLON);
reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */

4
src-input/duk_js_executor.c

@ -4640,6 +4640,10 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
* it would not work correctly if there are inherited
* properties in Object.prototype which might e.g.
* prevent a key from being added.
*
* With ES6 computed property names the literal keys
* may be arbitrary values and need to be ToPropertyKey()
* coerced at runtime.
*/
do {
/* XXX: faster initialization (direct access or better primitives) */

68
tests/ecmascript/test-dev-object-literal-computed.js

@ -0,0 +1,68 @@
/*
* ES6 computed property name.
*/
/*===
{"3":"three","5":"five"}
three
five
toString 1
toString 2
{"tostring1":"value1","tostring2":"value2"}
undefined
value1
undefined
value2
{"[object Object]":"object","1,2,3,4":"array"}
URIError
===*/
function computedPropertyName() {
var res;
// Simple example.
try {
res = eval('({ [1+2]: "three", [2+3]: "five" })');
print(JSON.stringify(res));
print(res[3]);
print(res['5']);
} catch (e) {
print(e.stack || e);
}
// Expression values are ToPropertyKey() coerced in order. Before ES6
// Symbols that means ToString() in practice.
try {
res = eval('({ [ { valueOf: function () { print("valueOf 1"); return "valueof1"; }, toString: function () { print("toString 1"); return "tostring1"; } } ]: "value1", [ { valueOf: function () { print("valueOf 2"); return "valueof2"; }, toString: function () { print("toString 2"); return "tostring2"; } } ]: "value2" })');
print(JSON.stringify(res));
print(res.valueof1);
print(res.tostring1);
print(res.valueof2);
print(res.tostring2);
} catch (e) {
print(e.stack || e);
}
// If an object is used as the computed key, it coerces to the string
// '[object Object]'. An Array coerces to a comma joined list.
try {
res = eval('({ [{}]: "object", [[1,2,3,4]]: "array" })');
print(JSON.stringify(res));
} catch (e) {
print(e.stack || e);
}
// An error may be thrown.
try {
res = eval('({ [{}]: "object", [decodeURIComponent("%XX")]: "other" })');
print(JSON.stringify(res));
} catch (e) {
print(e.name);
}
}
try {
computedPropertyName();
} catch (e) {
print(e.stack || e);
}
Loading…
Cancel
Save