1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
import { ParserState, Context } from '../common';
import { Token } from '../token';
import { Chars } from '../chars';
import { advanceChar, fromCodePoint } from './common';
import { parseEscape, Escape, handleStringError } from './string';
import { report, Errors } from '../errors';
/**
* Scan a template section. It can start either from the quote or closing brace.
*/
export function scanTemplate(parser: ParserState, context: Context): Token {
const { index: start } = parser;
let token: Token = Token.TemplateSpan;
let ret: string | void = '';
let char = advanceChar(parser);
while (char !== Chars.Backtick) {
if (char === Chars.Dollar && parser.source.charCodeAt(parser.index + 1) === Chars.LeftBrace) {
advanceChar(parser); // Skip: '}'
token = Token.TemplateContinuation;
break;
} else if ((char & 8) === 8 && char === Chars.Backslash) {
char = advanceChar(parser);
if (char > 0x7e) {
ret += fromCodePoint(char);
} else {
const code = parseEscape(parser, context | Context.Strict, char);
if (code >= 0) {
ret += fromCodePoint(code);
} else if (code !== Escape.Empty && context & Context.TaggedTemplate) {
ret = undefined;
char = scanBadTemplate(parser, char);
if (char < 0) token = Token.TemplateContinuation;
break;
} else {
handleStringError(parser, code as Escape, /* isTemplate */ 1);
}
}
} else {
if (
parser.index < parser.end &&
char === Chars.CarriageReturn &&
parser.source.charCodeAt(parser.index) === Chars.LineFeed
) {
ret += fromCodePoint(char);
parser.currentChar = parser.source.charCodeAt(++parser.index);
}
if (((char & 83) < 3 && char === Chars.LineFeed) || (char ^ Chars.LineSeparator) <= 1) {
parser.column = -1;
parser.line++;
}
ret += fromCodePoint(char);
}
if (parser.index >= parser.end) report(parser, Errors.UnterminatedTemplate);
char = advanceChar(parser);
}
advanceChar(parser); // Consume the quote or opening brace
parser.tokenValue = ret;
parser.tokenRaw = parser.source.slice(start + 1, parser.index - (token === Token.TemplateSpan ? 1 : 2));
return token;
}
/**
* Scans looser template segment
*
* @param parser Parser state
* @param ch Code point
*/
function scanBadTemplate(parser: ParserState, ch: number): number {
while (ch !== Chars.Backtick) {
switch (ch) {
case Chars.Dollar: {
const index = parser.index + 1;
if (index < parser.end && parser.source.charCodeAt(index) === Chars.LeftBrace) {
parser.index = index;
parser.column++;
return -ch;
}
break;
}
case Chars.LineFeed:
case Chars.LineSeparator:
case Chars.ParagraphSeparator:
parser.column = -1;
parser.line++;
// falls through
default:
// do nothing
}
if (parser.index >= parser.end) report(parser, Errors.UnterminatedTemplate);
ch = advanceChar(parser);
}
return ch;
}
export function scanTemplateTail(parser: ParserState, context: Context): Token {
if (parser.index >= parser.end) report(parser, Errors.Unexpected);
parser.index--;
parser.column--;
return scanTemplate(parser, context);
}
|