Implement tagged template literals (#3456)
Missing features: snapshot support JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function assertThrows(str, error) {
|
||||
try {
|
||||
eval(str);
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
if (typeof error === "function") {
|
||||
assert(e instanceof error);
|
||||
} else {
|
||||
assert(e === error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.ecma-international.org/ecma-262/6.0/#sec-string.raw 21.1.2.4
|
||||
// Note: the string error messages represents the nth step of the routine
|
||||
var abruptTests = [
|
||||
["undefined", TypeError], // 3.
|
||||
["{ get raw() { throw '5'; } }", '5'],
|
||||
["{ raw : undefined }", TypeError], // 5.toObject
|
||||
["{ raw : { get length() { throw '7.1'; } } }", '7.1'],
|
||||
["{ raw : { length : { toString() { throw '7.2'; } } } }", '7.2'],
|
||||
["{ raw : { length: 2, get '0'() { throw '12.b.1'} } }", '12.b.1'],
|
||||
["{ raw : { length: 2, '0' : { toString() { throw '12.b.2';} } } }", '12.b.2'],
|
||||
["{ raw : { length: 2, '0' : 1 } }, { toString() { throw '12.h';} }", '12.h'],
|
||||
];
|
||||
|
||||
abruptTests.forEach(e => {
|
||||
assertThrows("String.raw(" + e[0] + ")", e[1]);
|
||||
});
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw
|
||||
assert(String.raw`Hi\n${2+3}!` === 'Hi\\n5!');
|
||||
assert(String.raw`Hi\u000A!` === 'Hi\\u000A!');
|
||||
|
||||
let name = 'Bob';
|
||||
assert(String.raw`Hi\n${name}!` === "Hi\\nBob!");
|
||||
|
||||
let str = String.raw({
|
||||
raw: ['foo', 'bar', 'baz']
|
||||
}, 2 + 3, 'Java' + 'Script');
|
||||
assert(str === "foo5barJavaScriptbaz");
|
||||
|
||||
assert(String.raw({ raw: 'test' }, 0, 1, 2) === "t0e1s2t");
|
||||
@@ -24,7 +24,7 @@ var obj2 = {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
assert(+obj2 === 10);
|
||||
//assert(`${obj2}` === "hello"); //FIXME: template literals requires String hint during concatenation
|
||||
assert(`${obj2}` === "hello");
|
||||
assert(obj2 + '' === "true");
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
|
||||
// Tagged templates
|
||||
var person = 'Mike';
|
||||
var age = 28;
|
||||
|
||||
function myTag(strings, personExp, ageExp) {
|
||||
assert(strings[0] == "That ");
|
||||
assert(strings[1] == " is a ");
|
||||
var str0 = strings[0];
|
||||
var str1 = strings[1];
|
||||
|
||||
var ageStr;
|
||||
if (ageExp > 99){
|
||||
ageStr = 'centenarian';
|
||||
} else {
|
||||
ageStr = 'youngster';
|
||||
}
|
||||
|
||||
return `${str0}${personExp}${str1}${ageStr}`;
|
||||
}
|
||||
|
||||
var output = myTag`That ${ person } is a ${ age }`;
|
||||
assert(output === "That Mike is a youngster");
|
||||
|
||||
function template(strings, ...keys) {
|
||||
return (function(...values) {
|
||||
var dict = values[values.length - 1] || {};
|
||||
var result = [strings[0]];
|
||||
keys.forEach(function(key, i) {
|
||||
var value = Number.isInteger(key) ? values[key] : dict[key];
|
||||
result.push(value, strings[i + 1]);
|
||||
});
|
||||
return result.join('');
|
||||
});
|
||||
}
|
||||
|
||||
var t1Closure = template`${0}${1}${0}!`;
|
||||
assert(t1Closure('Y', 'A') === "YAY!");
|
||||
var t2Closure = template`${0} ${'foo'}!`;
|
||||
assert(t2Closure('Hello', {foo: 'World'}) === "Hello World!");
|
||||
|
||||
// Raw strings
|
||||
(function () {
|
||||
function tag(strings) {
|
||||
assert(strings.raw[0].length === 40);
|
||||
}
|
||||
|
||||
tag`string text line 1 \n string text line 2`;
|
||||
})();
|
||||
|
||||
assert (String.raw`Hi\n${2+3}!` === "Hi\\n5!");
|
||||
|
||||
(function () {
|
||||
function empty(strings, ...params) {
|
||||
assert(strings.length === 4);
|
||||
assert(strings.raw.length === 4);
|
||||
assert(params.length === 3);
|
||||
strings.forEach ((e) => assert (e === ""));
|
||||
strings.raw.forEach ((e) => assert (e === ""));
|
||||
params.forEach ((e) => assert (e === 1));
|
||||
}
|
||||
|
||||
empty`${1}${1}${1}`;
|
||||
})();
|
||||
|
||||
(function () {
|
||||
function f (str) {
|
||||
return str.raw[0].length;
|
||||
}
|
||||
assert (eval("f`a\u2029b`") === 3);
|
||||
})();
|
||||
|
||||
(function () {
|
||||
function testRaw(parts, a, b) {
|
||||
assert(parts instanceof Array);
|
||||
assert(parts.raw instanceof Array);
|
||||
assert(parts.length === 3);
|
||||
assert(parts[0] === "str");
|
||||
assert(parts[1] === "escaped\n");
|
||||
assert(parts[2] === "");
|
||||
assert(parts.raw.length === 3);
|
||||
assert(parts.raw[0] === "str");
|
||||
assert(parts.raw[1] === "escaped\\n");
|
||||
assert(parts.raw[2] === "");
|
||||
assert(a === 123);
|
||||
assert(b === 456);
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(testRaw `str${123}escaped\n${456}` === true);
|
||||
})();
|
||||
|
||||
// TemplateStrings call site caching
|
||||
(function () {
|
||||
let str = (arr) => arr;
|
||||
function getStr() {
|
||||
return str`foo`;
|
||||
}
|
||||
var chainedCall = getStr();
|
||||
var localCall = str`foo`;
|
||||
assert(chainedCall === getStr() && chainedCall !== localCall);
|
||||
})();
|
||||
|
||||
// TemplateStrings permanent caching
|
||||
(function () {
|
||||
let str = (arr) => arr;
|
||||
function getStr() {
|
||||
return str`foo`;
|
||||
}
|
||||
var chainedCall = getStr();
|
||||
var localNew = new getStr();
|
||||
assert(chainedCall === getStr() && chainedCall === localNew);
|
||||
})();
|
||||
@@ -41,9 +41,9 @@ switch (1)
|
||||
{
|
||||
default:
|
||||
|
||||
``
|
||||
`abc`
|
||||
`ab${a+b}${ `x` }c`
|
||||
``;
|
||||
`abc`;
|
||||
`ab${a+b}${ `x` }c`;
|
||||
|
||||
assert (`` === '');
|
||||
assert (`abc` === 'abc');
|
||||
@@ -90,3 +90,15 @@ must_throw ("`${}`");
|
||||
must_throw ("`${1}");
|
||||
must_throw ("`${1}.${");
|
||||
must_throw ("`${1}.${2}");
|
||||
|
||||
// line break normalization
|
||||
var cr = eval("`a" + String.fromCharCode(13) + "b`");
|
||||
var lf = eval("`a" + String.fromCharCode(10) + "b`");
|
||||
var crlf = eval("`a" + String.fromCharCode(13,10) + "b`");
|
||||
|
||||
assert(cr.length === 3);
|
||||
assert(lf.length === 3);
|
||||
assert(crlf.length === 3);
|
||||
assert(cr[1] === lf[1]);
|
||||
assert(lf[1] === crlf[1]);
|
||||
assert(crlf[1] === '\n');
|
||||
|
||||
@@ -223,7 +223,7 @@ main (void)
|
||||
/* Check the snapshot data. Unused bytes should be filled with zeroes */
|
||||
const uint8_t expected_data[] =
|
||||
{
|
||||
0x4A, 0x52, 0x52, 0x59, 0x22, 0x00, 0x00, 0x00,
|
||||
0x4A, 0x52, 0x52, 0x59, 0x23, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00,
|
||||
|
||||
Reference in New Issue
Block a user