Merge pull request #794 from fabiosantoscode/feature/harmony-template-strings-2
Harmony: template strings
This commit is contained in:
28
lib/ast.js
28
lib/ast.js
@@ -501,6 +501,34 @@ var AST_Destructuring = DEFNODE("Destructuring", "names is_array", {
|
||||
}
|
||||
});
|
||||
|
||||
var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_string prefix", {
|
||||
$documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`",
|
||||
$propdoc: {
|
||||
template_string: "[AST_TemplateString] The template string",
|
||||
prefix: "[AST_SymbolRef|AST_PropAccess] The prefix, which can be a symbol such as `foo` or a dotted expression such as `String.raw`."
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
this.prefix._walk(visitor);
|
||||
this.template_string._walk(visitor);
|
||||
}
|
||||
})
|
||||
|
||||
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, {
|
||||
|
||||
@@ -776,6 +776,24 @@ function OutputStream(options) {
|
||||
self._do_print(output);
|
||||
});
|
||||
|
||||
DEFPRINT(AST_PrefixedTemplateString, function(self, output) {
|
||||
self.prefix.print(output);
|
||||
self.template_string.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();
|
||||
|
||||
47
lib/parse.js
47
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;
|
||||
@@ -804,6 +807,7 @@ function parse($TEXT, options) {
|
||||
});
|
||||
case "[":
|
||||
case "(":
|
||||
case "`":
|
||||
return simple_statement();
|
||||
case ";":
|
||||
next();
|
||||
@@ -1333,6 +1337,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();
|
||||
}
|
||||
@@ -1349,6 +1355,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)) {
|
||||
@@ -1639,6 +1677,13 @@ function parse($TEXT, options) {
|
||||
});
|
||||
return arrow_function(expr);
|
||||
}
|
||||
if ((expr instanceof AST_SymbolRef || expr instanceof AST_PropAccess) && is("punc", "`")) {
|
||||
return new AST_PrefixedTemplateString({
|
||||
start: start,
|
||||
prefix: expr,
|
||||
template_string: template_string()
|
||||
})
|
||||
}
|
||||
if (commas && is("punc", ",")) {
|
||||
next();
|
||||
return new AST_Seq({
|
||||
|
||||
@@ -46,6 +46,24 @@ 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}`}`;";
|
||||
}
|
||||
|
||||
template_string_prefixes: {
|
||||
input: {
|
||||
String.raw`foo`;
|
||||
foo `bar`;
|
||||
}
|
||||
expect_exact: "String.raw`foo`;foo`bar`;";
|
||||
}
|
||||
|
||||
destructuring_arguments: {
|
||||
input: {
|
||||
(function ( a ) { });
|
||||
|
||||
Reference in New Issue
Block a user