de302d7f3b
This CL introduces StructuralParameter and StructuralParameterType classes. They are intended to replace TypeParameter and TypeParameterType respectively where those were used as type parameters defined by FunctionTypes. Previously, type parameters of FunctionTypes were represented by TypeParameter objects with the ‘parent’ field set to null. By introducing StructuralParameter and StructuralParameterType this CL unambiguously separates the two notions of type parameters. TEST=existing Change-Id: Ida3feb7ad96a7b2acef55840eacba9e36bf2a3e7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/312264 Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Aske Simon Christensen <askesc@google.com> Commit-Queue: Chloe Stefantsova <cstefantsova@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com> Reviewed-by: Mayank Patke <fishythefish@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com>
1858 lines
77 KiB
Dart
1858 lines
77 KiB
Dart
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
|
// 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.
|
|
|
|
import '../ast.dart';
|
|
import 'coverage.dart';
|
|
|
|
/// Helper class used to generate ASTs that contain all different nodes.
|
|
class NodeCreator {
|
|
final Uri _uri;
|
|
|
|
/// File offset counter.
|
|
///
|
|
/// Used to generate distinct file offsets through [_needFileOffset].
|
|
int _fileOffset = 0;
|
|
|
|
/// The parent [Component] for all created libraries, classes, extensions,
|
|
/// typedefs and members.
|
|
final Component _component = new Component();
|
|
|
|
/// These fields contain maps of requested nodes different kinds that are
|
|
/// still pending. The mapped values are used to track how many nodes of the
|
|
/// specific kind have been created. When all variants of a kind have been
|
|
/// created, the entry is removed from the map.
|
|
final Map<ExpressionKind, int> _pendingExpressions;
|
|
final Map<StatementKind, int> _pendingStatements;
|
|
final Map<DartTypeKind, int> _pendingDartTypes;
|
|
final Map<ConstantKind, int> _pendingConstants;
|
|
final Map<PatternKind, int> _pendingPatterns;
|
|
final Map<InitializerKind, int> _pendingInitializers;
|
|
final Map<MemberKind, int> _pendingMembers;
|
|
final Map<NodeKind, int> _pendingNodes;
|
|
|
|
/// The set of all kinds of nodes created by this node creator.
|
|
final Set<Object> _createdKinds = {};
|
|
|
|
/// These fields contain list of nodes needed for the creation of other nodes.
|
|
///
|
|
/// Needed nodes are nodes that need to exist prior to the node that required
|
|
/// it. For instance, to create an [InterfaceType] node, a [Class] node must
|
|
/// exist for the [InterfaceType] to reference.
|
|
///
|
|
/// Needed nodes are added to the context of the created nodes. For instance,
|
|
/// a needed [Class] is added to the [_component] and a needed
|
|
/// [VariableDeclaration] is added to a enclosing [Block].
|
|
List<Library> _neededLibraries = [];
|
|
List<Class> _neededClasses = [];
|
|
List<ExtensionTypeDeclaration> _neededExtensionTypeDeclarations = [];
|
|
List<Typedef> _neededTypedefs = [];
|
|
List<TypeParameter> _neededTypeParameters = [];
|
|
List<StructuralParameter> _neededStructuralParameters = [];
|
|
List<Constructor> _neededConstructors = [];
|
|
List<Procedure> _neededRedirectingFactories = [];
|
|
List<Procedure> _neededProcedures = [];
|
|
List<Field> _neededFields = [];
|
|
List<LibraryDependency> _neededLibraryDependencies = [];
|
|
List<VariableDeclaration> _neededVariableDeclarations = [];
|
|
List<LabeledStatement> _neededLabeledStatements = [];
|
|
List<FunctionDeclaration> _neededFunctionDeclarations = [];
|
|
List<SwitchCase> _neededSwitchCases = [];
|
|
|
|
/// Creates a [NodeCreator] requested to create nodes of the specified kinds.
|
|
NodeCreator({
|
|
Iterable<ExpressionKind> expressions = ExpressionKind.values,
|
|
Iterable<StatementKind> statements = StatementKind.values,
|
|
Iterable<DartTypeKind> dartTypes = DartTypeKind.values,
|
|
Iterable<ConstantKind> constants = ConstantKind.values,
|
|
Iterable<PatternKind> patterns = PatternKind.values,
|
|
Iterable<InitializerKind> initializers = InitializerKind.values,
|
|
Iterable<MemberKind> members = MemberKind.values,
|
|
Iterable<NodeKind> nodes = NodeKind.values,
|
|
}) : _pendingExpressions = new Map<ExpressionKind, int>.fromIterables(
|
|
expressions, new List<int>.filled(expressions.length, 0)),
|
|
_pendingStatements = new Map<StatementKind, int>.fromIterables(
|
|
statements, new List<int>.filled(statements.length, 0)),
|
|
_pendingDartTypes = new Map<DartTypeKind, int>.fromIterables(
|
|
dartTypes, new List<int>.filled(dartTypes.length, 0)),
|
|
_pendingConstants = new Map<ConstantKind, int>.fromIterables(
|
|
constants, new List<int>.filled(constants.length, 0)),
|
|
_pendingPatterns = new Map<PatternKind, int>.fromIterables(
|
|
patterns, new List<int>.filled(patterns.length, 0)),
|
|
_pendingInitializers = new Map<InitializerKind, int>.fromIterables(
|
|
initializers, new List<int>.filled(initializers.length, 0)),
|
|
_pendingMembers = new Map<MemberKind, int>.fromIterables(
|
|
members, new List<int>.filled(members.length, 0)),
|
|
_pendingNodes = new Map<NodeKind, int>.fromIterables(
|
|
nodes, new List<int>.filled(nodes.length, 0)),
|
|
_uri = Uri.parse('test:uri') {
|
|
_createdKinds.addAll(_pendingExpressions.keys);
|
|
_createdKinds.addAll(_pendingStatements.keys);
|
|
_createdKinds.addAll(_pendingDartTypes.keys);
|
|
_createdKinds.addAll(_pendingInitializers.keys);
|
|
_createdKinds.addAll(_pendingMembers.keys);
|
|
_createdKinds.addAll(_pendingNodes.keys);
|
|
}
|
|
|
|
/// The kinds created by this node creator.
|
|
Iterable<Object> get createdKinds => _createdKinds;
|
|
|
|
/// Wraps [statement] in nodes needed in the statement context.
|
|
///
|
|
/// For instance, if a [LabeledStatement] was needed for the creation of
|
|
/// [statement], [statement] is wrapped inside the labeled statement.
|
|
Statement _ensureContext(Statement statement) {
|
|
if (_neededSwitchCases.isNotEmpty) {
|
|
statement = SwitchStatement(NullLiteral(), [
|
|
..._neededSwitchCases,
|
|
SwitchCase([NullLiteral()], [TreeNode.noOffset], Block([statement]))
|
|
]);
|
|
}
|
|
_neededSwitchCases.clear();
|
|
for (LabeledStatement labeledStatement in _neededLabeledStatements) {
|
|
labeledStatement.body = statement;
|
|
statement = labeledStatement;
|
|
}
|
|
_neededLabeledStatements.clear();
|
|
statement = Block([
|
|
..._neededVariableDeclarations,
|
|
..._neededFunctionDeclarations,
|
|
statement
|
|
]);
|
|
_neededFunctionDeclarations.clear();
|
|
_neededVariableDeclarations.clear();
|
|
return statement;
|
|
}
|
|
|
|
/// Adds [statement] to [statements] including any nodes needed in the
|
|
/// context.
|
|
void _addStatement(List<Statement> statements, Statement statement) {
|
|
statements.add(_ensureContext(statement));
|
|
}
|
|
|
|
/// Adds [expression] to [statements] including any nodes needed in the
|
|
/// context.
|
|
void _addExpression(List<Statement> statements, Expression expression) {
|
|
_addStatement(statements, ExpressionStatement(expression));
|
|
}
|
|
|
|
/// Adds [type] to [statements] including any nodes needed in the context.
|
|
void _addDartType(List<Statement> statements, DartType type) {
|
|
_addExpression(statements, TypeLiteral(type));
|
|
}
|
|
|
|
/// Adds [constant] to [statements] including any nodes needed in the context.
|
|
void _addConstant(List<Statement> statements, Constant constant) {
|
|
_addExpression(statements, ConstantExpression(constant));
|
|
}
|
|
|
|
/// Adds [pattern] to [statements] including any nodes needed in the context.
|
|
void _addPattern(List<Statement> statements, Pattern pattern) {
|
|
_addExpression(statements, PatternAssignment(pattern, NullLiteral()));
|
|
}
|
|
|
|
/// Generates a list of [Statement] containing all pending in-body nodes.
|
|
List<Statement> _generateBodies() {
|
|
List<Statement> statements = [];
|
|
while (_pendingStatements.isNotEmpty) {
|
|
_addStatement(statements, _createStatement());
|
|
}
|
|
while (_pendingExpressions.isNotEmpty) {
|
|
_addExpression(statements, _createExpression());
|
|
}
|
|
while (_pendingDartTypes.isNotEmpty) {
|
|
_addDartType(statements, _createDartType());
|
|
}
|
|
while (_pendingConstants.isNotEmpty) {
|
|
_addConstant(statements, _createConstant());
|
|
}
|
|
for (NodeKind kind in inBodyNodeKinds) {
|
|
while (_pendingNodes.containsKey(kind)) {
|
|
Node node = _createNodeFromKind(kind);
|
|
switch (kind) {
|
|
case NodeKind.Name:
|
|
_addExpression(
|
|
statements,
|
|
DynamicGet(DynamicAccessKind.Dynamic, _createExpression(),
|
|
node as Name));
|
|
break;
|
|
case NodeKind.Arguments:
|
|
_addExpression(
|
|
statements,
|
|
DynamicInvocation(DynamicAccessKind.Dynamic,
|
|
_createExpression(), _createName(), node as Arguments));
|
|
break;
|
|
case NodeKind.Catch:
|
|
_addStatement(
|
|
statements, TryCatch(_createStatement(), [node as Catch]));
|
|
break;
|
|
case NodeKind.FunctionNode:
|
|
_addExpression(
|
|
statements, FunctionExpression(node as FunctionNode));
|
|
break;
|
|
case NodeKind.MapLiteralEntry:
|
|
_addExpression(statements, MapLiteral([node as MapLiteralEntry]));
|
|
break;
|
|
case NodeKind.MapPatternEntry:
|
|
_addPattern(
|
|
statements, MapPattern(null, null, [node as MapPatternEntry]));
|
|
break;
|
|
case NodeKind.MapPatternRestEntry:
|
|
_addPattern(statements,
|
|
MapPattern(null, null, [node as MapPatternRestEntry]));
|
|
break;
|
|
case NodeKind.NamedExpression:
|
|
_addExpression(
|
|
statements,
|
|
DynamicInvocation(
|
|
DynamicAccessKind.Dynamic,
|
|
_createExpression(),
|
|
_createName(),
|
|
Arguments([], named: [node as NamedExpression])));
|
|
break;
|
|
case NodeKind.NamedType:
|
|
_addDartType(
|
|
statements,
|
|
FunctionType([], _createDartType(), Nullability.nonNullable,
|
|
namedParameters: [node as NamedType]));
|
|
break;
|
|
case NodeKind.PatternSwitchCase:
|
|
_addStatement(
|
|
statements,
|
|
PatternSwitchStatement(
|
|
_createExpression(), [node as PatternSwitchCase]));
|
|
break;
|
|
case NodeKind.SwitchCase:
|
|
_addStatement(statements,
|
|
SwitchStatement(_createExpression(), [node as SwitchCase]));
|
|
break;
|
|
case NodeKind.SwitchExpressionCase:
|
|
_addExpression(
|
|
statements,
|
|
SwitchExpression(
|
|
_createExpression(), [node as SwitchExpressionCase]));
|
|
break;
|
|
case NodeKind.TypeParameter:
|
|
_addExpression(
|
|
statements,
|
|
FunctionExpression(FunctionNode(Block([]),
|
|
typeParameters: [node as TypeParameter])));
|
|
break;
|
|
default:
|
|
throw new UnimplementedError('Unhandled in body node $kind.');
|
|
}
|
|
}
|
|
}
|
|
return statements;
|
|
}
|
|
|
|
/// Generates [Statement]s containing occurrences of all requested nodes.
|
|
List<Statement> generateBodies() {
|
|
List<Statement> statements = _generateBodies();
|
|
Set<Object> unsupportedKinds = {};
|
|
if (_pendingInitializers.isNotEmpty) {
|
|
unsupportedKinds.addAll(_pendingInitializers.keys);
|
|
}
|
|
if (_pendingMembers.isNotEmpty) {
|
|
unsupportedKinds.addAll(_pendingMembers.keys);
|
|
}
|
|
if (_pendingNodes.isNotEmpty) {
|
|
assert(
|
|
_pendingNodes.keys.every((kind) => !inBodyNodeKinds.contains(kind)));
|
|
unsupportedKinds.addAll(_pendingNodes.keys);
|
|
}
|
|
if (unsupportedKinds.isNotEmpty) {
|
|
throw new UnsupportedError('Cannot create these node in a body context: '
|
|
'${unsupportedKinds.join(', ')}');
|
|
}
|
|
return statements;
|
|
}
|
|
|
|
/// Generates a [Component] containing occurrences of all requested and needed
|
|
/// nodes.
|
|
Component generateComponent() {
|
|
Class cls = _needClass();
|
|
for (Statement statement in _generateBodies()) {
|
|
cls.addProcedure(Procedure(
|
|
_createName(), ProcedureKind.Method, FunctionNode(statement),
|
|
fileUri: _uri));
|
|
}
|
|
while (_pendingInitializers.isNotEmpty) {
|
|
Initializer initializer = _createInitializer();
|
|
cls.addConstructor(Constructor(FunctionNode(null),
|
|
name: _createName(), fileUri: _uri, initializers: [initializer]));
|
|
}
|
|
while (_pendingMembers.isNotEmpty) {
|
|
Member member = _createMember();
|
|
if (member is Procedure) {
|
|
cls.addProcedure(member);
|
|
} else if (member is Field) {
|
|
cls.addField(member);
|
|
} else if (member is Constructor) {
|
|
cls.addConstructor(member);
|
|
} else {
|
|
throw new UnsupportedError(
|
|
'Unexpected member $member (${member.runtimeType})');
|
|
}
|
|
}
|
|
while (_pendingNodes.isNotEmpty) {
|
|
NodeKind kind = _pendingNodes.keys.first;
|
|
Node node = _createNodeFromKind(kind);
|
|
switch (kind) {
|
|
case NodeKind.Name:
|
|
case NodeKind.Arguments:
|
|
case NodeKind.Catch:
|
|
case NodeKind.FunctionNode:
|
|
case NodeKind.MapLiteralEntry:
|
|
case NodeKind.NamedExpression:
|
|
case NodeKind.NamedType:
|
|
case NodeKind.SwitchCase:
|
|
case NodeKind.TypeParameter:
|
|
case NodeKind.StructuralParameter:
|
|
case NodeKind.MapPatternEntry:
|
|
case NodeKind.MapPatternRestEntry:
|
|
case NodeKind.PatternGuard:
|
|
case NodeKind.PatternSwitchCase:
|
|
case NodeKind.SwitchExpressionCase:
|
|
throw new UnimplementedError('Expected in body node $kind.');
|
|
case NodeKind.Class:
|
|
_needLibrary().addClass(node as Class);
|
|
break;
|
|
case NodeKind.Combinator:
|
|
_needLibrary().addDependency(LibraryDependency.import(_needLibrary(),
|
|
combinators: [node as Combinator]));
|
|
break;
|
|
case NodeKind.Component:
|
|
assert(identical(node, _component),
|
|
"Cannot create multiple Component nodes.");
|
|
break;
|
|
case NodeKind.Extension:
|
|
_needLibrary().addExtension(node as Extension);
|
|
break;
|
|
case NodeKind.Library:
|
|
_component.libraries.add(node as Library);
|
|
break;
|
|
case NodeKind.LibraryDependency:
|
|
_needLibrary().addDependency(node as LibraryDependency);
|
|
break;
|
|
case NodeKind.LibraryPart:
|
|
_needLibrary().addPart(node as LibraryPart);
|
|
break;
|
|
case NodeKind.Supertype:
|
|
_needLibrary().addClass(
|
|
Class(name: 'foo', fileUri: _uri, supertype: node as Supertype));
|
|
break;
|
|
case NodeKind.Typedef:
|
|
_needLibrary().addTypedef(node as Typedef);
|
|
break;
|
|
case NodeKind.ExtensionTypeDeclaration:
|
|
_needLibrary()
|
|
.addExtensionTypeDeclaration(node as ExtensionTypeDeclaration);
|
|
break;
|
|
}
|
|
}
|
|
return _component;
|
|
}
|
|
|
|
/// Returns a [Library] node that fits the requirements.
|
|
///
|
|
/// If no such [Library] exists in [_neededLibraries], a new [Library] is
|
|
/// created and added to [_neededLibraries].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
Library _needLibrary() {
|
|
for (Library library in _neededLibraries) {
|
|
return library;
|
|
}
|
|
Library library = Library(_uri, fileUri: _uri);
|
|
_neededLibraries.add(library);
|
|
_component.libraries.add(library);
|
|
return library;
|
|
}
|
|
|
|
/// Returns a [LibraryDependency] node that fits the requirements.
|
|
///
|
|
/// If no such [LibraryDependency] exists in [_neededLibraryDependencies], a
|
|
/// new [LibraryDependency] is created and added to
|
|
/// [_neededLibraryDependencies].
|
|
LibraryDependency _needLibraryDependency({bool deferred = false}) {
|
|
for (LibraryDependency libraryDependency in _neededLibraryDependencies) {
|
|
if (!deferred || libraryDependency.isDeferred) {
|
|
return libraryDependency;
|
|
}
|
|
}
|
|
LibraryDependency libraryDependency = deferred
|
|
? LibraryDependency.deferredImport(_needLibrary(), 'foo')
|
|
: LibraryDependency.import(_needLibrary());
|
|
_neededLibraryDependencies.add(libraryDependency);
|
|
return libraryDependency;
|
|
}
|
|
|
|
/// Returns a [Class] node that fits the requirements.
|
|
///
|
|
/// If no such [Class] exists in [_neededClasses], a new [Class] is
|
|
/// created and added to [_neededClasses].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
Class _needClass() {
|
|
for (Class cls in _neededClasses) {
|
|
return cls;
|
|
}
|
|
Class cls = Class(name: 'Foo', fileUri: _uri);
|
|
_neededClasses.add(cls);
|
|
_needLibrary().addClass(cls);
|
|
return cls;
|
|
}
|
|
|
|
/// Returns an [ExtensionTypeDeclaration] node that fits the requirements.
|
|
///
|
|
/// If no such [ExtensionTypeDeclaration] exists in
|
|
/// [_neededExtensionTypeDeclarations], a new [ExtensionTypeDeclaration] is
|
|
/// created and added to [_neededExtensionTypeDeclarations].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
ExtensionTypeDeclaration _needExtensionTypeDeclaration() {
|
|
for (ExtensionTypeDeclaration extensionTypeDeclaration
|
|
in _neededExtensionTypeDeclarations) {
|
|
return extensionTypeDeclaration;
|
|
}
|
|
ExtensionTypeDeclaration extensionTypeDeclaration =
|
|
ExtensionTypeDeclaration(
|
|
name: 'foo',
|
|
fileUri: _uri,
|
|
declaredRepresentationType: const DynamicType());
|
|
_neededExtensionTypeDeclarations.add(extensionTypeDeclaration);
|
|
_needLibrary().addExtensionTypeDeclaration(extensionTypeDeclaration);
|
|
return extensionTypeDeclaration;
|
|
}
|
|
|
|
/// Returns a [Typedef] node that fits the requirements.
|
|
///
|
|
/// If no such [Typedef] exists in [_neededTypedefs], a new [Typedef] is
|
|
/// created and added to [_neededTypedefs].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
Typedef _needTypedef() {
|
|
for (Typedef typedef in _neededTypedefs) {
|
|
return typedef;
|
|
}
|
|
Typedef typedef = Typedef('foo', DynamicType(), fileUri: _uri);
|
|
_neededTypedefs.add(typedef);
|
|
_needLibrary().addTypedef(typedef);
|
|
return typedef;
|
|
}
|
|
|
|
/// Returns a [TypeParameter] node that fits the requirements.
|
|
///
|
|
/// If no such [TypeParameter] exists in [_neededTypeParameters], a new
|
|
/// [TypeParameter] is created and added to [_neededTypeParameters].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
TypeParameter _needTypeParameter() {
|
|
for (TypeParameter typeParameter in _neededTypeParameters) {
|
|
return typeParameter;
|
|
}
|
|
TypeParameter typeParameter =
|
|
TypeParameter('foo', DynamicType(), DynamicType());
|
|
_neededTypeParameters.add(typeParameter);
|
|
// TODO(johnniwinther): Add the type parameter to a context; class, method
|
|
// or function type.
|
|
return typeParameter;
|
|
}
|
|
|
|
/// Returns a [StructuralParameter] node that fits the requirements.
|
|
///
|
|
/// If no such [StructuralParameter] exists in
|
|
/// [_neededStructuralParameters], a new [StructuralParameter] is
|
|
/// created and added to [_neededStructuralParameters].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
StructuralParameter _needStructuralParameter() {
|
|
for (StructuralParameter typeParameter in _neededStructuralParameters) {
|
|
return typeParameter;
|
|
}
|
|
StructuralParameter functionTypeTypeParameter =
|
|
StructuralParameter('foo', DynamicType(), DynamicType());
|
|
_neededStructuralParameters.add(functionTypeTypeParameter);
|
|
// TODO(johnniwinther): Add the type parameter to a context, that is,
|
|
// function type.
|
|
return functionTypeTypeParameter;
|
|
}
|
|
|
|
/// Returns a [Procedure] node that fits the requirements.
|
|
///
|
|
/// If no such [Procedure] exists in [_neededProcedures], a new [Library] is
|
|
/// created and added to [_neededProcedures].
|
|
///
|
|
/// [index] is used to create multiple distinct [Procedure] nodes even when
|
|
/// these have the same requirements.
|
|
Procedure _needProcedure({int? index, bool? isStatic}) {
|
|
for (Procedure procedure in _neededProcedures) {
|
|
if (isStatic == null || isStatic == procedure.isStatic) {
|
|
if (index == null || index == 0) {
|
|
return procedure;
|
|
} else {
|
|
index--;
|
|
}
|
|
}
|
|
}
|
|
isStatic ??= true;
|
|
Procedure procedure = Procedure(
|
|
Name('foo'), ProcedureKind.Method, FunctionNode(Block([])),
|
|
fileUri: _uri, isStatic: isStatic);
|
|
_neededProcedures.add(procedure);
|
|
if (isStatic) {
|
|
_needLibrary().addProcedure(procedure);
|
|
} else {
|
|
_needClass().addProcedure(procedure);
|
|
}
|
|
return procedure;
|
|
}
|
|
|
|
/// Returns a [Constructor] node that fits the requirements.
|
|
///
|
|
/// If no such [Constructor] exists in [_neededConstructors], a new
|
|
/// [Constructor] is created and added to [_neededConstructors].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
Constructor _needConstructor() {
|
|
for (Constructor constructor in _neededConstructors) {
|
|
return constructor;
|
|
}
|
|
Constructor constructor =
|
|
Constructor(FunctionNode(null), name: Name('foo'), fileUri: _uri);
|
|
_needClass().addConstructor(constructor);
|
|
return constructor;
|
|
}
|
|
|
|
/// Returns a redirecting factory [Procedure] node that fits the requirements.
|
|
///
|
|
/// If no such [Library] exists in [_neededRedirectingFactories], a new
|
|
/// [Procedure] is created and added to [_neededRedirectingFactories].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
Procedure _needRedirectingFactory() {
|
|
for (Procedure redirectingFactory in _neededRedirectingFactories) {
|
|
return redirectingFactory;
|
|
}
|
|
Procedure redirectingFactory = Procedure(
|
|
Name('foo'),
|
|
ProcedureKind.Method,
|
|
FunctionNode(null)
|
|
..redirectingFactoryTarget =
|
|
new RedirectingFactoryTarget(_needConstructor(), []),
|
|
fileUri: _uri);
|
|
_needClass().addProcedure(redirectingFactory);
|
|
return redirectingFactory;
|
|
}
|
|
|
|
/// Returns a [Field] node that fits the requirements.
|
|
///
|
|
/// If no such [Field] exists in [_neededFields], a new [Field] is
|
|
/// created and added to [_neededFields].
|
|
///
|
|
/// [index] is used to create multiple distinct [Field] nodes even when
|
|
/// these have the same requirements.
|
|
Field _needField({int? index, bool? isStatic, bool? hasSetter}) {
|
|
for (Field field in _neededFields) {
|
|
if (isStatic == null ||
|
|
isStatic == field.isStatic && hasSetter == null ||
|
|
hasSetter == field.hasSetter) {
|
|
if (index == null || index == 0) {
|
|
return field;
|
|
} else {
|
|
index--;
|
|
}
|
|
}
|
|
}
|
|
hasSetter ??= false;
|
|
isStatic ??= true;
|
|
Field field = hasSetter
|
|
? new Field.immutable(Name('foo'), fileUri: _uri, isStatic: isStatic)
|
|
: new Field.mutable(Name('foo'), fileUri: _uri, isStatic: isStatic);
|
|
_neededFields.add(field);
|
|
if (isStatic) {
|
|
_needLibrary().addField(field);
|
|
} else {
|
|
_needClass().addField(field);
|
|
}
|
|
return field;
|
|
}
|
|
|
|
/// Returns a [VariableDeclaration] node that fits the requirements.
|
|
///
|
|
/// If no such [VariableDeclaration] exists in [_neededVariableDeclarations],
|
|
/// a new [VariableDeclaration] is created and added to
|
|
/// [_neededVariableDeclarations].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
VariableDeclaration _needVariableDeclaration() {
|
|
for (VariableDeclaration variableDeclaration
|
|
in _neededVariableDeclarations) {
|
|
return variableDeclaration;
|
|
}
|
|
VariableDeclaration variableDeclaration = VariableDeclaration('foo');
|
|
_neededVariableDeclarations.add(variableDeclaration);
|
|
return variableDeclaration;
|
|
}
|
|
|
|
/// Returns a [LabeledStatement] node that fits the requirements.
|
|
///
|
|
/// If no such [LabeledStatement] exists in [_neededLabeledStatements], a new
|
|
/// [LabeledStatement] is created and added to [_neededLabeledStatements].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
LabeledStatement _needLabeledStatement() {
|
|
for (LabeledStatement labeledStatement in _neededLabeledStatements) {
|
|
return labeledStatement;
|
|
}
|
|
LabeledStatement labeledStatement = LabeledStatement(null);
|
|
_neededLabeledStatements.add(labeledStatement);
|
|
return labeledStatement;
|
|
}
|
|
|
|
/// Returns a [SwitchCase] node that fits the requirements.
|
|
///
|
|
/// If no such [SwitchCase] exists in [_neededSwitchCases], a new [SwitchCase]
|
|
/// is created and added to [_neededSwitchCases].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
SwitchCase _needSwitchCase() {
|
|
for (SwitchCase switchCase in _neededSwitchCases) {
|
|
return switchCase;
|
|
}
|
|
SwitchCase switchCase =
|
|
SwitchCase([NullLiteral()], [TreeNode.noOffset], EmptyStatement());
|
|
_neededSwitchCases.add(switchCase);
|
|
return switchCase;
|
|
}
|
|
|
|
/// Returns a [FunctionDeclaration] node that fits the requirements.
|
|
///
|
|
/// If no such [FunctionDeclaration] exists in [_neededFunctionDeclarations],
|
|
/// a new [FunctionDeclaration] is created and added to
|
|
/// [_neededFunctionDeclarations].
|
|
// TODO(johnniwinther): Add requirements when/where needed.
|
|
FunctionDeclaration _needFunctionDeclaration() {
|
|
for (FunctionDeclaration functionDeclaration
|
|
in _neededFunctionDeclarations) {
|
|
return functionDeclaration;
|
|
}
|
|
FunctionDeclaration functionDeclaration = FunctionDeclaration(
|
|
VariableDeclaration('foo'), FunctionNode(Block([])));
|
|
_neededFunctionDeclarations.add(functionDeclaration);
|
|
return functionDeclaration;
|
|
}
|
|
|
|
/// Returns a fresh file offset value.
|
|
int _needFileOffset() => _fileOffset++;
|
|
|
|
/// Creates an [Expression] node.
|
|
///
|
|
/// If there are any pending expressions, one of these is created.
|
|
Expression _createExpression() {
|
|
if (_pendingExpressions.isEmpty) {
|
|
return NullLiteral()..fileOffset = _needFileOffset();
|
|
}
|
|
ExpressionKind kind = _pendingExpressions.keys.first;
|
|
return _createExpressionFromKind(kind);
|
|
}
|
|
|
|
/// Creates an [Expression] node of the specified [kind].
|
|
///
|
|
/// If there are any pending expressions of this [kind], one of these is
|
|
/// created.
|
|
Expression _createExpressionFromKind(ExpressionKind kind) {
|
|
int? index = _pendingExpressions.remove(kind);
|
|
switch (kind) {
|
|
case ExpressionKind.AsExpression:
|
|
return AsExpression(_createExpression(), _createDartType())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.AwaitExpression:
|
|
return AwaitExpression(_createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.BlockExpression:
|
|
return BlockExpression(
|
|
_createStatementFromKind(StatementKind.Block) as Block,
|
|
_createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.BoolLiteral:
|
|
return BoolLiteral(true)..fileOffset = _needFileOffset();
|
|
case ExpressionKind.CheckLibraryIsLoaded:
|
|
return CheckLibraryIsLoaded(_needLibraryDependency(deferred: true))
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.ConditionalExpression:
|
|
return ConditionalExpression(_createExpression(), _createExpression(),
|
|
_createExpression(), _createDartType())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.ConstantExpression:
|
|
return ConstantExpression(_createConstant(), _createDartType())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.ConstructorInvocation:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => ConstructorInvocation(_needConstructor(), _createArguments(),
|
|
isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => ConstructorInvocation(_needConstructor(), _createArguments(),
|
|
isConst: true)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.ConstructorTearOff:
|
|
return ConstructorTearOff(_needConstructor())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.DoubleLiteral:
|
|
return DoubleLiteral(42.5)..fileOffset = _needFileOffset();
|
|
case ExpressionKind.DynamicGet:
|
|
return DynamicGet(
|
|
DynamicAccessKind.Dynamic, _createExpression(), _createName())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.DynamicInvocation:
|
|
return DynamicInvocation(DynamicAccessKind.Dynamic, _createExpression(),
|
|
_createName(), _createArguments())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.DynamicSet:
|
|
return DynamicSet(DynamicAccessKind.Dynamic, _createExpression(),
|
|
_createName(), _createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.EqualsCall:
|
|
return EqualsCall(_createExpression(), _createExpression(),
|
|
functionType: _createFunctionType(),
|
|
interfaceTarget: _needProcedure())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.EqualsNull:
|
|
return EqualsNull(_createExpression())..fileOffset = _needFileOffset();
|
|
case ExpressionKind.FileUriExpression:
|
|
return FileUriExpression(_createExpression(), _uri)
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.FunctionExpression:
|
|
return FunctionExpression(_createFunctionNode())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.FunctionInvocation:
|
|
return FunctionInvocation(FunctionAccessKind.FunctionType,
|
|
_createExpression(), _createArguments(),
|
|
functionType: _createFunctionType())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.FunctionTearOff:
|
|
return FunctionTearOff(_createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.InstanceCreation:
|
|
return InstanceCreation(_needClass().reference, [], {}, [], [])
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.InstanceGet:
|
|
return InstanceGet(
|
|
InstanceAccessKind.Instance, _createExpression(), _createName(),
|
|
interfaceTarget: _needField(), resultType: _createDartType())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.InstanceGetterInvocation:
|
|
return InstanceGetterInvocation(InstanceAccessKind.Instance,
|
|
_createExpression(), _createName(), _createArguments(),
|
|
interfaceTarget: _needField(), functionType: _createFunctionType())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.InstanceInvocation:
|
|
return InstanceInvocation(InstanceAccessKind.Instance,
|
|
_createExpression(), _createName(), _createArguments(),
|
|
interfaceTarget: _needProcedure(),
|
|
functionType: _createFunctionType())
|
|
..fileOffset = _needFileOffset()
|
|
..isBoundsSafe = true;
|
|
case ExpressionKind.InstanceSet:
|
|
return InstanceSet(InstanceAccessKind.Instance, _createExpression(),
|
|
_createName(), _createExpression(),
|
|
interfaceTarget: _needField())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.InstanceTearOff:
|
|
return InstanceTearOff(
|
|
InstanceAccessKind.Instance, _createExpression(), _createName(),
|
|
interfaceTarget: _needProcedure(), resultType: _createDartType())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.Instantiation:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => Instantiation(_createExpression(), [])
|
|
..fileOffset = _needFileOffset(),
|
|
() => Instantiation(_createExpression(), [_createDartType()])
|
|
..fileOffset = _needFileOffset(),
|
|
() => Instantiation(
|
|
_createExpression(), [_createDartType(), _createDartType()])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.IntLiteral:
|
|
return IntLiteral(42)..fileOffset = _needFileOffset();
|
|
case ExpressionKind.InvalidExpression:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => InvalidExpression(null)..fileOffset = _needFileOffset(),
|
|
() => InvalidExpression('foo')..fileOffset = _needFileOffset(),
|
|
() => InvalidExpression('foo', _createExpression())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.IsExpression:
|
|
return IsExpression(
|
|
_createExpression(),
|
|
_createDartType(),
|
|
)..fileOffset = _needFileOffset();
|
|
case ExpressionKind.Let:
|
|
return Let(
|
|
_createStatementFromKind(StatementKind.VariableDeclaration)
|
|
as VariableDeclaration,
|
|
_createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.ListConcatenation:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => ListConcatenation([], typeArgument: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
() => ListConcatenation([_createExpression()],
|
|
typeArgument: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
() => ListConcatenation([_createExpression(), _createExpression()],
|
|
typeArgument: _createDartType())
|
|
..fileOffset = _needFileOffset()
|
|
]);
|
|
case ExpressionKind.ListLiteral:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => ListLiteral([], typeArgument: _createDartType(), isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => ListLiteral([_createExpression()],
|
|
typeArgument: _createDartType(), isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => ListLiteral([_createExpression(), _createExpression()],
|
|
typeArgument: _createDartType(), isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => ListLiteral([_createExpression(), _createExpression()],
|
|
typeArgument: _createDartType(), isConst: true)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.LoadLibrary:
|
|
return LoadLibrary(_needLibraryDependency(deferred: true))
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.LocalFunctionInvocation:
|
|
return LocalFunctionInvocation(
|
|
_needFunctionDeclaration().variable, _createArguments(),
|
|
functionType: _createFunctionType())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.LogicalExpression:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => LogicalExpression(_createExpression(),
|
|
LogicalExpressionOperator.AND, _createExpression())
|
|
..fileOffset = _needFileOffset(),
|
|
() => LogicalExpression(_createExpression(),
|
|
LogicalExpressionOperator.OR, _createExpression())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.MapConcatenation:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => MapConcatenation([],
|
|
keyType: _createDartType(), valueType: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
() => MapConcatenation([_createExpression()],
|
|
keyType: _createDartType(), valueType: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
() => MapConcatenation([_createExpression(), _createExpression()],
|
|
keyType: _createDartType(), valueType: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.MapLiteral:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => MapLiteral([],
|
|
keyType: _createDartType(),
|
|
valueType: _createDartType(),
|
|
isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => MapLiteral([_createMapLiteralEntry()],
|
|
keyType: _createDartType(),
|
|
valueType: _createDartType(),
|
|
isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => MapLiteral([
|
|
_createMapLiteralEntry(),
|
|
_createMapLiteralEntry(),
|
|
],
|
|
keyType: _createDartType(),
|
|
valueType: _createDartType(),
|
|
isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => MapLiteral([
|
|
_createMapLiteralEntry(),
|
|
_createMapLiteralEntry(),
|
|
],
|
|
keyType: _createDartType(),
|
|
valueType: _createDartType(),
|
|
isConst: true)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.Not:
|
|
return Not(_createExpression())..fileOffset = _needFileOffset();
|
|
case ExpressionKind.NullCheck:
|
|
return NullCheck(_createExpression())..fileOffset = _needFileOffset();
|
|
case ExpressionKind.NullLiteral:
|
|
return NullLiteral();
|
|
case ExpressionKind.RedirectingFactoryTearOff:
|
|
return RedirectingFactoryTearOff(_needRedirectingFactory())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.Rethrow:
|
|
return Rethrow()..fileOffset = _needFileOffset();
|
|
case ExpressionKind.SetConcatenation:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => SetConcatenation([], typeArgument: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
() => SetConcatenation([_createExpression()],
|
|
typeArgument: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
() => SetConcatenation([_createExpression(), _createExpression()],
|
|
typeArgument: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.SetLiteral:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => SetLiteral([], typeArgument: _createDartType(), isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => SetLiteral([_createExpression()],
|
|
typeArgument: _createDartType(), isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => SetLiteral([_createExpression(), _createExpression()],
|
|
typeArgument: _createDartType(), isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => SetLiteral([_createExpression(), _createExpression()],
|
|
typeArgument: _createDartType(), isConst: true)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.StaticGet:
|
|
return StaticGet(_needField())..fileOffset = _needFileOffset();
|
|
case ExpressionKind.StaticInvocation:
|
|
return StaticInvocation(_needProcedure(), _createArguments())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.StaticSet:
|
|
return StaticSet(_needField(), _createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.StaticTearOff:
|
|
return StaticTearOff(_needProcedure())..fileOffset = _needFileOffset();
|
|
case ExpressionKind.StringConcatenation:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => StringConcatenation([])..fileOffset = _needFileOffset(),
|
|
() => StringConcatenation([_createExpression()])
|
|
..fileOffset = _needFileOffset(),
|
|
() => StringConcatenation([_createExpression(), _createExpression()])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.StringLiteral:
|
|
return StringLiteral('foo');
|
|
case ExpressionKind.AbstractSuperMethodInvocation:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => AbstractSuperMethodInvocation(
|
|
_createName(), _createArguments(), _needProcedure())
|
|
..fileOffset = _needFileOffset(),
|
|
() => AbstractSuperMethodInvocation(
|
|
_createName(), _createArguments(), _needProcedure())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.SuperMethodInvocation:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => SuperMethodInvocation(
|
|
_createName(), _createArguments(), _needProcedure())
|
|
..fileOffset = _needFileOffset(),
|
|
() => SuperMethodInvocation(
|
|
_createName(), _createArguments(), _needProcedure())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.AbstractSuperPropertyGet:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => AbstractSuperPropertyGet(_createName(), _needProcedure())
|
|
..fileOffset = _needFileOffset(),
|
|
() => AbstractSuperPropertyGet(_createName(), _needField())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.AbstractSuperPropertySet:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => AbstractSuperPropertySet(
|
|
_createName(), _createExpression(), _needProcedure())
|
|
..fileOffset = _needFileOffset(),
|
|
() => AbstractSuperPropertySet(
|
|
_createName(), _createExpression(), _needField())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.SuperPropertyGet:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => SuperPropertyGet(_createName(), _needProcedure())
|
|
..fileOffset = _needFileOffset(),
|
|
() => SuperPropertyGet(_createName(), _needField())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.SuperPropertySet:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => SuperPropertySet(
|
|
_createName(), _createExpression(), _needProcedure())
|
|
..fileOffset = _needFileOffset(),
|
|
() =>
|
|
SuperPropertySet(_createName(), _createExpression(), _needField())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.SymbolLiteral:
|
|
return SymbolLiteral('foo')..fileOffset = _needFileOffset();
|
|
case ExpressionKind.ThisExpression:
|
|
return ThisExpression()..fileOffset = _needFileOffset();
|
|
case ExpressionKind.Throw:
|
|
return Throw(_createExpression())..fileOffset = _needFileOffset();
|
|
case ExpressionKind.TypeLiteral:
|
|
return TypeLiteral(_createDartType())..fileOffset = _needFileOffset();
|
|
case ExpressionKind.TypedefTearOff:
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
return TypedefTearOff([], _createExpression(), [])
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.VariableGet:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => VariableGet(_needVariableDeclaration())
|
|
..fileOffset = _needFileOffset(),
|
|
() => VariableGet(_needVariableDeclaration(), _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.VariableSet:
|
|
return VariableSet(_needVariableDeclaration(), _createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.RecordIndexGet:
|
|
return RecordIndexGet(_createExpression(),
|
|
new RecordType([_createDartType()], [], Nullability.nonNullable), 0)
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.RecordNameGet:
|
|
String name = _createName().text;
|
|
return RecordNameGet(
|
|
_createExpression(),
|
|
new RecordType([], [new NamedType(name, _createDartType())],
|
|
Nullability.nonNullable),
|
|
name)
|
|
..fileOffset = _needFileOffset();
|
|
case ExpressionKind.RecordLiteral:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => RecordLiteral([_createExpression()], [],
|
|
RecordType([_createDartType()], [], Nullability.nonNullable),
|
|
isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => RecordLiteral(
|
|
[],
|
|
[NamedExpression('foo', _createExpression())],
|
|
RecordType([], [NamedType('foo', _createDartType())],
|
|
Nullability.nonNullable),
|
|
isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => RecordLiteral(
|
|
[_createExpression()],
|
|
[NamedExpression('foo', _createExpression())],
|
|
RecordType(
|
|
[_createDartType()],
|
|
[NamedType('foo', _createDartType())],
|
|
Nullability.nonNullable),
|
|
isConst: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => RecordLiteral([_createExpression()], [],
|
|
RecordType([_createDartType()], [], Nullability.nonNullable),
|
|
isConst: true)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.SwitchExpression:
|
|
return _createOneOf(_pendingExpressions, kind, index, [
|
|
() => new SwitchExpression(_createExpression(), [])
|
|
..fileOffset = _needFileOffset(),
|
|
() => new SwitchExpression(_createExpression(), [
|
|
_createNodeFromKind(NodeKind.SwitchExpressionCase)
|
|
as SwitchExpressionCase
|
|
])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case ExpressionKind.PatternAssignment:
|
|
return new PatternAssignment(_createPattern(), _createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
}
|
|
}
|
|
|
|
/// Creates an [Pattern] node.
|
|
///
|
|
/// If there are any pending expressions, one of these is created.
|
|
Pattern _createPattern() {
|
|
if (_pendingPatterns.isEmpty) {
|
|
return ConstantPattern(NullLiteral()..fileOffset = _needFileOffset())
|
|
..fileOffset = _needFileOffset();
|
|
}
|
|
PatternKind kind = _pendingPatterns.keys.first;
|
|
return _createPatternFromKind(kind);
|
|
}
|
|
|
|
/// Creates an [Expression] node of the specified [kind].
|
|
///
|
|
/// If there are any pending expressions of this [kind], one of these is
|
|
/// created.
|
|
Pattern _createPatternFromKind(PatternKind kind) {
|
|
int? index = _pendingPatterns.remove(kind);
|
|
switch (kind) {
|
|
case PatternKind.AndPattern:
|
|
return AndPattern(_createPattern(), _createPattern())
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.AssignedVariablePattern:
|
|
return AssignedVariablePattern(_needVariableDeclaration())
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.CastPattern:
|
|
return CastPattern(_createPattern(), _createDartType())
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.ConstantPattern:
|
|
return ConstantPattern(_createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.NullAssertPattern:
|
|
return NullAssertPattern(_createPattern())
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.NullCheckPattern:
|
|
return NullCheckPattern(_createPattern())
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.InvalidPattern:
|
|
return InvalidPattern(_createExpression(), declaredVariables: [])
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.ListPattern:
|
|
return _createOneOf(_pendingPatterns, kind, index, [
|
|
() => ListPattern(null, [])..fileOffset = _needFileOffset(),
|
|
() => ListPattern(_createDartType(), [_createPattern()])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case PatternKind.MapPattern:
|
|
return _createOneOf(_pendingPatterns, kind, index, [
|
|
() => MapPattern(null, null, []),
|
|
() => MapPattern(_createDartType(), _createDartType(), [
|
|
_createNodeFromKind(NodeKind.MapPatternEntry) as MapPatternEntry
|
|
])
|
|
..fileOffset = _needFileOffset(),
|
|
() => MapPattern(_createDartType(), _createDartType(), [
|
|
_createNodeFromKind(NodeKind.MapPatternEntry)
|
|
as MapPatternEntry,
|
|
_createNodeFromKind(NodeKind.MapPatternRestEntry)
|
|
as MapPatternEntry
|
|
])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case PatternKind.NamedPattern:
|
|
return NamedPattern('foo', _createPattern())
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.ObjectPattern:
|
|
return _createOneOf(_pendingPatterns, kind, index, [
|
|
() => ObjectPattern(_createDartType(), [])
|
|
..fileOffset = _needFileOffset(),
|
|
() => ObjectPattern(_createDartType(), [
|
|
_createPatternFromKind(PatternKind.NamedPattern) as NamedPattern
|
|
])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case PatternKind.OrPattern:
|
|
return OrPattern(_createPattern(), _createPattern(),
|
|
orPatternJointVariables: [])
|
|
..fileOffset = _needFileOffset();
|
|
case PatternKind.RecordPattern:
|
|
return _createOneOf(_pendingPatterns, kind, index, [
|
|
() => RecordPattern([])..fileOffset = _needFileOffset(),
|
|
() =>
|
|
RecordPattern([_createPattern()])..fileOffset = _needFileOffset(),
|
|
]);
|
|
case PatternKind.RelationalPattern:
|
|
return _createOneOf(_pendingPatterns, kind, index, [
|
|
() => RelationalPattern(
|
|
RelationalPatternKind.equals, _createExpression())
|
|
..fileOffset = _needFileOffset(),
|
|
() => RelationalPattern(
|
|
RelationalPatternKind.lessThan, _createExpression())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case PatternKind.RestPattern:
|
|
return _createOneOf(_pendingPatterns, kind, index, [
|
|
() => RestPattern(null)..fileOffset = _needFileOffset(),
|
|
() => RestPattern(_createPattern())..fileOffset = _needFileOffset(),
|
|
]);
|
|
case PatternKind.VariablePattern:
|
|
return _createOneOf(_pendingPatterns, kind, index, [
|
|
() => VariablePattern(null, _createVariableDeclaration())
|
|
..fileOffset = _needFileOffset(),
|
|
() => VariablePattern(_createDartType(), _createVariableDeclaration())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case PatternKind.WildcardPattern:
|
|
return _createOneOf(_pendingPatterns, kind, index, [
|
|
() => WildcardPattern(null)..fileOffset = _needFileOffset(),
|
|
() => WildcardPattern(_createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/// Creates a [Statement] node.
|
|
///
|
|
/// If there are any pending statements, one of these is created.
|
|
Statement _createStatement() {
|
|
if (_pendingStatements.isEmpty) {
|
|
return EmptyStatement()..fileOffset = _needFileOffset();
|
|
}
|
|
StatementKind kind = _pendingStatements.keys.first;
|
|
return _createStatementFromKind(kind);
|
|
}
|
|
|
|
/// Creates a [Statement] of the specified [kind].
|
|
///
|
|
/// If there are any pending statements of this [kind], one of these is
|
|
/// created.
|
|
Statement _createStatementFromKind(StatementKind kind) {
|
|
int? index = _pendingStatements.remove(kind);
|
|
switch (kind) {
|
|
case StatementKind.AssertBlock:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => AssertBlock([])..fileOffset = _needFileOffset(),
|
|
() =>
|
|
AssertBlock([_createStatement()])..fileOffset = _needFileOffset(),
|
|
() => AssertBlock([_createStatement(), _createStatement()])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.AssertStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => AssertStatement(_createExpression(),
|
|
conditionStartOffset: _needFileOffset(),
|
|
conditionEndOffset: _needFileOffset())
|
|
..fileOffset = _needFileOffset(),
|
|
() => AssertStatement(_createExpression(),
|
|
message: _createExpression(),
|
|
conditionStartOffset: _needFileOffset(),
|
|
conditionEndOffset: _needFileOffset())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.Block:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => Block([])..fileOffset = _needFileOffset(),
|
|
() => Block([_createStatement()])..fileOffset = _needFileOffset(),
|
|
() => Block([_createStatement(), _createStatement()])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.BreakStatement:
|
|
return BreakStatement(_needLabeledStatement())
|
|
..fileOffset = _needFileOffset();
|
|
case StatementKind.ContinueSwitchStatement:
|
|
return ContinueSwitchStatement(_needSwitchCase())
|
|
..fileOffset = _needFileOffset();
|
|
case StatementKind.DoStatement:
|
|
return DoStatement(_createStatement(), _createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case StatementKind.EmptyStatement:
|
|
return EmptyStatement()..fileOffset = _needFileOffset();
|
|
case StatementKind.ExpressionStatement:
|
|
return ExpressionStatement(_createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case StatementKind.ForInStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => ForInStatement(_createVariableDeclaration(),
|
|
_createExpression(), _createStatement(),
|
|
isAsync: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => ForInStatement(_createVariableDeclaration(),
|
|
_createExpression(), _createStatement(),
|
|
isAsync: true)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.ForStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => ForStatement([], null, [], _createStatement())
|
|
..fileOffset = _needFileOffset(),
|
|
() => ForStatement([_createVariableDeclaration()],
|
|
_createExpression(), [_createExpression()], _createStatement())
|
|
..fileOffset = _needFileOffset(),
|
|
() => ForStatement(
|
|
[_createVariableDeclaration(), _createVariableDeclaration()],
|
|
_createExpression(),
|
|
[_createExpression(), _createExpression()],
|
|
_createStatement())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.FunctionDeclaration:
|
|
return FunctionDeclaration(
|
|
VariableDeclaration(null, isSynthesized: true),
|
|
_createFunctionNode())
|
|
..fileOffset = _needFileOffset();
|
|
case StatementKind.IfStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => IfStatement(_createExpression(), _createStatement(), null)
|
|
..fileOffset = _needFileOffset(),
|
|
() => IfStatement(
|
|
_createExpression(), _createStatement(), _createStatement())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.LabeledStatement:
|
|
return LabeledStatement(_createStatement())
|
|
..fileOffset = _needFileOffset();
|
|
case StatementKind.ReturnStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => ReturnStatement()..fileOffset = _needFileOffset(),
|
|
() => ReturnStatement(_createExpression())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.SwitchStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => SwitchStatement(_createExpression(), [])
|
|
..fileOffset = _needFileOffset(),
|
|
() => SwitchStatement(_createExpression(), [_createSwitchCase()])
|
|
..fileOffset = _needFileOffset(),
|
|
() => SwitchStatement(
|
|
_createExpression(), [_createSwitchCase(), _createSwitchCase()])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.TryCatch:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() =>
|
|
TryCatch(_createStatement(), [])..fileOffset = _needFileOffset(),
|
|
() => TryCatch(_createStatement(), [_createCatch()])
|
|
..fileOffset = _needFileOffset(),
|
|
() => TryCatch(_createStatement(), [_createCatch(), _createCatch()])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.TryFinally:
|
|
return TryFinally(_createStatement(), _createStatement())
|
|
..fileOffset = _needFileOffset();
|
|
case StatementKind.VariableDeclaration:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => VariableDeclaration('foo')..fileOffset = _needFileOffset(),
|
|
() => VariableDeclaration('foo', initializer: _createExpression())
|
|
..fileOffset = _needFileOffset(),
|
|
() => VariableDeclaration('foo', type: _createDartType())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.WhileStatement:
|
|
return WhileStatement(_createExpression(), _createStatement())
|
|
..fileOffset = _needFileOffset();
|
|
case StatementKind.YieldStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => YieldStatement(_createExpression(), isYieldStar: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => YieldStatement(_createExpression(), isYieldStar: true)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.PatternSwitchStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => PatternSwitchStatement(_createExpression(), [])
|
|
..fileOffset = _needFileOffset(),
|
|
() => PatternSwitchStatement(_createExpression(), [
|
|
_createNodeFromKind(NodeKind.PatternSwitchCase)
|
|
as PatternSwitchCase
|
|
])
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.IfCaseStatement:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => IfCaseStatement(
|
|
_createExpression(),
|
|
_createNodeFromKind(NodeKind.PatternGuard) as PatternGuard,
|
|
_createStatement())
|
|
..fileOffset = _needFileOffset(),
|
|
() => IfCaseStatement(
|
|
_createExpression(),
|
|
_createNodeFromKind(NodeKind.PatternGuard) as PatternGuard,
|
|
_createStatement(),
|
|
_createStatement())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case StatementKind.PatternVariableDeclaration:
|
|
return _createOneOf(_pendingStatements, kind, index, [
|
|
() => new PatternVariableDeclaration(
|
|
_createPattern(), _createExpression(),
|
|
isFinal: false)
|
|
..fileOffset = _needFileOffset(),
|
|
() => new PatternVariableDeclaration(
|
|
_createPattern(), _createExpression(),
|
|
isFinal: true)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/// Creates a [VariableDeclaration] node.
|
|
///
|
|
/// If there are any pending [VariableDeclaration] nodes, one of these is
|
|
/// created.
|
|
VariableDeclaration _createVariableDeclaration() {
|
|
return _createStatementFromKind(StatementKind.VariableDeclaration)
|
|
as VariableDeclaration;
|
|
}
|
|
|
|
/// Creates a [DartType] node.
|
|
///
|
|
/// If there are any pending types, one of these is created.
|
|
DartType _createDartType() {
|
|
if (_pendingDartTypes.isEmpty) {
|
|
return VoidType();
|
|
}
|
|
DartTypeKind kind = _pendingDartTypes.keys.first;
|
|
return _createDartTypeFromKind(kind);
|
|
}
|
|
|
|
/// Creates a [DartType] node of the specified [kind].
|
|
///
|
|
/// If there are any pending types of this [kind], one of these is created.
|
|
DartType _createDartTypeFromKind(DartTypeKind kind) {
|
|
int? index = _pendingDartTypes.remove(kind);
|
|
switch (kind) {
|
|
case DartTypeKind.DynamicType:
|
|
return DynamicType();
|
|
case DartTypeKind.FunctionType:
|
|
return _createOneOf(_pendingDartTypes, kind, index, [
|
|
// TODO(johnniwinther): Create non-trivial cases.
|
|
() => FunctionType([], _createDartType(), Nullability.nonNullable),
|
|
]);
|
|
case DartTypeKind.RecordType:
|
|
return _createOneOf(_pendingDartTypes, kind, index, [
|
|
// TODO(cstefantsova): Create non-trivial cases.
|
|
() => RecordType([], [], Nullability.nonNullable),
|
|
]);
|
|
case DartTypeKind.FutureOrType:
|
|
return FutureOrType(_createDartType(), Nullability.nonNullable);
|
|
case DartTypeKind.InterfaceType:
|
|
return _createOneOf(_pendingDartTypes, kind, index, [
|
|
// TODO(johnniwinther): Create non-trivial cases.
|
|
() => InterfaceType(_needClass(), Nullability.nonNullable, []),
|
|
]);
|
|
case DartTypeKind.InvalidType:
|
|
return InvalidType();
|
|
case DartTypeKind.NeverType:
|
|
return NeverType.nonNullable();
|
|
case DartTypeKind.NullType:
|
|
return NullType();
|
|
case DartTypeKind.TypeParameterType:
|
|
return _createOneOf(_pendingDartTypes, kind, index, [
|
|
() =>
|
|
TypeParameterType(_needTypeParameter(), Nullability.nonNullable),
|
|
]);
|
|
case DartTypeKind.StructuralParameterType:
|
|
return _createOneOf(_pendingDartTypes, kind, index, [
|
|
() => StructuralParameterType(
|
|
_needStructuralParameter(), Nullability.nonNullable),
|
|
]);
|
|
case DartTypeKind.IntersectionType:
|
|
return _createOneOf(_pendingDartTypes, kind, index, [
|
|
() => IntersectionType(
|
|
TypeParameterType(_needTypeParameter(), Nullability.nonNullable),
|
|
_createDartType()),
|
|
]);
|
|
case DartTypeKind.TypedefType:
|
|
return _createOneOf(_pendingDartTypes, kind, index, [
|
|
// TODO(johnniwinther): Create non-trivial cases.
|
|
() => TypedefType(_needTypedef(), Nullability.nonNullable, []),
|
|
]);
|
|
case DartTypeKind.ExtensionType:
|
|
return ExtensionType(
|
|
_needExtensionTypeDeclaration(), Nullability.nonNullable);
|
|
case DartTypeKind.VoidType:
|
|
return VoidType();
|
|
}
|
|
}
|
|
|
|
/// Creates a [FunctionType] node.
|
|
///
|
|
/// If there are any pending [FunctionType] nodes, one of these is created.
|
|
FunctionType _createFunctionType() {
|
|
return _createDartTypeFromKind(DartTypeKind.FunctionType) as FunctionType;
|
|
}
|
|
|
|
/// Creates a [Constant] node.
|
|
///
|
|
/// If there are any pending constants, one of these is created.
|
|
Constant _createConstant() {
|
|
if (_pendingConstants.isEmpty) {
|
|
return NullConstant();
|
|
}
|
|
ConstantKind kind = _pendingConstants.keys.first;
|
|
return _createConstantFromKind(kind);
|
|
}
|
|
|
|
/// Creates a [Constant] node of the specified [kind].
|
|
///
|
|
/// If there are any pending constants of this [kind], one of these is
|
|
/// created.
|
|
Constant _createConstantFromKind(ConstantKind kind) {
|
|
int? index = _pendingConstants.remove(kind);
|
|
switch (kind) {
|
|
case ConstantKind.BoolConstant:
|
|
return BoolConstant(true);
|
|
case ConstantKind.ConstructorTearOffConstant:
|
|
return ConstructorTearOffConstant(_needConstructor());
|
|
case ConstantKind.DoubleConstant:
|
|
return DoubleConstant(42.5);
|
|
case ConstantKind.InstanceConstant:
|
|
return _createOneOf(_pendingConstants, kind, index, [
|
|
() => InstanceConstant(_needClass().reference, [], {}),
|
|
() => InstanceConstant(_needClass().reference, [
|
|
_createDartType()
|
|
], {
|
|
_needField(isStatic: false, hasSetter: false).getterReference:
|
|
_createConstant()
|
|
}),
|
|
() => InstanceConstant(_needClass().reference, [
|
|
_createDartType()
|
|
], {
|
|
_needField(index: 0, isStatic: false, hasSetter: false)
|
|
.getterReference: _createConstant(),
|
|
_needField(index: 1, isStatic: false, hasSetter: false)
|
|
.getterReference: _createConstant()
|
|
}),
|
|
]);
|
|
case ConstantKind.InstantiationConstant:
|
|
return InstantiationConstant(_createConstant(), [_createDartType()]);
|
|
case ConstantKind.IntConstant:
|
|
return IntConstant(42);
|
|
case ConstantKind.ListConstant:
|
|
return _createOneOf(_pendingConstants, kind, index, [
|
|
() => ListConstant(_createDartType(), []),
|
|
() => ListConstant(_createDartType(), [_createConstant()]),
|
|
() => ListConstant(
|
|
_createDartType(), [_createConstant(), _createConstant()]),
|
|
]);
|
|
case ConstantKind.MapConstant:
|
|
return _createOneOf(_pendingConstants, kind, index, [
|
|
() => MapConstant(_createDartType(), _createDartType(), []),
|
|
() => MapConstant(_createDartType(), _createDartType(),
|
|
[ConstantMapEntry(_createConstant(), _createConstant())]),
|
|
() => MapConstant(_createDartType(), _createDartType(), [
|
|
ConstantMapEntry(_createConstant(), _createConstant()),
|
|
ConstantMapEntry(_createConstant(), _createConstant())
|
|
]),
|
|
]);
|
|
case ConstantKind.RecordConstant:
|
|
return _createOneOf(_pendingConstants, kind, index, [
|
|
() => RecordConstant(
|
|
[], {}, RecordType([], [], Nullability.nonNullable)),
|
|
() => RecordConstant(
|
|
[_createConstant(), _createConstant()],
|
|
{},
|
|
RecordType([_createDartType(), _createDartType()], [],
|
|
Nullability.nonNullable)),
|
|
() => RecordConstant(
|
|
[],
|
|
{
|
|
'a': _createConstant(),
|
|
'b': _createConstant(),
|
|
},
|
|
RecordType([], [
|
|
NamedType('a', _createDartType()),
|
|
NamedType('b', _createDartType())
|
|
], Nullability.nonNullable)),
|
|
() => RecordConstant(
|
|
[_createConstant()],
|
|
{'a': _createConstant()},
|
|
RecordType(
|
|
[_createDartType()],
|
|
[NamedType('a', _createDartType())],
|
|
Nullability.nonNullable)),
|
|
]);
|
|
case ConstantKind.NullConstant:
|
|
return NullConstant();
|
|
case ConstantKind.RedirectingFactoryTearOffConstant:
|
|
return RedirectingFactoryTearOffConstant(_needRedirectingFactory());
|
|
case ConstantKind.SetConstant:
|
|
return _createOneOf(_pendingConstants, kind, index, [
|
|
() => SetConstant(_createDartType(), []),
|
|
() => SetConstant(_createDartType(), [_createConstant()]),
|
|
() => SetConstant(
|
|
_createDartType(), [_createConstant(), _createConstant()]),
|
|
]);
|
|
case ConstantKind.StaticTearOffConstant:
|
|
return StaticTearOffConstant(_needProcedure());
|
|
case ConstantKind.StringConstant:
|
|
return StringConstant('foo');
|
|
case ConstantKind.SymbolConstant:
|
|
return _createOneOf(_pendingConstants, kind, index, [
|
|
() => SymbolConstant('foo', null),
|
|
() => SymbolConstant('_foo', _needLibrary().reference),
|
|
]);
|
|
case ConstantKind.TypeLiteralConstant:
|
|
return TypeLiteralConstant(_createDartType());
|
|
case ConstantKind.TypedefTearOffConstant:
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
return TypedefTearOffConstant(
|
|
[],
|
|
_createConstantFromKind(ConstantKind.ConstructorTearOffConstant)
|
|
as TearOffConstant,
|
|
[]);
|
|
case ConstantKind.UnevaluatedConstant:
|
|
return UnevaluatedConstant(_createExpression());
|
|
}
|
|
}
|
|
|
|
/// Creates an [Initializer] node.
|
|
///
|
|
/// If there are any pending initializers, one of these is created.
|
|
Initializer _createInitializer() {
|
|
if (_pendingInitializers.isEmpty) {
|
|
return InvalidInitializer()..fileOffset = _needFileOffset();
|
|
}
|
|
InitializerKind kind = _pendingInitializers.keys.first;
|
|
return _createInitializerFromKind(kind);
|
|
}
|
|
|
|
/// Creates an [Initializer] node of the specified [kind].
|
|
///
|
|
/// If there are any pending initializers of this [kind], one of these is
|
|
/// created.
|
|
Initializer _createInitializerFromKind(InitializerKind kind) {
|
|
// ignore: unused_local_variable
|
|
int? index = _pendingInitializers.remove(kind);
|
|
switch (kind) {
|
|
case InitializerKind.AssertInitializer:
|
|
return AssertInitializer(
|
|
_createStatementFromKind(StatementKind.AssertStatement)
|
|
as AssertStatement)
|
|
..fileOffset = _needFileOffset();
|
|
case InitializerKind.FieldInitializer:
|
|
return FieldInitializer(
|
|
_needField(isStatic: false), _createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case InitializerKind.InvalidInitializer:
|
|
return InvalidInitializer()..fileOffset = _needFileOffset();
|
|
case InitializerKind.LocalInitializer:
|
|
return LocalInitializer(_createVariableDeclaration())
|
|
..fileOffset = _needFileOffset();
|
|
case InitializerKind.RedirectingInitializer:
|
|
return RedirectingInitializer(_needConstructor(), _createArguments())
|
|
..fileOffset = _needFileOffset();
|
|
case InitializerKind.SuperInitializer:
|
|
return SuperInitializer(_needConstructor(), _createArguments())
|
|
..fileOffset = _needFileOffset();
|
|
}
|
|
}
|
|
|
|
/// Creates a [Member] node.
|
|
///
|
|
/// If there are any pending members, one of these is created.
|
|
Member _createMember() {
|
|
if (_pendingMembers.isEmpty) {
|
|
return Field.immutable(_createName(), fileUri: _uri)
|
|
..fileOffset = _needFileOffset();
|
|
}
|
|
MemberKind kind = _pendingMembers.keys.first;
|
|
return _createMemberKind(kind);
|
|
}
|
|
|
|
/// Creates a [Member] node of the specified [kind].
|
|
///
|
|
/// If there are any pending members of this [kind], one of these is created.
|
|
Member _createMemberKind(MemberKind kind) {
|
|
int? index = _pendingMembers.remove(kind);
|
|
switch (kind) {
|
|
case MemberKind.Constructor:
|
|
return Constructor(_createFunctionNode(),
|
|
name: _createName(), fileUri: _uri)
|
|
..fileOffset = _needFileOffset();
|
|
case MemberKind.Field:
|
|
return _createOneOf(_pendingMembers, kind, index, [
|
|
() => Field.mutable(_createName(), fileUri: _uri)
|
|
..fileOffset = _needFileOffset(),
|
|
() => Field.immutable(_createName(), fileUri: _uri)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case MemberKind.Procedure:
|
|
return _createOneOf(_pendingMembers, kind, index, [
|
|
() => Procedure(
|
|
_createName(), ProcedureKind.Method, _createFunctionNode(),
|
|
fileUri: _uri)
|
|
..fileOffset = _needFileOffset(),
|
|
() => Procedure(
|
|
_createName(), ProcedureKind.Operator, _createFunctionNode(),
|
|
fileUri: _uri)
|
|
..fileOffset = _needFileOffset(),
|
|
() => Procedure(
|
|
_createName(), ProcedureKind.Getter, _createFunctionNode(),
|
|
fileUri: _uri)
|
|
..fileOffset = _needFileOffset(),
|
|
() => Procedure(
|
|
_createName(), ProcedureKind.Setter, _createFunctionNode(),
|
|
fileUri: _uri)
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/// Creates an [Arguments] node.
|
|
///
|
|
/// If there are any pending [Arguments] nodes, one of these is created.
|
|
Arguments _createArguments() {
|
|
return _createNodeFromKind(NodeKind.Arguments) as Arguments;
|
|
}
|
|
|
|
/// Creates a [Name] node.
|
|
///
|
|
/// If there are any pending [Name] nodes, one of these is created.
|
|
Name _createName() {
|
|
return _createNodeFromKind(NodeKind.Name) as Name;
|
|
}
|
|
|
|
/// Creates a [FunctionNode] node.
|
|
///
|
|
/// If there are any pending [FunctionNode] nodes, one of these is created.
|
|
FunctionNode _createFunctionNode() {
|
|
return _createNodeFromKind(NodeKind.FunctionNode) as FunctionNode;
|
|
}
|
|
|
|
/// Creates a [MapLiteralEntry] node.
|
|
///
|
|
/// If there are any pending [MapLiteralEntry] nodes, one of these is created.
|
|
MapLiteralEntry _createMapLiteralEntry() {
|
|
return _createNodeFromKind(NodeKind.MapLiteralEntry) as MapLiteralEntry;
|
|
}
|
|
|
|
/// Creates a [SwitchCase] node.
|
|
///
|
|
/// If there are any pending [SwitchCase] nodes, one of these is created.
|
|
SwitchCase _createSwitchCase() {
|
|
return _createNodeFromKind(NodeKind.SwitchCase) as SwitchCase;
|
|
}
|
|
|
|
/// Creates a [Catch] node.
|
|
///
|
|
/// If there are any pending [Catch] nodes, one of these is created.
|
|
Catch _createCatch() {
|
|
return _createNodeFromKind(NodeKind.Catch) as Catch;
|
|
}
|
|
|
|
/// Creates a [Node] of the specified [kind].
|
|
///
|
|
/// If there are any pending nodes of this [kind], one of these is created.
|
|
Node _createNodeFromKind(NodeKind kind) {
|
|
int? index = _pendingNodes.remove(kind);
|
|
switch (kind) {
|
|
case NodeKind.Arguments:
|
|
return _createOneOf(_pendingNodes, kind, index, [
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
() => Arguments([])..fileOffset = _needFileOffset(),
|
|
]);
|
|
case NodeKind.Catch:
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
return Catch(null, _createStatement())..fileOffset = _needFileOffset();
|
|
case NodeKind.Class:
|
|
return Class(name: 'foo', fileUri: _uri)
|
|
..fileOffset = _needFileOffset();
|
|
case NodeKind.Combinator:
|
|
return _createOneOf(_pendingNodes, kind, index, [
|
|
() => Combinator.show([])..fileOffset = _needFileOffset(),
|
|
() => Combinator.show(['foo'])..fileOffset = _needFileOffset(),
|
|
() => Combinator.show(['foo', 'bar'])..fileOffset = _needFileOffset(),
|
|
() => Combinator.hide([])..fileOffset = _needFileOffset(),
|
|
() => Combinator.hide(['foo'])..fileOffset = _needFileOffset(),
|
|
() => Combinator.hide(['foo', 'bar'])..fileOffset = _needFileOffset(),
|
|
]);
|
|
case NodeKind.Component:
|
|
return _component;
|
|
case NodeKind.Extension:
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
return Extension(name: 'foo', fileUri: _uri)
|
|
..fileOffset = _needFileOffset()
|
|
..onType = _createDartType();
|
|
case NodeKind.FunctionNode:
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
return FunctionNode(_createStatement())..fileOffset = _needFileOffset();
|
|
case NodeKind.Library:
|
|
return Library(_uri, fileUri: _uri)..fileOffset = _needFileOffset();
|
|
case NodeKind.LibraryDependency:
|
|
return _createOneOf(_pendingNodes, kind, index, [
|
|
// TODO(johnniwinther): Add more cases.
|
|
() => LibraryDependency.import(_needLibrary())
|
|
..fileOffset = _needFileOffset(),
|
|
() => LibraryDependency.import(_needLibrary(), name: 'foo')
|
|
..fileOffset = _needFileOffset(),
|
|
() => LibraryDependency.export(_needLibrary())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case NodeKind.LibraryPart:
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
// TODO(johnniwinther): Do we need to use a valid part uri?
|
|
return LibraryPart([], 'foo')..fileOffset = _needFileOffset();
|
|
case NodeKind.MapLiteralEntry:
|
|
return MapLiteralEntry(_createExpression(), _createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case NodeKind.Name:
|
|
return _createOneOf(_pendingNodes, kind, index, [
|
|
() => Name('foo'),
|
|
() => Name('_foo', _needLibrary()),
|
|
]);
|
|
case NodeKind.NamedExpression:
|
|
return NamedExpression('foo', _createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
case NodeKind.NamedType:
|
|
return NamedType('foo', _createDartType());
|
|
case NodeKind.Supertype:
|
|
return _createOneOf(_pendingNodes, kind, index, [
|
|
() => Supertype(_needClass(), []),
|
|
() => Supertype(_needClass(), [_createDartType()]),
|
|
() => Supertype(_needClass(), [_createDartType(), _createDartType()]),
|
|
]);
|
|
case NodeKind.SwitchCase:
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
return SwitchCase(
|
|
[NullLiteral()], [TreeNode.noOffset], _createStatement())
|
|
..fileOffset = _needFileOffset();
|
|
case NodeKind.TypeParameter:
|
|
return TypeParameter('foo', _createDartType(), _createDartType())
|
|
..fileOffset = _needFileOffset();
|
|
case NodeKind.StructuralParameter:
|
|
return StructuralParameter('foo', _createDartType(), _createDartType());
|
|
case NodeKind.Typedef:
|
|
return Typedef('foo', _createDartType(), fileUri: _uri)
|
|
..fileOffset = _needFileOffset();
|
|
case NodeKind.ExtensionTypeDeclaration:
|
|
// TODO(johnniwinther): Add non-trivial cases.
|
|
return ExtensionTypeDeclaration(name: 'foo', fileUri: _uri)
|
|
..fileOffset = _needFileOffset()
|
|
..declaredRepresentationType = _createDartType();
|
|
case NodeKind.MapPatternEntry:
|
|
return MapPatternEntry(_createExpression(), _createPattern())
|
|
..fileOffset = _needFileOffset();
|
|
case NodeKind.MapPatternRestEntry:
|
|
return MapPatternRestEntry()..fileOffset = _needFileOffset();
|
|
case NodeKind.PatternGuard:
|
|
return _createOneOf(_pendingNodes, kind, index, [
|
|
() => new PatternGuard(_createPattern())
|
|
..fileOffset = _needFileOffset(),
|
|
() => new PatternGuard(_createPattern(), _createExpression())
|
|
..fileOffset = _needFileOffset(),
|
|
]);
|
|
case NodeKind.PatternSwitchCase:
|
|
return _createOneOf(_pendingNodes, kind, index, [
|
|
() => new PatternSwitchCase([], [], _createStatement(),
|
|
isDefault: true,
|
|
hasLabel: false,
|
|
jointVariables: [],
|
|
jointVariableFirstUseOffsets: null),
|
|
() => new PatternSwitchCase(
|
|
[0],
|
|
[_createNodeFromKind(NodeKind.PatternGuard) as PatternGuard],
|
|
_createStatement(),
|
|
isDefault: false,
|
|
hasLabel: true,
|
|
jointVariables: [],
|
|
jointVariableFirstUseOffsets: null),
|
|
]);
|
|
case NodeKind.SwitchExpressionCase:
|
|
return new SwitchExpressionCase(
|
|
_createNodeFromKind(NodeKind.PatternGuard) as PatternGuard,
|
|
_createExpression())
|
|
..fileOffset = _needFileOffset();
|
|
}
|
|
}
|
|
|
|
/// Helper that creates a node of type [V] using the list of [creators].
|
|
///
|
|
/// The [index] indicates how many nodes of the [kind] that have currently
|
|
/// been created. If there are more [creators] left after having created the
|
|
/// [index]th node, [pending] is updated with the next pending index. If all
|
|
/// pending nodes of the given [kind] have been created, [index] is `null` and
|
|
/// the first [creators] function is used.
|
|
V _createOneOf<K, V>(
|
|
Map<K, int> pending, K kind, int? index, List<V Function()> creators) {
|
|
if (index == null) {
|
|
// All pending nodes have been created so we just create the first.
|
|
return creators[0]();
|
|
}
|
|
if (index + 1 < creators.length) {
|
|
pending[kind] = index + 1;
|
|
}
|
|
return creators[index]();
|
|
}
|
|
}
|
|
|
|
/// [NodeKind]s for nodes that can occur inside member bodies.
|
|
const Set<NodeKind> inBodyNodeKinds = {
|
|
NodeKind.Arguments,
|
|
NodeKind.Catch,
|
|
NodeKind.FunctionNode,
|
|
NodeKind.MapLiteralEntry,
|
|
NodeKind.MapPatternEntry,
|
|
NodeKind.MapPatternRestEntry,
|
|
NodeKind.Name,
|
|
NodeKind.NamedExpression,
|
|
NodeKind.NamedType,
|
|
NodeKind.SwitchCase,
|
|
NodeKind.TypeParameter,
|
|
NodeKind.PatternGuard,
|
|
NodeKind.PatternSwitchCase,
|
|
NodeKind.SwitchExpressionCase,
|
|
};
|