| // Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import '../ast.dart'; | |
| import 'coverage.dart'; | |
| /// Helper class used to generate ASTs that contain all different nodes. | |
| class NodeCreator { | |
| final Uri _uri; | |
| /// File offset counter. | |
| /// | |
| /// Used to generate distinct file offsets through [_needFileOffset]. | |
| int _fileOffset = 0; | |
| /// The parent [Component] for all created libraries, classes, extensions, | |
| /// typedefs and members. | |
| final Component _component = new Component(); | |
| /// These fields contain maps of requested nodes different kinds that are | |
| /// still pending. The mapped values are used to track how many nodes of the | |
| /// specific kind have been created. When all variants of a kind have been | |
| /// created, the entry is removed from the map. | |
| final Map<ExpressionKind, int> _pendingExpressions; | |
| final Map<StatementKind, int> _pendingStatements; | |
| final Map<DartTypeKind, int> _pendingDartTypes; | |
| final Map<ConstantKind, int> _pendingConstants; | |
| final Map<PatternKind, int> _pendingPatterns; | |
| final Map<InitializerKind, int> _pendingInitializers; | |
| final Map<MemberKind, int> _pendingMembers; | |
| final Map<NodeKind, int> _pendingNodes; | |
| /// The set of all kinds of nodes created by this node creator. | |
| final Set<Object> _createdKinds = {}; | |
| /// These fields contain list of nodes needed for the creation of other nodes. | |
| /// | |
| /// Needed nodes are nodes that need to exist prior to the node that required | |
| /// it. For instance, to create an [InterfaceType] node, a [Class] node must | |
| /// exist for the [InterfaceType] to reference. | |
| /// | |
| /// Needed nodes are added to the context of the created nodes. For instance, | |
| /// a needed [Class] is added to the [_component] and a needed | |
| /// [VariableDeclaration] is added to a enclosing [Block]. | |
| List<Library> _neededLibraries = []; | |
| List<Class> _neededClasses = []; | |
| List<Extension> _neededExtensions = []; | |
| List<InlineClass> _neededInlineClasses = []; | |
| 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<PatternKind> patterns = PatternKind.values, | |
| Iterable<InitializerKind> initializers = InitializerKind.values, | |
| Iterable<MemberKind> members = MemberKind.values, | |
| Iterable<NodeKind> nodes = NodeKind.values, | |
| }) : _pendingExpressions = new Map<ExpressionKind, int>.fromIterables( | |
| expressions, new List<int>.filled(expressions.length, 0)), | |
| _pendingStatements = new Map<StatementKind, int>.fromIterables( | |
| statements, new List<int>.filled(statements.length, 0)), | |
| _pendingDartTypes = new Map<DartTypeKind, int>.fromIterables( | |
| dartTypes, new List<int>.filled(dartTypes.length, 0)), | |
| _pendingConstants = new Map<ConstantKind, int>.fromIterables( | |
| constants, new List<int>.filled(constants.length, 0)), | |
| _pendingPatterns = new Map<PatternKind, int>.fromIterables( | |
| patterns, new List<int>.filled(patterns.length, 0)), | |
| _pendingInitializers = new Map<InitializerKind, int>.fromIterables( | |
| initializers, new List<int>.filled(initializers.length, 0)), | |
| _pendingMembers = new Map<MemberKind, int>.fromIterables( | |
| members, new List<int>.filled(members.length, 0)), | |
| _pendingNodes = new Map<NodeKind, int>.fromIterables( | |
| nodes, new List<int>.filled(nodes.length, 0)), | |
| _uri = Uri.parse('test:uri') { | |
| _createdKinds.addAll(_pendingExpressions.keys); | |
| _createdKinds.addAll(_pendingStatements.keys); | |
| _createdKinds.addAll(_pendingDartTypes.keys); | |
| _createdKinds.addAll(_pendingInitializers.keys); | |
| _createdKinds.addAll(_pendingMembers.keys); | |
| _createdKinds.addAll(_pendingNodes.keys); | |
| } | |
| /// The kinds created by this node creator. | |
| Iterable<Object> get createdKinds => _createdKinds; | |
| /// Wraps [statement] in nodes needed in the statement context. | |
| /// | |
| /// For instance, if a [LabeledStatement] was needed for the creation of | |
| /// [statement], [statement] is wrapped inside the labeled statement. | |
| Statement _ensureContext(Statement statement) { | |
| if (_neededSwitchCases.isNotEmpty) { | |
| statement = SwitchStatement(NullLiteral(), [ | |
| ..._neededSwitchCases, | |
| SwitchCase([NullLiteral()], [TreeNode.noOffset], Block([statement])) | |
| ]); | |
| } | |
| _neededSwitchCases.clear(); | |
| for (LabeledStatement labeledStatement in _neededLabeledStatements) { | |
| labeledStatement.body = statement; | |
| statement = labeledStatement; | |
| } | |
| _neededLabeledStatements.clear(); | |
| statement = Block([ | |
| ..._neededVariableDeclarations, | |
| ..._neededFunctionDeclarations, | |
| statement | |
| ]); | |
| _neededFunctionDeclarations.clear(); | |
| _neededVariableDeclarations.clear(); | |
| return statement; | |
| } | |
| /// Adds [statement] to [statements] including any nodes needed in the | |
| /// context. | |
| void _addStatement(List<Statement> statements, Statement statement) { | |
| statements.add(_ensureContext(statement)); | |
| } | |
| /// Adds [expression] to [statements] including any nodes needed in the | |
| /// context. | |
| void _addExpression(List<Statement> statements, Expression expression) { | |
| _addStatement(statements, ExpressionStatement(expression)); | |
| } | |
| /// Adds [type] to [statements] including any nodes needed in the context. | |
| void _addDartType(List<Statement> statements, DartType type) { | |
| _addExpression(statements, TypeLiteral(type)); | |
| } | |
| /// Adds [constant] to [statements] including any nodes needed in the context. | |
| void _addConstant(List<Statement> statements, Constant constant) { | |
| _addExpression(statements, ConstantExpression(constant)); | |
| } | |
| /// Adds [pattern] to [statements] including any nodes needed in the context. | |
| void _addPattern(List<Statement> statements, Pattern pattern) { | |
| _addExpression(statements, PatternAssignment(pattern, NullLiteral())); | |
| } | |
| /// Generates a list of [Statement] containing all pending in-body nodes. | |
| List<Statement> _generateBodies() { | |
| List<Statement> statements = []; | |
| while (_pendingStatements.isNotEmpty) { | |
| _addStatement(statements, _createStatement()); | |
| } | |
| while (_pendingExpressions.isNotEmpty) { | |
| _addExpression(statements, _createExpression()); | |
| } | |
| while (_pendingDartTypes.isNotEmpty) { | |
| _addDartType(statements, _createDartType()); | |
| } | |
| while (_pendingConstants.isNotEmpty) { | |
| _addConstant(statements, _createConstant()); | |
| } | |
| for (NodeKind kind in inBodyNodeKinds) { | |
| while (_pendingNodes.containsKey(kind)) { | |
| Node node = _createNodeFromKind(kind); | |
| switch (kind) { | |
| case NodeKind.Name: | |
| _addExpression( | |
| statements, | |
| DynamicGet(DynamicAccessKind.Dynamic, _createExpression(), | |
| node as Name)); | |
| break; | |
| case NodeKind.Arguments: | |
| _addExpression( | |
| statements, | |
| DynamicInvocation(DynamicAccessKind.Dynamic, | |
| _createExpression(), _createName(), node as Arguments)); | |
| break; | |
| case NodeKind.Catch: | |
| _addStatement( | |
| statements, TryCatch(_createStatement(), [node as Catch])); | |
| break; | |
| case NodeKind.FunctionNode: | |
| _addExpression( | |
| statements, FunctionExpression(node as FunctionNode)); | |
| break; | |
| case NodeKind.MapLiteralEntry: | |
| _addExpression(statements, MapLiteral([node as MapLiteralEntry])); | |
| break; | |
| case NodeKind.MapPatternEntry: | |
| _addPattern( | |
| statements, MapPattern(null, null, [node as MapPatternEntry])); | |
| break; | |
| case NodeKind.MapPatternRestEntry: | |
| _addPattern(statements, | |
| MapPattern(null, null, [node as MapPatternRestEntry])); | |
| break; | |
| case NodeKind.NamedExpression: | |
| _addExpression( | |
| statements, | |
| DynamicInvocation( | |
| DynamicAccessKind.Dynamic, | |
| _createExpression(), | |
| _createName(), | |
| Arguments([], named: [node as NamedExpression]))); | |
| break; | |
| case NodeKind.NamedType: | |
| _addDartType( | |
| statements, | |
| FunctionType([], _createDartType(), Nullability.nonNullable, | |
| namedParameters: [node as NamedType])); | |
| break; | |
| case NodeKind.PatternSwitchCase: | |
| _addStatement( | |
| statements, | |
| PatternSwitchStatement( | |
| _createExpression(), [node as PatternSwitchCase])); | |
| break; | |
| case NodeKind.SwitchCase: | |
| _addStatement(statements, | |
| SwitchStatement(_createExpression(), [node as SwitchCase])); | |
| break; | |
| case NodeKind.SwitchExpressionCase: | |
| _addExpression( | |
| statements, | |
| SwitchExpression( | |
| _createExpression(), [node as SwitchExpressionCase])); | |
| break; | |
| case NodeKind.TypeParameter: | |
| _addExpression( | |
| statements, | |
| FunctionExpression(FunctionNode(Block([]), | |
| typeParameters: [node as TypeParameter]))); | |
| break; | |
| default: | |
| throw new UnimplementedError('Unhandled in body node $kind.'); | |
| } | |
| } | |
| } | |
| return statements; | |
| } | |
| /// Generates [Statement]s containing occurrences of all requested nodes. | |
| List<Statement> generateBodies() { | |
| List<Statement> statements = _generateBodies(); | |
| Set<Object> unsupportedKinds = {}; | |
| if (_pendingInitializers.isNotEmpty) { | |
| unsupportedKinds.addAll(_pendingInitializers.keys); | |
| } | |
| if (_pendingMembers.isNotEmpty) { | |
| unsupportedKinds.addAll(_pendingMembers.keys); | |
| } | |
| if (_pendingNodes.isNotEmpty) { | |
| assert( | |
| _pendingNodes.keys.every((kind) => !inBodyNodeKinds.contains(kind))); | |
| unsupportedKinds.addAll(_pendingNodes.keys); | |
| } | |
| if (unsupportedKinds.isNotEmpty) { | |
| throw new UnsupportedError('Cannot create these node in a body context: ' | |
| '${unsupportedKinds.join(', ')}'); | |
| } | |
| return statements; | |
| } | |
| /// Generates a [Component] containing occurrences of all requested and needed | |
| /// nodes. | |
| Component generateComponent() { | |
| Class cls = _needClass(); | |
| for (Statement statement in _generateBodies()) { | |
| cls.addProcedure(Procedure( | |
| _createName(), ProcedureKind.Method, FunctionNode(statement), | |
| fileUri: _uri)); | |
| } | |
| while (_pendingInitializers.isNotEmpty) { | |
| Initializer initializer = _createInitializer(); | |
| cls.addConstructor(Constructor(FunctionNode(null), | |
| name: _createName(), fileUri: _uri, initializers: [initializer])); | |
| } | |
| while (_pendingMembers.isNotEmpty) { | |
| Member member = _createMember(); | |
| if (member is Procedure) { | |
| cls.addProcedure(member); | |
| } else if (member is Field) { | |
| cls.addField(member); | |
| } else if (member is Constructor) { | |
| cls.addConstructor(member); | |
| } else 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: | |
| case NodeKind.MapPatternEntry: | |
| case NodeKind.MapPatternRestEntry: | |
| case NodeKind.PatternGuard: | |
| case NodeKind.PatternSwitchCase: | |
| case NodeKind.SwitchExpressionCase: | |
| throw new UnimplementedError('Expected in body node $kind.'); | |
| case NodeKind.Class: | |
| _needLibrary().addClass(node as Class); | |
| break; | |
| case NodeKind.Combinator: | |
| _needLibrary().addDependency(LibraryDependency.import(_needLibrary(), | |
| combinators: [node as Combinator])); | |
| break; | |
| case NodeKind.Component: | |
| assert(identical(node, _component), | |
| "Cannot create multiple Component nodes."); | |
| break; | |
| case NodeKind.Extension: | |
| _needLibrary().addExtension(node as Extension); | |
| break; | |
| case NodeKind.Library: | |
| _component.libraries.add(node as Library); | |
| break; | |
| case NodeKind.LibraryDependency: | |
| _needLibrary().addDependency(node as LibraryDependency); | |
| break; | |
| case NodeKind.LibraryPart: | |
| _needLibrary().addPart(node as LibraryPart); | |
| break; | |
| case NodeKind.Supertype: | |
| _needLibrary().addClass( | |
| Class(name: 'foo', fileUri: _uri, supertype: node as Supertype)); | |
| break; | |
| case NodeKind.Typedef: | |
| _needLibrary().addTypedef(node as Typedef); | |
| break; | |
| case NodeKind.InlineClass: | |
| _needLibrary().addInlineClass(node as InlineClass); | |
| 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 [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: const DynamicType()); | |
| _neededExtensions.add(extension); | |
| _needLibrary().addExtension(extension); | |
| return extension; | |
| } | |
| /// Returns an [InlineClass] node that fits the requirements. | |
| /// | |
| /// If no such [InlineClass] exists in [_neededInlineClasses], a new | |
| /// [InlineClass] is created and added to [_neededInlineClasses]. | |
| // TODO(johnniwinther): Add requirements when/where needed. | |
| InlineClass _needInlineClass() { | |
| for (InlineClass inlineClass in _neededInlineClasses) { | |
| return inlineClass; | |
| } | |
| InlineClass inlineClass = InlineClass( | |
| name: 'foo', | |
| fileUri: _uri, | |
| declaredRepresentationType: const DynamicType()); | |
| _neededInlineClasses.add(inlineClass); | |
| _needLibrary().addInlineClass(inlineClass); | |
| return inlineClass; | |
| } | |
| /// 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.AbstractSuperMethodInvocation: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => AbstractSuperMethodInvocation( | |
| _createName(), _createArguments(), _needProcedure()) | |
| ..fileOffset = _needFileOffset(), | |
| () => AbstractSuperMethodInvocation( | |
| _createName(), _createArguments(), _needProcedure()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SuperMethodInvocation: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => SuperMethodInvocation( | |
| _createName(), _createArguments(), _needProcedure()) | |
| ..fileOffset = _needFileOffset(), | |
| () => SuperMethodInvocation( | |
| _createName(), _createArguments(), _needProcedure()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.AbstractSuperPropertyGet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => AbstractSuperPropertyGet(_createName(), _needProcedure()) | |
| ..fileOffset = _needFileOffset(), | |
| () => AbstractSuperPropertyGet(_createName(), _needField()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.AbstractSuperPropertySet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => AbstractSuperPropertySet( | |
| _createName(), _createExpression(), _needProcedure()) | |
| ..fileOffset = _needFileOffset(), | |
| () => AbstractSuperPropertySet( | |
| _createName(), _createExpression(), _needField()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SuperPropertyGet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => SuperPropertyGet(_createName(), _needProcedure()) | |
| ..fileOffset = _needFileOffset(), | |
| () => SuperPropertyGet(_createName(), _needField()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SuperPropertySet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => SuperPropertySet( | |
| _createName(), _createExpression(), _needProcedure()) | |
| ..fileOffset = _needFileOffset(), | |
| () => | |
| SuperPropertySet(_createName(), _createExpression(), _needField()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SymbolLiteral: | |
| return SymbolLiteral('foo')..fileOffset = _needFileOffset(); | |
| case ExpressionKind.ThisExpression: | |
| return ThisExpression()..fileOffset = _needFileOffset(); | |
| case ExpressionKind.Throw: | |
| return Throw(_createExpression())..fileOffset = _needFileOffset(); | |
| case ExpressionKind.TypeLiteral: | |
| return TypeLiteral(_createDartType())..fileOffset = _needFileOffset(); | |
| case ExpressionKind.TypedefTearOff: | |
| // TODO(johnniwinther): Add non-trivial cases. | |
| return TypedefTearOff([], _createExpression(), []) | |
| ..fileOffset = _needFileOffset(); | |
| case ExpressionKind.VariableGet: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => VariableGet(_needVariableDeclaration()) | |
| ..fileOffset = _needFileOffset(), | |
| () => VariableGet(_needVariableDeclaration(), _createDartType()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.VariableSet: | |
| return VariableSet(_needVariableDeclaration(), _createExpression()) | |
| ..fileOffset = _needFileOffset(); | |
| case ExpressionKind.RecordIndexGet: | |
| return RecordIndexGet(_createExpression(), | |
| new RecordType([_createDartType()], [], Nullability.nonNullable), 0) | |
| ..fileOffset = _needFileOffset(); | |
| case ExpressionKind.RecordNameGet: | |
| String name = _createName().text; | |
| return RecordNameGet( | |
| _createExpression(), | |
| new RecordType([], [new NamedType(name, _createDartType())], | |
| Nullability.nonNullable), | |
| name) | |
| ..fileOffset = _needFileOffset(); | |
| case ExpressionKind.RecordLiteral: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => RecordLiteral([_createExpression()], [], | |
| RecordType([_createDartType()], [], Nullability.nonNullable), | |
| isConst: false) | |
| ..fileOffset = _needFileOffset(), | |
| () => RecordLiteral( | |
| [], | |
| [NamedExpression('foo', _createExpression())], | |
| RecordType([], [NamedType('foo', _createDartType())], | |
| Nullability.nonNullable), | |
| isConst: false) | |
| ..fileOffset = _needFileOffset(), | |
| () => RecordLiteral( | |
| [_createExpression()], | |
| [NamedExpression('foo', _createExpression())], | |
| RecordType( | |
| [_createDartType()], | |
| [NamedType('foo', _createDartType())], | |
| Nullability.nonNullable), | |
| isConst: false) | |
| ..fileOffset = _needFileOffset(), | |
| () => RecordLiteral([_createExpression()], [], | |
| RecordType([_createDartType()], [], Nullability.nonNullable), | |
| isConst: true) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.SwitchExpression: | |
| return _createOneOf(_pendingExpressions, kind, index, [ | |
| () => new SwitchExpression(_createExpression(), []) | |
| ..fileOffset = _needFileOffset(), | |
| () => new SwitchExpression(_createExpression(), [ | |
| _createNodeFromKind(NodeKind.SwitchExpressionCase) | |
| as SwitchExpressionCase | |
| ]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case ExpressionKind.PatternAssignment: | |
| return new PatternAssignment(_createPattern(), _createExpression()) | |
| ..fileOffset = _needFileOffset(); | |
| } | |
| } | |
| /// Creates an [Pattern] node. | |
| /// | |
| /// If there are any pending expressions, one of these is created. | |
| Pattern _createPattern() { | |
| if (_pendingPatterns.isEmpty) { | |
| return ConstantPattern(NullLiteral()..fileOffset = _needFileOffset()) | |
| ..fileOffset = _needFileOffset(); | |
| } | |
| PatternKind kind = _pendingPatterns.keys.first; | |
| return _createPatternFromKind(kind); | |
| } | |
| /// Creates an [Expression] node of the specified [kind]. | |
| /// | |
| /// If there are any pending expressions of this [kind], one of these is | |
| /// created. | |
| Pattern _createPatternFromKind(PatternKind kind) { | |
| int? index = _pendingPatterns.remove(kind); | |
| switch (kind) { | |
| case PatternKind.AndPattern: | |
| return AndPattern(_createPattern(), _createPattern()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.AssignedVariablePattern: | |
| return AssignedVariablePattern(_needVariableDeclaration()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.CastPattern: | |
| return CastPattern(_createPattern(), _createDartType()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.ConstantPattern: | |
| return ConstantPattern(_createExpression()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.NullAssertPattern: | |
| return NullAssertPattern(_createPattern()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.NullCheckPattern: | |
| return NullCheckPattern(_createPattern()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.InvalidPattern: | |
| return InvalidPattern(_createExpression(), declaredVariables: []) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.ListPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => ListPattern(null, [])..fileOffset = _needFileOffset(), | |
| () => ListPattern(_createDartType(), [_createPattern()]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.MapPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => MapPattern(null, null, []), | |
| () => MapPattern(_createDartType(), _createDartType(), [ | |
| _createNodeFromKind(NodeKind.MapPatternEntry) as MapPatternEntry | |
| ]) | |
| ..fileOffset = _needFileOffset(), | |
| () => MapPattern(_createDartType(), _createDartType(), [ | |
| _createNodeFromKind(NodeKind.MapPatternEntry) | |
| as MapPatternEntry, | |
| _createNodeFromKind(NodeKind.MapPatternRestEntry) | |
| as MapPatternEntry | |
| ]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.NamedPattern: | |
| return NamedPattern('foo', _createPattern()) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.ObjectPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => ObjectPattern(_createDartType(), []) | |
| ..fileOffset = _needFileOffset(), | |
| () => ObjectPattern(_createDartType(), [ | |
| _createPatternFromKind(PatternKind.NamedPattern) as NamedPattern | |
| ]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.OrPattern: | |
| return OrPattern(_createPattern(), _createPattern(), | |
| orPatternJointVariables: []) | |
| ..fileOffset = _needFileOffset(); | |
| case PatternKind.RecordPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => RecordPattern([])..fileOffset = _needFileOffset(), | |
| () => | |
| RecordPattern([_createPattern()])..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.RelationalPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => RelationalPattern( | |
| RelationalPatternKind.equals, _createExpression()) | |
| ..fileOffset = _needFileOffset(), | |
| () => RelationalPattern( | |
| RelationalPatternKind.lessThan, _createExpression()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.RestPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => RestPattern(null)..fileOffset = _needFileOffset(), | |
| () => RestPattern(_createPattern())..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.VariablePattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => VariablePattern(null, _createVariableDeclaration()) | |
| ..fileOffset = _needFileOffset(), | |
| () => VariablePattern(_createDartType(), _createVariableDeclaration()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case PatternKind.WildcardPattern: | |
| return _createOneOf(_pendingPatterns, kind, index, [ | |
| () => WildcardPattern(null)..fileOffset = _needFileOffset(), | |
| () => WildcardPattern(_createDartType()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| } | |
| } | |
| /// Creates a [Statement] node. | |
| /// | |
| /// If there are any pending statements, one of these is created. | |
| Statement _createStatement() { | |
| if (_pendingStatements.isEmpty) { | |
| return EmptyStatement()..fileOffset = _needFileOffset(); | |
| } | |
| StatementKind kind = _pendingStatements.keys.first; | |
| return _createStatementFromKind(kind); | |
| } | |
| /// Creates a [Statement] of the specified [kind]. | |
| /// | |
| /// If there are any pending statements of this [kind], one of these is | |
| /// created. | |
| Statement _createStatementFromKind(StatementKind kind) { | |
| int? index = _pendingStatements.remove(kind); | |
| switch (kind) { | |
| case StatementKind.AssertBlock: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => AssertBlock([])..fileOffset = _needFileOffset(), | |
| () => | |
| AssertBlock([_createStatement()])..fileOffset = _needFileOffset(), | |
| () => AssertBlock([_createStatement(), _createStatement()]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.AssertStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => AssertStatement(_createExpression(), | |
| conditionStartOffset: _needFileOffset(), | |
| conditionEndOffset: _needFileOffset()) | |
| ..fileOffset = _needFileOffset(), | |
| () => AssertStatement(_createExpression(), | |
| message: _createExpression(), | |
| conditionStartOffset: _needFileOffset(), | |
| conditionEndOffset: _needFileOffset()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.Block: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => Block([])..fileOffset = _needFileOffset(), | |
| () => Block([_createStatement()])..fileOffset = _needFileOffset(), | |
| () => Block([_createStatement(), _createStatement()]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.BreakStatement: | |
| return BreakStatement(_needLabeledStatement()) | |
| ..fileOffset = _needFileOffset(); | |
| case StatementKind.ContinueSwitchStatement: | |
| return ContinueSwitchStatement(_needSwitchCase()) | |
| ..fileOffset = _needFileOffset(); | |
| case StatementKind.DoStatement: | |
| return DoStatement(_createStatement(), _createExpression()) | |
| ..fileOffset = _needFileOffset(); | |
| case StatementKind.EmptyStatement: | |
| return EmptyStatement()..fileOffset = _needFileOffset(); | |
| case StatementKind.ExpressionStatement: | |
| return ExpressionStatement(_createExpression()) | |
| ..fileOffset = _needFileOffset(); | |
| case StatementKind.ForInStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => ForInStatement(_createVariableDeclaration(), | |
| _createExpression(), _createStatement(), | |
| isAsync: false) | |
| ..fileOffset = _needFileOffset(), | |
| () => ForInStatement(_createVariableDeclaration(), | |
| _createExpression(), _createStatement(), | |
| isAsync: true) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.ForStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => ForStatement([], null, [], _createStatement()) | |
| ..fileOffset = _needFileOffset(), | |
| () => ForStatement([_createVariableDeclaration()], | |
| _createExpression(), [_createExpression()], _createStatement()) | |
| ..fileOffset = _needFileOffset(), | |
| () => ForStatement( | |
| [_createVariableDeclaration(), _createVariableDeclaration()], | |
| _createExpression(), | |
| [_createExpression(), _createExpression()], | |
| _createStatement()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.FunctionDeclaration: | |
| return FunctionDeclaration( | |
| VariableDeclaration(null, isSynthesized: true), | |
| _createFunctionNode()) | |
| ..fileOffset = _needFileOffset(); | |
| case StatementKind.IfStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => IfStatement(_createExpression(), _createStatement(), null) | |
| ..fileOffset = _needFileOffset(), | |
| () => IfStatement( | |
| _createExpression(), _createStatement(), _createStatement()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.LabeledStatement: | |
| return LabeledStatement(_createStatement()) | |
| ..fileOffset = _needFileOffset(); | |
| case StatementKind.ReturnStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => ReturnStatement()..fileOffset = _needFileOffset(), | |
| () => ReturnStatement(_createExpression()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.SwitchStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => SwitchStatement(_createExpression(), []) | |
| ..fileOffset = _needFileOffset(), | |
| () => SwitchStatement(_createExpression(), [_createSwitchCase()]) | |
| ..fileOffset = _needFileOffset(), | |
| () => SwitchStatement( | |
| _createExpression(), [_createSwitchCase(), _createSwitchCase()]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.TryCatch: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => | |
| TryCatch(_createStatement(), [])..fileOffset = _needFileOffset(), | |
| () => TryCatch(_createStatement(), [_createCatch()]) | |
| ..fileOffset = _needFileOffset(), | |
| () => TryCatch(_createStatement(), [_createCatch(), _createCatch()]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.TryFinally: | |
| return TryFinally(_createStatement(), _createStatement()) | |
| ..fileOffset = _needFileOffset(); | |
| case StatementKind.VariableDeclaration: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => VariableDeclaration('foo')..fileOffset = _needFileOffset(), | |
| () => VariableDeclaration('foo', initializer: _createExpression()) | |
| ..fileOffset = _needFileOffset(), | |
| () => VariableDeclaration('foo', type: _createDartType()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.WhileStatement: | |
| return WhileStatement(_createExpression(), _createStatement()) | |
| ..fileOffset = _needFileOffset(); | |
| case StatementKind.YieldStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => YieldStatement(_createExpression(), isYieldStar: false) | |
| ..fileOffset = _needFileOffset(), | |
| () => YieldStatement(_createExpression(), isYieldStar: true) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.PatternSwitchStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => PatternSwitchStatement(_createExpression(), []) | |
| ..fileOffset = _needFileOffset(), | |
| () => PatternSwitchStatement(_createExpression(), [ | |
| _createNodeFromKind(NodeKind.PatternSwitchCase) | |
| as PatternSwitchCase | |
| ]) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.IfCaseStatement: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => IfCaseStatement( | |
| _createExpression(), | |
| _createNodeFromKind(NodeKind.PatternGuard) as PatternGuard, | |
| _createStatement()) | |
| ..fileOffset = _needFileOffset(), | |
| () => IfCaseStatement( | |
| _createExpression(), | |
| _createNodeFromKind(NodeKind.PatternGuard) as PatternGuard, | |
| _createStatement(), | |
| _createStatement()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case StatementKind.PatternVariableDeclaration: | |
| return _createOneOf(_pendingStatements, kind, index, [ | |
| () => new PatternVariableDeclaration( | |
| _createPattern(), _createExpression(), | |
| isFinal: false) | |
| ..fileOffset = _needFileOffset(), | |
| () => new PatternVariableDeclaration( | |
| _createPattern(), _createExpression(), | |
| isFinal: true) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| } | |
| } | |
| /// Creates a [VariableDeclaration] node. | |
| /// | |
| /// If there are any pending [VariableDeclaration] nodes, one of these is | |
| /// created. | |
| VariableDeclaration _createVariableDeclaration() { | |
| return _createStatementFromKind(StatementKind.VariableDeclaration) | |
| as VariableDeclaration; | |
| } | |
| /// Creates a [DartType] node. | |
| /// | |
| /// If there are any pending types, one of these is created. | |
| DartType _createDartType() { | |
| if (_pendingDartTypes.isEmpty) { | |
| return VoidType(); | |
| } | |
| DartTypeKind kind = _pendingDartTypes.keys.first; | |
| return _createDartTypeFromKind(kind); | |
| } | |
| /// Creates a [DartType] node of the specified [kind]. | |
| /// | |
| /// If there are any pending types of this [kind], one of these is created. | |
| DartType _createDartTypeFromKind(DartTypeKind kind) { | |
| int? index = _pendingDartTypes.remove(kind); | |
| switch (kind) { | |
| case DartTypeKind.DynamicType: | |
| return DynamicType(); | |
| case DartTypeKind.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.RecordType: | |
| return _createOneOf(_pendingDartTypes, kind, index, [ | |
| // TODO(cstefantsova): Create non-trivial cases. | |
| () => RecordType([], [], Nullability.nonNullable), | |
| ]); | |
| case DartTypeKind.FutureOrType: | |
| return FutureOrType(_createDartType(), Nullability.nonNullable); | |
| case DartTypeKind.InterfaceType: | |
| return _createOneOf(_pendingDartTypes, kind, index, [ | |
| // TODO(johnniwinther): Create non-trivial cases. | |
| () => InterfaceType(_needClass(), Nullability.nonNullable, []), | |
| ]); | |
| case DartTypeKind.InvalidType: | |
| return InvalidType(); | |
| case DartTypeKind.NeverType: | |
| return NeverType.nonNullable(); | |
| case DartTypeKind.NullType: | |
| return NullType(); | |
| case DartTypeKind.TypeParameterType: | |
| return _createOneOf(_pendingDartTypes, kind, index, [ | |
| () => | |
| TypeParameterType(_needTypeParameter(), Nullability.nonNullable), | |
| ]); | |
| case DartTypeKind.IntersectionType: | |
| return _createOneOf(_pendingDartTypes, kind, index, [ | |
| () => IntersectionType( | |
| TypeParameterType(_needTypeParameter(), Nullability.nonNullable), | |
| _createDartType()), | |
| ]); | |
| case DartTypeKind.TypedefType: | |
| return _createOneOf(_pendingDartTypes, kind, index, [ | |
| // TODO(johnniwinther): Create non-trivial cases. | |
| () => TypedefType(_needTypedef(), Nullability.nonNullable, []), | |
| ]); | |
| case DartTypeKind.InlineType: | |
| return InlineType(_needInlineClass(), Nullability.nonNullable); | |
| case DartTypeKind.VoidType: | |
| return VoidType(); | |
| } | |
| } | |
| /// Creates a [FunctionType] node. | |
| /// | |
| /// If there are any pending [FunctionType] nodes, one of these is created. | |
| FunctionType _createFunctionType() { | |
| return _createDartTypeFromKind(DartTypeKind.FunctionType) as FunctionType; | |
| } | |
| /// Creates a [Constant] node. | |
| /// | |
| /// If there are any pending constants, one of these is created. | |
| Constant _createConstant() { | |
| if (_pendingConstants.isEmpty) { | |
| return NullConstant(); | |
| } | |
| ConstantKind kind = _pendingConstants.keys.first; | |
| return _createConstantFromKind(kind); | |
| } | |
| /// Creates a [Constant] node of the specified [kind]. | |
| /// | |
| /// If there are any pending constants of this [kind], one of these is | |
| /// created. | |
| Constant _createConstantFromKind(ConstantKind kind) { | |
| int? index = _pendingConstants.remove(kind); | |
| switch (kind) { | |
| case ConstantKind.BoolConstant: | |
| return BoolConstant(true); | |
| case ConstantKind.ConstructorTearOffConstant: | |
| return ConstructorTearOffConstant(_needConstructor()); | |
| case ConstantKind.DoubleConstant: | |
| return DoubleConstant(42.5); | |
| case ConstantKind.InstanceConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => InstanceConstant(_needClass().reference, [], {}), | |
| () => InstanceConstant(_needClass().reference, [ | |
| _createDartType() | |
| ], { | |
| _needField(isStatic: false, hasSetter: false).getterReference: | |
| _createConstant() | |
| }), | |
| () => InstanceConstant(_needClass().reference, [ | |
| _createDartType() | |
| ], { | |
| _needField(index: 0, isStatic: false, hasSetter: false) | |
| .getterReference: _createConstant(), | |
| _needField(index: 1, isStatic: false, hasSetter: false) | |
| .getterReference: _createConstant() | |
| }), | |
| ]); | |
| case ConstantKind.InstantiationConstant: | |
| return InstantiationConstant(_createConstant(), [_createDartType()]); | |
| case ConstantKind.IntConstant: | |
| return IntConstant(42); | |
| case ConstantKind.ListConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => ListConstant(_createDartType(), []), | |
| () => ListConstant(_createDartType(), [_createConstant()]), | |
| () => ListConstant( | |
| _createDartType(), [_createConstant(), _createConstant()]), | |
| ]); | |
| case ConstantKind.MapConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => MapConstant(_createDartType(), _createDartType(), []), | |
| () => MapConstant(_createDartType(), _createDartType(), | |
| [ConstantMapEntry(_createConstant(), _createConstant())]), | |
| () => MapConstant(_createDartType(), _createDartType(), [ | |
| ConstantMapEntry(_createConstant(), _createConstant()), | |
| ConstantMapEntry(_createConstant(), _createConstant()) | |
| ]), | |
| ]); | |
| case ConstantKind.RecordConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => RecordConstant( | |
| [], {}, RecordType([], [], Nullability.nonNullable)), | |
| () => RecordConstant( | |
| [_createConstant(), _createConstant()], | |
| {}, | |
| RecordType([_createDartType(), _createDartType()], [], | |
| Nullability.nonNullable)), | |
| () => RecordConstant( | |
| [], | |
| { | |
| 'a': _createConstant(), | |
| 'b': _createConstant(), | |
| }, | |
| RecordType([], [ | |
| NamedType('a', _createDartType()), | |
| NamedType('b', _createDartType()) | |
| ], Nullability.nonNullable)), | |
| () => RecordConstant( | |
| [_createConstant()], | |
| {'a': _createConstant()}, | |
| RecordType( | |
| [_createDartType()], | |
| [NamedType('a', _createDartType())], | |
| Nullability.nonNullable)), | |
| ]); | |
| case ConstantKind.NullConstant: | |
| return NullConstant(); | |
| case ConstantKind.RedirectingFactoryTearOffConstant: | |
| return RedirectingFactoryTearOffConstant(_needRedirectingFactory()); | |
| case ConstantKind.SetConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => SetConstant(_createDartType(), []), | |
| () => SetConstant(_createDartType(), [_createConstant()]), | |
| () => SetConstant( | |
| _createDartType(), [_createConstant(), _createConstant()]), | |
| ]); | |
| case ConstantKind.StaticTearOffConstant: | |
| return StaticTearOffConstant(_needProcedure()); | |
| case ConstantKind.StringConstant: | |
| return StringConstant('foo'); | |
| case ConstantKind.SymbolConstant: | |
| return _createOneOf(_pendingConstants, kind, index, [ | |
| () => SymbolConstant('foo', null), | |
| () => SymbolConstant('_foo', _needLibrary().reference), | |
| ]); | |
| case ConstantKind.TypeLiteralConstant: | |
| return TypeLiteralConstant(_createDartType()); | |
| case ConstantKind.TypedefTearOffConstant: | |
| // TODO(johnniwinther): Add non-trivial cases. | |
| return TypedefTearOffConstant( | |
| [], | |
| _createConstantFromKind(ConstantKind.ConstructorTearOffConstant) | |
| as TearOffConstant, | |
| []); | |
| case ConstantKind.UnevaluatedConstant: | |
| return UnevaluatedConstant(_createExpression()); | |
| } | |
| } | |
| /// Creates an [Initializer] node. | |
| /// | |
| /// If there are any pending initializers, one of these is created. | |
| Initializer _createInitializer() { | |
| if (_pendingInitializers.isEmpty) { | |
| return InvalidInitializer()..fileOffset = _needFileOffset(); | |
| } | |
| InitializerKind kind = _pendingInitializers.keys.first; | |
| return _createInitializerFromKind(kind); | |
| } | |
| /// Creates an [Initializer] node of the specified [kind]. | |
| /// | |
| /// If there are any pending initializers of this [kind], one of these is | |
| /// created. | |
| Initializer _createInitializerFromKind(InitializerKind kind) { | |
| // ignore: unused_local_variable | |
| int? index = _pendingInitializers.remove(kind); | |
| switch (kind) { | |
| case InitializerKind.AssertInitializer: | |
| return AssertInitializer( | |
| _createStatementFromKind(StatementKind.AssertStatement) | |
| as AssertStatement) | |
| ..fileOffset = _needFileOffset(); | |
| case InitializerKind.FieldInitializer: | |
| return FieldInitializer( | |
| _needField(isStatic: false), _createExpression()) | |
| ..fileOffset = _needFileOffset(); | |
| case InitializerKind.InvalidInitializer: | |
| return InvalidInitializer()..fileOffset = _needFileOffset(); | |
| case InitializerKind.LocalInitializer: | |
| return LocalInitializer(_createVariableDeclaration()) | |
| ..fileOffset = _needFileOffset(); | |
| case InitializerKind.RedirectingInitializer: | |
| return RedirectingInitializer(_needConstructor(), _createArguments()) | |
| ..fileOffset = _needFileOffset(); | |
| case InitializerKind.SuperInitializer: | |
| return SuperInitializer(_needConstructor(), _createArguments()) | |
| ..fileOffset = _needFileOffset(); | |
| } | |
| } | |
| /// Creates a [Member] node. | |
| /// | |
| /// If there are any pending members, one of these is created. | |
| Member _createMember() { | |
| if (_pendingMembers.isEmpty) { | |
| return Field.immutable(_createName(), fileUri: _uri) | |
| ..fileOffset = _needFileOffset(); | |
| } | |
| MemberKind kind = _pendingMembers.keys.first; | |
| return _createMemberKind(kind); | |
| } | |
| /// Creates a [Member] node of the specified [kind]. | |
| /// | |
| /// If there are any pending members of this [kind], one of these is created. | |
| Member _createMemberKind(MemberKind kind) { | |
| int? index = _pendingMembers.remove(kind); | |
| switch (kind) { | |
| case MemberKind.Constructor: | |
| return Constructor(_createFunctionNode(), | |
| name: _createName(), fileUri: _uri) | |
| ..fileOffset = _needFileOffset(); | |
| case MemberKind.Field: | |
| return _createOneOf(_pendingMembers, kind, index, [ | |
| () => Field.mutable(_createName(), fileUri: _uri) | |
| ..fileOffset = _needFileOffset(), | |
| () => Field.immutable(_createName(), fileUri: _uri) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case MemberKind.Procedure: | |
| return _createOneOf(_pendingMembers, kind, index, [ | |
| () => Procedure( | |
| _createName(), ProcedureKind.Method, _createFunctionNode(), | |
| fileUri: _uri) | |
| ..fileOffset = _needFileOffset(), | |
| () => Procedure( | |
| _createName(), ProcedureKind.Operator, _createFunctionNode(), | |
| fileUri: _uri) | |
| ..fileOffset = _needFileOffset(), | |
| () => Procedure( | |
| _createName(), ProcedureKind.Getter, _createFunctionNode(), | |
| fileUri: _uri) | |
| ..fileOffset = _needFileOffset(), | |
| () => Procedure( | |
| _createName(), ProcedureKind.Setter, _createFunctionNode(), | |
| fileUri: _uri) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| 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(); | |
| case NodeKind.InlineClass: | |
| // TODO(johnniwinther): Add non-trivial cases. | |
| return InlineClass(name: 'foo', fileUri: _uri) | |
| ..fileOffset = _needFileOffset() | |
| ..declaredRepresentationType = _createDartType(); | |
| case NodeKind.MapPatternEntry: | |
| return MapPatternEntry(_createExpression(), _createPattern()) | |
| ..fileOffset = _needFileOffset(); | |
| case NodeKind.MapPatternRestEntry: | |
| return MapPatternRestEntry()..fileOffset = _needFileOffset(); | |
| case NodeKind.PatternGuard: | |
| return _createOneOf(_pendingNodes, kind, index, [ | |
| () => new PatternGuard(_createPattern()) | |
| ..fileOffset = _needFileOffset(), | |
| () => new PatternGuard(_createPattern(), _createExpression()) | |
| ..fileOffset = _needFileOffset(), | |
| ]); | |
| case NodeKind.PatternSwitchCase: | |
| return _createOneOf(_pendingNodes, kind, index, [ | |
| () => new PatternSwitchCase([], [], _createStatement(), | |
| isDefault: true, | |
| hasLabel: false, | |
| jointVariables: [], | |
| jointVariableFirstUseOffsets: null), | |
| () => new PatternSwitchCase( | |
| [0], | |
| [_createNodeFromKind(NodeKind.PatternGuard) as PatternGuard], | |
| _createStatement(), | |
| isDefault: false, | |
| hasLabel: true, | |
| jointVariables: [], | |
| jointVariableFirstUseOffsets: null), | |
| ]); | |
| case NodeKind.SwitchExpressionCase: | |
| return new SwitchExpressionCase( | |
| _createNodeFromKind(NodeKind.PatternGuard) as PatternGuard, | |
| _createExpression()) | |
| ..fileOffset = _needFileOffset(); | |
| } | |
| } | |
| /// Helper that creates a node of type [V] using the list of [creators]. | |
| /// | |
| /// The [index] indicates how many nodes of the [kind] that have currently | |
| /// been created. If there are more [creators] left after having created the | |
| /// [index]th node, [pending] is updated with the next pending index. If all | |
| /// pending nodes of the given [kind] have been created, [index] is `null` and | |
| /// the first [creators] function is used. | |
| V _createOneOf<K, V>( | |
| Map<K, int> pending, K kind, int? index, List<V Function()> creators) { | |
| if (index == null) { | |
| // All pending nodes have been created so we just create the first. | |
| return creators[0](); | |
| } | |
| if (index + 1 < creators.length) { | |
| pending[kind] = index + 1; | |
| } | |
| return creators[index](); | |
| } | |
| } | |
| /// [NodeKind]s for nodes that can occur inside member bodies. | |
| const Set<NodeKind> inBodyNodeKinds = { | |
| NodeKind.Arguments, | |
| NodeKind.Catch, | |
| NodeKind.FunctionNode, | |
| NodeKind.MapLiteralEntry, | |
| NodeKind.MapPatternEntry, | |
| NodeKind.MapPatternRestEntry, | |
| NodeKind.Name, | |
| NodeKind.NamedExpression, | |
| NodeKind.NamedType, | |
| NodeKind.SwitchCase, | |
| NodeKind.TypeParameter, | |
| NodeKind.PatternGuard, | |
| NodeKind.PatternSwitchCase, | |
| NodeKind.SwitchExpressionCase, | |
| }; |