From f745ac75f1adbfc5dc4d1e4a8c365eb9463def01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Sat, 4 Jun 2022 11:23:16 +0100 Subject: [PATCH] fix parsing of nested template strings. Closes #1204 --- lib/ast.js | 9 +++++++++ lib/parse.js | 17 +++++++++-------- test/compress/template-string.js | 11 +++++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 625999990..f7de7040e 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -93,6 +93,7 @@ const set_tok_flag = (tok, flag, truth) => { const TOK_FLAG_NLB = 0b0001; const TOK_FLAG_QUOTE_SINGLE = 0b0010; const TOK_FLAG_QUOTE_EXISTS = 0b0100; +const TOK_FLAG_TEMPLATE_END = 0b1000; class AST_Token { constructor(type, value, line, col, pos, nlb, comments_before, comments_after, file) { @@ -128,6 +129,14 @@ class AST_Token { set_tok_flag(this, TOK_FLAG_QUOTE_SINGLE, quote_type === "'"); set_tok_flag(this, TOK_FLAG_QUOTE_EXISTS, !!quote_type); } + + get template_end() { + return has_tok_flag(this, TOK_FLAG_TEMPLATE_END); + } + + set template_end(new_template_end) { + set_tok_flag(this, TOK_FLAG_TEMPLATE_END, new_template_end); + } } var AST_Node = DEFNODE("Node", "start end", function AST_Node(props) { diff --git a/lib/parse.js b/lib/parse.js index c99016a08..b1c22fb4f 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -162,7 +162,7 @@ import { } from "./ast.js"; var LATEST_RAW = ""; // Only used for numbers and template strings -var LATEST_TEMPLATE_END = true; +var TEMPLATE_RAWS = new Map(); // Raw template strings var KEYWORDS = "break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with"; var KEYWORDS_ATOM = "false null true"; @@ -693,8 +693,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) { next(true, true); S.brace_counter++; tok = token(begin ? "template_head" : "template_substitution", content); - LATEST_RAW = raw; - LATEST_TEMPLATE_END = false; + TEMPLATE_RAWS.set(tok, raw); + tok.template_end = false; return tok; } @@ -710,8 +710,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) { } S.template_braces.pop(); tok = token(begin ? "template_head" : "template_substitution", content); - LATEST_RAW = raw; - LATEST_TEMPLATE_END = true; + TEMPLATE_RAWS.set(tok, raw); + tok.template_end = true; return tok; }); @@ -2367,19 +2367,19 @@ function parse($TEXT, options) { segments.push(new AST_TemplateSegment({ start: S.token, - raw: LATEST_RAW, + raw: TEMPLATE_RAWS.get(S.token), value: S.token.value, end: S.token })); - while (!LATEST_TEMPLATE_END) { + while (!S.token.template_end) { next(); handle_regexp(); segments.push(expression(true)); segments.push(new AST_TemplateSegment({ start: S.token, - raw: LATEST_RAW, + raw: TEMPLATE_RAWS.get(S.token), value: S.token.value, end: S.token })); @@ -3342,6 +3342,7 @@ function parse($TEXT, options) { } else { toplevel = new AST_Toplevel({ start: start, body: body, end: end }); } + TEMPLATE_RAWS = new Map(); return toplevel; })(); diff --git a/test/compress/template-string.js b/test/compress/template-string.js index 61e9079c1..61306b5a2 100644 --- a/test/compress/template-string.js +++ b/test/compress/template-string.js @@ -947,3 +947,14 @@ template_string_new_parens: { } expect_exact: "(new Thing)``;" } + +template_string_nested: { + input: { + console.log(`${`${2,0}`} ${1}`) + console.log(`${String.raw`${2,0}\n`} ${1}`) + } + expect_stdout: [ + "0 1", + "0\\n 1", + ] +}