if (depth == 0) {
if (s->token.u.str.sep == '`')
goto done1;
- emit_op(s, OP_get_field2);
- emit_atom(s, JS_ATOM_concat);
+ } else {
+ emit_op(s, OP_add);
}
depth++;
} else {
return -1;
if (js_parse_expr(s))
return -1;
+ /* XXX: should instead add OP_to_string and OP_concat so that
+ all the strings can be concatenated at the end (faster) */
+ if (!call) {
+ /* ToString right away, before the next substitution is evaluated
+ (ECMA-262 13.2.8.6). OP_to_propkey keeps a symbol, which
+ OP_add then rejects, as ToString does. */
+ emit_op(s, OP_to_propkey);
+ emit_op(s, OP_add);
+ }
depth++;
if (s->token.val != '}') {
return js_parse_error(s, "expected '}' after template expression");
}
- /* XXX: should convert to string at this stage? */
free_token(s, &s->token);
/* Resume TOK_TEMPLATE parsing (s->token.line_num and
* s->token.ptr are OK) */
seal_template_obj(ctx, raw_array);
seal_template_obj(ctx, template_object);
*argc = depth + 1;
- } else {
- emit_op(s, OP_call_method);
- emit_u16(s, depth - 1);
}
done1:
return next_token(s);
assert(b, "BaraBarbaz");
}
+function test_template_tostring_order()
+{
+ /* each substitution is converted with ToString right after it is
+ evaluated (ECMA-262 13.2.8.6), and String.prototype.concat is not
+ involved */
+ var log = [];
+ var o = { toString() { log.push("o"); return "O"; } };
+ assert(`${o}${(log.push("next"), "n")}`, "On");
+ assert(log.join(), "o,next");
+
+ var c = { n: 0, toString() { return "" + this.n; } };
+ assert(`${c} ${c.n++}`, "0 0");
+
+ var d = new Date(2024, 0, 15, 12);
+ assert(`${d}|${d.setFullYear(2000)}`.indexOf("2024"), 11);
+
+ var p = { [Symbol.toPrimitive](hint) { return hint; } };
+ assert(`${p}`, "string");
+ var v = { valueOf() { return 1; }, toString() { return "s"; } };
+ assert(`${v}`, "s");
+
+ var concat = String.prototype.concat;
+ String.prototype.concat = function() { return "concat"; };
+ try {
+ assert(`a${1}b${2}`, "a1b2");
+ } finally {
+ String.prototype.concat = concat;
+ }
+
+ assert_throws(TypeError, () => `${Symbol()}`);
+}
+
function test_object_literal()
{
var x = 0, get = 1, set = 2, async = 3;
test_class();
test_template();
test_template_skip();
+test_template_tostring_order();
test_object_literal();
test_regexp_skip();
test_labels();