F(prototype, "prototype") \
F(this, "this") \
F(throw_iterator_result_not_an_object, "ThrowIteratorResultNotAnObject") \
+ F(to_string, "ToString") \
F(use_asm, "use asm") \
F(use_strong, "use strong") \
F(use_strict, "use strict") \
if (!tag) {
// Build tree of BinaryOps to simplify code-generation
- Expression* expr = NULL;
+ Expression* expr = cooked_strings->at(0);
+ int i = 0;
+ while (i < expressions->length()) {
+ Expression* sub = expressions->at(i++);
+ Expression* cooked_str = cooked_strings->at(i);
+
+ // Let middle be ToString(sub).
+ ZoneList<Expression*>* args =
+ new (zone()) ZoneList<Expression*>(1, zone());
+ args->Add(sub, zone());
+ Expression* middle = factory()->NewCallRuntime(
+ ast_value_factory()->to_string_string(), NULL, args,
+ sub->position());
- if (expressions->length() == 0) {
- // Simple case: treat as string literal
- expr = cooked_strings->at(0);
- } else {
- int i;
- Expression* cooked_str = cooked_strings->at(0);
expr = factory()->NewBinaryOperation(
- Token::ADD, cooked_str, expressions->at(0), cooked_str->position());
- for (i = 1; i < expressions->length(); ++i) {
- cooked_str = cooked_strings->at(i);
- expr = factory()->NewBinaryOperation(
- Token::ADD, expr, factory()->NewBinaryOperation(
- Token::ADD, cooked_str, expressions->at(i),
- cooked_str->position()),
- cooked_str->position());
- }
- cooked_str = cooked_strings->at(i);
- expr = factory()->NewBinaryOperation(Token::ADD, expr, cooked_str,
- cooked_str->position());
+ Token::ADD, factory()->NewBinaryOperation(
+ Token::ADD, expr, middle, expr->position()),
+ cooked_str, sub->position());
}
return expr;
} else {
assertEquals("12345", String.raw(callSiteObj, arg(2), arg(4), arg(6)));
assertEquals(["length", "raw1", "arg2", "raw3", "arg4", "raw5"], order);
})();
+
+
+(function testStringRawToStringSubstitutionsOrder() {
+ var subs = [];
+ var log = [];
+ function stringify(toString) {
+ var valueOf = "_" + toString + "_";
+ return {
+ toString: function() { return toString; },
+ valueOf: function() { return valueOf; }
+ };
+ }
+ function getter(name, value) {
+ return {
+ get: function() {
+ log.push("get" + name);
+ return value;
+ },
+ set: function(v) {
+ log.push("set" + name);
+ }
+ };
+ }
+ Object.defineProperties(subs, {
+ 0: getter(0, stringify("a")),
+ 1: getter(1, stringify("b")),
+ 2: getter(2, stringify("c"))
+ });
+
+ assertEquals("-a-b-c-", String.raw`-${subs[0]}-${subs[1]}-${subs[2]}-`);
+ assertArrayEquals(["get0", "get1", "get2"], log);
+
+ log.length = 0;
+ assertEquals("-a-", String.raw`-${subs[0]}-`);
+ assertArrayEquals(["get0"], log);
+})();
"raw;test3"
], raw);
})();
+
+
+(function testToStringSubstitutions() {
+ var a = {
+ toString: function() { return "a"; },
+ valueOf: function() { return "-a-"; }
+ };
+ var b = {
+ toString: function() { return "b"; },
+ valueOf: function() { return "-b-"; }
+ };
+ assertEquals("a", `${a}`);
+ assertEquals("ab", `${a}${b}`);
+ assertEquals("-a--b-", `${a + b}`);
+ assertEquals("-a-", `${a + ""}`);
+ assertEquals("1a", `1${a}`);
+ assertEquals("1a2", `1${a}2`);
+ assertEquals("1a2b", `1${a}2${b}`);
+ assertEquals("1a2b3", `1${a}2${b}3`);
+})();
+
+
+(function testToStringSubstitutionsOrder() {
+ var subs = [];
+ var log = [];
+ function getter(name, value) {
+ return {
+ get: function() {
+ log.push("get" + name);
+ return value;
+ },
+ set: function(v) {
+ log.push("set" + name);
+ }
+ };
+ }
+ Object.defineProperties(subs, {
+ 0: getter(0, "a"),
+ 1: getter(1, "b"),
+ 2: getter(2, "c")
+ });
+
+ assertEquals("-a-b-c-", `-${subs[0]}-${subs[1]}-${subs[2]}-`);
+ assertArrayEquals(["get0", "get1", "get2"], log);
+})();
+
+
+(function testTaggedToStringSubstitutionsOrder() {
+ var subs = [];
+ var log = [];
+ var tagged = [];
+ function getter(name, value) {
+ return {
+ get: function() {
+ log.push("get" + name);
+ return value;
+ },
+ set: function(v) {
+ log.push("set" + name);
+ }
+ };
+ }
+ Object.defineProperties(subs, {
+ 0: getter(0, 1),
+ 1: getter(1, 2),
+ 2: getter(2, 3)
+ });
+
+ function tag(cs) {
+ var n_substitutions = arguments.length - 1;
+ var n_cooked = cs.length;
+ var e = cs[0];
+ var i = 0;
+ assertEquals(n_cooked, n_substitutions + 1);
+ while (i < n_substitutions) {
+ var sub = arguments[i++ + 1];
+ var tail = cs[i];
+ tagged.push(sub);
+ e = e.concat(sub, tail);
+ }
+ return e;
+ }
+
+ assertEquals("-1-2-3-", tag`-${subs[0]}-${subs[1]}-${subs[2]}-`);
+ assertArrayEquals(["get0", "get1", "get2"], log);
+ assertArrayEquals([1, 2, 3], tagged);
+
+ tagged.length = 0;
+ log.length = 0;
+ assertEquals("-1-", tag`-${subs[0]}-`);
+ assertArrayEquals(["get0"], log);
+ assertArrayEquals([1], tagged);
+})();