| // 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<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<Extension> _neededExtensions = []; |
| List<Typedef> _neededTypedefs = []; |
| List<TypeParameter> _neededTypeParameters = []; |
| 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<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)), |
| _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)); |
| } |
| |
| /// 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.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.SwitchCase: |
| _addStatement(statements, |
| SwitchStatement(_createExpression(), [node as SwitchCase])); |
| 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 if (member is RedirectingFactory) { |
| cls.addRedirectingFactory(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: |
| 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; |
| } |
| } |
| 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 a [Extension] node that fits the requirements. |
| /// |
| /// If no such [Extension] exists in [_neededExtensions], a new [Extension] is |
| /// created and added to [_neededExtensions]. |
| // TODO(johnniwinther): Add requirements when/where needed. |
| Extension _needExtension() { |
| for (Extension extension in _neededExtensions) { |
| return extension; |
| } |
| Extension extension = Extension(name: 'foo', fileUri: _uri) |
| ..onType = DynamicType(); |
| _neededExtensions.add(extension); |
| _needLibrary().addExtension(extension); |
| return extension; |
| } |
| |
| /// 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 [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), |
| fileUri: _uri) |
| ..isRedirectingFactory = true; |
| _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.SuperMethodInvocation: |
| return _createOneOf(_pendingExpressions, kind, index, [ |
| () => SuperMethodInvocation(_createName(), _createArguments()) |
| ..fileOffset = _needFileOffset(), |
| () => SuperMethodInvocation( |
| _createName(), _createArguments(), _needProcedure()) |
| ..fileOffset = _needFileOffset(), |
| ]); |
| case ExpressionKind.SuperPropertyGet: |
| return _createOneOf(_pendingExpressions, kind, index, [ |
| () => SuperPropertyGet(_createName())..fileOffset = _needFileOffset(), |
| () => SuperPropertyGet(_createName(), _needField()) |
| ..fileOffset = _needFileOffset(), |
| ]); |
| case ExpressionKind.SuperPropertySet: |
| return _createOneOf(_pendingExpressions, kind, index, [ |
| () => SuperPropertySet(_createName(), _createExpression(), null) |
| ..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(); |
| } |
| } |
| |
| /// 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), _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(), |
| ]); |
| } |
| } |
| |
| /// 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.ExtensionType: |
| return ExtensionType(_needExtension(), Nullability.nonNullable); |
| case DartTypeKind.FunctionType: |
| return _createOneOf(_pendingDartTypes, kind, index, [ |
| // TODO(johnniwinther): Create non-trivial cases. |
| () => FunctionType([], _createDartType(), 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), |
| () => 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.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.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(), |
| ]); |
| case MemberKind.RedirectingFactory: |
| return RedirectingFactory(null, |
| name: _createName(), function: _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.Typedef: |
| return Typedef('foo', _createDartType(), fileUri: _uri) |
| ..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.Name, |
| NodeKind.NamedExpression, |
| NodeKind.NamedType, |
| NodeKind.SwitchCase, |
| NodeKind.TypeParameter, |
| }; |