| // 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'; | |
| Map<T, int> _createPending<T>( | |
| Iterable<T> kinds, [ | |
| Set<T> experimentalKinds = const {}, | |
| ]) { | |
| return <T, int>{ | |
| for (T kind in kinds) | |
| if (!experimentalKinds.contains(kind)) kind: 0, | |
| }; | |
| } | |
| /// 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; | |
| final Map<VariableKind, int> _pendingVariables; | |
| /// 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 | |
| /// [Variable] 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<DeclaredVariable> _neededVariables = []; | |
| List<LabeledStatement> _neededLabeledStatements = []; | |
| List<FunctionDeclaration> _neededFunctionDeclarations = []; | |
| List<SwitchCase> _neededSwitchCases = []; | |
| /// Creates a [NodeCreator] requested to create nodes of the specified kinds. | |
| new({ | |
| 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<VariableKind> variables = VariableKind.values, | |
| Iterable<NodeKind> nodes = NodeKind.values, | |
| }) : _pendingExpressions = _createPending<ExpressionKind>(expressions, {}), | |
| _pendingStatements = _createPending<StatementKind>(statements), | |
| _pendingDartTypes = _createPending<DartTypeKind>(dartTypes, { | |
| DartTypeKind.FunctionTypeParameterType, | |
| DartTypeKind.ClassTypeParameterType, | |
| }), | |
| _pendingConstants = _createPending<ConstantKind>(constants), | |
| _pendingPatterns = _createPending<PatternKind>(patterns), | |
| _pendingInitializers = _createPending<InitializerKind>(initializers), | |
| _pendingMembers = _createPending<MemberKind>(members), | |
| _pendingVariables = _createPending<VariableKind>(variables), | |
| _pendingNodes = _createPending<NodeKind>(nodes, {NodeKind.TypeVariable}), | |
| _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(_pendingVariables.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(ExpressionList(NullLiteral()), [ | |
| TreeNode.noOffset, | |
| ], Block([statement])), | |
| ]); | |
| } | |
| _neededSwitchCases.clear(); | |
| for (LabeledStatement labeledStatement in _neededLabeledStatements) { | |
| labeledStatement.body = statement; | |
| statement = labeledStatement; | |
| } | |
| _neededLabeledStatements.clear(); | |
| statement = Block([ | |
| for (DeclaredVariable neededVariable in _neededVariables) | |
| VariableStatement(VariableDeclaration(neededVariable)), | |
| ..._neededFunctionDeclarations, | |
| statement, | |
| ]); | |
| _neededFunctionDeclarations.clear(); | |
| _neededVariables.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: pattern, | |
| expression: NullLiteral(), | |
| matchedValueType: _createDartType(), | |
| ), | |
| ); | |
| } | |
| /// 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()); | |
| } | |
| while (_pendingVariables.isNotEmpty) { | |
| Variable variable = _createVariableFromKind(_pendingVariables.keys.first); | |
| switch (variable) { | |
| case DeclaredVariable(): | |
| _addStatement( | |
| statements, | |
| VariableStatement(VariableDeclaration(variable)), | |
| ); | |
| case CatchVariable(): | |
| _addStatement( | |
| statements, | |
| TryCatch(Block([]), [Catch(variable, Block([]))]), | |
| ); | |
| case ThisVariable(): | |
| _addExpression( | |
| statements, | |
| FunctionExpression(FunctionNode(null, thisVariable: variable)), | |
| ); | |
| case PositionalParameter(): | |
| _addExpression( | |
| statements, | |
| FunctionExpression( | |
| FunctionNode( | |
| null, | |
| positionalParameters: PositionalParameterList(variable), | |
| ), | |
| ), | |
| ); | |
| case NamedParameter(): | |
| _addExpression( | |
| statements, | |
| FunctionExpression( | |
| FunctionNode(null, namedParameters: NamedParameterList(variable)), | |
| ), | |
| ); | |
| } | |
| } | |
| 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( | |
| keyType: null, | |
| valueType: null, | |
| entries: [node as MapPatternEntry], | |
| requiredType: _createDartType(), | |
| matchedValueType: _createDartType(), | |
| needsCheck: false, | |
| lookupType: _createDartType(), | |
| containsKeyTarget: _needProcedure(), | |
| containsKeyType: _createFunctionType(), | |
| indexGetTarget: _needProcedure(), | |
| indexGetType: _createFunctionType(), | |
| ), | |
| ); | |
| break; | |
| case NodeKind.MapPatternRestEntry: | |
| _addPattern( | |
| statements, | |
| MapPattern( | |
| keyType: null, | |
| valueType: null, | |
| entries: [node as MapPatternRestEntry], | |
| requiredType: _createDartType(), | |
| matchedValueType: _createDartType(), | |
| needsCheck: false, | |
| lookupType: _createDartType(), | |
| containsKeyTarget: _needProcedure(), | |
| containsKeyType: _createFunctionType(), | |
| indexGetTarget: _needProcedure(), | |
| indexGetType: _createFunctionType(), | |
| ), | |
| ); | |
| break; | |
| case NodeKind.NamedExpression: | |
| _addExpression( | |
| statements, | |
| DynamicInvocation( | |
| DynamicAccessKind.Dynamic, | |
| _createExpression(), | |
| _createName(), | |
| Arguments( | |
| ExpressionList.empty, | |
| named: NamedExpressionList(node as NamedExpression), | |
| ), | |
| ), | |
| ); | |
| break; | |
| case NodeKind.NamedType: | |
| _addDartType( | |
| statements, | |
| FunctionType( | |
| DartTypeList.empty, | |
| _createDartType(), | |
| Nullability.nonNullable, | |
| namedParameters: NamedDartTypeList(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.NominalParameter: | |
| _addExpression( | |
| statements, | |
| FunctionExpression( | |
| FunctionNode( | |
| Block([]), | |
| typeParameters: TypeParameterList(node as TypeParameter), | |
| ), | |
| ), | |
| ); | |
| break; | |
| case NodeKind.VariableDeclaration: | |
| _addStatement( | |
| statements, | |
| VariableStatement(node as VariableDeclaration), | |
| ); | |
| 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.NominalParameter: | |
| case NodeKind.StructuralParameter: | |
| case NodeKind.MapPatternEntry: | |
| case NodeKind.MapPatternRestEntry: | |
| case NodeKind.PatternGuard: | |
| case NodeKind.PatternSwitchCase: | |
| case NodeKind.SwitchExpressionCase: | |
| case NodeKind.TypeVariable: | |
| case NodeKind.VariableDeclaration: | |
| 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 = null; | |
| bool? isStatic = null; | |
| 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(), | |
| DartTypeList.empty, | |
| ), | |
| 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 [DeclaredVariable] node that fits the requirements. | |
| /// | |
| /// If no such [DeclaredVariable] exists in [_neededVariables], | |
| /// a new [DeclaredVariable] is created and added to | |
| /// [_neededVariables]. | |
| // TODO(johnniwinther): Add requirements when/where needed. | |
| DeclaredVariable _needVariable() { | |
| for (DeclaredVariable variable in _neededVariables) { | |
| return variable; | |
| } | |
| DeclaredVariable variable = LocalVariable(name: 'foo', type: null); | |
| _neededVariables.add(variable); | |
| return variable; | |
| } | |
| /// 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(ExpressionList(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( | |
| LocalFunctionVariable(name: '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, | |
| DartTypeList.empty, | |
| {}, | |
| [], | |
| ExpressionList.empty, | |
| )..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(), DartTypeList.empty) | |
| ..fileOffset = _needFileOffset(), | |
| () => Instantiation( | |
| _createExpression(), | |
| DartTypeList(_createDartType()), | |
| )..fileOffset = _needFileOffset(), | |
| () => Instantiation( | |
| _createExpression(), | |
| DartTypeList(_createDartType(), _createDartType()), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.IntLiteral: | |
| return IntLiteral(42)..fileOffset = _needFileOffset(); | |
| case ExpressionKind.InvalidExpression: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => InvalidExpression('foo')..fileOffset = _needFileOffset(), | |
| () => | |
| InvalidExpression('foo', _createExpression()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.IsExpression: | |
| return IsExpression(_createExpression(), _createDartType()) | |
| ..fileOffset = _needFileOffset(); | |
| case ExpressionKind.Let: | |
| return Let( | |
| variable: _createVariableFromKind( | |
| VariableKind.SyntheticVariable, | |
| ) as SyntheticVariable, | |
| value: _createExpression(), | |
| body: _createExpression(), | |
| )..fileOffset = _needFileOffset(); | |
| case ExpressionKind.ListConcatenation: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => ListConcatenation( | |
| ExpressionList.empty, | |
| typeArgument: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| () => ListConcatenation( | |
| ExpressionList(_createExpression()), | |
| typeArgument: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| () => ListConcatenation( | |
| ExpressionList(_createExpression(), _createExpression()), | |
| typeArgument: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.ListLiteral: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => ListLiteral( | |
| ExpressionList.empty, | |
| typeArgument: _createDartType(), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => ListLiteral( | |
| ExpressionList(_createExpression()), | |
| typeArgument: _createDartType(), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => ListLiteral( | |
| ExpressionList(_createExpression(), _createExpression()), | |
| typeArgument: _createDartType(), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => ListLiteral( | |
| ExpressionList(_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( | |
| ExpressionList.empty, | |
| keyType: _createDartType(), | |
| valueType: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| () => MapConcatenation( | |
| ExpressionList(_createExpression()), | |
| keyType: _createDartType(), | |
| valueType: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| () => MapConcatenation( | |
| ExpressionList(_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( | |
| ExpressionList.empty, | |
| typeArgument: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| () => SetConcatenation( | |
| ExpressionList(_createExpression()), | |
| typeArgument: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| () => SetConcatenation( | |
| ExpressionList(_createExpression(), _createExpression()), | |
| typeArgument: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SetLiteral: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => SetLiteral( | |
| ExpressionList.empty, | |
| typeArgument: _createDartType(), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => SetLiteral( | |
| ExpressionList(_createExpression()), | |
| typeArgument: _createDartType(), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => SetLiteral( | |
| ExpressionList(_createExpression(), _createExpression()), | |
| typeArgument: _createDartType(), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => SetLiteral( | |
| ExpressionList(_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(ExpressionList.empty) | |
| ..fileOffset = _needFileOffset(), | |
| () => | |
| StringConcatenation(ExpressionList(_createExpression())) | |
| ..fileOffset = _needFileOffset(), | |
| () => StringConcatenation( | |
| ExpressionList(_createExpression(), _createExpression()), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.StringLiteral: | |
| return StringLiteral('foo'); | |
| case ExpressionKind.AbstractSuperMethodInvocation: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => AbstractSuperMethodInvocation( | |
| new ThisExpression(), | |
| _createName(), | |
| _createArguments(), | |
| _needProcedure(), | |
| )..fileOffset = _needFileOffset(), | |
| () => AbstractSuperMethodInvocation( | |
| new ThisExpression(), | |
| _createName(), | |
| _createArguments(), | |
| _needProcedure(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SuperMethodInvocation: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => SuperMethodInvocation( | |
| new ThisExpression(), | |
| _createName(), | |
| _createArguments(), | |
| _needProcedure(), | |
| )..fileOffset = _needFileOffset(), | |
| () => SuperMethodInvocation( | |
| new ThisExpression(), | |
| _createName(), | |
| _createArguments(), | |
| _needProcedure(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.AbstractSuperPropertyGet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => AbstractSuperPropertyGet( | |
| new ThisExpression(), | |
| _createName(), | |
| _needProcedure(), | |
| )..fileOffset = _needFileOffset(), | |
| () => AbstractSuperPropertyGet( | |
| new ThisExpression(), | |
| _createName(), | |
| _needField(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.AbstractSuperPropertySet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => AbstractSuperPropertySet( | |
| new ThisExpression(), | |
| _createName(), | |
| _createExpression(), | |
| _needProcedure(), | |
| )..fileOffset = _needFileOffset(), | |
| () => AbstractSuperPropertySet( | |
| new ThisExpression(), | |
| _createName(), | |
| _createExpression(), | |
| _needField(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SuperPropertyGet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => SuperPropertyGet( | |
| new ThisExpression(), | |
| _createName(), | |
| _needProcedure(), | |
| )..fileOffset = _needFileOffset(), | |
| () => SuperPropertyGet( | |
| new ThisExpression(), | |
| _createName(), | |
| _needField(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SuperPropertySet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => SuperPropertySet( | |
| new ThisExpression(), | |
| _createName(), | |
| _createExpression(), | |
| _needProcedure(), | |
| )..fileOffset = _needFileOffset(), | |
| () => SuperPropertySet( | |
| new ThisExpression(), | |
| _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( | |
| StructuralParameterList.empty, | |
| _createExpression(), | |
| DartTypeList.empty, | |
| )..fileOffset = _needFileOffset(); | |
| case ExpressionKind.VariableGet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => VariableGet(_needVariable())..fileOffset = _needFileOffset(), | |
| () => | |
| VariableGet(_needVariable(), _createDartType()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.VariableSet: | |
| return VariableSet(_needVariable(), _createExpression()) | |
| ..fileOffset = _needFileOffset(); | |
| case ExpressionKind.RecordIndexGet: | |
| return RecordIndexGet( | |
| _createExpression(), | |
| new RecordType( | |
| DartTypeList(_createDartType()), | |
| NamedDartTypeList.empty, | |
| Nullability.nonNullable, | |
| ), | |
| 0, | |
| )..fileOffset = _needFileOffset(); | |
| case ExpressionKind.RecordNameGet: | |
| String name = _createName().text; | |
| return RecordNameGet( | |
| _createExpression(), | |
| new RecordType( | |
| DartTypeList.empty, | |
| NamedDartTypeList(new NamedType(name, _createDartType())), | |
| Nullability.nonNullable, | |
| ), | |
| name, | |
| )..fileOffset = _needFileOffset(); | |
| case ExpressionKind.RecordLiteral: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => RecordLiteral( | |
| ExpressionList(_createExpression()), | |
| NamedExpressionList.empty, | |
| RecordType( | |
| DartTypeList(_createDartType()), | |
| NamedDartTypeList.empty, | |
| Nullability.nonNullable, | |
| ), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => RecordLiteral( | |
| ExpressionList.empty, | |
| NamedExpressionList(NamedExpression('foo', _createExpression())), | |
| RecordType( | |
| DartTypeList.empty, | |
| NamedDartTypeList(NamedType('foo', _createDartType())), | |
| Nullability.nonNullable, | |
| ), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => RecordLiteral( | |
| ExpressionList(_createExpression()), | |
| NamedExpressionList(NamedExpression('foo', _createExpression())), | |
| RecordType( | |
| DartTypeList(_createDartType()), | |
| NamedDartTypeList(NamedType('foo', _createDartType())), | |
| Nullability.nonNullable, | |
| ), | |
| isConst: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => RecordLiteral( | |
| ExpressionList(_createExpression()), | |
| NamedExpressionList.empty, | |
| RecordType( | |
| DartTypeList(_createDartType()), | |
| NamedDartTypeList.empty, | |
| 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( | |
| pattern: _createPattern(), | |
| expression: _createExpression(), | |
| matchedValueType: _createDartType(), | |
| )..fileOffset = _needFileOffset(); | |
| case ExpressionKind.RedirectingFactoryInvocation: | |
| return new RedirectingFactoryInvocation( | |
| _needRedirectingFactory(), | |
| _createExpressionFromKind(ExpressionKind.ConstructorInvocation) | |
| as InvocationExpression, | |
| ); | |
| } | |
| } | |
| /// Creates an [Pattern] node. | |
| /// | |
| /// If there are any pending expressions, one of these is created. | |
| Pattern _createPattern() { | |
| if (_pendingPatterns.isEmpty) { | |
| return ConstantPattern( | |
| expression: NullLiteral()..fileOffset = _needFileOffset(), | |
| expressionType: _createDartType(), | |
| equalsTarget: _needProcedure(), | |
| equalsType: _createFunctionType(), | |
| )..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( | |
| variableName: '', | |
| variableType: dummyDartType, | |
| writeVariable: _needVariable(), | |
| matchedValueType: dummyDartType, | |
| needsCast: false, | |
| hasObservableEffect: false, | |
| )..fileOffset = _needFileOffset(); | |
| case PatternKind.CastPattern: | |
| return CastPattern(_createPattern(), _createDartType()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.ConstantPattern: | |
| return ConstantPattern.byReference( | |
| expression: _createExpression(), | |
| expressionType: dummyDartType, | |
| equalsTargetReference: dummyReference, | |
| equalsType: dummyFunctionType, | |
| )..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.byReference( | |
| typeArgument: null, | |
| patterns: [], | |
| requiredType: dummyDartType, | |
| matchedValueType: dummyDartType, | |
| flags: 0, | |
| lookupType: dummyDartType, | |
| lengthTargetReference: dummyReference, | |
| lengthType: dummyDartType, | |
| lengthCheckTargetReference: dummyReference, | |
| lengthCheckType: dummyFunctionType, | |
| sublistTargetReference: dummyReference, | |
| sublistType: dummyFunctionType, | |
| minusTargetReference: dummyReference, | |
| minusType: dummyFunctionType, | |
| indexGetTargetReference: dummyReference, | |
| indexGetType: dummyFunctionType, | |
| )..fileOffset = _needFileOffset(), | |
| () => ListPattern.byReference( | |
| typeArgument: _createDartType(), | |
| patterns: [_createPattern()], | |
| requiredType: dummyDartType, | |
| matchedValueType: dummyDartType, | |
| flags: 0, | |
| lookupType: dummyDartType, | |
| lengthTargetReference: dummyReference, | |
| lengthType: dummyDartType, | |
| lengthCheckTargetReference: dummyReference, | |
| lengthCheckType: dummyFunctionType, | |
| sublistTargetReference: dummyReference, | |
| sublistType: dummyFunctionType, | |
| minusTargetReference: dummyReference, | |
| minusType: dummyFunctionType, | |
| indexGetTargetReference: dummyReference, | |
| indexGetType: dummyFunctionType, | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.MapPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => MapPattern.byReference( | |
| keyType: null, | |
| valueType: null, | |
| entries: [], | |
| requiredType: dummyDartType, | |
| matchedValueType: dummyDartType, | |
| flags: 0, | |
| lookupType: dummyDartType, | |
| containsKeyTargetReference: dummyReference, | |
| containsKeyType: dummyFunctionType, | |
| indexGetTargetReference: dummyReference, | |
| indexGetType: dummyFunctionType, | |
| ), | |
| () => MapPattern.byReference( | |
| keyType: _createDartType(), | |
| valueType: _createDartType(), | |
| entries: [ | |
| _createNodeFromKind(NodeKind.MapPatternEntry) as MapPatternEntry, | |
| ], | |
| requiredType: dummyDartType, | |
| matchedValueType: dummyDartType, | |
| flags: 0, | |
| lookupType: dummyDartType, | |
| containsKeyTargetReference: dummyReference, | |
| containsKeyType: dummyFunctionType, | |
| indexGetTargetReference: dummyReference, | |
| indexGetType: dummyFunctionType, | |
| )..fileOffset = _needFileOffset(), | |
| () => MapPattern.byReference( | |
| keyType: _createDartType(), | |
| valueType: _createDartType(), | |
| entries: [ | |
| _createNodeFromKind(NodeKind.MapPatternEntry) as MapPatternEntry, | |
| _createNodeFromKind(NodeKind.MapPatternRestEntry) | |
| as MapPatternEntry, | |
| ], | |
| requiredType: dummyDartType, | |
| matchedValueType: dummyDartType, | |
| flags: 0, | |
| lookupType: dummyDartType, | |
| containsKeyTargetReference: dummyReference, | |
| containsKeyType: dummyFunctionType, | |
| indexGetTargetReference: dummyReference, | |
| indexGetType: dummyFunctionType, | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.NamedPattern: | |
| return NamedPattern('foo', _createPattern()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.ObjectPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => ObjectPattern( | |
| requiredType: dummyDartType, | |
| fields: [], | |
| matchedValueType: dummyDartType, | |
| needsCheck: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => ObjectPattern( | |
| requiredType: dummyDartType, | |
| fields: [ | |
| _createPatternFromKind(PatternKind.NamedPattern) as NamedPattern, | |
| ], | |
| matchedValueType: dummyDartType, | |
| needsCheck: false, | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.OrPattern: | |
| return OrPattern( | |
| _createPattern(), | |
| _createPattern(), | |
| orPatternJointVariables: [], | |
| )..fileOffset = _needFileOffset(); | |
| case PatternKind.RecordPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => RecordPattern( | |
| patterns: [], | |
| requiredType: dummyRecordType, | |
| matchedValueType: dummyDartType, | |
| needsCheck: false, | |
| lookupType: dummyRecordType, | |
| )..fileOffset = _needFileOffset(), | |
| () => RecordPattern( | |
| patterns: [_createPattern()], | |
| requiredType: dummyRecordType, | |
| matchedValueType: dummyDartType, | |
| needsCheck: false, | |
| lookupType: dummyRecordType, | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.RelationalPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => RelationalPattern( | |
| kind: RelationalPatternKind.equals, | |
| expression: _createExpression(), | |
| expressionType: dummyDartType, | |
| matchedValueType: dummyDartType, | |
| accessKind: RelationalAccessKind.Dynamic, | |
| name: null, | |
| target: null, | |
| typeArguments: null, | |
| functionType: null, | |
| )..fileOffset = _needFileOffset(), | |
| () => RelationalPattern( | |
| kind: RelationalPatternKind.lessThan, | |
| expression: _createExpression(), | |
| expressionType: dummyDartType, | |
| matchedValueType: dummyDartType, | |
| accessKind: RelationalAccessKind.Dynamic, | |
| name: null, | |
| target: null, | |
| typeArguments: null, | |
| functionType: null, | |
| )..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( | |
| type: null, | |
| variable: _createVariableFromKind( | |
| VariableKind.LocalVariable, | |
| ) as DeclaredVariable, | |
| matchedValueType: dummyDartType, | |
| )..fileOffset = _needFileOffset(), | |
| () => VariablePattern( | |
| type: _createDartType(), | |
| variable: _createVariableFromKind( | |
| VariableKind.LocalVariable, | |
| ) as DeclaredVariable, | |
| matchedValueType: dummyDartType, | |
| )..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( | |
| _createVariableFromKind(VariableKind.LocalVariable) | |
| as DeclaredVariable, | |
| _createExpression(), | |
| _createStatement(), | |
| isAsync: false, | |
| )..fileOffset = _needFileOffset(), | |
| () => ForInStatement( | |
| _createVariableFromKind(VariableKind.LocalVariable) | |
| as DeclaredVariable, | |
| _createExpression(), | |
| _createStatement(), | |
| isAsync: true, | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.ForStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => | |
| ForStatement([], null, ExpressionList.empty, _createStatement()) | |
| ..fileOffset = _needFileOffset(), | |
| () => ForStatement( | |
| [ | |
| VariableDeclaration( | |
| _createVariableFromKind(VariableKind.LocalVariable) | |
| as DeclaredVariable, | |
| ), | |
| ], | |
| _createExpression(), | |
| ExpressionList(_createExpression()), | |
| _createStatement(), | |
| )..fileOffset = _needFileOffset(), | |
| () => ForStatement( | |
| [ | |
| VariableDeclaration( | |
| _createVariableFromKind(VariableKind.LocalVariable) | |
| as DeclaredVariable, | |
| ), | |
| VariableDeclaration( | |
| _createVariableFromKind(VariableKind.LocalVariable) | |
| as DeclaredVariable, | |
| ), | |
| ], | |
| _createExpression(), | |
| ExpressionList(_createExpression(), _createExpression()), | |
| _createStatement(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.FunctionDeclaration: | |
| return FunctionDeclaration( | |
| LocalFunctionVariable(name: 'foo'), | |
| _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.VariableStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => VariableStatement( | |
| VariableDeclaration( | |
| LocalVariable(name: 'foo')..fileOffset = _needFileOffset(), | |
| )..fileOffset = _needFileOffset(), | |
| )..fileOffset = _needFileOffset(), | |
| () => VariableStatement( | |
| VariableDeclaration( | |
| LocalVariable(name: 'foo', initializer: _createExpression()) | |
| ..fileOffset = _needFileOffset(), | |
| )..fileOffset = _needFileOffset(), | |
| )..fileOffset = _needFileOffset(), | |
| () => VariableStatement( | |
| VariableDeclaration( | |
| LocalVariable(name: 'foo', type: _createDartType()) | |
| ..fileOffset = _needFileOffset(), | |
| )..fileOffset = _needFileOffset(), | |
| )..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( | |
| expression: _createExpression(), | |
| patternGuard: | |
| _createNodeFromKind(NodeKind.PatternGuard) as PatternGuard, | |
| then: _createStatement(), | |
| otherwise: null, | |
| matchedValueType: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| () => IfCaseStatement( | |
| expression: _createExpression(), | |
| patternGuard: | |
| _createNodeFromKind(NodeKind.PatternGuard) as PatternGuard, | |
| then: _createStatement(), | |
| otherwise: _createStatement(), | |
| matchedValueType: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.PatternVariableDeclaration: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => new PatternVariableDeclaration( | |
| _createPattern(), | |
| _createExpression(), | |
| isFinal: false, | |
| matchedValueType: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| () => new PatternVariableDeclaration( | |
| _createPattern(), | |
| _createExpression(), | |
| isFinal: true, | |
| matchedValueType: _createDartType(), | |
| )..fileOffset = _needFileOffset(), | |
| ]); | |
| } | |
| } | |
| /// Creates a [Variable] node. | |
| /// | |
| /// If there are any pending [Variable] nodes, one of these is | |
| /// created. | |
| Variable _createVariableFromKind(VariableKind kind) { | |
| int? index = _pendingVariables.remove(kind); | |
| switch (kind) { | |
| case VariableKind.CatchVariable: | |
| return CatchVariable(name: 'e'); | |
| case VariableKind.LateVariable: | |
| return LateVariable(name: 'foo'); | |
| case VariableKind.LocalFunctionVariable: | |
| return LocalFunctionVariable(name: 'foo'); | |
| case VariableKind.ConstVariable: | |
| return ConstVariable(name: 'foo'); | |
| case VariableKind.LocalVariable: | |
| return _createOneOf(_pendingVariables, kind, index, [ | |
| () => LocalVariable(name: 'foo')..fileOffset = _needFileOffset(), | |
| () => | |
| LocalVariable(name: 'foo', initializer: _createExpression()) | |
| ..fileOffset = _needFileOffset(), | |
| () => | |
| LocalVariable(name: 'foo', type: _createDartType()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case VariableKind.NamedParameter: | |
| return NamedParameter(parameterName: 'foo'); | |
| case VariableKind.PositionalParameter: | |
| return PositionalParameter(parameterName: 'foo'); | |
| case VariableKind.SyntheticVariable: | |
| return SyntheticVariable(); | |
| case VariableKind.ThisVariable: | |
| return ThisVariable(type: _createDartType()); | |
| } | |
| } | |
| /// 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( | |
| DartTypeList.empty, | |
| _createDartType(), | |
| Nullability.nonNullable, | |
| ), | |
| ]); | |
| case DartTypeKind.RecordType: | |
| return _createOneOf(_pendingDartTypes, kind, index, [ | |
| // TODO(cstefantsova): Create non-trivial cases. | |
| () => RecordType( | |
| DartTypeList.empty, | |
| NamedDartTypeList.empty, | |
| 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, | |
| DartTypeList.empty, | |
| ), | |
| ]); | |
| 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, | |
| DartTypeList.empty, | |
| ), | |
| ]); | |
| case DartTypeKind.ExtensionType: | |
| return ExtensionType( | |
| _needExtensionTypeDeclaration(), | |
| Nullability.nonNullable, | |
| ); | |
| case DartTypeKind.VoidType: | |
| return VoidType(); | |
| case DartTypeKind.FunctionTypeParameterType: | |
| throw new UnimplementedError("Unimplemented support for $kind."); | |
| case DartTypeKind.ClassTypeParameterType: | |
| throw new UnimplementedError("Unimplemented support for $kind."); | |
| } | |
| } | |
| /// 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, DartTypeList.empty, {}), | |
| () => InstanceConstant( | |
| _needClass().reference, | |
| DartTypeList(_createDartType()), | |
| { | |
| _needField(isStatic: false, hasSetter: false).getterReference: | |
| _createConstant(), | |
| }, | |
| ), | |
| () => InstanceConstant( | |
| _needClass().reference, | |
| DartTypeList(_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(), | |
| DartTypeList(_createDartType()), | |
| ); | |
| case ConstantKind.IntConstant: | |
| return IntConstant(42); | |
| case ConstantKind.ListConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => ListConstant(_createDartType(), ConstantList.empty), | |
| () => | |
| ListConstant(_createDartType(), ConstantList(_createConstant())), | |
| () => ListConstant( | |
| _createDartType(), | |
| ConstantList(_createConstant(), _createConstant()), | |
| ), | |
| ]); | |
| case ConstantKind.MapConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => MapConstant( | |
| _createDartType(), | |
| _createDartType(), | |
| ConstantMapEntryList.empty, | |
| ), | |
| () => MapConstant( | |
| _createDartType(), | |
| _createDartType(), | |
| ConstantMapEntryList( | |
| ConstantMapEntry(_createConstant(), _createConstant()), | |
| ), | |
| ), | |
| () => MapConstant( | |
| _createDartType(), | |
| _createDartType(), | |
| ConstantMapEntryList( | |
| ConstantMapEntry(_createConstant(), _createConstant()), | |
| ConstantMapEntry(_createConstant(), _createConstant()), | |
| ), | |
| ), | |
| ]); | |
| case ConstantKind.RecordConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => RecordConstant( | |
| ConstantList.empty, | |
| {}, | |
| RecordType( | |
| DartTypeList.empty, | |
| NamedDartTypeList.empty, | |
| Nullability.nonNullable, | |
| ), | |
| ), | |
| () => RecordConstant( | |
| ConstantList(_createConstant(), _createConstant()), | |
| {}, | |
| RecordType( | |
| DartTypeList(_createDartType(), _createDartType()), | |
| NamedDartTypeList.empty, | |
| Nullability.nonNullable, | |
| ), | |
| ), | |
| () => RecordConstant( | |
| ConstantList.empty, | |
| {'a': _createConstant(), 'b': _createConstant()}, | |
| RecordType( | |
| DartTypeList.empty, | |
| NamedDartTypeList( | |
| NamedType('a', _createDartType()), | |
| NamedType('b', _createDartType()), | |
| ), | |
| Nullability.nonNullable, | |
| ), | |
| ), | |
| () => RecordConstant( | |
| ConstantList(_createConstant()), | |
| {'a': _createConstant()}, | |
| RecordType( | |
| DartTypeList(_createDartType()), | |
| NamedDartTypeList(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(), ConstantList.empty), | |
| () => SetConstant(_createDartType(), ConstantList(_createConstant())), | |
| () => SetConstant( | |
| _createDartType(), | |
| ConstantList(_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( | |
| StructuralParameterList.empty, | |
| _createConstantFromKind(ConstantKind.ConstructorTearOffConstant) | |
| as TearOffConstant, | |
| DartTypeList.empty, | |
| ); | |
| 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( | |
| _createVariableFromKind(VariableKind.SyntheticVariable) | |
| as SyntheticVariable, | |
| _createExpression(), | |
| )..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.empty()..fileOffset = _needFileOffset(), | |
| ]); | |
| case NodeKind.Catch: | |
| return _createOneOf(_pendingNodes, kind, index, [ | |
| () => Catch(null, _createStatement())..fileOffset = _needFileOffset(), | |
| () => Catch( | |
| _createVariableFromKind(VariableKind.CatchVariable) | |
| as CatchVariable, | |
| _createStatement(), | |
| )..fileOffset = _needFileOffset(), | |
| () => Catch( | |
| null, | |
| _createStatement(), | |
| stackTrace: _createVariableFromKind( | |
| VariableKind.CatchVariable, | |
| ) as CatchVariable, | |
| )..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: | |
| return _createOneOf(_pendingNodes, kind, index, [ | |
| () => | |
| FunctionNode(_createStatement())..fileOffset = _needFileOffset(), | |
| () => FunctionNode( | |
| _createStatement(), | |
| positionalParameters: PositionalParameterList( | |
| _createVariableFromKind(VariableKind.PositionalParameter) | |
| as PositionalParameter, | |
| ), | |
| )..fileOffset = _needFileOffset(), | |
| () => FunctionNode( | |
| _createStatement(), | |
| namedParameters: NamedParameterList( | |
| _createVariableFromKind(VariableKind.NamedParameter) | |
| as NamedParameter, | |
| ), | |
| )..fileOffset = _needFileOffset(), | |
| () => FunctionNode( | |
| _createStatement(), | |
| thisVariable: _createVariableFromKind( | |
| VariableKind.ThisVariable, | |
| ) as ThisVariable, | |
| )..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', _uri)..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(), DartTypeList.empty), | |
| () => Supertype(_needClass(), DartTypeList(_createDartType())), | |
| () => Supertype( | |
| _needClass(), | |
| DartTypeList(_createDartType(), _createDartType()), | |
| ), | |
| ]); | |
| case NodeKind.SwitchCase: | |
| // TODO(johnniwinther): Add non-trivial cases. | |
| return SwitchCase(ExpressionList(NullLiteral()), [ | |
| TreeNode.noOffset, | |
| ], _createStatement())..fileOffset = _needFileOffset(); | |
| case NodeKind.NominalParameter: | |
| 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, | |
| jointVariableDeclarations: [], | |
| jointVariableFirstUseOffsets: null, | |
| jointVariableScope: null, | |
| ), | |
| () => new PatternSwitchCase( | |
| [0], | |
| [_createNodeFromKind(NodeKind.PatternGuard) as PatternGuard], | |
| _createStatement(), | |
| isDefault: false, | |
| hasLabel: true, | |
| jointVariableDeclarations: [], | |
| jointVariableFirstUseOffsets: null, | |
| jointVariableScope: null, | |
| ), | |
| ]); | |
| case NodeKind.SwitchExpressionCase: | |
| return new SwitchExpressionCase( | |
| _createNodeFromKind(NodeKind.PatternGuard) as PatternGuard, | |
| _createExpression(), | |
| )..fileOffset = _needFileOffset(); | |
| case NodeKind.VariableDeclaration: | |
| return _createOneOf(_pendingNodes, kind, index, [ | |
| () => new VariableDeclaration( | |
| _createVariableFromKind(VariableKind.LocalVariable) | |
| as DeclaredVariable, | |
| ), | |
| () => new VariableDeclaration( | |
| _createVariableFromKind(VariableKind.LateVariable) | |
| as DeclaredVariable, | |
| ), | |
| ]); | |
| case NodeKind.TypeVariable: | |
| throw new UnimplementedError("Unimplemented support for kind $kind."); | |
| } | |
| } | |
| /// 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.NominalParameter, | |
| NodeKind.PatternGuard, | |
| NodeKind.PatternSwitchCase, | |
| NodeKind.SwitchExpressionCase, | |
| NodeKind.VariableDeclaration, | |
| }; |