From e1cb1a0e3ca2312fd403d10fee5960691287a436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Sat, 5 Sep 2015 22:32:57 +0100 Subject: [PATCH] Parse and output ES6 template strings. Yikes! --- lib/ast.js | 16 ++++++++++++++++ lib/output.js | 14 ++++++++++++++ lib/parse.js | 40 +++++++++++++++++++++++++++++++++++++++- test/compress/harmony.js | 10 ++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/lib/ast.js b/lib/ast.js index 7e7503ee..13260582 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -501,6 +501,22 @@ var AST_Destructuring = DEFNODE("Destructuring", "names is_array", { } }); +var AST_TemplateString = DEFNODE("TemplateString", "segments", { + $documentation: "A template string literal", + $propdoc: { + segments: "[string|AST_Expression]* One or more segments. They can be the parts that are evaluated, or the raw string parts." + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.segments.forEach(function(seg, i){ + if (i % 2 !== 0) { + seg._walk(visitor); + } + }); + }); + } +}); + /* -----[ JUMPS ]----- */ var AST_Jump = DEFNODE("Jump", null, { diff --git a/lib/output.js b/lib/output.js index 5d8bef10..c6cb254e 100644 --- a/lib/output.js +++ b/lib/output.js @@ -776,6 +776,20 @@ function OutputStream(options) { self._do_print(output); }); + DEFPRINT(AST_TemplateString, function(self, output) { + output.print("`"); + for (var i = 0; i < self.segments.length; i++) { + if (typeof self.segments[i] !== "string") { + output.print("${"); + self.segments[i].print(output); + output.print("}"); + } else { + output.print(self.segments[i]); + } + } + output.print("`"); + }); + AST_Arrow.DEFMETHOD("_do_print", function(output){ var self = this; var parent = output.parent(); diff --git a/lib/parse.js b/lib/parse.js index 3d3eb664..00ba3f55 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -114,7 +114,7 @@ var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u18 var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:")); -var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); +var PUNC_CHARS = makePredicate(characters("[]{}(),;:`")); var REGEXP_MODIFIERS = makePredicate(characters("gmsiy")); @@ -595,6 +595,9 @@ function tokenizer($TEXT, filename, html5_comments) { parse_error("Unexpected character '" + ch + "'"); }; + next_token.next = next; + next_token.peek = peek; + next_token.context = function(nc) { if (nc) S = nc; return S; @@ -805,6 +808,7 @@ function parse($TEXT, options) { }); case "[": case "(": + case "`": return simple_statement(); case ";": next(); @@ -1336,6 +1340,8 @@ function parse($TEXT, options) { return subscripts(array_(), allow_calls); case "{": return subscripts(object_or_object_destructuring_(), allow_calls); + case "`": + return subscripts(template_string(), allow_calls); } unexpected(); } @@ -1352,6 +1358,38 @@ function parse($TEXT, options) { unexpected(); }; + function template_string() { + var tokenizer_S = S.input, start = S.token, segments = [], segment = "", ch; + + while ((ch = tokenizer_S.next()) !== "`") { + if (ch === "$" && tokenizer_S.peek() === "{") { + segments.push(segment); segment = ""; + tokenizer_S.next(); + next(); + segments.push(expression()); + expect("}"); + if (is("punc", "`")) { + break; + } + continue; + } + segment += ch; + if (ch === "\\") { + segment += tokenizer_S.next(); + } + } + + segments.push(segment); + + next(); + + return new AST_TemplateString({ + start: start, + segments: segments, + end: S.token + }); + } + function expr_list(closing, allow_trailing_comma, allow_empty) { var first = true, a = []; while (!is("punc", closing)) { diff --git a/test/compress/harmony.js b/test/compress/harmony.js index 2fcfd70f..f55c9868 100644 --- a/test/compress/harmony.js +++ b/test/compress/harmony.js @@ -46,6 +46,16 @@ typeof_arrow_functions: { expect_exact: "\"function\";" } +template_strings: { + input: { + ``; + `xx\`x`; + `${ foo + 2 }`; + ` foo ${ bar + `baz ${ qux }` }`; + } + expect_exact: "``;`xx\\`x`;`${foo+2}`;` foo ${bar+`baz ${qux}`}`;"; +} + destructuring_arguments: { input: { (function ( a ) { });