mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:07:11 +00:00
[js_ast] Migrate template.dart and builder.dart
Change-Id: I049ca6282ca4a5db5a275a824f973ed135f924e9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/239002 Reviewed-by: Nicholas Shahan <nshahan@google.com> Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
parent
b5909dc494
commit
985220bd5b
3 changed files with 181 additions and 197 deletions
|
@ -114,16 +114,8 @@
|
|||
"Dynamic access of 'name'.": 1,
|
||||
"Dynamic invocation of '-'.": 1
|
||||
},
|
||||
"pkg/js_ast/lib/src/builder.dart": {
|
||||
"Dynamic invocation of 'call'.": 2
|
||||
},
|
||||
"pkg/js_ast/lib/src/template.dart": {
|
||||
"Dynamic access of 'keys'.": 1,
|
||||
"Dynamic access of 'length'.": 1,
|
||||
"Dynamic invocation of '[]'.": 9,
|
||||
"Dynamic invocation of 'containsKey'.": 2,
|
||||
"Dynamic invocation of 'join'.": 1,
|
||||
"Dynamic invocation of 'toStatement'.": 3,
|
||||
"Dynamic invocation of 'where'.": 1
|
||||
"Dynamic invocation of 'toStatement'.": 1
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart=2.15
|
||||
|
||||
/// Utilities for building JS ASTs at runtime. Contains a builder class and a
|
||||
/// parser that parses part of the language.
|
||||
library js_ast.builder;
|
||||
|
@ -198,19 +200,19 @@ class JsBuilder {
|
|||
/// '#' signs.
|
||||
Expression call(String source, [var arguments]) {
|
||||
Template template = _findExpressionTemplate(source);
|
||||
if (arguments == null) return template.instantiate([]);
|
||||
arguments ??= [];
|
||||
// We allow a single argument to be given directly.
|
||||
if (arguments is! List && arguments is! Map) arguments = [arguments];
|
||||
return template.instantiate(arguments);
|
||||
return template.instantiate(arguments) as Expression;
|
||||
}
|
||||
|
||||
/// Parses a JavaScript Statement, otherwise just like [call].
|
||||
Statement statement(String source, [var arguments]) {
|
||||
Template template = _findStatementTemplate(source);
|
||||
if (arguments == null) return template.instantiate([]);
|
||||
arguments ??= [];
|
||||
// We allow a single argument to be given directly.
|
||||
if (arguments is! List && arguments is! Map) arguments = [arguments];
|
||||
return template.instantiate(arguments);
|
||||
return template.instantiate(arguments) as Statement;
|
||||
}
|
||||
|
||||
/// Parses JavaScript written in the `JS` foreign instruction.
|
||||
|
@ -229,7 +231,7 @@ class JsBuilder {
|
|||
}
|
||||
|
||||
Template _findExpressionTemplate(String source) {
|
||||
Template template = templateManager.lookupExpressionTemplate(source);
|
||||
Template? template = templateManager.lookupExpressionTemplate(source);
|
||||
if (template == null) {
|
||||
MiniJsParser parser = MiniJsParser(source);
|
||||
Expression expression = parser.expression();
|
||||
|
@ -239,7 +241,7 @@ class JsBuilder {
|
|||
}
|
||||
|
||||
Template _findStatementTemplate(String source) {
|
||||
Template template = templateManager.lookupStatementTemplate(source);
|
||||
Template? template = templateManager.lookupStatementTemplate(source);
|
||||
if (template == null) {
|
||||
MiniJsParser parser = MiniJsParser(source);
|
||||
Statement statement = parser.statement();
|
||||
|
@ -272,11 +274,11 @@ class JsBuilder {
|
|||
/// Create an Expression template which has [ast] as the result. This is used
|
||||
/// to wrap a generated AST in a zero-argument Template so it can be passed to
|
||||
/// context that expects a template.
|
||||
Template expressionTemplateYielding(Node ast) {
|
||||
Template expressionTemplateYielding(Expression ast) {
|
||||
return Template.withExpressionResult(ast);
|
||||
}
|
||||
|
||||
Template statementTemplateYielding(Node ast) {
|
||||
Template statementTemplateYielding(Statement ast) {
|
||||
return Template.withStatementResult(ast);
|
||||
}
|
||||
|
||||
|
@ -739,7 +741,7 @@ class MiniJsParser {
|
|||
if (lastToken == '=>') {
|
||||
lastCategory = ARROW;
|
||||
} else {
|
||||
int binaryPrecedence = BINARY_PRECEDENCE[lastToken];
|
||||
int? binaryPrecedence = BINARY_PRECEDENCE[lastToken];
|
||||
if (binaryPrecedence == null &&
|
||||
!UNARY_OPERATORS.contains(lastToken)) {
|
||||
error("Unknown operator");
|
||||
|
@ -791,7 +793,7 @@ class MiniJsParser {
|
|||
return false;
|
||||
}
|
||||
|
||||
void error(message) {
|
||||
Never error(message) {
|
||||
throw MiniJsParserError(this, message);
|
||||
}
|
||||
|
||||
|
@ -850,7 +852,7 @@ class MiniJsParser {
|
|||
expectCategory(COMMA);
|
||||
}
|
||||
return ArrayInitializer(values);
|
||||
} else if (last != null && last.startsWith("/")) {
|
||||
} else if (last.startsWith("/")) {
|
||||
String regexp = getRegExp(lastPosition);
|
||||
getToken();
|
||||
String flags = lastToken;
|
||||
|
@ -865,7 +867,6 @@ class MiniJsParser {
|
|||
return expression;
|
||||
} else {
|
||||
error("Expected primary expression");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -877,7 +878,7 @@ class MiniJsParser {
|
|||
return parseFun();
|
||||
}
|
||||
|
||||
Expression parseFun() {
|
||||
Fun parseFun() {
|
||||
List<Parameter> params = [];
|
||||
expectCategory(LPAREN);
|
||||
if (!acceptCategory(RPAREN)) {
|
||||
|
@ -951,7 +952,7 @@ class MiniJsParser {
|
|||
Expression value = parseAssignment();
|
||||
return Property(propertyName, value);
|
||||
} else {
|
||||
Expression fun = parseFun();
|
||||
final fun = parseFun();
|
||||
return MethodDefinition(propertyName, fun);
|
||||
}
|
||||
}
|
||||
|
@ -1066,27 +1067,29 @@ class MiniJsParser {
|
|||
|
||||
Expression parseBinary(int maxPrecedence) {
|
||||
Expression lhs = parseUnaryLow();
|
||||
int minPrecedence;
|
||||
String lastSymbol;
|
||||
Expression rhs; // This is null first time around.
|
||||
Expression? rhs; // This is null first time around.
|
||||
late int minPrecedence;
|
||||
late String lastSymbol;
|
||||
|
||||
while (true) {
|
||||
String symbol = lastToken;
|
||||
if (lastCategory != SYMBOL ||
|
||||
!BINARY_PRECEDENCE.containsKey(symbol) ||
|
||||
BINARY_PRECEDENCE[symbol] > maxPrecedence) {
|
||||
break;
|
||||
}
|
||||
final symbol = lastToken;
|
||||
if (lastCategory != SYMBOL) break;
|
||||
final symbolPrecedence = BINARY_PRECEDENCE[symbol];
|
||||
if (symbolPrecedence == null) break;
|
||||
if (symbolPrecedence > maxPrecedence) break;
|
||||
|
||||
expectCategory(SYMBOL);
|
||||
if (rhs == null || BINARY_PRECEDENCE[symbol] >= minPrecedence) {
|
||||
if (rhs == null || symbolPrecedence >= minPrecedence) {
|
||||
if (rhs != null) lhs = Binary(lastSymbol, lhs, rhs);
|
||||
minPrecedence = BINARY_PRECEDENCE[symbol];
|
||||
minPrecedence = symbolPrecedence;
|
||||
rhs = parseUnaryLow();
|
||||
lastSymbol = symbol;
|
||||
} else {
|
||||
Expression higher = parseBinary(BINARY_PRECEDENCE[symbol]);
|
||||
Expression higher = parseBinary(symbolPrecedence);
|
||||
rhs = Binary(symbol, rhs, higher);
|
||||
}
|
||||
}
|
||||
|
||||
if (rhs == null) return lhs;
|
||||
return Binary(lastSymbol, lhs, rhs);
|
||||
}
|
||||
|
@ -1173,7 +1176,7 @@ class MiniJsParser {
|
|||
var initialization = <VariableInitialization>[];
|
||||
|
||||
void declare(Declaration declaration) {
|
||||
Expression initializer = null;
|
||||
Expression? initializer = null;
|
||||
if (acceptString("=")) {
|
||||
initializer = parseAssignment();
|
||||
}
|
||||
|
@ -1318,7 +1321,7 @@ class MiniJsParser {
|
|||
return Throw(expression);
|
||||
}
|
||||
|
||||
Statement parseBreakOrContinue(constructor) {
|
||||
Statement parseBreakOrContinue(Statement Function(String?) constructor) {
|
||||
var identifier = lastToken;
|
||||
if (!skippedNewline && acceptCategory(ALPHA)) {
|
||||
expectSemicolon();
|
||||
|
@ -1349,13 +1352,13 @@ class MiniJsParser {
|
|||
//
|
||||
// for (var variable in Expression) Statement
|
||||
//
|
||||
Statement finishFor(Expression init) {
|
||||
Expression condition = null;
|
||||
Statement finishFor(Expression? init) {
|
||||
Expression? condition = null;
|
||||
if (!acceptCategory(SEMICOLON)) {
|
||||
condition = parseExpression();
|
||||
expectCategory(SEMICOLON);
|
||||
}
|
||||
Expression update = null;
|
||||
Expression? update = null;
|
||||
if (!acceptCategory(RPAREN)) {
|
||||
update = parseExpression();
|
||||
expectCategory(RPAREN);
|
||||
|
@ -1407,16 +1410,16 @@ class MiniJsParser {
|
|||
|
||||
Statement parseFunctionDeclaration() {
|
||||
Declaration name = parseVariableDeclaration();
|
||||
Expression fun = parseFun();
|
||||
Fun fun = parseFun();
|
||||
return FunctionDeclaration(name, fun);
|
||||
}
|
||||
|
||||
Statement parseTry() {
|
||||
expectCategory(LBRACE);
|
||||
Block body = parseBlock();
|
||||
Catch catchPart = null;
|
||||
Catch? catchPart = null;
|
||||
if (acceptString('catch')) catchPart = parseCatch();
|
||||
Block finallyPart = null;
|
||||
Block? finallyPart = null;
|
||||
if (acceptString('finally')) {
|
||||
expectCategory(LBRACE);
|
||||
finallyPart = parseBlock();
|
||||
|
@ -1427,7 +1430,7 @@ class MiniJsParser {
|
|||
}
|
||||
|
||||
SwitchClause parseSwitchClause() {
|
||||
Expression expression = null;
|
||||
Expression? expression = null;
|
||||
if (acceptString('case')) {
|
||||
expression = parseExpression();
|
||||
expectCategory(COLON);
|
||||
|
@ -1437,7 +1440,7 @@ class MiniJsParser {
|
|||
}
|
||||
expectCategory(COLON);
|
||||
}
|
||||
List statements = <Statement>[];
|
||||
List<Statement> statements = [];
|
||||
while (lastCategory != RBRACE &&
|
||||
lastToken != 'case' &&
|
||||
lastToken != 'default') {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// @dart=2.15
|
||||
|
||||
library js_ast.template;
|
||||
|
||||
import 'nodes.dart';
|
||||
|
@ -12,7 +14,7 @@ class TemplateManager {
|
|||
|
||||
TemplateManager();
|
||||
|
||||
Template lookupExpressionTemplate(String source) {
|
||||
Template? lookupExpressionTemplate(String source) {
|
||||
return expressionTemplates[source];
|
||||
}
|
||||
|
||||
|
@ -23,7 +25,7 @@ class TemplateManager {
|
|||
return template;
|
||||
}
|
||||
|
||||
Template lookupStatementTemplate(String source) {
|
||||
Template? lookupStatementTemplate(String source) {
|
||||
return statementTemplates[source];
|
||||
}
|
||||
|
||||
|
@ -41,66 +43,75 @@ class TemplateManager {
|
|||
/// The [instantiate] method creates an AST that looks like the original with
|
||||
/// the placeholders replaced by the arguments to [instantiate].
|
||||
class Template {
|
||||
final String source;
|
||||
final String? source;
|
||||
final bool isExpression;
|
||||
final bool forceCopy;
|
||||
final Node ast;
|
||||
|
||||
Instantiator instantiator;
|
||||
final Instantiator instantiator;
|
||||
|
||||
int positionalArgumentCount = -1;
|
||||
final int positionalArgumentCount;
|
||||
|
||||
// Null, unless there are named holes.
|
||||
List<String> holeNames;
|
||||
bool get isPositional => holeNames == null;
|
||||
// Names of named holes, empty if there are no named holes.
|
||||
final List<String> holeNames;
|
||||
|
||||
Template(this.source, this.ast,
|
||||
{this.isExpression = true, this.forceCopy = false}) {
|
||||
assert(this.isExpression ? ast is Expression : ast is Statement);
|
||||
_compile();
|
||||
bool get isPositional => holeNames.isEmpty;
|
||||
|
||||
Template._(this.source, this.ast,
|
||||
{required this.instantiator,
|
||||
required this.isExpression,
|
||||
required this.forceCopy,
|
||||
required this.positionalArgumentCount,
|
||||
this.holeNames = const []});
|
||||
|
||||
factory Template(String? source, Node ast,
|
||||
{bool isExpression = true, bool forceCopy = false}) {
|
||||
assert(isExpression ? ast is Expression : ast is Statement);
|
||||
|
||||
final generator = InstantiatorGeneratorVisitor(forceCopy);
|
||||
final instantiator = generator.compile(ast);
|
||||
final positionalArgumentCount = generator.analysis.count;
|
||||
final names = generator.analysis.holeNames;
|
||||
final holeNames = names.toList(growable: false);
|
||||
|
||||
return Template._(source, ast,
|
||||
instantiator: instantiator,
|
||||
isExpression: isExpression,
|
||||
forceCopy: forceCopy,
|
||||
positionalArgumentCount: positionalArgumentCount,
|
||||
holeNames: holeNames);
|
||||
}
|
||||
|
||||
Template.withExpressionResult(this.ast)
|
||||
: source = null,
|
||||
isExpression = true,
|
||||
forceCopy = false {
|
||||
assert(ast is Expression);
|
||||
assert(_checkNoPlaceholders());
|
||||
positionalArgumentCount = 0;
|
||||
instantiator = (arguments) => ast;
|
||||
factory Template.withExpressionResult(Expression ast) {
|
||||
assert(_checkNoPlaceholders(ast));
|
||||
return Template._(null, ast,
|
||||
instantiator: (arguments) => ast,
|
||||
isExpression: true,
|
||||
forceCopy: false,
|
||||
positionalArgumentCount: 0);
|
||||
}
|
||||
|
||||
Template.withStatementResult(this.ast)
|
||||
: source = null,
|
||||
isExpression = false,
|
||||
forceCopy = false {
|
||||
assert(ast is Statement);
|
||||
assert(_checkNoPlaceholders());
|
||||
positionalArgumentCount = 0;
|
||||
instantiator = (arguments) => ast;
|
||||
factory Template.withStatementResult(Statement ast) {
|
||||
assert(_checkNoPlaceholders(ast));
|
||||
return Template._(null, ast,
|
||||
instantiator: (arguments) => ast,
|
||||
isExpression: false,
|
||||
forceCopy: false,
|
||||
positionalArgumentCount: 0);
|
||||
}
|
||||
|
||||
bool _checkNoPlaceholders() {
|
||||
static bool _checkNoPlaceholders(Node ast) {
|
||||
InstantiatorGeneratorVisitor generator =
|
||||
InstantiatorGeneratorVisitor(false);
|
||||
generator.compile(ast);
|
||||
return generator.analysis.count == 0;
|
||||
}
|
||||
|
||||
void _compile() {
|
||||
InstantiatorGeneratorVisitor generator =
|
||||
InstantiatorGeneratorVisitor(forceCopy);
|
||||
instantiator = generator.compile(ast);
|
||||
positionalArgumentCount = generator.analysis.count;
|
||||
Set<String> names = generator.analysis.holeNames;
|
||||
holeNames = names.toList(growable: false);
|
||||
}
|
||||
|
||||
/// Instantiates the template with the given [arguments].
|
||||
///
|
||||
/// This method fills in the holes with the given arguments. The [arguments]
|
||||
/// must be either a [List] or a [Map].
|
||||
Node instantiate(var arguments) {
|
||||
Node instantiate(Object arguments) {
|
||||
if (arguments is List) {
|
||||
if (arguments.length != positionalArgumentCount) {
|
||||
throw 'Wrong number of template arguments, given ${arguments.length}, '
|
||||
|
@ -109,20 +120,23 @@ class Template {
|
|||
}
|
||||
return instantiator(arguments);
|
||||
}
|
||||
assert(arguments is Map);
|
||||
if (holeNames.length < arguments.length) {
|
||||
// This search is in O(n), but we only do it in case of an error, and the
|
||||
// number of holes should be quite limited.
|
||||
String unusedNames =
|
||||
arguments.keys.where((name) => !holeNames.contains(name)).join(", ");
|
||||
throw "Template arguments has unused mappings: $unusedNames";
|
||||
if (arguments is Map) {
|
||||
if (holeNames.length < arguments.length) {
|
||||
// This search is in O(n), but we only do it in case of an error, and the
|
||||
// number of holes should be quite limited.
|
||||
String unusedNames = arguments.keys
|
||||
.where((name) => !holeNames.contains(name))
|
||||
.join(", ");
|
||||
throw "Template arguments has unused mappings: $unusedNames";
|
||||
}
|
||||
if (!holeNames.every((String name) => arguments.containsKey(name))) {
|
||||
String notFound =
|
||||
holeNames.where((name) => !arguments.containsKey(name)).join(", ");
|
||||
throw "Template arguments is missing mappings for: $notFound";
|
||||
}
|
||||
return instantiator(arguments);
|
||||
}
|
||||
if (!holeNames.every((String name) => arguments.containsKey(name))) {
|
||||
String notFound =
|
||||
holeNames.where((name) => !arguments.containsKey(name)).join(", ");
|
||||
throw "Template arguments is missing mappings for: $notFound";
|
||||
}
|
||||
return instantiator(arguments);
|
||||
throw ArgumentError.value(arguments, 'arguments', 'Must be a List or Map');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,12 +163,12 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
return result;
|
||||
}
|
||||
|
||||
static error(String message) {
|
||||
static Never error(String message) {
|
||||
throw message;
|
||||
}
|
||||
|
||||
static Instantiator same(Node node) => (arguments) => node;
|
||||
static Node makeNull(arguments) => null;
|
||||
static Null makeNull(arguments) => null;
|
||||
|
||||
Instantiator visit(Node node) {
|
||||
if (forceCopy || analysis.containsInterpolatedNodes(node)) {
|
||||
|
@ -163,7 +177,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
return same(node);
|
||||
}
|
||||
|
||||
Instantiator visitNullable(Node node) {
|
||||
Instantiator visitNullable(Node? node) {
|
||||
if (node == null) return makeNull;
|
||||
return visit(node);
|
||||
}
|
||||
|
@ -310,44 +324,34 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
List<Instantiator> instantiators =
|
||||
node.body.map(visitSplayableStatement).toList();
|
||||
return (arguments) {
|
||||
List<Statement> statements = [];
|
||||
void add(node) {
|
||||
if (node is EmptyStatement) return;
|
||||
if (node is Iterable) {
|
||||
statements.addAll(node);
|
||||
} else {
|
||||
statements.add(node.toStatement());
|
||||
}
|
||||
}
|
||||
|
||||
for (Instantiator instantiator in instantiators) {
|
||||
add(instantiator(arguments));
|
||||
}
|
||||
return Program(statements);
|
||||
return Program(splayStatements(instantiators, arguments));
|
||||
};
|
||||
}
|
||||
|
||||
List<Statement> splayStatements(List<Instantiator> instantiators, arguments) {
|
||||
var statements = <Statement>[];
|
||||
for (var instantiator in instantiators) {
|
||||
final node = instantiator(arguments);
|
||||
if (node is EmptyStatement) continue;
|
||||
if (node is Iterable) {
|
||||
statements.addAll(node as Iterable<Statement>);
|
||||
} else if (node is Block /*&& !node.isScope*/) {
|
||||
statements.addAll(node.statements);
|
||||
} else if (node is Statement) {
|
||||
statements.add(node);
|
||||
} else {
|
||||
error('Not splayable as statement: $node');
|
||||
}
|
||||
}
|
||||
return statements;
|
||||
}
|
||||
|
||||
@override
|
||||
Instantiator visitBlock(Block node) {
|
||||
List<Instantiator> instantiators =
|
||||
node.statements.map(visitSplayableStatement).toList();
|
||||
return (arguments) {
|
||||
List<Statement> statements = [];
|
||||
void add(node) {
|
||||
if (node is EmptyStatement) return;
|
||||
if (node is Iterable) {
|
||||
statements.addAll(node);
|
||||
} else if (node is Block) {
|
||||
statements.addAll(node.statements);
|
||||
} else {
|
||||
statements.add(node.toStatement());
|
||||
}
|
||||
}
|
||||
|
||||
for (Instantiator instantiator in instantiators) {
|
||||
add(instantiator(arguments));
|
||||
}
|
||||
return Block(statements);
|
||||
return Block(splayStatements(instantiators, arguments));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -365,40 +369,35 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
|
||||
@override
|
||||
Instantiator visitIf(If node) {
|
||||
if (node.condition is InterpolatedExpression) {
|
||||
return visitIfConditionalCompilation(node);
|
||||
final condition = node.condition;
|
||||
if (condition is InterpolatedExpression) {
|
||||
return visitIfConditionalCompilation(node, condition);
|
||||
} else {
|
||||
return visitIfNormal(node);
|
||||
}
|
||||
}
|
||||
|
||||
Instantiator visitIfConditionalCompilation(If node) {
|
||||
// Special version of visitInterpolatedExpression that permits bools.
|
||||
compileCondition(InterpolatedExpression node) {
|
||||
var nameOrPosition = node.nameOrPosition;
|
||||
return (arguments) {
|
||||
var value = arguments[nameOrPosition];
|
||||
if (value is bool) return value;
|
||||
if (value is Expression) return value;
|
||||
if (value is String) return convertStringToVariableUse(value);
|
||||
throw error('Interpolated value #$nameOrPosition '
|
||||
'is not an Expression: $value');
|
||||
};
|
||||
}
|
||||
|
||||
var makeCondition = compileCondition(node.condition);
|
||||
Instantiator visitIfConditionalCompilation(
|
||||
If node, InterpolatedExpression condition) {
|
||||
final nameOrPosition = condition.nameOrPosition;
|
||||
Instantiator makeThen = visit(node.then);
|
||||
Instantiator makeOtherwise = visit(node.otherwise);
|
||||
return (arguments) {
|
||||
var condition = makeCondition(arguments);
|
||||
if (condition is bool) {
|
||||
if (condition == true) {
|
||||
return makeThen(arguments);
|
||||
} else {
|
||||
return makeOtherwise(arguments);
|
||||
}
|
||||
// Allow booleans to be used for conditional compilation.
|
||||
var value = arguments[nameOrPosition];
|
||||
if (value is bool) {
|
||||
return value ? makeThen(arguments) : makeOtherwise(arguments);
|
||||
}
|
||||
return If(condition, makeThen(arguments), makeOtherwise(arguments));
|
||||
Expression newCondition;
|
||||
if (value is Expression) {
|
||||
newCondition = value;
|
||||
} else if (value is String) {
|
||||
newCondition = convertStringToVariableUse(value);
|
||||
} else {
|
||||
error('Interpolated value #$nameOrPosition '
|
||||
'is not an Expression: $value');
|
||||
}
|
||||
return If(newCondition, makeThen(arguments), makeOtherwise(arguments));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -567,8 +566,8 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
@override
|
||||
Instantiator visitAssignment(Assignment node) {
|
||||
Instantiator makeLeftHandSide = visit(node.leftHandSide);
|
||||
String op = node.op;
|
||||
Instantiator makeValue = visitNullable(node.value);
|
||||
String? op = node.op;
|
||||
Instantiator makeValue = visit(node.value);
|
||||
return (arguments) {
|
||||
return Assignment.compound(
|
||||
makeLeftHandSide(arguments), op, makeValue(arguments));
|
||||
|
@ -611,15 +610,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
// copying.
|
||||
return (arguments) {
|
||||
Node target = makeTarget(arguments);
|
||||
List<Expression> callArguments = [];
|
||||
for (Instantiator instantiator in argumentMakers) {
|
||||
var result = instantiator(arguments);
|
||||
if (result is Iterable) {
|
||||
callArguments.addAll(result);
|
||||
} else {
|
||||
callArguments.add(result);
|
||||
}
|
||||
}
|
||||
List<Expression> callArguments = splay(argumentMakers, arguments);
|
||||
return finish(target, callArguments.toList(growable: false));
|
||||
};
|
||||
}
|
||||
|
@ -683,16 +674,8 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
Instantiator makeBody = visit(node.body);
|
||||
// TODO(sra): Avoid copying params if no interpolation or forced copying.
|
||||
return (arguments) {
|
||||
List<Parameter> params = [];
|
||||
for (Instantiator instantiator in paramMakers) {
|
||||
var result = instantiator(arguments);
|
||||
if (result is Iterable) {
|
||||
params.addAll(result);
|
||||
} else {
|
||||
params.add(result);
|
||||
}
|
||||
}
|
||||
Statement body = makeBody(arguments);
|
||||
List<Parameter> params = splayParameters(paramMakers, arguments);
|
||||
Block body = makeBody(arguments);
|
||||
return Fun(params, body);
|
||||
};
|
||||
}
|
||||
|
@ -703,21 +686,34 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
Instantiator makeBody = visit(node.body);
|
||||
// TODO(sra): Avoid copying params if no interpolation or forced copying.
|
||||
return (arguments) {
|
||||
List<Parameter> params = [];
|
||||
for (Instantiator instantiator in paramMakers) {
|
||||
var result = instantiator(arguments);
|
||||
if (result is Iterable) {
|
||||
params.addAll(result);
|
||||
} else {
|
||||
params.add(result);
|
||||
}
|
||||
}
|
||||
List<Parameter> params = splayParameters(paramMakers, arguments);
|
||||
// Either a Block or Expression.
|
||||
Node body = makeBody(arguments);
|
||||
return ArrowFunction(params, body);
|
||||
};
|
||||
}
|
||||
|
||||
List<Parameter> splayParameters(List<Instantiator> instantiators, arguments) {
|
||||
// TODO(sra): This will be different when parameters include destructuring
|
||||
// and default values.
|
||||
return splay<Parameter>(instantiators, arguments);
|
||||
}
|
||||
|
||||
List<T> splay<T>(Iterable<Instantiator> instantiators, arguments) {
|
||||
List<T> results = [];
|
||||
for (Instantiator instantiator in instantiators) {
|
||||
var result = instantiator(arguments);
|
||||
if (result is Iterable) {
|
||||
for (final item in result) {
|
||||
results.add(item as T);
|
||||
}
|
||||
} else {
|
||||
results.add(result as T);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@override
|
||||
Instantiator visitDeferredExpression(DeferredExpression node) => same(node);
|
||||
|
||||
|
@ -751,9 +747,10 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
List<Instantiator> partMakers =
|
||||
node.parts.map(visit).toList(growable: false);
|
||||
return (arguments) {
|
||||
List<Literal> parts = partMakers
|
||||
.map((Instantiator instantiator) => instantiator(arguments))
|
||||
.toList(growable: false);
|
||||
List<Literal> parts = [
|
||||
for (final instantiator in partMakers)
|
||||
instantiator(arguments) as Literal
|
||||
];
|
||||
return StringConcatenation(parts);
|
||||
};
|
||||
}
|
||||
|
@ -795,15 +792,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
node.properties.map(visitSplayable).toList();
|
||||
bool isOneLiner = node.isOneLiner;
|
||||
return (arguments) {
|
||||
List<Property> properties = [];
|
||||
for (Instantiator instantiator in propertyMakers) {
|
||||
var result = instantiator(arguments);
|
||||
if (result is Iterable) {
|
||||
properties.addAll(result);
|
||||
} else {
|
||||
properties.add(result);
|
||||
}
|
||||
}
|
||||
List<Property> properties = splay(propertyMakers, arguments);
|
||||
return ObjectInitializer(properties, isOneLiner: isOneLiner);
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue