Skip to content

Commit e8085ac

Browse files
author
Jenn Kaplan
committed
Added support and tests for ES6 Template Strings
1 parent 9f64546 commit e8085ac

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

lib/complexion-js.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,105 @@
11811181
};
11821182
}
11831183

1184+
/**
1185+
* Matches a template string
1186+
*
1187+
* @return {Complexion~matcher}
1188+
*/
1189+
function matchTemplateString() {
1190+
function movePastEscape(str, offset) {
1191+
var c;
1192+
1193+
c = str.charAt(offset);
1194+
1195+
// You can't escape a line terminator
1196+
if (isLineTerminator(c)) {
1197+
return 0;
1198+
}
1199+
1200+
if (c >= '4' && c <= '7') {
1201+
// Octal numbers that can only be two digits
1202+
c = str.charAt(offset + 1);
1203+
1204+
if (c >= '0' && c <= '7') {
1205+
return 2;
1206+
}
1207+
} else if (c >= '0' && c <= '3') {
1208+
// Octal numbers that can be three digits
1209+
c = str.charAt(offset + 1);
1210+
1211+
if (c >= '0' && c <= '7') {
1212+
c = str.charAt(offset + 2);
1213+
1214+
if (c >= '0' && c <= '7') {
1215+
return 3;
1216+
}
1217+
1218+
return 2;
1219+
}
1220+
} else if (c === 'x') {
1221+
// Hex
1222+
if (isHex(str.charAt(offset + 1)) && isHex(str.charAt(offset + 2))) {
1223+
return 3;
1224+
}
1225+
} else if (c === 'u') {
1226+
// Unicode
1227+
if (isHex(str.charAt(offset + 1)) && isHex(str.charAt(offset + 2)) && isHex(str.charAt(offset + 3)) && isHex(str.charAt(offset + 4))) {
1228+
return 5;
1229+
}
1230+
}
1231+
1232+
// We are just escaping a single character
1233+
return 1;
1234+
}
1235+
1236+
return function (str, offset) {
1237+
var c, checkId, inId, len, quote;
1238+
1239+
inId = false;
1240+
checkId = false;
1241+
quote = str.charAt(offset);
1242+
1243+
// It must start with single or double quotes
1244+
if (quote !== '`') {
1245+
return null;
1246+
}
1247+
1248+
len = 1;
1249+
c = str.charAt(offset + len);
1250+
1251+
// Strings must not contain CR, LF, LS, nor PS
1252+
while (c && c !== quote && !isLineTerminator(c)) {
1253+
len += 1;
1254+
1255+
if (c === "\\") {
1256+
len += movePastEscape(str, offset + len);
1257+
}
1258+
1259+
if (checkId && c === "{") {
1260+
checkId = false;
1261+
inId = true;
1262+
}
1263+
1264+
if (inId && c === '}') {
1265+
inId = false;
1266+
}
1267+
1268+
if (c === "$") {
1269+
checkId = true;
1270+
}
1271+
1272+
c = str.charAt(offset + len);
1273+
}
1274+
1275+
if (c !== quote || inId) {
1276+
return null;
1277+
}
1278+
1279+
return str.substr(offset, len + 1);
1280+
};
1281+
}
1282+
11841283

11851284
/**
11861285
* Matches any character
@@ -1328,6 +1427,7 @@
13281427
add('LINE_TERMINATOR', matchLineTerminator); // Can set implicitSemicolonFlag
13291428
add('KEYWORD', matchKeyword); // Uses keywordFromIdentifierName
13301429
add('STRING_LITERAL', matchStringLiteral);
1430+
add('TEMPLATE_STRING', matchTemplateString);
13311431
add('SINGLE_LINE_COMMENT', matchSingleLineComment);
13321432
add('BOOLEAN_LITERAL', matchBooleanLiteral); // Uses keywordFromIdentifierName
13331433
add('NULL_LITERAL', matchNullLiteral); // Uses keywordFromIdentifierName

tests/complexion-js.spec.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,39 @@
401401
});
402402
});
403403
});
404+
describe('TEMPLATE_STRING', function () {
405+
[
406+
'``', // Empty
407+
"`\\r\\n`", // Properly escaped newlines in single quotes
408+
"`\\0`", // NULL
409+
"`\\xfF\\u0123\\12\\012\\321`", // Escaped characters
410+
"`random string \\a\\b\\c\\d\\e`", // Letters that do not need escaping
411+
"`${id}`", // Properly closed identifier
412+
"`{literal}`", // Curly braces with no $
413+
"`{literal`" // Curly braces with no $
414+
].forEach(function (str) {
415+
it('matches a valid template string: ' + JSON.stringify(str), function () {
416+
var result;
417+
418+
result = tokenize(str + 'xyz');
419+
expect(result[0]).toEqual('TEMPLATE_STRING:' + str);
420+
});
421+
});
422+
[
423+
"`\n`", // Must not have a newline
424+
"`", // Must be closed
425+
"\"`", // Must be properly closed
426+
"`\\\n`", // Can not escape a newline character,
427+
"`${id`" // Unclosed identifier
428+
].forEach(function (str) {
429+
it('does not match an invalid string: ' + JSON.stringify(str), function () {
430+
var result;
431+
432+
result = tokenize(str + 'xyz');
433+
expect(result[0]).toEqual('UNKNOWN:' + str.charAt(0));
434+
});
435+
});
436+
});
404437
describe('UNKNOWN', function () {
405438
it('matches odd characters', function () {
406439
// Start with a hash but not a shebang.

0 commit comments

Comments
 (0)