Run dartfmt on js_ast

BUG=
R=sra@google.com

Review-Url: https://codereview.chromium.org/2748103010 .
This commit is contained in:
Jacob Richman 2017-03-15 21:22:40 -07:00
parent 33717e010a
commit 11950984e4
7 changed files with 498 additions and 428 deletions

View file

@ -7,7 +7,6 @@
part of js_ast;
/**
* Global template manager. We should aim to have a fixed number of
* templates. This implies that we do not use js('xxx') to parse text that is
@ -18,7 +17,6 @@ part of js_ast;
*/
TemplateManager templateManager = new TemplateManager();
/**
[js] is a singleton instace of JsBuilder. JsBuilder is a set of conveniences
@ -187,7 +185,6 @@ What is not implemented:
*/
const JsBuilder js = const JsBuilder();
class JsBuilder {
const JsBuilder();
@ -271,8 +268,8 @@ class JsBuilder {
Template uncachedExpressionTemplate(String source) {
MiniJsParser parser = new MiniJsParser(source);
Expression expression = parser.expression();
return new Template(
source, expression, isExpression: true, forceCopy: false);
return new Template(source, expression,
isExpression: true, forceCopy: false);
}
/**
@ -281,8 +278,8 @@ class JsBuilder {
Template uncachedStatementTemplate(String source) {
MiniJsParser parser = new MiniJsParser(source);
Statement statement = parser.statement();
return new Template(
source, statement, isExpression: false, forceCopy: false);
return new Template(source, statement,
isExpression: false, forceCopy: false);
}
/**
@ -300,19 +297,26 @@ class JsBuilder {
/// Creates a literal js string from [value].
LiteralString _legacyEscapedString(String value) {
// Start by escaping the backslashes.
// Start by escaping the backslashes.
String escaped = value.replaceAll('\\', '\\\\');
// Do not escape unicode characters and ' because they are allowed in the
// string literal anyway.
escaped = escaped.replaceAllMapped(new RegExp('\n|"|\b|\t|\v|\r'), (match) {
switch (match.group(0)) {
case "\n" : return r"\n";
case "\"" : return r'\"';
case "\b" : return r"\b";
case "\t" : return r"\t";
case "\f" : return r"\f";
case "\r" : return r"\r";
case "\v" : return r"\v";
case "\n":
return r"\n";
case "\"":
return r'\"';
case "\b":
return r"\b";
case "\t":
return r"\t";
case "\f":
return r"\f";
case "\r":
return r"\r";
case "\v":
return r"\v";
}
});
LiteralString result = string(escaped);
@ -324,7 +328,7 @@ class JsBuilder {
/// Creates a literal js string from [value].
LiteralString escapedString(String value,
{bool utf8: false, bool ascii: false}) {
{bool utf8: false, bool ascii: false}) {
if (utf8 == false && ascii == false) return _legacyEscapedString(value);
if (utf8 && ascii) throw new ArgumentError('Cannot be both UTF8 and ASCII');
@ -340,12 +344,16 @@ class JsBuilder {
++singleQuotes;
} else if (rune == charCodes.$DQ) {
++doubleQuotes;
} else if (rune == charCodes.$LF || rune == charCodes.$CR ||
rune == charCodes.$LS || rune == charCodes.$PS) {
} else if (rune == charCodes.$LF ||
rune == charCodes.$CR ||
rune == charCodes.$LS ||
rune == charCodes.$PS) {
// Line terminators.
++otherEscapes;
} else if (rune == charCodes.$BS || rune == charCodes.$TAB ||
rune == charCodes.$VTAB || rune == charCodes.$FF) {
} else if (rune == charCodes.$BS ||
rune == charCodes.$TAB ||
rune == charCodes.$VTAB ||
rune == charCodes.$FF) {
++otherEscapes;
} else if (_isUnpairedSurrogate(rune)) {
++unpairedSurrogates;
@ -408,15 +416,24 @@ class JsBuilder {
static String _irregularEscape(int code, bool useSingleQuotes) {
switch (code) {
case charCodes.$SQ: return useSingleQuotes ? r"\'" : r"'";
case charCodes.$DQ: return useSingleQuotes ? r'"' : r'\"';
case charCodes.$BACKSLASH: return r'\\';
case charCodes.$BS: return r'\b';
case charCodes.$TAB: return r'\t';
case charCodes.$LF: return r'\n';
case charCodes.$VTAB: return r'\v';
case charCodes.$FF: return r'\f';
case charCodes.$CR: return r'\r';
case charCodes.$SQ:
return useSingleQuotes ? r"\'" : r"'";
case charCodes.$DQ:
return useSingleQuotes ? r'"' : r'\"';
case charCodes.$BACKSLASH:
return r'\\';
case charCodes.$BS:
return r'\b';
case charCodes.$TAB:
return r'\t';
case charCodes.$LF:
return r'\n';
case charCodes.$VTAB:
return r'\v';
case charCodes.$FF:
return r'\f';
case charCodes.$CR:
return r'\r';
}
return null;
}
@ -435,13 +452,13 @@ class JsBuilder {
LiteralString stringPart(String value) => new LiteralString(value);
StringConcatenation concatenateStrings(Iterable<Literal> parts,
{addQuotes: false}) {
{addQuotes: false}) {
List<Literal> _parts;
if (addQuotes) {
Literal quote = stringPart('"');
_parts = <Literal>[quote]
..addAll(parts)
..add(quote);
..addAll(parts)
..add(quote);
} else {
_parts = new List.from(parts, growable: false);
}
@ -472,9 +489,8 @@ class JsBuilder {
Comment comment(String text) => new Comment(text);
Call propertyCall(Expression receiver,
Expression fieldName,
List<Expression> arguments) {
Call propertyCall(
Expression receiver, Expression fieldName, List<Expression> arguments) {
return new Call(new PropertyAccess(receiver, fieldName), arguments);
}
@ -491,29 +507,31 @@ LiteralString string(String value) => js.string(value);
LiteralString quoteName(Name name, {allowNull: false}) {
return js.quoteName(name, allowNull: allowNull);
}
LiteralString stringPart(String value) => js.stringPart(value);
Iterable<Literal> joinLiterals(Iterable<Literal> list, Literal separator) {
return js.joinLiterals(list, separator);
}
StringConcatenation concatenateStrings(Iterable<Literal> parts,
{addQuotes: false}) {
{addQuotes: false}) {
return js.concatenateStrings(parts, addQuotes: addQuotes);
}
LiteralNumber number(num value) => js.number(value);
ArrayInitializer numArray(Iterable<int> list) => js.numArray(list);
ArrayInitializer stringArray(Iterable<String> list) => js.stringArray(list);
Call propertyCall(Expression receiver,
Expression fieldName,
List<Expression> arguments) {
Call propertyCall(
Expression receiver, Expression fieldName, List<Expression> arguments) {
return js.propertyCall(receiver, fieldName, arguments);
}
ObjectInitializer objectLiteral(Map<String, Expression> map) {
return js.objectLiteral(map);
}
class MiniJsParserError {
MiniJsParserError(this.parser, this.message) { }
MiniJsParserError(this.parser, this.message) {}
final MiniJsParser parser;
final String message;
@ -575,7 +593,7 @@ class MiniJsParser {
String lastToken = null;
int lastPosition = 0;
int position = 0;
bool skippedNewline = false; // skipped newline in last getToken?
bool skippedNewline = false; // skipped newline in last getToken?
final String src;
final List<InterpolatedNode> interpolatedValues = <InterpolatedNode>[];
@ -610,49 +628,70 @@ class MiniJsParser {
static String categoryToString(int cat) {
switch (cat) {
case NONE: return "NONE";
case ALPHA: return "ALPHA";
case NUMERIC: return "NUMERIC";
case SYMBOL: return "SYMBOL";
case ASSIGNMENT: return "ASSIGNMENT";
case DOT: return "DOT";
case LPAREN: return "LPAREN";
case RPAREN: return "RPAREN";
case LBRACE: return "LBRACE";
case RBRACE: return "RBRACE";
case LSQUARE: return "LSQUARE";
case RSQUARE: return "RSQUARE";
case STRING: return "STRING";
case COMMA: return "COMMA";
case QUERY: return "QUERY";
case COLON: return "COLON";
case SEMICOLON: return "SEMICOLON";
case HASH: return "HASH";
case WHITESPACE: return "WHITESPACE";
case OTHER: return "OTHER";
case NONE:
return "NONE";
case ALPHA:
return "ALPHA";
case NUMERIC:
return "NUMERIC";
case SYMBOL:
return "SYMBOL";
case ASSIGNMENT:
return "ASSIGNMENT";
case DOT:
return "DOT";
case LPAREN:
return "LPAREN";
case RPAREN:
return "RPAREN";
case LBRACE:
return "LBRACE";
case RBRACE:
return "RBRACE";
case LSQUARE:
return "LSQUARE";
case RSQUARE:
return "RSQUARE";
case STRING:
return "STRING";
case COMMA:
return "COMMA";
case QUERY:
return "QUERY";
case COLON:
return "COLON";
case SEMICOLON:
return "SEMICOLON";
case HASH:
return "HASH";
case WHITESPACE:
return "WHITESPACE";
case OTHER:
return "OTHER";
}
return "Unknown: $cat";
}
static const CATEGORIES = const <int>[
OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 0-7
OTHER, WHITESPACE, WHITESPACE, OTHER, OTHER, WHITESPACE, // 8-13
OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 14-21
OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 22-29
OTHER, OTHER, WHITESPACE, // 30-32
SYMBOL, OTHER, HASH, ALPHA, SYMBOL, SYMBOL, OTHER, // !"#$%&´
LPAREN, RPAREN, SYMBOL, SYMBOL, COMMA, SYMBOL, DOT, SYMBOL, // ()*+,-./
NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, // 01234
NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, // 56789
COLON, SEMICOLON, SYMBOL, SYMBOL, SYMBOL, QUERY, OTHER, // :;<=>?@
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // ABCDEFGH
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // IJKLMNOP
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // QRSTUVWX
ALPHA, ALPHA, LSQUARE, OTHER, RSQUARE, SYMBOL, ALPHA, OTHER, // YZ[\]^_'
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // abcdefgh
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // ijklmnop
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // qrstuvwx
ALPHA, ALPHA, LBRACE, SYMBOL, RBRACE, SYMBOL]; // yz{|}~
OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 0-7
OTHER, WHITESPACE, WHITESPACE, OTHER, OTHER, WHITESPACE, // 8-13
OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 14-21
OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 22-29
OTHER, OTHER, WHITESPACE, // 30-32
SYMBOL, OTHER, HASH, ALPHA, SYMBOL, SYMBOL, OTHER, // !"#$%&´
LPAREN, RPAREN, SYMBOL, SYMBOL, COMMA, SYMBOL, DOT, SYMBOL, // ()*+,-./
NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, // 01234
NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, // 56789
COLON, SEMICOLON, SYMBOL, SYMBOL, SYMBOL, QUERY, OTHER, // :;<=>?@
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // ABCDEFGH
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // IJKLMNOP
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // QRSTUVWX
ALPHA, ALPHA, LSQUARE, OTHER, RSQUARE, SYMBOL, ALPHA, OTHER, // YZ[\]^_'
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // abcdefgh
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // ijklmnop
ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // qrstuvwx
ALPHA, ALPHA, LBRACE, SYMBOL, RBRACE, SYMBOL
]; // yz{|}~
// This must be a >= the highest precedence number handled by parseBinary.
static var HIGHEST_PARSE_BINARY_PRECEDENCE = 16;
@ -660,22 +699,54 @@ class MiniJsParser {
// From https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Operator_Precedence
static final BINARY_PRECEDENCE = {
'+=': 17, '-=': 17, '*=': 17, '/=': 17, '%=': 17, '^=': 17, '|=': 17,
'&=': 17, '<<=': 17, '>>=': 17, '>>>=': 17, '=': 17,
'||': 14,
'&&': 13,
'|': 12,
'^': 11,
'&': 10,
'!=': 9, '==': 9, '!==': 9, '===': 9,
'<': 8, '<=': 8, '>=': 8, '>': 8, 'in': 8, 'instanceof': 8,
'<<': 7, '>>': 7, '>>>': 7,
'+': 6, '-': 6,
'*': 5, '/': 5, '%': 5
'+=': 17,
'-=': 17,
'*=': 17,
'/=': 17,
'%=': 17,
'^=': 17,
'|=': 17,
'&=': 17,
'<<=': 17,
'>>=': 17,
'>>>=': 17,
'=': 17,
'||': 14,
'&&': 13,
'|': 12,
'^': 11,
'&': 10,
'!=': 9,
'==': 9,
'!==': 9,
'===': 9,
'<': 8,
'<=': 8,
'>=': 8,
'>': 8,
'in': 8,
'instanceof': 8,
'<<': 7,
'>>': 7,
'>>>': 7,
'+': 6,
'-': 6,
'*': 5,
'/': 5,
'%': 5
};
static final UNARY_OPERATORS =
['++', '--', '+', '-', '~', '!', 'typeof', 'void', 'delete', 'await']
.toSet();
static final UNARY_OPERATORS = [
'++',
'--',
'+',
'-',
'~',
'!',
'typeof',
'void',
'delete',
'await'
].toSet();
static final OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS =
['typeof', 'void', 'delete', 'in', 'instanceof', 'await'].toSet();
@ -697,8 +768,10 @@ class MiniJsParser {
if (currentCode == charCodes.$BACKSLASH) {
if (++position >= src.length) error("Unterminated literal");
int escaped = src.codeUnitAt(position);
if (escaped == charCodes.$x || escaped == charCodes.$X ||
escaped == charCodes.$u || escaped == charCodes.$U ||
if (escaped == charCodes.$x ||
escaped == charCodes.$X ||
escaped == charCodes.$u ||
escaped == charCodes.$U ||
category(escaped) == NUMERIC) {
error('Numeric and hex escapes are not allowed in literals');
}
@ -714,8 +787,7 @@ class MiniJsParser {
if (position >= src.length) break;
int code = src.codeUnitAt(position);
// Skip '//' and '/*' style comments.
if (code == charCodes.$SLASH &&
position + 1 < src.length) {
if (code == charCodes.$SLASH && position + 1 < src.length) {
if (src.codeUnitAt(position + 1) == charCodes.$SLASH) {
int nextPosition = src.indexOf('\n', position);
if (nextPosition == -1) nextPosition = src.length;
@ -746,8 +818,8 @@ class MiniJsParser {
lastCategory = STRING;
lastToken = getDelimited(position);
} else if (code == charCodes.$0 &&
position + 2 < src.length &&
src.codeUnitAt(position + 1) == charCodes.$x) {
position + 2 < src.length &&
src.codeUnitAt(position + 1) == charCodes.$x) {
// Hex literal.
for (position += 2; position < src.length; position++) {
int cat = category(src.codeUnitAt(position));
@ -777,16 +849,15 @@ class MiniJsParser {
// Special code to disallow !, ~ and / in non-first position in token,
// so that !! and ~~ parse as two tokens and != parses as one, while =/
// parses as a an equals token followed by a regexp literal start.
newCat =
(code == charCodes.$BANG ||
code == charCodes.$SLASH ||
code == charCodes.$TILDE)
newCat = (code == charCodes.$BANG ||
code == charCodes.$SLASH ||
code == charCodes.$TILDE)
? NONE
: category(code);
} while (!singleCharCategory(cat) &&
(cat == newCat ||
(cat == ALPHA && newCat == NUMERIC) || // eg. level42.
(cat == NUMERIC && newCat == DOT))); // eg. 3.1415
(cat == newCat ||
(cat == ALPHA && newCat == NUMERIC) || // eg. level42.
(cat == NUMERIC && newCat == DOT))); // eg. 3.1415
lastCategory = cat;
lastToken = src.substring(lastPosition, position);
if (cat == NUMERIC) {
@ -829,7 +900,7 @@ class MiniJsParser {
// Accept semicolon or automatically inserted semicolon before close brace.
// Miniparser forbids other kinds of semicolon insertion.
if (RBRACE == lastCategory) return true;
if (NONE == lastCategory) return true; // end of input
if (NONE == lastCategory) return true; // end of input
if (skippedNewline) {
error('No automatic semicolon insertion at preceding newline');
}
@ -984,7 +1055,8 @@ class MiniJsParser {
propertyName = new LiteralString('"$identifier"');
} else if (acceptCategory(STRING)) {
propertyName = new LiteralString(identifier);
} else if (acceptCategory(SYMBOL)) { // e.g. void
} else if (acceptCategory(SYMBOL)) {
// e.g. void
propertyName = new LiteralString('"$identifier"');
} else if (acceptCategory(HASH)) {
var nameOrPosition = parseHash();
@ -1034,9 +1106,9 @@ class MiniJsParser {
expectCategory(COMMA);
}
}
receiver = constructor ?
new New(receiver, arguments) :
new Call(receiver, arguments);
receiver = constructor
? new New(receiver, arguments)
: new Call(receiver, arguments);
constructor = false;
} else if (!constructor && acceptCategory(LSQUARE)) {
Expression inBraces = parseExpression();
@ -1091,7 +1163,8 @@ class MiniJsParser {
Expression parseUnaryHigh() {
String operator = lastToken;
if (lastCategory == SYMBOL && UNARY_OPERATORS.contains(operator) &&
if (lastCategory == SYMBOL &&
UNARY_OPERATORS.contains(operator) &&
(acceptString("++") || acceptString("--") || acceptString('await'))) {
if (operator == "await") return new Await(parsePostfix());
return new Prefix(operator, parsePostfix());
@ -1101,8 +1174,10 @@ class MiniJsParser {
Expression parseUnaryLow() {
String operator = lastToken;
if (lastCategory == SYMBOL && UNARY_OPERATORS.contains(operator) &&
operator != "++" && operator != "--") {
if (lastCategory == SYMBOL &&
UNARY_OPERATORS.contains(operator) &&
operator != "++" &&
operator != "--") {
expectCategory(SYMBOL);
if (operator == "await") return new Await(parsePostfix());
return new Prefix(operator, parseUnaryLow());
@ -1114,7 +1189,7 @@ class MiniJsParser {
Expression lhs = parseUnaryLow();
int minPrecedence;
String lastSymbol;
Expression rhs; // This is null first time around.
Expression rhs; // This is null first time around.
while (true) {
String symbol = lastToken;
if (lastCategory != SYMBOL ||
@ -1146,7 +1221,6 @@ class MiniJsParser {
return new Conditional(lhs, ifTrue, ifFalse);
}
Expression parseAssignment() {
Expression lhs = parseConditional();
String assignmentOperator = lastToken;
@ -1154,7 +1228,7 @@ class MiniJsParser {
Expression rhs = parseAssignment();
if (assignmentOperator == "=") {
return new Assignment(lhs, rhs);
} else {
} else {
// Handle +=, -=, etc.
String operator =
assignmentOperator.substring(0, assignmentOperator.length - 1);
@ -1280,7 +1354,6 @@ class MiniJsParser {
if (lastToken == 'with') {
error('Not implemented in mini parser');
}
}
bool checkForInterpolatedStatement = lastCategory == HASH;
@ -1387,8 +1460,8 @@ class MiniJsParser {
expectCategory(RPAREN);
Statement body = parseStatement();
return new ForIn(
new VariableDeclarationList([
new VariableInitialization(declaration, null)]),
new VariableDeclarationList(
[new VariableInitialization(declaration, null)]),
objectExpression,
body);
}
@ -1450,8 +1523,8 @@ class MiniJsParser {
}
List statements = new List<Statement>();
while (lastCategory != RBRACE &&
lastToken != 'case' &&
lastToken != 'default') {
lastToken != 'case' &&
lastToken != 'default') {
statements.add(parseStatement());
}
return expression == null
@ -1484,7 +1557,7 @@ class MiniJsParser {
expectCategory(RPAREN);
expectCategory(LBRACE);
List<SwitchClause> clauses = new List<SwitchClause>();
while(lastCategory != RBRACE) {
while (lastCategory != RBRACE) {
clauses.add(parseSwitchClause());
}
expectCategory(RBRACE);

View file

@ -6,7 +6,7 @@ library js_character_codes;
const int $EOF = 0;
const int $STX = 2;
const int $BS = 8;
const int $BS = 8;
const int $TAB = 9;
const int $LF = 10;
const int $VTAB = 11;

View file

@ -95,8 +95,7 @@ class BaseVisitor<T> implements NodeVisitor<T> {
T visitJump(Statement node) => visitStatement(node);
T visitBlock(Block node) => visitStatement(node);
T visitExpressionStatement(ExpressionStatement node)
=> visitStatement(node);
T visitExpressionStatement(ExpressionStatement node) => visitStatement(node);
T visitEmptyStatement(EmptyStatement node) => visitStatement(node);
T visitIf(If node) => visitStatement(node);
T visitFor(For node) => visitLoop(node);
@ -109,8 +108,7 @@ class BaseVisitor<T> implements NodeVisitor<T> {
T visitThrow(Throw node) => visitJump(node);
T visitTry(Try node) => visitStatement(node);
T visitSwitch(Switch node) => visitStatement(node);
T visitFunctionDeclaration(FunctionDeclaration node)
=> visitStatement(node);
T visitFunctionDeclaration(FunctionDeclaration node) => visitStatement(node);
T visitLabeledStatement(LabeledStatement node) => visitStatement(node);
T visitLiteralStatement(LiteralStatement node) => visitStatement(node);
@ -122,8 +120,8 @@ class BaseVisitor<T> implements NodeVisitor<T> {
T visitVariableReference(VariableReference node) => visitExpression(node);
T visitLiteralExpression(LiteralExpression node) => visitExpression(node);
T visitVariableDeclarationList(VariableDeclarationList node)
=> visitExpression(node);
T visitVariableDeclarationList(VariableDeclarationList node) =>
visitExpression(node);
T visitAssignment(Assignment node) => visitExpression(node);
T visitVariableInitialization(VariableInitialization node) {
if (node.value != null) {
@ -132,6 +130,7 @@ class BaseVisitor<T> implements NodeVisitor<T> {
return visitExpression(node);
}
}
T visitConditional(Conditional node) => visitExpression(node);
T visitNew(New node) => visitExpression(node);
T visitCall(Call node) => visitExpression(node);
@ -141,8 +140,8 @@ class BaseVisitor<T> implements NodeVisitor<T> {
T visitAccess(PropertyAccess node) => visitExpression(node);
T visitVariableUse(VariableUse node) => visitVariableReference(node);
T visitVariableDeclaration(VariableDeclaration node)
=> visitVariableReference(node);
T visitVariableDeclaration(VariableDeclaration node) =>
visitVariableReference(node);
T visitParameter(Parameter node) => visitVariableDeclaration(node);
T visitThis(This node) => visitParameter(node);
@ -174,16 +173,16 @@ class BaseVisitor<T> implements NodeVisitor<T> {
T visitInterpolatedNode(InterpolatedNode node) => visitNode(node);
T visitInterpolatedExpression(InterpolatedExpression node)
=> visitInterpolatedNode(node);
T visitInterpolatedLiteral(InterpolatedLiteral node)
=> visitInterpolatedNode(node);
T visitInterpolatedParameter(InterpolatedParameter node)
=> visitInterpolatedNode(node);
T visitInterpolatedSelector(InterpolatedSelector node)
=> visitInterpolatedNode(node);
T visitInterpolatedStatement(InterpolatedStatement node)
=> visitInterpolatedNode(node);
T visitInterpolatedExpression(InterpolatedExpression node) =>
visitInterpolatedNode(node);
T visitInterpolatedLiteral(InterpolatedLiteral node) =>
visitInterpolatedNode(node);
T visitInterpolatedParameter(InterpolatedParameter node) =>
visitInterpolatedNode(node);
T visitInterpolatedSelector(InterpolatedSelector node) =>
visitInterpolatedNode(node);
T visitInterpolatedStatement(InterpolatedStatement node) =>
visitInterpolatedNode(node);
T visitInterpolatedDeclaration(InterpolatedDeclaration node) {
return visitInterpolatedNode(node);
}
@ -244,6 +243,7 @@ class Program extends Node {
void visitChildren(NodeVisitor visitor) {
for (Statement statement in body) statement.accept(visitor);
}
Program _clone() => new Program(body);
}
@ -260,6 +260,7 @@ class Block extends Statement {
void visitChildren(NodeVisitor visitor) {
for (Statement statement in statements) statement.accept(visitor);
}
Block _clone() => new Block(statements);
}
@ -270,7 +271,10 @@ class ExpressionStatement extends Statement {
}
accept(NodeVisitor visitor) => visitor.visitExpressionStatement(this);
void visitChildren(NodeVisitor visitor) { expression.accept(visitor); }
void visitChildren(NodeVisitor visitor) {
expression.accept(visitor);
}
ExpressionStatement _clone() => new ExpressionStatement(expression);
}
@ -290,7 +294,7 @@ class If extends Statement {
If(this.condition, this.then, this.otherwise);
If.noElse(this.condition, this.then) : this.otherwise = new EmptyStatement();
bool get hasElse => otherwise is !EmptyStatement;
bool get hasElse => otherwise is! EmptyStatement;
accept(NodeVisitor visitor) => visitor.visitIf(this);
@ -377,7 +381,7 @@ class Do extends Loop {
}
class Continue extends Statement {
final String targetLabel; // Can be null.
final String targetLabel; // Can be null.
Continue(this.targetLabel);
@ -388,7 +392,7 @@ class Continue extends Statement {
}
class Break extends Statement {
final String targetLabel; // Can be null.
final String targetLabel; // Can be null.
Break(this.targetLabel);
@ -399,7 +403,7 @@ class Break extends Statement {
}
class Return extends Statement {
final Expression value; // Can be null.
final Expression value; // Can be null.
Return([this.value = null]);
@ -428,8 +432,8 @@ class Throw extends Statement {
class Try extends Statement {
final Block body;
final Catch catchPart; // Can be null if [finallyPart] is non-null.
final Block finallyPart; // Can be null if [catchPart] is non-null.
final Catch catchPart; // Can be null if [finallyPart] is non-null.
final Block finallyPart; // Can be null if [catchPart] is non-null.
Try(this.body, this.catchPart, this.finallyPart) {
assert(catchPart != null || finallyPart != null);
@ -548,7 +552,7 @@ class LiteralStatement extends Statement {
LiteralStatement(this.code);
accept(NodeVisitor visitor) => visitor.visitLiteralStatement(this);
void visitChildren(NodeVisitor visitor) { }
void visitChildren(NodeVisitor visitor) {}
LiteralStatement _clone() => new LiteralStatement(code);
}
@ -577,9 +581,7 @@ abstract class Expression extends Node {
Statement toStatement() => new ExpressionStatement(this);
}
abstract class Declaration implements VariableReference {
}
abstract class Declaration implements VariableReference {}
/// An implementation of [Name] represents a potentially late bound name in
/// the generated ast.
@ -660,11 +662,10 @@ class VariableDeclarationList extends Expression {
class Assignment extends Expression {
final Expression leftHandSide;
final String op; // Null, if the assignment is not compound.
final Expression value; // May be null, for [VariableInitialization]s.
final String op; // Null, if the assignment is not compound.
final Expression value; // May be null, for [VariableInitialization]s.
Assignment(leftHandSide, value)
: this.compound(leftHandSide, null, value);
Assignment(leftHandSide, value) : this.compound(leftHandSide, null, value);
// If `this.op == null` this will be a non-compound assignment.
Assignment.compound(this.leftHandSide, this.op, this.value);
@ -679,8 +680,7 @@ class Assignment extends Expression {
if (value != null) value.accept(visitor);
}
Assignment _clone() =>
new Assignment.compound(leftHandSide, op, value);
Assignment _clone() => new Assignment.compound(leftHandSide, op, value);
}
class VariableInitialization extends Assignment {
@ -721,7 +721,7 @@ class Call extends Expression {
List<Expression> arguments;
Call(this.target, this.arguments,
{JavaScriptNodeSourceInformation sourceInformation}) {
{JavaScriptNodeSourceInformation sourceInformation}) {
this._sourceInformation = sourceInformation;
}
@ -840,7 +840,6 @@ class Postfix extends Expression {
argument.accept(visitor);
}
int get precedenceLevel => UNARY;
}
@ -902,6 +901,7 @@ class NamedFunction extends Expression {
name.accept(visitor);
function.accept(visitor);
}
NamedFunction _clone() => new NamedFunction(name, function);
int get precedenceLevel => LEFT_HAND_SIDE;
@ -1074,7 +1074,7 @@ class StringConcatenation extends Literal {
}
class LiteralNumber extends Literal {
final String value; // Must be a valid JavaScript number literal.
final String value; // Must be a valid JavaScript number literal.
LiteralNumber(this.value);
@ -1170,8 +1170,7 @@ class InterpolatedExpression extends Expression with InterpolatedNode {
accept(NodeVisitor visitor) => visitor.visitInterpolatedExpression(this);
void visitChildren(NodeVisitor visitor) {}
InterpolatedExpression _clone() =>
new InterpolatedExpression(nameOrPosition);
InterpolatedExpression _clone() => new InterpolatedExpression(nameOrPosition);
int get precedenceLevel => PRIMARY;
}
@ -1186,11 +1185,15 @@ class InterpolatedLiteral extends Literal with InterpolatedNode {
InterpolatedLiteral _clone() => new InterpolatedLiteral(nameOrPosition);
}
class InterpolatedParameter extends Expression with InterpolatedNode
class InterpolatedParameter extends Expression
with InterpolatedNode
implements Parameter {
final nameOrPosition;
String get name { throw "InterpolatedParameter.name must not be invoked"; }
String get name {
throw "InterpolatedParameter.name must not be invoked";
}
bool get allowRename => false;
InterpolatedParameter(this.nameOrPosition);
@ -1225,8 +1228,8 @@ class InterpolatedStatement extends Statement with InterpolatedNode {
}
class InterpolatedDeclaration extends Expression
with InterpolatedNode
implements Declaration {
with InterpolatedNode
implements Declaration {
final nameOrPosition;
InterpolatedDeclaration(this.nameOrPosition);

View file

@ -4,7 +4,6 @@
part of js_ast;
typedef String Renamer(Name);
class JavaScriptPrintingOptions {
@ -15,19 +14,20 @@ class JavaScriptPrintingOptions {
JavaScriptPrintingOptions(
{this.shouldCompressOutput: false,
this.minifyLocalVariables: false,
this.preferSemicolonToNewlineInMinifiedOutput: false,
this.renamerForNames: identityRenamer});
this.minifyLocalVariables: false,
this.preferSemicolonToNewlineInMinifiedOutput: false,
this.renamerForNames: identityRenamer});
static String identityRenamer(Name name) => name.name;
}
/// An environment in which JavaScript printing is done. Provides emitting of
/// text and pre- and post-visit callbacks.
abstract class JavaScriptPrintingContext {
/// Signals an error. This should happen only for serious internal errors.
void error(String message) { throw message; }
void error(String message) {
throw message;
}
/// Adds [string] to the output.
void emit(String string);
@ -46,10 +46,8 @@ abstract class JavaScriptPrintingContext {
/// [Fun] nodes and is `null` otherwise.
///
/// [enterNode] is called in post-traversal order.
void exitNode(Node node,
int startPosition,
int endPosition,
int closingPosition) {}
void exitNode(
Node node, int startPosition, int endPosition, int closingPosition) {}
}
/// A simple implementation of [JavaScriptPrintingContext] suitable for tests.
@ -63,7 +61,6 @@ class SimpleJavaScriptPrintingContext extends JavaScriptPrintingContext {
String getText() => buffer.toString();
}
class Printer implements NodeVisitor {
final JavaScriptPrintingOptions options;
final JavaScriptPrintingContext context;
@ -85,22 +82,21 @@ class Printer implements NodeVisitor {
static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]');
static final expressionContinuationRegExp = new RegExp(r'^[-+([]');
Printer(JavaScriptPrintingOptions options,
JavaScriptPrintingContext context)
Printer(JavaScriptPrintingOptions options, JavaScriptPrintingContext context)
: options = options,
context = context,
shouldCompressOutput = options.shouldCompressOutput,
danglingElseVisitor = new DanglingElseVisitor(context),
localNamer = determineRenamer(options.shouldCompressOutput,
options.minifyLocalVariables);
localNamer = determineRenamer(
options.shouldCompressOutput, options.minifyLocalVariables);
static LocalNamer determineRenamer(bool shouldCompressOutput,
bool allowVariableMinification) {
static LocalNamer determineRenamer(
bool shouldCompressOutput, bool allowVariableMinification) {
return (shouldCompressOutput && allowVariableMinification)
? new MinifyRenamer() : new IdentityNamer();
? new MinifyRenamer()
: new IdentityNamer();
}
// The current indentation string.
String get indentation {
// Lazily add new indentation strings as required.
@ -236,7 +232,7 @@ class Printer implements NodeVisitor {
}
void visitCommaSeparated(List<Node> nodes, int hasRequiredType,
{bool newInForInit, bool newAtStatementBegin}) {
{bool newInForInit, bool newAtStatementBegin}) {
for (int i = 0; i < nodes.length; i++) {
if (i != 0) {
atStatementBegin = false;
@ -244,8 +240,7 @@ class Printer implements NodeVisitor {
spaceOut();
}
visitNestedExpression(nodes[i], hasRequiredType,
newInForInit: newInForInit,
newAtStatementBegin: newAtStatementBegin);
newInForInit: newInForInit, newAtStatementBegin: newAtStatementBegin);
}
}
@ -325,7 +320,7 @@ class Printer implements NodeVisitor {
void visitExpressionStatement(ExpressionStatement node) {
indent();
visitNestedExpression(node.expression, EXPRESSION,
newInForInit: false, newAtStatementBegin: true);
newInForInit: false, newAtStatementBegin: true);
outSemicolonLn();
}
@ -353,7 +348,7 @@ class Printer implements NodeVisitor {
spaceOut();
out("(");
visitNestedExpression(node.condition, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out(")");
bool thenWasBlock =
blockBody(then, needsSeparation: false, needsNewline: !hasElse);
@ -371,7 +366,7 @@ class Printer implements NodeVisitor {
endNode(elsePart);
} else {
blockBody(unwrapBlockIfSingleStatement(elsePart),
needsSeparation: true, needsNewline: true);
needsSeparation: true, needsNewline: true);
}
}
}
@ -388,23 +383,23 @@ class Printer implements NodeVisitor {
out("(");
if (loop.init != null) {
visitNestedExpression(loop.init, EXPRESSION,
newInForInit: true, newAtStatementBegin: false);
newInForInit: true, newAtStatementBegin: false);
}
out(";");
if (loop.condition != null) {
spaceOut();
visitNestedExpression(loop.condition, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
}
out(";");
if (loop.update != null) {
spaceOut();
visitNestedExpression(loop.update, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
}
out(")");
blockBody(unwrapBlockIfSingleStatement(loop.body),
needsSeparation: false, needsNewline: true);
needsSeparation: false, needsNewline: true);
}
@override
@ -413,14 +408,14 @@ class Printer implements NodeVisitor {
spaceOut();
out("(");
visitNestedExpression(loop.leftHandSide, EXPRESSION,
newInForInit: true, newAtStatementBegin: false);
newInForInit: true, newAtStatementBegin: false);
out(" in");
pendingSpace = true;
visitNestedExpression(loop.object, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out(")");
blockBody(unwrapBlockIfSingleStatement(loop.body),
needsSeparation: false, needsNewline: true);
needsSeparation: false, needsNewline: true);
}
@override
@ -429,17 +424,17 @@ class Printer implements NodeVisitor {
spaceOut();
out("(");
visitNestedExpression(loop.condition, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out(")");
blockBody(unwrapBlockIfSingleStatement(loop.body),
needsSeparation: false, needsNewline: true);
needsSeparation: false, needsNewline: true);
}
@override
void visitDo(Do loop) {
outIndent("do");
if (blockBody(unwrapBlockIfSingleStatement(loop.body),
needsSeparation: true, needsNewline: false)) {
needsSeparation: true, needsNewline: false)) {
spaceOut();
} else {
indent();
@ -448,7 +443,7 @@ class Printer implements NodeVisitor {
spaceOut();
out("(");
visitNestedExpression(loop.condition, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out(")");
outSemicolonLn();
}
@ -481,7 +476,7 @@ class Printer implements NodeVisitor {
outIndent("return");
pendingSpace = true;
visitNestedExpression(node.value, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
}
outSemicolonLn();
}
@ -495,7 +490,7 @@ class Printer implements NodeVisitor {
}
pendingSpace = true;
visitNestedExpression(node.expression, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
outSemicolonLn();
}
@ -504,7 +499,7 @@ class Printer implements NodeVisitor {
outIndent("throw");
pendingSpace = true;
visitNestedExpression(node.expression, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
outSemicolonLn();
}
@ -531,7 +526,7 @@ class Printer implements NodeVisitor {
spaceOut();
out("(");
visitNestedExpression(node.declaration, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out(")");
blockBody(node.body, needsSeparation: false, needsNewline: false);
}
@ -542,7 +537,7 @@ class Printer implements NodeVisitor {
spaceOut();
out("(");
visitNestedExpression(node.key, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out(")");
spaceOut();
outLn("{");
@ -557,7 +552,7 @@ class Printer implements NodeVisitor {
outIndent("case");
pendingSpace = true;
visitNestedExpression(node.expression, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
outLn(":");
if (!node.body.statements.isEmpty) {
indentMore();
@ -598,13 +593,13 @@ class Printer implements NodeVisitor {
out(" ");
// Name must be a [Decl]. Therefore only test for primary expressions.
visitNestedExpression(name, PRIMARY,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
}
localNamer.enterScope(vars);
out("(");
if (fun.params != null) {
visitCommaSeparated(fun.params, PRIMARY,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
}
out(")");
switch (fun.asyncModifier) {
@ -628,7 +623,6 @@ class Printer implements NodeVisitor {
blockOut(fun.body, shouldIndent: false, needsNewline: false);
localNamer.leaveScope();
return closingPosition;
}
@override
@ -644,18 +638,19 @@ class Printer implements NodeVisitor {
}
visitNestedExpression(Expression node, int requiredPrecedence,
{bool newInForInit, bool newAtStatementBegin}) {
{bool newInForInit, bool newAtStatementBegin}) {
bool needsParentheses =
// a - (b + c).
(requiredPrecedence != EXPRESSION &&
node.precedenceLevel < requiredPrecedence) ||
// for (a = (x in o); ... ; ... ) { ... }
(newInForInit && node is Binary && node.op == "in") ||
// (function() { ... })().
// ({a: 2, b: 3}.toString()).
(newAtStatementBegin && (node is NamedFunction ||
node is Fun ||
node is ObjectInitializer));
node.precedenceLevel < requiredPrecedence) ||
// for (a = (x in o); ... ; ... ) { ... }
(newInForInit && node is Binary && node.op == "in") ||
// (function() { ... })().
// ({a: 2, b: 3}.toString()).
(newAtStatementBegin &&
(node is NamedFunction ||
node is Fun ||
node is ObjectInitializer));
if (needsParentheses) {
inForInit = false;
atStatementBegin = false;
@ -673,14 +668,13 @@ class Printer implements NodeVisitor {
visitVariableDeclarationList(VariableDeclarationList list) {
out("var ");
visitCommaSeparated(list.declarations, ASSIGNMENT,
newInForInit: inForInit, newAtStatementBegin: false);
newInForInit: inForInit, newAtStatementBegin: false);
}
@override
visitAssignment(Assignment assignment) {
visitNestedExpression(assignment.leftHandSide, CALL,
newInForInit: inForInit,
newAtStatementBegin: atStatementBegin);
newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
if (assignment.value != null) {
spaceOut();
String op = assignment.op;
@ -688,8 +682,7 @@ class Printer implements NodeVisitor {
out("=");
spaceOut();
visitNestedExpression(assignment.value, ASSIGNMENT,
newInForInit: inForInit,
newAtStatementBegin: false);
newInForInit: inForInit, newAtStatementBegin: false);
}
}
@ -701,40 +694,38 @@ class Printer implements NodeVisitor {
@override
visitConditional(Conditional cond) {
visitNestedExpression(cond.condition, LOGICAL_OR,
newInForInit: inForInit,
newAtStatementBegin: atStatementBegin);
newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
spaceOut();
out("?");
spaceOut();
// The then part is allowed to have an 'in'.
visitNestedExpression(cond.then, ASSIGNMENT,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
spaceOut();
out(":");
spaceOut();
visitNestedExpression(cond.otherwise, ASSIGNMENT,
newInForInit: inForInit, newAtStatementBegin: false);
newInForInit: inForInit, newAtStatementBegin: false);
}
@override
visitNew(New node) {
out("new ");
visitNestedExpression(node.target, LEFT_HAND_SIDE,
newInForInit: inForInit, newAtStatementBegin: false);
newInForInit: inForInit, newAtStatementBegin: false);
out("(");
visitCommaSeparated(node.arguments, ASSIGNMENT,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out(")");
}
@override
visitCall(Call call) {
visitNestedExpression(call.target, CALL,
newInForInit: inForInit,
newAtStatementBegin: atStatementBegin);
newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
out("(");
visitCommaSeparated(call.arguments, ASSIGNMENT,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out(")");
}
@ -745,7 +736,7 @@ class Printer implements NodeVisitor {
String op = binary.op;
int leftPrecedenceRequirement;
int rightPrecedenceRequirement;
bool leftSpace = true; // left<HERE>op right
bool leftSpace = true; // left<HERE>op right
switch (op) {
case ',':
// x, (y, z) <=> (x, y), z.
@ -822,8 +813,7 @@ class Printer implements NodeVisitor {
}
visitNestedExpression(left, leftPrecedenceRequirement,
newInForInit: inForInit,
newAtStatementBegin: atStatementBegin);
newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
if (op == "in" || op == "instanceof") {
// There are cases where the space is not required but without further
@ -837,8 +827,7 @@ class Printer implements NodeVisitor {
spaceOut();
}
visitNestedExpression(right, rightPrecedenceRequirement,
newInForInit: inForInit,
newAtStatementBegin: false);
newInForInit: inForInit, newAtStatementBegin: false);
}
@override
@ -867,14 +856,13 @@ class Printer implements NodeVisitor {
out(op);
}
visitNestedExpression(unary.argument, UNARY,
newInForInit: inForInit, newAtStatementBegin: false);
newInForInit: inForInit, newAtStatementBegin: false);
}
@override
void visitPostfix(Postfix postfix) {
visitNestedExpression(postfix.argument, CALL,
newInForInit: inForInit,
newAtStatementBegin: atStatementBegin);
newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
out(postfix.op);
}
@ -909,10 +897,10 @@ class Printer implements NodeVisitor {
// TODO(floitsch): allow more characters.
int charCode = field.codeUnitAt(i);
if (!(charCodes.$a <= charCode && charCode <= charCodes.$z ||
charCodes.$A <= charCode && charCode <= charCodes.$Z ||
charCode == charCodes.$$ ||
charCode == charCodes.$_ ||
i != 1 && isDigit(charCode))) {
charCodes.$A <= charCode && charCode <= charCodes.$Z ||
charCode == charCodes.$$ ||
charCode == charCodes.$_ ||
i != 1 && isDigit(charCode))) {
return false;
}
}
@ -927,8 +915,7 @@ class Printer implements NodeVisitor {
@override
void visitAccess(PropertyAccess access) {
visitNestedExpression(access.receiver, CALL,
newInForInit: inForInit,
newAtStatementBegin: atStatementBegin);
newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
Node selector = access.selector;
if (selector is LiteralString) {
LiteralString selectorString = selector;
@ -957,7 +944,7 @@ class Printer implements NodeVisitor {
}
out("[");
visitNestedExpression(selector, EXPRESSION,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
out("]");
}
@ -1051,7 +1038,7 @@ class Printer implements NodeVisitor {
}
if (i != 0) spaceOut();
visitNestedExpression(element, ASSIGNMENT,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
// We can skip the trailing "," for the last element (since it's not
// an array hole).
if (i != elements.length - 1) out(",");
@ -1070,8 +1057,7 @@ class Printer implements NodeVisitor {
// property. Ideally, we would use a proper pretty-printer to make the
// decision based on layout.
bool exitOneLinerMode(Expression value) {
return
value is Fun ||
return value is Fun ||
value is ArrayInitializer && value.elements.any((e) => e is Fun);
}
@ -1122,7 +1108,7 @@ class Printer implements NodeVisitor {
out(":");
spaceOut();
visitNestedExpression(node.value, ASSIGNMENT,
newInForInit: false, newAtStatementBegin: false);
newInForInit: false, newAtStatementBegin: false);
}
@override
@ -1205,12 +1191,13 @@ class Printer implements NodeVisitor {
}
}
class OrderedSet<T> {
final Set<T> set;
final List<T> list;
OrderedSet() : set = new Set<T>(), list = <T>[];
OrderedSet()
: set = new Set<T>(),
list = <T>[];
void add(T x) {
if (set.add(x)) {
@ -1235,9 +1222,10 @@ class VarCollector extends BaseVisitor {
static final String disableVariableMinificationPattern = "::norenaming::";
static final String enableVariableMinificationPattern = "::dorenaming::";
VarCollector() : nested = false,
vars = new OrderedSet<String>(),
params = new OrderedSet<String>();
VarCollector()
: nested = false,
vars = new OrderedSet<String>(),
params = new OrderedSet<String>();
void forEachVar(void fn(String v)) => vars.forEach(fn);
void forEachParam(void fn(String p)) => params.forEach(fn);
@ -1284,7 +1272,6 @@ class VarCollector extends BaseVisitor {
}
}
/**
* Returns true, if the given node must be wrapped into braces when used
* as then-statement in an [If] that has an else branch.
@ -1308,6 +1295,7 @@ class DanglingElseVisitor extends BaseVisitor<bool> {
if (!node.hasElse) return true;
return node.otherwise.accept(this);
}
bool visitFor(For node) => node.body.accept(this);
bool visitForIn(ForIn node) => node.body.accept(this);
bool visitWhile(While node) => node.body.accept(this);
@ -1323,19 +1311,18 @@ class DanglingElseVisitor extends BaseVisitor<bool> {
return node.catchPart.accept(this);
}
}
bool visitCatch(Catch node) => node.body.accept(this);
bool visitSwitch(Switch node) => false;
bool visitCase(Case node) => false;
bool visitDefault(Default node) => false;
bool visitFunctionDeclaration(FunctionDeclaration node) => false;
bool visitLabeledStatement(LabeledStatement node)
=> node.body.accept(this);
bool visitLabeledStatement(LabeledStatement node) => node.body.accept(this);
bool visitLiteralStatement(LiteralStatement node) => true;
bool visitExpression(Expression node) => false;
}
abstract class LocalNamer {
String getName(String oldName);
String declareVariable(String oldName);
@ -1344,7 +1331,6 @@ abstract class LocalNamer {
void leaveScope();
}
class IdentityNamer implements LocalNamer {
String getName(String oldName) => oldName;
String declareVariable(String oldName) => oldName;
@ -1353,7 +1339,6 @@ class IdentityNamer implements LocalNamer {
void leaveScope() {}
}
class MinifyRenamer implements LocalNamer {
final List<Map<String, String>> maps = [];
final List<int> parameterNumberStack = [];
@ -1392,9 +1377,9 @@ class MinifyRenamer implements LocalNamer {
static const DIGITS = 10;
static int nthLetter(int n) {
return (n < LOWER_CASE_LETTERS) ?
charCodes.$a + n :
charCodes.$A + n - LOWER_CASE_LETTERS;
return (n < LOWER_CASE_LETTERS)
? charCodes.$a + n
: charCodes.$A + n - LOWER_CASE_LETTERS;
}
// Parameters go from a to z and variables go from z to a. This makes each

View file

@ -10,7 +10,6 @@ class TemplateManager {
TemplateManager();
Template lookupExpressionTemplate(String source) {
return expressionTemplates[source];
}
@ -55,13 +54,15 @@ class Template {
bool get isPositional => holeNames == null;
Template(this.source, this.ast,
{this.isExpression: true, this.forceCopy: false}) {
{this.isExpression: true, this.forceCopy: false}) {
assert(this.isExpression ? ast is Expression : ast is Statement);
_compile();
}
Template.withExpressionResult(this.ast)
: source = null, isExpression = true, forceCopy = false {
: source = null,
isExpression = true,
forceCopy = false {
assert(ast is Expression);
assert(_checkNoPlaceholders());
positionalArgumentCount = 0;
@ -69,7 +70,9 @@ class Template {
}
Template.withStatementResult(this.ast)
: source = null, isExpression = false, forceCopy = false {
: source = null,
isExpression = false,
forceCopy = false {
assert(ast is Statement);
assert(_checkNoPlaceholders());
positionalArgumentCount = 0;
@ -89,7 +92,7 @@ class Template {
instantiator = generator.compile(ast);
positionalArgumentCount = generator.analysis.count;
Set<String> names = generator.analysis.holeNames;
holeNames = names.toList(growable:false);
holeNames = names.toList(growable: false);
}
/// Instantiates the template with the given [arguments].
@ -128,14 +131,12 @@ class Template {
*/
typedef Node Instantiator(var arguments);
/**
* InstantiatorGeneratorVisitor compiles a template. This class compiles a tree
* containing [InterpolatedNode]s into a function that will create a copy of the
* tree with the interpolated nodes substituted with provided values.
*/
class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
final bool forceCopy;
InterpolatedNodeAnalysis analysis = new InterpolatedNodeAnalysis();
@ -222,6 +223,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
return error('Interpolated value #$nameOrPosition is not '
'an Expression or List of Expressions: $value');
}
if (value is Iterable) return value.map(toExpression);
return toExpression(value);
};
@ -247,8 +249,9 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
if (item is Parameter) return item;
if (item is String) return new Parameter(item);
return error('Interpolated value #$nameOrPosition is not a Parameter or'
' List of Parameters: $value');
' List of Parameters: $value');
}
if (value is Iterable) return value.map(toParameter);
return toParameter(value);
};
@ -283,10 +286,12 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
var value = arguments[nameOrPosition];
Statement toStatement(item) {
if (item is Statement) return item;
if (item is Expression) return item.toStatement();;
if (item is Expression) return item.toStatement();
;
return error('Interpolated value #$nameOrPosition is not '
'a Statement or List of Statements: $value');
'a Statement or List of Statements: $value');
}
if (value is Iterable) return value.map(toStatement);
return toStatement(value);
};
@ -306,6 +311,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
statements.add(node.toStatement());
}
}
for (Instantiator instantiator in instantiators) {
add(instantiator(arguments));
}
@ -327,6 +333,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
statements.add(node.toStatement());
}
}
for (Instantiator instantiator in instantiators) {
add(instantiator(arguments));
}
@ -360,11 +367,13 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
var value = arguments[nameOrPosition];
if (value is bool) return value;
if (value is Expression) return value;
if (value is String) return convertStringToVariableUse(value);;
if (value is String) return convertStringToVariableUse(value);
;
error('Interpolated value #$nameOrPosition '
'is not an Expression: $value');
'is not an Expression: $value');
};
}
var makeCondition = compileCondition(node.condition);
Instantiator makeThen = visit(node.then);
Instantiator makeOtherwise = visit(node.otherwise);
@ -377,10 +386,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
return makeOtherwise(arguments);
}
}
return new If(
condition,
makeThen(arguments),
makeOtherwise(arguments));
return new If(condition, makeThen(arguments), makeOtherwise(arguments));
};
}
@ -389,9 +395,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator makeThen = visit(node.then);
Instantiator makeOtherwise = visit(node.otherwise);
return (arguments) {
return new If(
makeCondition(arguments),
makeThen(arguments),
return new If(makeCondition(arguments), makeThen(arguments),
makeOtherwise(arguments));
};
}
@ -402,9 +406,8 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator makeUpdate = visitNullable(node.update);
Instantiator makeBody = visit(node.body);
return (arguments) {
return new For(
makeInit(arguments), makeCondition(arguments), makeUpdate(arguments),
makeBody(arguments));
return new For(makeInit(arguments), makeCondition(arguments),
makeUpdate(arguments), makeBody(arguments));
};
}
@ -413,9 +416,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator makeObject = visit(node.object);
Instantiator makeBody = visit(node.body);
return (arguments) {
return new ForIn(
makeLeftHandSide(arguments),
makeObject(arguments),
return new ForIn(makeLeftHandSide(arguments), makeObject(arguments),
makeBody(arguments));
};
}
@ -453,7 +454,8 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator visitDartYield(DartYield node) {
Instantiator makeExpression = visit(node.expression);
return (arguments) => new DartYield(makeExpression(arguments), node.hasStar);
return (arguments) =>
new DartYield(makeExpression(arguments), node.hasStar);
}
Instantiator visitThrow(Throw node) {
@ -472,17 +474,19 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator visitCatch(Catch node) {
Instantiator makeDeclaration = visit(node.declaration);
Instantiator makeBody = visit(node.body);
return (arguments) => new Catch(
makeDeclaration(arguments), makeBody(arguments));
return (arguments) =>
new Catch(makeDeclaration(arguments), makeBody(arguments));
}
Instantiator visitSwitch(Switch node) {
Instantiator makeKey = visit(node.key);
Iterable<Instantiator> makeCases = node.cases.map(visit);
return (arguments) {
return new Switch(makeKey(arguments),
makeCases.map((Instantiator makeCase) => makeCase(arguments))
.toList());
return new Switch(
makeKey(arguments),
makeCases
.map((Instantiator makeCase) => makeCase(arguments))
.toList());
};
}
@ -537,9 +541,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator makeValue = visitNullable(node.value);
return (arguments) {
return new Assignment.compound(
makeLeftHandSide(arguments),
op,
makeValue(arguments));
makeLeftHandSide(arguments), op, makeValue(arguments));
};
}
@ -556,10 +558,8 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator makeCondition = visit(cond.condition);
Instantiator makeThen = visit(cond.then);
Instantiator makeOtherwise = visit(cond.otherwise);
return (arguments) => new Conditional(
makeCondition(arguments),
makeThen(arguments),
makeOtherwise(arguments));
return (arguments) => new Conditional(makeCondition(arguments),
makeThen(arguments), makeOtherwise(arguments));
}
Instantiator visitNew(New node) =>
@ -658,8 +658,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator visitDeferredNumber(DeferredNumber node) => same(node);
Instantiator visitDeferredString(DeferredString node) =>
(arguments) => node;
Instantiator visitDeferredString(DeferredString node) => (arguments) => node;
Instantiator visitLiteralBool(LiteralBool node) =>
(arguments) => new LiteralBool(node.value);
@ -674,9 +673,8 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
(arguments) => new LiteralNull();
Instantiator visitStringConcatenation(StringConcatenation node) {
List<Instantiator> partMakers = node.parts
.map(visit)
.toList(growable: false);
List<Instantiator> partMakers =
node.parts.map(visit).toList(growable: false);
return (arguments) {
List<Literal> parts = partMakers
.map((Instantiator instantiator) => instantiator(arguments))
@ -689,9 +687,8 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator visitArrayInitializer(ArrayInitializer node) {
// TODO(sra): Implement splicing?
List<Instantiator> elementMakers = node.elements
.map(visit)
.toList(growable: false);
List<Instantiator> elementMakers =
node.elements.map(visit).toList(growable: false);
return (arguments) {
List<Expression> elements = elementMakers
.map((Instantiator instantiator) => instantiator(arguments))

View file

@ -25,9 +25,7 @@ class TestCase {
/// Map from template names to the inserted values.
final Map<String, String> environment;
const TestCase(
this.data,
[this.environment = const {}]);
const TestCase(this.data, [this.environment = const {}]);
}
const List<TestCase> DATA = const <TestCase>[
@ -44,12 +42,11 @@ function(a, b) {
function(a, b) {
return null;
@0}""",
TestMode.EXIT: """
TestMode.EXIT: """
function(a@1, b@2) {
return null@5;
@4}@3@0"""
}),
const TestCase(const {
TestMode.NONE: """
function() {
@ -108,7 +105,6 @@ function() {
@26 }@22
@20}@1@0""",
}),
const TestCase(const {
TestMode.NONE: """
function() {
@ -125,13 +121,12 @@ function() {
function foo() {
@3}
@0}""",
TestMode.EXIT: """
TestMode.EXIT: """
function() {
function foo@4() {
}@5@3
@2}@1@0"""
}),
const TestCase(const {
TestMode.INPUT: """
function() {
@ -153,20 +148,21 @@ function() {
a.b;
[1,, 2];
@0}""",
TestMode.EXIT: """
TestMode.EXIT: """
function() {
a@4.b@5@3;
@2 [1@8,,@9 2@10]@7;
@6}@1@0""",
}),
const TestCase(const {
TestMode.INPUT: "a.#nameTemplate = #nameTemplate",
TestMode.NONE: "a.nameValue = nameValue",
TestMode.ENTER: "@0@1@2a.@3nameValue = @3nameValue",
TestMode.DELIMITER: "a.nameValue = nameValue",
TestMode.EXIT: "a@2.nameValue@3@1 = nameValue@3@0",
}, const {'nameTemplate': 'nameValue'}),
}, const {
'nameTemplate': 'nameValue'
}),
];
class FixedName extends Name {
@ -221,10 +217,8 @@ class Context extends SimpleJavaScriptPrintingContext {
}
}
void exitNode(Node node,
int startPosition,
int endPosition,
int delimiterPosition) {
void exitNode(
Node node, int startPosition, int endPosition, int delimiterPosition) {
int value = id(node);
if (mode == TestMode.DELIMITER && delimiterPosition != null) {
tagMap.putIfAbsent(delimiterPosition, () => []).add(tag(value));

View file

@ -23,127 +23,145 @@ void main() {
}
test('simple', () {
check('', [$DQ, $DQ]);
check('a', [$DQ, $a, $DQ]);
});
check('', [$DQ, $DQ]);
check('a', [$DQ, $a, $DQ]);
});
test('simple-escapes', () {
check([$BS], [$DQ, $BACKSLASH, $b, $DQ]);
check([$BS], [$DQ, $BACKSLASH, $b, $DQ], ascii: true);
check([$BS], [$DQ, $BACKSLASH, $b, $DQ], utf8: true);
check([$BS], [$DQ, $BACKSLASH, $b, $DQ]);
check([$BS], [$DQ, $BACKSLASH, $b, $DQ], ascii: true);
check([$BS], [$DQ, $BACKSLASH, $b, $DQ], utf8: true);
check([$LF], [$DQ, $BACKSLASH, $n, $DQ]);
check([$LF], [$DQ, $BACKSLASH, $n, $DQ], ascii: true);
check([$LF], [$DQ, $BACKSLASH, $n, $DQ], utf8: true);
check([$LF], [$DQ, $BACKSLASH, $n, $DQ]);
check([$LF], [$DQ, $BACKSLASH, $n, $DQ], ascii: true);
check([$LF], [$DQ, $BACKSLASH, $n, $DQ], utf8: true);
check([$FF], [$DQ, $FF, $DQ]);
check([$FF], [$DQ, $BACKSLASH, $f, $DQ], ascii: true);
check([$FF], [$DQ, $BACKSLASH, $f, $DQ], utf8: true);
check([$FF], [$DQ, $FF, $DQ]);
check([$FF], [$DQ, $BACKSLASH, $f, $DQ], ascii: true);
check([$FF], [$DQ, $BACKSLASH, $f, $DQ], utf8: true);
check([$CR], [$DQ, $BACKSLASH, $r, $DQ]);
check([$CR], [$DQ, $BACKSLASH, $r, $DQ], ascii: true);
check([$CR], [$DQ, $BACKSLASH, $r, $DQ], utf8: true);
check([$CR], [$DQ, $BACKSLASH, $r, $DQ]);
check([$CR], [$DQ, $BACKSLASH, $r, $DQ], ascii: true);
check([$CR], [$DQ, $BACKSLASH, $r, $DQ], utf8: true);
check([$TAB], [$DQ, $BACKSLASH, $t, $DQ]);
check([$TAB], [$DQ, $BACKSLASH, $t, $DQ], ascii: true);
check([$TAB], [$DQ, $BACKSLASH, $t, $DQ], utf8: true);
check([$TAB], [$DQ, $BACKSLASH, $t, $DQ]);
check([$TAB], [$DQ, $BACKSLASH, $t, $DQ], ascii: true);
check([$TAB], [$DQ, $BACKSLASH, $t, $DQ], utf8: true);
check([$VTAB], [$DQ, $BACKSLASH, $v, $DQ]);
check([$VTAB], [$DQ, $BACKSLASH, $v, $DQ], ascii: true);
check([$VTAB], [$DQ, $BACKSLASH, $v, $DQ], utf8: true);
});
check([$VTAB], [$DQ, $BACKSLASH, $v, $DQ]);
check([$VTAB], [$DQ, $BACKSLASH, $v, $DQ], ascii: true);
check([$VTAB], [$DQ, $BACKSLASH, $v, $DQ], utf8: true);
});
test('unnamed-control-codes-escapes', () {
check([0, 1, 2, 3], [$DQ, 0, 1, 2, 3, $DQ]);
check([0, 1, 2, 3], r'''"\x00\x01\x02\x03"''', ascii: true);
check([0, 1, 2, 3], [$DQ, 0, 1, 2, 3, $DQ], utf8: true);
});
check([0, 1, 2, 3], [$DQ, 0, 1, 2, 3, $DQ]);
check([0, 1, 2, 3], r'''"\x00\x01\x02\x03"''', ascii: true);
check([0, 1, 2, 3], [$DQ, 0, 1, 2, 3, $DQ], utf8: true);
});
test('line-separator', () {
// Legacy escaper is broken.
// check([$LS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $8, $DQ]);
check([$LS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $8, $DQ], ascii: true);
check([$LS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $8, $DQ], utf8: true);
});
// Legacy escaper is broken.
// check([$LS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $8, $DQ]);
check([$LS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $8, $DQ], ascii: true);
check([$LS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $8, $DQ], utf8: true);
});
test('page-separator', () {
// Legacy escaper is broken.
// check([$PS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $9, $DQ]);
check([$PS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $9, $DQ], ascii: true);
check([$PS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $9, $DQ], utf8: true);
});
// Legacy escaper is broken.
// check([$PS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $9, $DQ]);
check([$PS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $9, $DQ], ascii: true);
check([$PS], [$DQ, $BACKSLASH, $u, $2, $0, $2, $9, $DQ], utf8: true);
});
test('legacy-escaper-is-broken', () {
check([$LS], [$DQ, 0x2028, $DQ]);
check([$PS], [$DQ, 0x2029, $DQ]);
});
check([$LS], [$DQ, 0x2028, $DQ]);
check([$PS], [$DQ, 0x2029, $DQ]);
});
test('choose-quotes', () {
check('\'', [$DQ, $SQ, $DQ]);
check('"', [$SQ, $DQ, $SQ], ascii: true);
check("'", [$DQ, $SQ, $DQ], ascii: true);
// Legacy always double-quotes
check([$DQ, $DQ, $SQ],
[$DQ, $BACKSLASH, $DQ, $BACKSLASH, $DQ, $SQ, $DQ]);
// Using single quotes saves us one backslash:
check([$DQ, $DQ, $SQ],
[$SQ, $DQ, $DQ, $BACKSLASH, $SQ, $SQ],
ascii: true);
check([$DQ, $SQ, $SQ],
[$DQ, $BACKSLASH, $DQ, $SQ, $SQ, $DQ],
ascii: true);
});
check('\'', [$DQ, $SQ, $DQ]);
check('"', [$SQ, $DQ, $SQ], ascii: true);
check("'", [$DQ, $SQ, $DQ], ascii: true);
// Legacy always double-quotes
check([$DQ, $DQ, $SQ], [$DQ, $BACKSLASH, $DQ, $BACKSLASH, $DQ, $SQ, $DQ]);
// Using single quotes saves us one backslash:
check([$DQ, $DQ, $SQ], [$SQ, $DQ, $DQ, $BACKSLASH, $SQ, $SQ], ascii: true);
check([$DQ, $SQ, $SQ], [$DQ, $BACKSLASH, $DQ, $SQ, $SQ, $DQ], ascii: true);
});
test('u1234', () {
check('\u1234', [$DQ, 0x1234, $DQ]);
check('\u1234', [$DQ, $BACKSLASH, $u, $1, $2, $3, $4, $DQ], ascii: true);
check('\u1234', [$DQ, 0x1234, $DQ], utf8: true);
});
check('\u1234', [$DQ, 0x1234, $DQ]);
check('\u1234', [$DQ, $BACKSLASH, $u, $1, $2, $3, $4, $DQ], ascii: true);
check('\u1234', [$DQ, 0x1234, $DQ], utf8: true);
});
test('u12345', () {
check([0x12345], [$DQ, 55304, 57157, $DQ]);
// TODO: ES6 option:
//check([0x12345],
// [$DQ, $BACKSLASH, $u, $LCURLY, $1, $2, $3, $4, $5, $RCURLY, $DQ],
// ascii: true);
check([0x12345], r'''"\ud808\udf45"''', ascii: true);
check([0x12345],
[$DQ, $BACKSLASH, $u, $d, $8, $0, $8,
$BACKSLASH, $u, $d, $f, $4, $5, $DQ],
ascii: true);
check([0x12345], [$DQ, 55304, 57157, $DQ], utf8: true);
});
check([0x12345], [$DQ, 55304, 57157, $DQ]);
// TODO: ES6 option:
//check([0x12345],
// [$DQ, $BACKSLASH, $u, $LCURLY, $1, $2, $3, $4, $5, $RCURLY, $DQ],
// ascii: true);
check([0x12345], r'''"\ud808\udf45"''', ascii: true);
check([
0x12345
], [
$DQ,
$BACKSLASH,
$u,
$d,
$8,
$0,
$8,
$BACKSLASH,
$u,
$d,
$f,
$4,
$5,
$DQ
], ascii: true);
check([0x12345], [$DQ, 55304, 57157, $DQ], utf8: true);
});
test('unpaired-surrogate', () {
// (0xD834, 0xDD1E) = 0x1D11E
// Strings containing unpaired surrogates must be encoded to prevent
// problems with the utf8 file-level encoding.
check([0xD834], [$DQ, 0xD834, $DQ]); // Legacy escapedString broken.
check([0xD834], [$DQ, $BACKSLASH, $u, $d, $8, $3, $4, $DQ], ascii: true);
check([0xD834], [$DQ, $BACKSLASH, $u, $d, $8, $3, $4, $DQ], utf8: true);
// (0xD834, 0xDD1E) = 0x1D11E
// Strings containing unpaired surrogates must be encoded to prevent
// problems with the utf8 file-level encoding.
check([0xD834], [$DQ, 0xD834, $DQ]); // Legacy escapedString broken.
check([0xD834], [$DQ, $BACKSLASH, $u, $d, $8, $3, $4, $DQ], ascii: true);
check([0xD834], [$DQ, $BACKSLASH, $u, $d, $8, $3, $4, $DQ], utf8: true);
check([0xDD1E], [$DQ, 0xDD1E, $DQ]); // Legacy escapedString broken.
check([0xDD1E], [$DQ, $BACKSLASH, $u, $d, $d, $1, $e, $DQ], ascii: true);
check([0xDD1E], [$DQ, $BACKSLASH, $u, $d, $d, $1, $e, $DQ], utf8: true);
check([0xDD1E], [$DQ, 0xDD1E, $DQ]); // Legacy escapedString broken.
check([0xDD1E], [$DQ, $BACKSLASH, $u, $d, $d, $1, $e, $DQ], ascii: true);
check([0xDD1E], [$DQ, $BACKSLASH, $u, $d, $d, $1, $e, $DQ], utf8: true);
check([0xD834, $A],
[$DQ, 0xD834, $A, $DQ]); // Legacy escapedString broken.
check([0xD834, $A],
[$DQ, $BACKSLASH, $u, $d, $8, $3, $4, $A, $DQ],
ascii: true);
check([0xD834, $A],
[$DQ, $BACKSLASH, $u, $d, $8, $3, $4, $A, $DQ],
utf8: true);
check([0xD834, $A], [$DQ, 0xD834, $A, $DQ]); // Legacy escapedString broken.
check([0xD834, $A], [$DQ, $BACKSLASH, $u, $d, $8, $3, $4, $A, $DQ],
ascii: true);
check([0xD834, $A], [$DQ, $BACKSLASH, $u, $d, $8, $3, $4, $A, $DQ],
utf8: true);
check([0xD834, 0xDD1E], [$DQ, 0xD834, 0xDD1E, $DQ]); // Legacy ok.
check([0xD834, 0xDD1E],
[$DQ,
$BACKSLASH, $u, $d, $8, $3, $4,
$BACKSLASH, $u, $d, $d, $1, $e,
$DQ],
ascii: true);
check([0xD834, 0xDD1E], r'''"\ud834\udd1e"''', ascii: true);
check([0xD834, 0xDD1E], [$DQ, 0xD834, 0xDD1E, $DQ], utf8: true);
});
check([0xD834, 0xDD1E], [$DQ, 0xD834, 0xDD1E, $DQ]); // Legacy ok.
check([
0xD834,
0xDD1E
], [
$DQ,
$BACKSLASH,
$u,
$d,
$8,
$3,
$4,
$BACKSLASH,
$u,
$d,
$d,
$1,
$e,
$DQ
], ascii: true);
check([0xD834, 0xDD1E], r'''"\ud834\udd1e"''', ascii: true);
check([0xD834, 0xDD1E], [$DQ, 0xD834, 0xDD1E, $DQ], utf8: true);
});
}