| // Copyright (c) 2016, 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 'package:_fe_analyzer_shared/src/messages/codes.dart' |
| show |
| LocatedMessage, |
| Message, |
| MessageCode, |
| codeBuiltInIdentifierInDeclaration, |
| messageAbstractLateField, |
| messageAbstractStaticField, |
| messageConstConstructorWithBody, |
| messageConstFactory, |
| messageConstructorWithTypeParameters, |
| messageDirectiveAfterDeclaration, |
| messageExpectedStatement, |
| messageExternalLateField, |
| messageFieldInitializerOutsideConstructor, |
| messageIllegalAssignmentToNonAssignable, |
| messageInterpolationInUri, |
| messageInvalidInitializer, |
| messageInvalidSuperInInitializer, |
| messageInvalidThisInInitializer, |
| messageMissingAssignableSelector, |
| messageNativeClauseShouldBeAnnotation, |
| messageOperatorWithTypeParameters, |
| messagePositionalAfterNamedArgument, |
| templateDuplicateLabelInSwitchStatement, |
| templateExpectedIdentifier, |
| templateExperimentNotEnabled, |
| templateExtraneousModifier, |
| templateInternalProblemUnhandled; |
| import 'package:_fe_analyzer_shared/src/parser/parser.dart' |
| show |
| Assert, |
| BlockKind, |
| boolFromToken, |
| ConstructorReferenceContext, |
| DeclarationHeaderKind, |
| DeclarationKind, |
| doubleFromToken, |
| FormalParameterKind, |
| IdentifierContext, |
| intFromToken, |
| MemberKind, |
| optional, |
| Parser; |
| import 'package:_fe_analyzer_shared/src/parser/quote.dart'; |
| import 'package:_fe_analyzer_shared/src/parser/stack_listener.dart' |
| show NullValues, StackListener; |
| import 'package:_fe_analyzer_shared/src/scanner/errors.dart' |
| show translateErrorToken; |
| import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'; |
| import 'package:_fe_analyzer_shared/src/scanner/token.dart' |
| show KeywordToken, StringToken, SyntheticToken; |
| import 'package:_fe_analyzer_shared/src/scanner/token_constants.dart'; |
| import 'package:_fe_analyzer_shared/src/util/null_value.dart'; |
| import 'package:analyzer/dart/analysis/features.dart'; |
| import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/error/error.dart'; |
| import 'package:analyzer/error/listener.dart'; |
| import 'package:analyzer/source/line_info.dart'; |
| import 'package:analyzer/src/dart/analysis/experiments.dart'; |
| import 'package:analyzer/src/dart/ast/ast.dart'; |
| import 'package:analyzer/src/dart/ast/extensions.dart'; |
| import 'package:analyzer/src/dart/error/syntactic_errors.dart'; |
| import 'package:analyzer/src/fasta/doc_comment_builder.dart'; |
| import 'package:analyzer/src/fasta/error_converter.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:analyzer/src/summary2/ast_binary_tokens.dart'; |
| import 'package:collection/collection.dart'; |
| import 'package:meta/meta.dart'; |
| import 'package:pub_semver/pub_semver.dart'; |
| |
| /// A parser listener that builds the analyzer's AST structure. |
| class AstBuilder extends StackListener { |
| final FastaErrorReporter errorReporter; |
| final Uri fileUri; |
| ScriptTagImpl? scriptTag; |
| final List<DirectiveImpl> directives = []; |
| final List<CompilationUnitMemberImpl> declarations = []; |
| final List<AstNodeImpl> invalidNodes = []; |
| |
| @override |
| final Uri uri; |
| |
| /// The parser that uses this listener, used to parse optional parts, e.g. |
| /// `native` support. |
| late Parser parser; |
| |
| /// The class like declaration being parsed. |
| _ClassLikeDeclarationBuilder? _classLikeBuilder; |
| |
| /// If true, this is building a full AST. Otherwise, only create method |
| /// bodies. |
| final bool isFullAst; |
| |
| /// `true` if the `native` clause is allowed |
| /// in class, method, and function declarations. |
| /// |
| /// This is being replaced by the @native(...) annotation. |
| // |
| // TODO(danrubel): Move this flag to a better location |
| // and should only be true if either: |
| // * The current library is a platform library |
| // * The current library has an import that uses the scheme "dart-ext". |
| bool allowNativeClause = false; |
| |
| StringLiteralImpl? nativeName; |
| |
| bool parseFunctionBodies = true; |
| |
| /// Whether the 'augmentations' feature is enabled. |
| final bool enableAugmentations; |
| |
| /// `true` if triple-shift behavior is enabled |
| final bool enableTripleShift; |
| |
| /// `true` if nonfunction-type-aliases behavior is enabled |
| final bool enableNonFunctionTypeAliases; |
| |
| /// `true` if variance behavior is enabled |
| final bool enableVariance; |
| |
| /// `true` if constructor tearoffs are enabled |
| final bool enableConstructorTearoffs; |
| |
| /// `true` if named arguments anywhere are enabled |
| final bool enableNamedArgumentsAnywhere; |
| |
| /// `true` if super parameters are enabled |
| final bool enableSuperParameters; |
| |
| /// `true` if enhanced enums are enabled |
| final bool enableEnhancedEnums; |
| |
| /// Whether the 'enhanced_parts' feature is enabled. |
| final bool enableEnhancedParts; |
| |
| /// Whether the 'macros' feature is enabled. |
| final bool enableMacros; |
| |
| /// `true` if records are enabled |
| final bool enableRecords; |
| |
| /// `true` if unnamed-library behavior is enabled |
| final bool enableUnnamedLibraries; |
| |
| /// `true` if inline-class is enabled |
| final bool enableInlineClass; |
| |
| /// `true` if sealed-class is enabled |
| final bool enableSealedClass; |
| |
| /// `true` if class-modifiers is enabled |
| final bool enableClassModifiers; |
| |
| /// `true` if null-aware elements is enabled |
| final bool enableNullAwareElements; |
| |
| /// `true` if dot-shorthands is enabled |
| final bool enabledDotShorthands; |
| |
| /// `true` if digit-separators is enabled. |
| final bool _enableDigitSeparators; |
| |
| final FeatureSet _featureSet; |
| |
| final LibraryLanguageVersion _languageVersion; |
| |
| final LineInfo _lineInfo; |
| |
| Token? _enclosingDeclarationAugmentToken; |
| |
| AstBuilder(ErrorReporter? errorReporter, this.fileUri, this.isFullAst, |
| this._featureSet, this._languageVersion, this._lineInfo, |
| [Uri? uri]) |
| : errorReporter = FastaErrorReporter(errorReporter), |
| enableAugmentations = _featureSet.isEnabled(Feature.augmentations), |
| enableTripleShift = _featureSet.isEnabled(Feature.triple_shift), |
| enableNonFunctionTypeAliases = |
| _featureSet.isEnabled(Feature.nonfunction_type_aliases), |
| enableVariance = _featureSet.isEnabled(Feature.variance), |
| enableConstructorTearoffs = |
| _featureSet.isEnabled(Feature.constructor_tearoffs), |
| enableNamedArgumentsAnywhere = |
| _featureSet.isEnabled(Feature.named_arguments_anywhere), |
| enableSuperParameters = _featureSet.isEnabled(Feature.super_parameters), |
| enableEnhancedEnums = _featureSet.isEnabled(Feature.enhanced_enums), |
| enableEnhancedParts = _featureSet.isEnabled(Feature.enhanced_parts), |
| enableMacros = _featureSet.isEnabled(Feature.macros), |
| enableRecords = _featureSet.isEnabled(Feature.records), |
| enableUnnamedLibraries = |
| _featureSet.isEnabled(Feature.unnamedLibraries), |
| enableInlineClass = _featureSet.isEnabled(Feature.inline_class), |
| enableSealedClass = _featureSet.isEnabled(Feature.sealed_class), |
| enableClassModifiers = _featureSet.isEnabled(Feature.class_modifiers), |
| enableNullAwareElements = |
| _featureSet.isEnabled(Feature.null_aware_elements), |
| enabledDotShorthands = _featureSet.isEnabled(Feature.dot_shorthands), |
| _enableDigitSeparators = |
| _featureSet.isEnabled(Feature.digit_separators), |
| uri = uri ?? fileUri; |
| |
| @override |
| bool get isDartLibrary => |
| uri.isScheme("dart") || uri.isScheme("org-dartlang-sdk"); |
| |
| @override |
| void addProblem(Message message, int charOffset, int length, |
| {bool wasHandled = false, List<LocatedMessage>? context}) { |
| if (directives.isEmpty && |
| (message.code.analyzerCodes |
| ?.contains('NON_PART_OF_DIRECTIVE_IN_PART') ?? |
| false)) { |
| message = messageDirectiveAfterDeclaration; |
| } |
| errorReporter.reportMessage(message, charOffset, length); |
| } |
| |
| @override |
| void beginAsOperatorType(Token asOperator) {} |
| |
| @override |
| void beginCascade(Token token) { |
| assert(optional('..', token) || optional('?..', token)); |
| debugEvent("beginCascade"); |
| |
| var expression = pop() as ExpressionImpl; |
| push(token); |
| if (expression is CascadeExpressionImpl) { |
| push(expression); |
| } else { |
| push( |
| CascadeExpressionImpl( |
| target: expression, |
| cascadeSections: <ExpressionImpl>[], |
| ), |
| ); |
| } |
| push(NullValues.CascadeReceiver); |
| } |
| |
| @override |
| void beginClassDeclaration( |
| Token begin, |
| Token? abstractToken, |
| Token? macroToken, |
| Token? sealedToken, |
| Token? baseToken, |
| Token? interfaceToken, |
| Token? finalToken, |
| Token? augmentToken, |
| Token? mixinToken, |
| Token name) { |
| assert(_classLikeBuilder == null); |
| push(_Modifiers()..abstractKeyword = abstractToken); |
| if (!enableMacros) { |
| if (macroToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.macros, |
| startToken: macroToken, |
| ); |
| // Pretend that 'macro' didn't occur while this feature is incomplete. |
| macroToken = null; |
| } |
| } |
| if (!enableSealedClass) { |
| if (sealedToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.sealed_class, |
| startToken: sealedToken, |
| ); |
| // Pretend that 'sealed' didn't occur while this feature is incomplete. |
| sealedToken = null; |
| } |
| } |
| if (!enableClassModifiers) { |
| if (baseToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: baseToken, |
| ); |
| // Pretend that 'base' didn't occur while this feature is incomplete. |
| baseToken = null; |
| } |
| if (interfaceToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: interfaceToken, |
| ); |
| // Pretend that 'interface' didn't occur while this feature is |
| // incomplete. |
| interfaceToken = null; |
| } |
| if (finalToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: finalToken, |
| ); |
| // Pretend that 'final' didn't occur while this feature is |
| // incomplete. |
| finalToken = null; |
| } |
| if (mixinToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: mixinToken, |
| ); |
| // Pretend that 'mixin' didn't occur while this feature is incomplete. |
| mixinToken = null; |
| } |
| } |
| push(macroToken ?? NullValues.Token); |
| push(sealedToken ?? NullValues.Token); |
| push(baseToken ?? NullValues.Token); |
| push(interfaceToken ?? NullValues.Token); |
| push(finalToken ?? NullValues.Token); |
| push(augmentToken ?? NullValues.Token); |
| push(mixinToken ?? NullValues.Token); |
| } |
| |
| @override |
| void beginCompilationUnit(Token token) { |
| push(token); |
| } |
| |
| @override |
| void beginConstantPattern(Token? constKeyword) {} |
| |
| @override |
| void beginEnum(Token enumKeyword) {} |
| |
| @override |
| void beginExtensionDeclaration( |
| Token? augmentKeyword, Token extensionKeyword, Token? nameToken) { |
| assert(optional('extension', extensionKeyword)); |
| assert(_classLikeBuilder == null); |
| debugEvent("ExtensionHeader"); |
| |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, extensionKeyword); |
| |
| _classLikeBuilder = _ExtensionDeclarationBuilder( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| extensionKeyword: extensionKeyword, |
| name: nameToken, |
| typeParameters: typeParameters, |
| leftBracket: Tokens.openCurlyBracket(), |
| rightBracket: Tokens.closeCurlyBracket(), |
| ); |
| } |
| |
| @override |
| void beginExtensionTypeDeclaration( |
| Token? augmentKeyword, Token extensionKeyword, Token name) { |
| assert(optional('extension', extensionKeyword)); |
| assert(_classLikeBuilder == null); |
| |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, extensionKeyword); |
| |
| _classLikeBuilder = _ExtensionTypeDeclarationBuilder( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| extensionKeyword: extensionKeyword, |
| name: name, |
| typeParameters: typeParameters, |
| leftBracket: Tokens.openCurlyBracket(), |
| rightBracket: Tokens.closeCurlyBracket(), |
| ); |
| } |
| |
| @override |
| void beginFactoryMethod(DeclarationKind declarationKind, Token lastConsumed, |
| Token? externalToken, Token? constToken) { |
| push(_Modifiers() |
| ..externalKeyword = externalToken |
| ..finalConstOrVarKeyword = constToken); |
| } |
| |
| @override |
| void beginFields( |
| DeclarationKind declarationKind, |
| Token? abstractToken, |
| Token? augmentToken, |
| Token? externalToken, |
| Token? staticToken, |
| Token? covariantToken, |
| Token? lateToken, |
| Token? varFinalOrConst, |
| Token lastConsumed, |
| ) { |
| _enclosingDeclarationAugmentToken = augmentToken; |
| |
| super.beginFields( |
| declarationKind, |
| abstractToken, |
| augmentToken, |
| externalToken, |
| staticToken, |
| covariantToken, |
| lateToken, |
| varFinalOrConst, |
| lastConsumed, |
| ); |
| } |
| |
| @override |
| void beginFormalParameter(Token token, MemberKind kind, Token? requiredToken, |
| Token? covariantToken, Token? varFinalOrConst) { |
| push(_Modifiers() |
| ..covariantKeyword = covariantToken |
| ..finalConstOrVarKeyword = varFinalOrConst |
| ..requiredToken = requiredToken); |
| } |
| |
| @override |
| void beginFormalParameterDefaultValueExpression() {} |
| |
| @override |
| void beginIfControlFlow(Token ifToken) { |
| push(ifToken); |
| } |
| |
| @override |
| void beginIsOperatorType(Token asOperator) {} |
| |
| @override |
| void beginLibraryAugmentation(Token augmentKeyword, Token libraryKeyword) {} |
| |
| @override |
| void beginLiteralString(Token literalString) { |
| assert(identical(literalString.kind, STRING_TOKEN)); |
| debugEvent("beginLiteralString"); |
| |
| push(literalString); |
| } |
| |
| @override |
| void beginMetadataStar(Token token) { |
| debugEvent("beginMetadataStar"); |
| } |
| |
| @override |
| void beginMethod( |
| DeclarationKind declarationKind, |
| Token? augmentToken, |
| Token? externalToken, |
| Token? staticToken, |
| Token? covariantToken, |
| Token? varFinalOrConst, |
| Token? getOrSet, |
| Token name, |
| String? enclosingDeclarationName) { |
| _Modifiers modifiers = _Modifiers(); |
| if (augmentToken != null) { |
| assert(augmentToken.isModifier); |
| modifiers.augmentKeyword = augmentToken; |
| _enclosingDeclarationAugmentToken = augmentToken; |
| } |
| if (externalToken != null) { |
| assert(externalToken.isModifier); |
| modifiers.externalKeyword = externalToken; |
| } |
| if (staticToken != null) { |
| assert(staticToken.isModifier); |
| var builder = _classLikeBuilder; |
| if (builder is! _ClassDeclarationBuilder || |
| builder.name.lexeme != name.lexeme || |
| getOrSet != null) { |
| modifiers.staticKeyword = staticToken; |
| } |
| } |
| if (covariantToken != null) { |
| assert(covariantToken.isModifier); |
| modifiers.covariantKeyword = covariantToken; |
| } |
| if (varFinalOrConst != null) { |
| assert(varFinalOrConst.isModifier); |
| modifiers.finalConstOrVarKeyword = varFinalOrConst; |
| } |
| push(modifiers); |
| } |
| |
| @override |
| void beginMixinDeclaration(Token beginToken, Token? augmentToken, |
| Token? baseToken, Token mixinKeyword, Token name) { |
| assert(_classLikeBuilder == null); |
| if (!enableClassModifiers) { |
| if (baseToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: baseToken, |
| ); |
| // Pretend that 'base' didn't occur while this feature is incomplete. |
| baseToken = null; |
| } |
| } |
| push(augmentToken ?? NullValues.Token); |
| push(baseToken ?? NullValues.Token); |
| } |
| |
| @override |
| void beginNamedMixinApplication( |
| Token begin, |
| Token? abstractToken, |
| Token? macroToken, |
| Token? sealedToken, |
| Token? baseToken, |
| Token? interfaceToken, |
| Token? finalToken, |
| Token? augmentToken, |
| Token? mixinToken, |
| Token name) { |
| push(_Modifiers()..abstractKeyword = abstractToken); |
| if (!enableMacros) { |
| if (macroToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.macros, |
| startToken: macroToken, |
| ); |
| // Pretend that 'macro' didn't occur while this feature is incomplete. |
| macroToken = null; |
| } |
| } |
| if (!enableSealedClass) { |
| if (sealedToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.sealed_class, |
| startToken: sealedToken, |
| ); |
| // Pretend that 'sealed' didn't occur while this feature is incomplete. |
| sealedToken = null; |
| } |
| } |
| if (!enableClassModifiers) { |
| if (baseToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: baseToken, |
| ); |
| // Pretend that 'base' didn't occur while this feature is incomplete. |
| baseToken = null; |
| } |
| if (interfaceToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: interfaceToken, |
| ); |
| // Pretend that 'interface' didn't occur while this feature is |
| // incomplete. |
| interfaceToken = null; |
| } |
| if (finalToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: finalToken, |
| ); |
| // Pretend that 'final' didn't occur while this feature is incomplete. |
| finalToken = null; |
| } |
| if (mixinToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.class_modifiers, |
| startToken: mixinToken, |
| ); |
| // Pretend that 'mixin' didn't occur while this feature is incomplete. |
| mixinToken = null; |
| } |
| } |
| push(macroToken ?? NullValues.Token); |
| push(sealedToken ?? NullValues.Token); |
| push(baseToken ?? NullValues.Token); |
| push(interfaceToken ?? NullValues.Token); |
| push(finalToken ?? NullValues.Token); |
| push(augmentToken ?? NullValues.Token); |
| push(mixinToken ?? NullValues.Token); |
| } |
| |
| @override |
| void beginPattern(Token token) { |
| debugEvent("Pattern"); |
| } |
| |
| @override |
| void beginPatternGuard(Token when) { |
| debugEvent("PatternGuard"); |
| } |
| |
| @override |
| void beginPrimaryConstructor(Token beginToken) { |
| debugEvent("PrimaryConstructor"); |
| } |
| |
| @override |
| void beginSwitchCaseWhenClause(Token when) { |
| debugEvent("PatternSwitchCaseGuard"); |
| } |
| |
| @override |
| void beginTopLevelMethod( |
| Token lastConsumed, Token? augmentToken, Token? externalToken) { |
| _enclosingDeclarationAugmentToken = augmentToken; |
| push(_Modifiers() |
| ..augmentKeyword = augmentToken |
| ..externalKeyword = externalToken); |
| } |
| |
| @override |
| void beginTypeVariable(Token token) { |
| debugEvent("beginTypeVariable"); |
| var name = pop() as SimpleIdentifierImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| |
| var comment = _findComment(metadata, name.beginToken); |
| var typeParameter = TypeParameterImpl( |
| comment: comment, |
| metadata: metadata, |
| name: name.token, |
| extendsKeyword: null, |
| bound: null, |
| ); |
| push(typeParameter); |
| } |
| |
| @override |
| void beginVariablesDeclaration( |
| Token token, Token? lateToken, Token? varFinalOrConst) { |
| debugEvent("beginVariablesDeclaration"); |
| if (varFinalOrConst != null || lateToken != null) { |
| push(_Modifiers() |
| ..finalConstOrVarKeyword = varFinalOrConst |
| ..lateToken = lateToken); |
| } else { |
| push(NullValues.Modifiers); |
| } |
| } |
| |
| ConstructorInitializerImpl? buildInitializer(Object initializerObject) { |
| if (initializerObject is FunctionExpressionInvocationImpl) { |
| var function = initializerObject.function; |
| if (function is SuperExpressionImpl) { |
| return SuperConstructorInvocationImpl( |
| superKeyword: function.superKeyword, |
| period: null, |
| constructorName: null, |
| argumentList: initializerObject.argumentList, |
| ); |
| } |
| if (function is ThisExpressionImpl) { |
| return RedirectingConstructorInvocationImpl( |
| thisKeyword: function.thisKeyword, |
| period: null, |
| constructorName: null, |
| argumentList: initializerObject.argumentList, |
| ); |
| } |
| return null; |
| } |
| |
| if (initializerObject is MethodInvocationImpl) { |
| var target = initializerObject.target; |
| if (target is SuperExpressionImpl) { |
| return SuperConstructorInvocationImpl( |
| superKeyword: target.superKeyword, |
| period: initializerObject.operator, |
| constructorName: initializerObject.methodName, |
| argumentList: initializerObject.argumentList, |
| ); |
| } |
| if (target is ThisExpressionImpl) { |
| return RedirectingConstructorInvocationImpl( |
| thisKeyword: target.thisKeyword, |
| period: initializerObject.operator, |
| constructorName: initializerObject.methodName, |
| argumentList: initializerObject.argumentList, |
| ); |
| } |
| return buildInitializerTargetExpressionRecovery( |
| target, initializerObject); |
| } |
| |
| if (initializerObject is PropertyAccessImpl) { |
| return buildInitializerTargetExpressionRecovery( |
| initializerObject.target, initializerObject); |
| } |
| |
| if (initializerObject is AssignmentExpressionImpl) { |
| Token? thisKeyword; |
| Token? period; |
| SimpleIdentifierImpl fieldName; |
| var left = initializerObject.leftHandSide; |
| if (left is PropertyAccessImpl) { |
| var target = left.target; |
| if (target is ThisExpressionImpl) { |
| thisKeyword = target.thisKeyword; |
| period = left.operator; |
| } else { |
| assert(target is SuperExpressionImpl); |
| // Recovery: |
| // Parser has reported FieldInitializedOutsideDeclaringClass. |
| } |
| fieldName = left.propertyName; |
| } else if (left is SimpleIdentifierImpl) { |
| fieldName = left; |
| } else { |
| return null; |
| } |
| return ConstructorFieldInitializerImpl( |
| thisKeyword: thisKeyword, |
| period: period, |
| fieldName: fieldName, |
| equals: initializerObject.operator, |
| expression: initializerObject.rightHandSide, |
| ); |
| } |
| |
| if (initializerObject is AssertInitializerImpl) { |
| return initializerObject; |
| } |
| |
| if (initializerObject is IndexExpressionImpl) { |
| return buildInitializerTargetExpressionRecovery( |
| initializerObject.target, initializerObject); |
| } |
| |
| if (initializerObject is CascadeExpressionImpl) { |
| return buildInitializerTargetExpressionRecovery( |
| initializerObject.target, initializerObject); |
| } |
| |
| return null; |
| } |
| |
| ConstructorInitializerImpl? buildInitializerTargetExpressionRecovery( |
| ExpressionImpl? target, Object initializerObject) { |
| ArgumentListImpl? argumentList; |
| while (true) { |
| if (target is FunctionExpressionInvocationImpl) { |
| argumentList = target.argumentList; |
| target = target.function; |
| } else if (target is MethodInvocationImpl) { |
| argumentList = target.argumentList; |
| target = target.target; |
| } else if (target is PropertyAccessImpl) { |
| argumentList = null; |
| target = target.target; |
| } else { |
| break; |
| } |
| } |
| if (target is SuperExpressionImpl) { |
| // TODO(danrubel): Consider generating this error in the parser |
| // This error is also reported in the body builder |
| handleRecoverableError(messageInvalidSuperInInitializer, |
| target.superKeyword, target.superKeyword); |
| return SuperConstructorInvocationImpl( |
| superKeyword: target.superKeyword, |
| period: null, |
| constructorName: null, |
| argumentList: |
| argumentList ?? _syntheticArgumentList(target.superKeyword), |
| ); |
| } else if (target is ThisExpressionImpl) { |
| // TODO(danrubel): Consider generating this error in the parser |
| // This error is also reported in the body builder |
| handleRecoverableError(messageInvalidThisInInitializer, |
| target.thisKeyword, target.thisKeyword); |
| return RedirectingConstructorInvocationImpl( |
| thisKeyword: target.thisKeyword, |
| period: null, |
| constructorName: null, |
| argumentList: |
| argumentList ?? _syntheticArgumentList(target.thisKeyword), |
| ); |
| } |
| return null; |
| } |
| |
| void checkFieldFormalParameters(FormalParameterListImpl? parameterList) { |
| var parameters = parameterList?.parameters; |
| if (parameters != null) { |
| for (var parameter in parameters) { |
| if (parameter is FieldFormalParameterImpl) { |
| // This error is reported in the BodyBuilder.endFormalParameter. |
| handleRecoverableError(messageFieldInitializerOutsideConstructor, |
| parameter.thisKeyword, parameter.thisKeyword); |
| } |
| } |
| } |
| } |
| |
| // TODO(scheglov): We should not do this. |
| // Ideally, we should not test parsing pieces of class, and instead parse |
| // the whole unit, and extract pieces that we need to validate. |
| _ClassDeclarationBuilder createFakeClassDeclarationBuilder(String className) { |
| return _classLikeBuilder = _ClassDeclarationBuilder( |
| comment: null, |
| metadata: null, |
| abstractKeyword: null, |
| macroKeyword: null, |
| sealedKeyword: null, |
| baseKeyword: null, |
| interfaceKeyword: null, |
| finalKeyword: null, |
| augmentKeyword: null, |
| mixinKeyword: null, |
| classKeyword: Token(Keyword.CLASS, 0), |
| name: StringToken(TokenType.STRING, className, -1), |
| typeParameters: null, |
| extendsClause: null, |
| withClause: null, |
| implementsClause: null, |
| nativeClause: null, |
| leftBracket: Tokens.openCurlyBracket(), |
| rightBracket: Tokens.closeCurlyBracket(), |
| ); |
| } |
| |
| @override |
| void debugEvent(String name) { |
| // printEvent('AstBuilder: $name'); |
| } |
| |
| void doDotExpression(Token dot) { |
| var identifierOrInvoke = pop() as ExpressionImpl; |
| var receiver = pop() as ExpressionImpl?; |
| if (identifierOrInvoke is SimpleIdentifierImpl) { |
| if (receiver is SimpleIdentifierImpl && identical('.', dot.stringValue)) { |
| push( |
| PrefixedIdentifierImpl( |
| prefix: receiver, |
| period: dot, |
| identifier: identifierOrInvoke, |
| ), |
| ); |
| } else { |
| push( |
| PropertyAccessImpl( |
| target: receiver, |
| operator: dot, |
| propertyName: identifierOrInvoke, |
| ), |
| ); |
| } |
| } else if (identifierOrInvoke is MethodInvocationImpl) { |
| assert(identifierOrInvoke.target == null); |
| identifierOrInvoke |
| ..target = receiver |
| ..operator = dot; |
| push(identifierOrInvoke); |
| } else { |
| // This same error is reported in BodyBuilder.doDotOrCascadeExpression |
| Token token = identifierOrInvoke.beginToken; |
| // TODO(danrubel): Consider specializing the error message based |
| // upon the type of expression. e.g. "x.this" -> templateThisAsIdentifier |
| handleRecoverableError( |
| templateExpectedIdentifier.withArguments(token), token, token); |
| SimpleIdentifierImpl identifier = SimpleIdentifierImpl(token); |
| push( |
| PropertyAccessImpl( |
| target: receiver, |
| operator: dot, |
| propertyName: identifier, |
| ), |
| ); |
| } |
| } |
| |
| void doInvocation( |
| TypeArgumentListImpl? typeArguments, MethodInvocationImpl arguments) { |
| var receiver = pop() as ExpressionImpl; |
| switch (receiver) { |
| case AugmentedExpressionImpl(): |
| push( |
| AugmentedInvocationImpl( |
| augmentedKeyword: receiver.augmentedKeyword, |
| typeArguments: typeArguments, |
| arguments: arguments.argumentList, |
| ), |
| ); |
| case SimpleIdentifierImpl(): |
| arguments.methodName = receiver; |
| if (typeArguments != null) { |
| arguments.typeArguments = typeArguments; |
| } |
| push(arguments); |
| default: |
| push( |
| FunctionExpressionInvocationImpl( |
| function: receiver, |
| typeArguments: typeArguments, |
| argumentList: arguments.argumentList, |
| ), |
| ); |
| } |
| } |
| |
| void doPropertyGet() {} |
| |
| @override |
| void endArguments(int count, Token leftParenthesis, Token rightParenthesis) { |
| assert(optional('(', leftParenthesis)); |
| assert(optional(')', rightParenthesis)); |
| debugEvent("Arguments"); |
| |
| var expressions = popTypedList2<ExpressionImpl>(count); |
| for (var expression in expressions) { |
| reportErrorIfSuper(expression); |
| } |
| |
| var arguments = ArgumentListImpl( |
| leftParenthesis: leftParenthesis, |
| arguments: expressions, |
| rightParenthesis: rightParenthesis, |
| ); |
| |
| if (!enableNamedArgumentsAnywhere) { |
| bool hasSeenNamedArgument = false; |
| for (var expression in expressions) { |
| if (expression is NamedExpressionImpl) { |
| hasSeenNamedArgument = true; |
| } else if (hasSeenNamedArgument) { |
| // Positional argument after named argument. |
| handleRecoverableError(messagePositionalAfterNamedArgument, |
| expression.beginToken, expression.endToken); |
| } |
| } |
| } |
| |
| push( |
| MethodInvocationImpl( |
| target: null, |
| operator: null, |
| methodName: _tmpSimpleIdentifier(), |
| typeArguments: null, |
| argumentList: arguments, |
| ), |
| ); |
| } |
| |
| @override |
| void endAsOperatorType(Token asOperator) { |
| debugEvent("AsOperatorType"); |
| } |
| |
| @override |
| void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis, |
| Token? comma, Token endToken) { |
| assert(optional('assert', assertKeyword)); |
| assert(optional('(', leftParenthesis)); |
| assert(optionalOrNull(',', comma)); |
| assert(kind != Assert.Statement || optionalOrNull(';', endToken.next!)); |
| debugEvent("Assert"); |
| |
| var message = popIfNotNull(comma) as ExpressionImpl?; |
| var condition = pop() as ExpressionImpl; |
| switch (kind) { |
| case Assert.Expression: |
| // The parser has already reported an error indicating that assert |
| // cannot be used in an expression. Insert a placeholder. |
| var arguments = <ExpressionImpl>[condition]; |
| if (message != null) { |
| arguments.add(message); |
| } |
| push( |
| FunctionExpressionInvocationImpl( |
| function: SimpleIdentifierImpl(assertKeyword), |
| typeArguments: null, |
| argumentList: ArgumentListImpl( |
| leftParenthesis: leftParenthesis, |
| arguments: arguments, |
| rightParenthesis: leftParenthesis.endGroup!, |
| ), |
| ), |
| ); |
| case Assert.Initializer: |
| push( |
| AssertInitializerImpl( |
| assertKeyword: assertKeyword, |
| leftParenthesis: leftParenthesis, |
| condition: condition, |
| comma: comma, |
| message: message, |
| rightParenthesis: leftParenthesis.endGroup!, |
| ), |
| ); |
| case Assert.Statement: |
| push( |
| AssertStatementImpl( |
| assertKeyword: assertKeyword, |
| leftParenthesis: leftParenthesis, |
| condition: condition, |
| comma: comma, |
| message: message, |
| rightParenthesis: leftParenthesis.endGroup!, |
| semicolon: endToken.next!, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void endAwaitExpression(Token awaitKeyword, Token endToken) { |
| assert(optional('await', awaitKeyword)); |
| debugEvent("AwaitExpression"); |
| |
| var expression = pop() as ExpressionImpl; |
| reportErrorIfSuper(expression); |
| |
| push( |
| AwaitExpressionImpl( |
| awaitKeyword: awaitKeyword, |
| expression: expression, |
| ), |
| ); |
| } |
| |
| @override |
| void endBinaryExpression(Token operatorToken, Token endToken) { |
| assert(operatorToken.isOperator || |
| optional('.', operatorToken) || |
| optional('?.', operatorToken) || |
| optional('..', operatorToken) || |
| optional('?..', operatorToken) || |
| optional('===', operatorToken) || |
| optional('!==', operatorToken)); |
| debugEvent("BinaryExpression"); |
| |
| if (identical(".", operatorToken.stringValue) || |
| identical("?.", operatorToken.stringValue) || |
| identical("..", operatorToken.stringValue) || |
| identical("?..", operatorToken.stringValue)) { |
| doDotExpression(operatorToken); |
| } else { |
| var right = pop() as ExpressionImpl; |
| var left = pop() as ExpressionImpl; |
| reportErrorIfSuper(right); |
| push( |
| BinaryExpressionImpl( |
| leftOperand: left, |
| operator: operatorToken, |
| rightOperand: right, |
| ), |
| ); |
| if (!enableTripleShift && operatorToken.type == TokenType.GT_GT_GT) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.triple_shift, |
| startToken: operatorToken, |
| ); |
| } |
| } |
| } |
| |
| @override |
| void endBinaryPattern(Token operatorToken) { |
| assert(operatorToken.isOperator); |
| debugEvent("BinaryPattern"); |
| |
| var right = pop() as DartPatternImpl; |
| var left = pop() as DartPatternImpl; |
| if (operatorToken.lexeme == '&&') { |
| push( |
| LogicalAndPatternImpl( |
| leftOperand: left, |
| operator: operatorToken, |
| rightOperand: right, |
| ), |
| ); |
| } else if (operatorToken.lexeme == '||') { |
| push( |
| LogicalOrPatternImpl( |
| leftOperand: left, |
| operator: operatorToken, |
| rightOperand: right, |
| ), |
| ); |
| } else { |
| throw UnimplementedError('operatorToken: $operatorToken'); |
| } |
| } |
| |
| @override |
| void endBlock( |
| int count, Token leftBracket, Token rightBracket, BlockKind blockKind) { |
| assert(optional('{', leftBracket)); |
| assert(optional('}', rightBracket)); |
| debugEvent("Block"); |
| |
| var statements = popTypedList2<StatementImpl>(count); |
| push( |
| BlockImpl( |
| leftBracket: leftBracket, |
| statements: statements, |
| rightBracket: rightBracket, |
| ), |
| ); |
| } |
| |
| @override |
| void endBlockFunctionBody(int count, Token leftBracket, Token rightBracket) { |
| assert(optional('{', leftBracket)); |
| assert(optional('}', rightBracket)); |
| debugEvent("BlockFunctionBody"); |
| |
| var statements = popTypedList2<StatementImpl>(count); |
| var block = BlockImpl( |
| leftBracket: leftBracket, |
| statements: statements, |
| rightBracket: rightBracket, |
| ); |
| var star = pop() as Token?; |
| var asyncKeyword = pop() as Token?; |
| if (parseFunctionBodies) { |
| push( |
| BlockFunctionBodyImpl( |
| keyword: asyncKeyword, |
| star: star, |
| block: block, |
| ), |
| ); |
| } else { |
| // TODO(danrubel): Skip the block rather than parsing it. |
| push( |
| EmptyFunctionBodyImpl( |
| semicolon: SyntheticToken( |
| TokenType.SEMICOLON, |
| leftBracket.charOffset, |
| ), |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void endCascade() { |
| debugEvent("Cascade"); |
| |
| var expression = pop() as ExpressionImpl; |
| var cascade = pop() as CascadeExpressionImpl; |
| pop(); // Token. |
| push( |
| CascadeExpressionImpl( |
| target: cascade.target, |
| cascadeSections: <ExpressionImpl>[ |
| ...cascade.cascadeSections, |
| expression, |
| ], |
| ), |
| ); |
| } |
| |
| @override |
| void endCaseExpression(Token caseKeyword, Token? when, Token colon) { |
| assert(optional('case', caseKeyword)); |
| assert(optional(':', colon)); |
| debugEvent("CaseMatch"); |
| |
| WhenClauseImpl? whenClause; |
| if (when != null) { |
| var expression = pop() as ExpressionImpl; |
| whenClause = WhenClauseImpl( |
| whenKeyword: when, |
| expression: expression, |
| ); |
| } |
| |
| if (_featureSet.isEnabled(Feature.patterns)) { |
| var pattern = pop() as DartPatternImpl; |
| push( |
| SwitchPatternCaseImpl( |
| labels: <LabelImpl>[], |
| keyword: caseKeyword, |
| guardedPattern: GuardedPatternImpl( |
| pattern: pattern, |
| whenClause: whenClause, |
| ), |
| colon: colon, |
| statements: <StatementImpl>[], |
| ), |
| ); |
| } else { |
| var expression = pop() as ExpressionImpl; |
| push( |
| SwitchCaseImpl( |
| labels: <LabelImpl>[], |
| keyword: caseKeyword, |
| expression: expression, |
| colon: colon, |
| statements: <StatementImpl>[], |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void endClassConstructor(Token? getOrSet, Token beginToken, Token beginParam, |
| Token? beginInitializers, Token endToken) { |
| assert(getOrSet == null || |
| optional('get', getOrSet) || |
| optional('set', getOrSet)); |
| debugEvent("ClassConstructor"); |
| |
| _classLikeBuilder?.members.add( |
| _buildConstructorDeclaration( |
| beginToken: beginToken, |
| endToken: endToken, |
| ), |
| ); |
| _enclosingDeclarationAugmentToken = null; |
| } |
| |
| @override |
| void endClassDeclaration(Token beginToken, Token endToken) { |
| debugEvent("ClassDeclaration"); |
| |
| var builder = _classLikeBuilder as _ClassDeclarationBuilder; |
| declarations.add( |
| builder.build(), |
| ); |
| |
| _classLikeBuilder = null; |
| } |
| |
| @override |
| void endClassFactoryMethod( |
| Token beginToken, Token factoryKeyword, Token endToken) { |
| assert(optional('factory', factoryKeyword)); |
| assert(optional(';', endToken) || optional('}', endToken)); |
| debugEvent("ClassFactoryMethod"); |
| |
| _classLikeBuilder?.members.add( |
| _buildFactoryConstructorDeclaration( |
| beginToken: beginToken, |
| factoryKeyword: factoryKeyword, |
| endToken: endToken, |
| ), |
| ); |
| } |
| |
| @override |
| void endClassFields( |
| Token? abstractToken, |
| Token? augmentToken, |
| Token? externalToken, |
| Token? staticToken, |
| Token? covariantToken, |
| Token? lateToken, |
| Token? varFinalOrConst, |
| int count, |
| Token beginToken, |
| Token semicolon) { |
| assert(optional(';', semicolon)); |
| debugEvent("Fields"); |
| |
| if (abstractToken != null) { |
| if (staticToken != null) { |
| handleRecoverableError( |
| messageAbstractStaticField, abstractToken, abstractToken); |
| } |
| if (lateToken != null) { |
| handleRecoverableError( |
| messageAbstractLateField, abstractToken, abstractToken); |
| } |
| } |
| if (externalToken != null) { |
| if (lateToken != null) { |
| handleRecoverableError( |
| messageExternalLateField, externalToken, externalToken); |
| } |
| } |
| |
| var variables = popTypedList2<VariableDeclarationImpl>(count); |
| var type = pop() as TypeAnnotationImpl?; |
| var variableList = VariableDeclarationListImpl( |
| comment: null, |
| metadata: null, |
| lateKeyword: lateToken, |
| keyword: varFinalOrConst, |
| type: type, |
| variables: variables, |
| ); |
| var covariantKeyword = covariantToken; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, beginToken); |
| _classLikeBuilder?.members.add( |
| FieldDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| abstractKeyword: abstractToken, |
| augmentKeyword: augmentToken, |
| covariantKeyword: covariantKeyword, |
| externalKeyword: externalToken, |
| staticKeyword: staticToken, |
| fieldList: variableList, |
| semicolon: semicolon, |
| ), |
| ); |
| _enclosingDeclarationAugmentToken = null; |
| } |
| |
| @override |
| void endClassMethod(Token? getOrSet, Token beginToken, Token beginParam, |
| Token? beginInitializers, Token endToken) { |
| assert(getOrSet == null || |
| optional('get', getOrSet) || |
| optional('set', getOrSet)); |
| debugEvent("ClassMethod"); |
| |
| var bodyObject = pop(); |
| pop(); // initializers |
| pop(); // separator |
| var parameters = pop() as FormalParameterListImpl?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var name = pop(); |
| var returnType = pop() as TypeAnnotationImpl?; |
| var modifiers = pop() as _Modifiers?; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, beginToken); |
| |
| assert(parameters != null || optional('get', getOrSet!)); |
| |
| FunctionBodyImpl body; |
| if (bodyObject is FunctionBodyImpl) { |
| body = bodyObject; |
| } else if (bodyObject is _RedirectingFactoryBody) { |
| body = EmptyFunctionBodyImpl( |
| semicolon: endToken, |
| ); |
| } else { |
| internalProblem( |
| templateInternalProblemUnhandled.withArguments( |
| "${bodyObject.runtimeType}", "bodyObject"), |
| beginToken.charOffset, |
| uri); |
| } |
| |
| Token? operatorKeyword; |
| SimpleIdentifierImpl nameId; |
| if (name is SimpleIdentifierImpl) { |
| nameId = name; |
| } else if (name is _OperatorName) { |
| operatorKeyword = name.operatorKeyword; |
| nameId = name.name; |
| if (typeParameters != null) { |
| handleRecoverableError(messageOperatorWithTypeParameters, |
| typeParameters.beginToken, typeParameters.endToken); |
| } |
| } else { |
| throw UnimplementedError( |
| 'name is an instance of ${name.runtimeType} in endClassMethod'); |
| } |
| |
| checkFieldFormalParameters(parameters); |
| _classLikeBuilder?.members.add( |
| MethodDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: modifiers?.augmentKeyword, |
| externalKeyword: modifiers?.externalKeyword, |
| modifierKeyword: modifiers?.abstractKeyword ?? modifiers?.staticKeyword, |
| returnType: returnType, |
| propertyKeyword: getOrSet, |
| operatorKeyword: operatorKeyword, |
| name: nameId.token, |
| typeParameters: typeParameters, |
| parameters: parameters, |
| body: body, |
| ), |
| ); |
| _enclosingDeclarationAugmentToken = null; |
| } |
| |
| @override |
| void endClassOrMixinOrExtensionBody(DeclarationKind kind, int memberCount, |
| Token leftBracket, Token rightBracket) { |
| // TODO(danrubel): consider renaming endClassOrMixinBody |
| // to endClassOrMixinOrExtensionBody |
| assert(optional('{', leftBracket)); |
| assert(optional('}', rightBracket)); |
| debugEvent("ClassOrMixinBody"); |
| |
| var builder = _classLikeBuilder; |
| if (builder != null) { |
| builder |
| ..leftBracket = leftBracket |
| ..rightBracket = rightBracket; |
| } |
| } |
| |
| @override |
| void endCombinators(int count) { |
| debugEvent("Combinators"); |
| push(popTypedList<CombinatorImpl>(count) ?? NullValues.Combinators); |
| } |
| |
| @override |
| void endCompilationUnit(int count, Token endToken) { |
| debugEvent("CompilationUnit"); |
| |
| assert(_enclosingDeclarationAugmentToken == null); |
| |
| var beginToken = pop() as Token; |
| checkEmpty(endToken.charOffset); |
| |
| CompilationUnitImpl unit = CompilationUnitImpl( |
| beginToken: beginToken, |
| scriptTag: scriptTag, |
| directives: directives, |
| declarations: declarations, |
| endToken: endToken, |
| featureSet: _featureSet, |
| lineInfo: _lineInfo, |
| languageVersion: _languageVersion, |
| invalidNodes: invalidNodes, |
| ); |
| push(unit); |
| } |
| |
| @override |
| void endConditionalExpression(Token question, Token colon, Token endToken) { |
| assert(optional('?', question)); |
| assert(optional(':', colon)); |
| debugEvent("ConditionalExpression"); |
| |
| var elseExpression = pop() as ExpressionImpl; |
| var thenExpression = pop() as ExpressionImpl; |
| var condition = pop() as ExpressionImpl; |
| reportErrorIfSuper(elseExpression); |
| reportErrorIfSuper(thenExpression); |
| push( |
| ConditionalExpressionImpl( |
| condition: condition, |
| question: question, |
| thenExpression: thenExpression, |
| colon: colon, |
| elseExpression: elseExpression, |
| ), |
| ); |
| } |
| |
| @override |
| void endConditionalUri(Token ifKeyword, Token leftParen, Token? equalSign) { |
| assert(optional('if', ifKeyword)); |
| assert(optionalOrNull('(', leftParen)); |
| assert(optionalOrNull('==', equalSign)); |
| debugEvent("ConditionalUri"); |
| |
| var libraryUri = pop() as StringLiteralImpl; |
| var value = popIfNotNull(equalSign) as StringLiteralImpl?; |
| if (value is StringInterpolationImpl) { |
| for (var child in value.childEntities) { |
| if (child is InterpolationExpressionImpl) { |
| // This error is reported in OutlineBuilder.endLiteralString |
| handleRecoverableError( |
| messageInterpolationInUri, child.beginToken, child.endToken); |
| break; |
| } |
| } |
| } |
| var name = pop() as DottedNameImpl; |
| push( |
| ConfigurationImpl( |
| ifKeyword: ifKeyword, |
| leftParenthesis: leftParen, |
| name: name, |
| equalToken: equalSign, |
| value: value, |
| rightParenthesis: leftParen.endGroup!, |
| uri: libraryUri, |
| ), |
| ); |
| } |
| |
| @override |
| void endConditionalUris(int count) { |
| debugEvent("ConditionalUris"); |
| |
| push(popTypedList<ConfigurationImpl>(count) ?? NullValues.ConditionalUris); |
| } |
| |
| @override |
| void endConstantPattern(Token? constKeyword) { |
| push(ConstantPatternImpl( |
| constKeyword: constKeyword, expression: pop() as ExpressionImpl)); |
| } |
| |
| @override |
| void endConstDotShorthand(Token token) { |
| debugEvent("endConstDotShorthand"); |
| if (!enabledDotShorthands) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.dot_shorthands, |
| startToken: token, |
| ); |
| } |
| |
| // TODO(kallentu): Handle dot shorthands. |
| } |
| |
| @override |
| void endConstExpression(Token constKeyword) { |
| assert(optional('const', constKeyword)); |
| debugEvent("ConstExpression"); |
| |
| _handleInstanceCreation(constKeyword); |
| } |
| |
| @override |
| void endConstLiteral(Token endToken) { |
| debugEvent("endConstLiteral"); |
| } |
| |
| @override |
| void endConstructorReference(Token start, Token? periodBeforeName, |
| Token endToken, ConstructorReferenceContext constructorReferenceContext) { |
| assert(optionalOrNull('.', periodBeforeName)); |
| debugEvent("ConstructorReference"); |
| |
| var constructorName = pop() as SimpleIdentifierImpl?; |
| var typeArguments = pop() as TypeArgumentListImpl?; |
| var typeNameIdentifier = pop() as IdentifierImpl; |
| push( |
| ConstructorNameImpl( |
| type: typeNameIdentifier.toNamedType( |
| typeArguments: typeArguments, |
| question: null, |
| ), |
| period: periodBeforeName, |
| name: constructorName, |
| ), |
| ); |
| } |
| |
| @override |
| void endDoWhileStatement( |
| Token doKeyword, Token whileKeyword, Token semicolon) { |
| assert(optional('do', doKeyword)); |
| assert(optional('while', whileKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("DoWhileStatement"); |
| |
| var condition = pop() as _ParenthesizedCondition; |
| var body = pop() as StatementImpl; |
| push( |
| DoStatementImpl( |
| doKeyword: doKeyword, |
| body: body, |
| whileKeyword: whileKeyword, |
| leftParenthesis: condition.leftParenthesis, |
| condition: condition.expression, |
| rightParenthesis: condition.rightParenthesis, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void endDoWhileStatementBody(Token token) { |
| debugEvent("endDoWhileStatementBody"); |
| } |
| |
| @override |
| void endElseStatement(Token beginToken, Token endToken) { |
| debugEvent("endElseStatement"); |
| } |
| |
| @override |
| void endEnum(Token beginToken, Token enumKeyword, Token leftBrace, |
| int memberCount, Token endToken) { |
| assert(optional('enum', enumKeyword)); |
| assert(optional('{', leftBrace)); |
| debugEvent("Enum"); |
| |
| var builder = _classLikeBuilder as _EnumDeclarationBuilder; |
| declarations.add( |
| builder.build(), |
| ); |
| _classLikeBuilder = null; |
| } |
| |
| @override |
| void endEnumConstructor(Token? getOrSet, Token beginToken, Token beginParam, |
| Token? beginInitializers, Token endToken) { |
| debugEvent("endEnumConstructor"); |
| endClassConstructor( |
| getOrSet, beginToken, beginParam, beginInitializers, endToken); |
| } |
| |
| @override |
| void endExport(Token exportKeyword, Token semicolon) { |
| assert(optional('export', exportKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("Export"); |
| |
| var combinators = pop() as List<CombinatorImpl>?; |
| var configurations = pop() as List<ConfigurationImpl>?; |
| var uri = pop() as StringLiteralImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, exportKeyword); |
| directives.add( |
| ExportDirectiveImpl( |
| comment: comment, |
| metadata: metadata, |
| exportKeyword: exportKeyword, |
| uri: uri, |
| configurations: configurations, |
| combinators: combinators, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void endExtensionConstructor(Token? getOrSet, Token beginToken, |
| Token beginParam, Token? beginInitializers, Token endToken) { |
| debugEvent("ExtensionConstructor"); |
| |
| invalidNodes.add( |
| _buildConstructorDeclaration( |
| beginToken: beginToken, |
| endToken: endToken, |
| ), |
| ); |
| } |
| |
| @override |
| void endExtensionDeclaration( |
| Token beginToken, Token extensionKeyword, Token? onKeyword, Token token) { |
| var builder = _classLikeBuilder as _ExtensionDeclarationBuilder; |
| |
| ExtensionOnClauseImpl? onClause; |
| if (onKeyword != null) { |
| var extendedType = pop() as TypeAnnotationImpl; |
| onClause = ExtensionOnClauseImpl( |
| onKeyword: onKeyword, |
| extendedType: extendedType, |
| ); |
| } |
| |
| declarations.add( |
| builder.build( |
| typeKeyword: null, |
| onClause: onClause, |
| ), |
| ); |
| |
| _classLikeBuilder = null; |
| } |
| |
| @override |
| void endExtensionFactoryMethod( |
| Token beginToken, Token factoryKeyword, Token endToken) { |
| assert(optional('factory', factoryKeyword)); |
| assert(optional(';', endToken) || optional('}', endToken)); |
| debugEvent("ExtensionFactoryMethod"); |
| |
| invalidNodes.add( |
| _buildFactoryConstructorDeclaration( |
| beginToken: beginToken, |
| factoryKeyword: factoryKeyword, |
| endToken: endToken, |
| ), |
| ); |
| } |
| |
| @override |
| void endExtensionFields( |
| Token? abstractToken, |
| Token? augmentToken, |
| Token? externalToken, |
| Token? staticToken, |
| Token? covariantToken, |
| Token? lateToken, |
| Token? varFinalOrConst, |
| int count, |
| Token beginToken, |
| Token endToken) { |
| if (staticToken == null) { |
| // TODO(danrubel): Decide how to handle instance field declarations |
| // within extensions. They are invalid and the parser has already reported |
| // an error at this point, but we include them in order to get navigation, |
| // search, etc. |
| } |
| endClassFields( |
| abstractToken, |
| augmentToken, |
| externalToken, |
| staticToken, |
| covariantToken, |
| lateToken, |
| varFinalOrConst, |
| count, |
| beginToken, |
| endToken); |
| } |
| |
| @override |
| void endExtensionMethod(Token? getOrSet, Token beginToken, Token beginParam, |
| Token? beginInitializers, Token endToken) { |
| debugEvent("ExtensionMethod"); |
| endClassMethod( |
| getOrSet, beginToken, beginParam, beginInitializers, endToken); |
| } |
| |
| @override |
| void endExtensionTypeDeclaration(Token beginToken, Token? augmentToken, |
| Token extensionKeyword, Token typeKeyword, Token endToken) { |
| var implementsClause = |
| pop(NullValues.IdentifierList) as ImplementsClauseImpl?; |
| var representation = pop(const NullValue<RepresentationDeclarationImpl>()) |
| as RepresentationDeclarationImpl?; |
| var constKeyword = pop() as Token?; |
| |
| if (enableInlineClass) { |
| var builder = _classLikeBuilder as _ExtensionTypeDeclarationBuilder; |
| if (representation == null) { |
| var leftParenthesis = parser.rewriter.insertParens(builder.name, true); |
| var typeName = leftParenthesis.next!; |
| var rightParenthesis = leftParenthesis.endGroup!; |
| var fieldName = parser.rewriter.insertSyntheticIdentifier(typeName); |
| representation = RepresentationDeclarationImpl( |
| constructorName: null, |
| leftParenthesis: leftParenthesis, |
| fieldMetadata: [], |
| fieldType: NamedTypeImpl( |
| importPrefix: null, |
| name2: typeName, |
| question: null, |
| typeArguments: null), |
| fieldName: fieldName, |
| rightParenthesis: rightParenthesis, |
| ); |
| } |
| // Check for extension type name conflict. |
| var representationName = representation.fieldName; |
| if (representationName.lexeme == builder.name.lexeme) { |
| errorReporter.errorReporter?.atToken( |
| representationName, |
| ParserErrorCode.MEMBER_WITH_CLASS_NAME, |
| ); |
| } |
| declarations.add( |
| builder.build( |
| typeKeyword: typeKeyword, |
| constKeyword: constKeyword, |
| representation: representation, |
| implementsClause: implementsClause, |
| ), |
| ); |
| } else { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.inline_class, |
| startToken: typeKeyword, |
| ); |
| } |
| |
| _classLikeBuilder = null; |
| } |
| |
| @override |
| void endFieldInitializer(Token equals, Token endToken) { |
| assert(optional('=', equals)); |
| debugEvent("FieldInitializer"); |
| |
| var initializer = pop() as ExpressionImpl; |
| var name = pop() as SimpleIdentifierImpl; |
| reportErrorIfSuper(initializer); |
| push( |
| VariableDeclarationImpl( |
| name: name.token, |
| equals: equals, |
| initializer: initializer, |
| ), |
| ); |
| } |
| |
| @override |
| void endForControlFlow(Token token) { |
| debugEvent("endForControlFlow"); |
| var body = pop() as CollectionElementImpl; |
| var forLoopParts = pop() as ForPartsImpl; |
| var leftParenthesis = pop() as Token; |
| var forToken = pop() as Token; |
| |
| push( |
| ForElementImpl( |
| awaitKeyword: null, |
| forKeyword: forToken, |
| leftParenthesis: leftParenthesis, |
| forLoopParts: forLoopParts, |
| rightParenthesis: leftParenthesis.endGroup!, |
| body: body, |
| ), |
| ); |
| } |
| |
| @override |
| void endForIn(Token endToken) { |
| debugEvent("ForInExpression"); |
| |
| var body = pop() as StatementImpl; |
| var forLoopParts = pop() as ForEachPartsImpl; |
| var leftParenthesis = pop() as Token; |
| var forToken = pop() as Token; |
| var awaitToken = pop(NullValues.AwaitToken) as Token?; |
| |
| push( |
| ForStatementImpl( |
| awaitKeyword: awaitToken, |
| forKeyword: forToken, |
| leftParenthesis: leftParenthesis, |
| forLoopParts: forLoopParts, |
| rightParenthesis: leftParenthesis.endGroup!, |
| body: body, |
| ), |
| ); |
| } |
| |
| @override |
| void endForInBody(Token endToken) { |
| debugEvent("endForInBody"); |
| } |
| |
| @override |
| void endForInControlFlow(Token token) { |
| debugEvent("endForInControlFlow"); |
| |
| var body = pop() as CollectionElementImpl; |
| var forLoopParts = pop() as ForEachPartsImpl; |
| var leftParenthesis = pop() as Token; |
| var forToken = pop() as Token; |
| var awaitToken = pop(NullValues.AwaitToken) as Token?; |
| |
| push( |
| ForElementImpl( |
| awaitKeyword: awaitToken, |
| forKeyword: forToken, |
| leftParenthesis: leftParenthesis, |
| forLoopParts: forLoopParts, |
| rightParenthesis: leftParenthesis.endGroup!, |
| body: body, |
| ), |
| ); |
| } |
| |
| @override |
| void endForInExpression(Token token) { |
| debugEvent("ForInExpression"); |
| } |
| |
| @override |
| void endFormalParameter( |
| Token? thisKeyword, |
| Token? superKeyword, |
| Token? periodAfterThisOrSuper, |
| Token nameToken, |
| Token? initializerStart, |
| Token? initializerEnd, |
| FormalParameterKind kind, |
| MemberKind memberKind) { |
| assert(optionalOrNull('this', thisKeyword)); |
| assert(optionalOrNull('super', superKeyword)); |
| assert(thisKeyword == null && superKeyword == null |
| ? periodAfterThisOrSuper == null |
| : optional('.', periodAfterThisOrSuper!)); |
| debugEvent("FormalParameter"); |
| |
| if (superKeyword != null && !enableSuperParameters) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.super_parameters, |
| startToken: superKeyword, |
| ); |
| } |
| |
| var defaultValue = pop() as _ParameterDefaultValue?; |
| var name = pop() as SimpleIdentifierImpl?; |
| var typeOrFunctionTypedParameter = pop() as AstNodeImpl?; |
| var modifiers = pop() as _Modifiers?; |
| var keyword = modifiers?.finalConstOrVarKeyword; |
| var covariantKeyword = modifiers?.covariantKeyword; |
| var requiredKeyword = modifiers?.requiredToken; |
| |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, |
| thisKeyword ?? typeOrFunctionTypedParameter?.beginToken ?? nameToken); |
| |
| NormalFormalParameterImpl node; |
| if (typeOrFunctionTypedParameter is FunctionTypedFormalParameterImpl) { |
| // This is a temporary AST node that was constructed in |
| // [endFunctionTypedFormalParameter]. We now deconstruct it and create |
| // the final AST node. |
| if (superKeyword != null) { |
| assert(thisKeyword == null, |
| "Can't have both 'this' and 'super' in a parameter."); |
| node = SuperFormalParameterImpl( |
| name: name!.token, |
| comment: comment, |
| metadata: metadata, |
| covariantKeyword: covariantKeyword, |
| keyword: keyword, |
| requiredKeyword: requiredKeyword, |
| type: typeOrFunctionTypedParameter.returnType, |
| superKeyword: superKeyword, |
| period: periodAfterThisOrSuper!, |
| typeParameters: typeOrFunctionTypedParameter.typeParameters, |
| parameters: typeOrFunctionTypedParameter.parameters, |
| question: typeOrFunctionTypedParameter.question, |
| ); |
| } else if (thisKeyword != null) { |
| assert(superKeyword == null, |
| "Can't have both 'this' and 'super' in a parameter."); |
| node = FieldFormalParameterImpl( |
| name: name!.token, |
| comment: comment, |
| metadata: metadata, |
| covariantKeyword: covariantKeyword, |
| keyword: keyword, |
| requiredKeyword: requiredKeyword, |
| type: typeOrFunctionTypedParameter.returnType, |
| thisKeyword: thisKeyword, |
| period: periodAfterThisOrSuper!, |
| typeParameters: typeOrFunctionTypedParameter.typeParameters, |
| parameters: typeOrFunctionTypedParameter.parameters, |
| question: typeOrFunctionTypedParameter.question, |
| ); |
| } else { |
| node = FunctionTypedFormalParameterImpl( |
| name: name!.token, |
| comment: comment, |
| metadata: metadata, |
| covariantKeyword: covariantKeyword, |
| requiredKeyword: requiredKeyword, |
| returnType: typeOrFunctionTypedParameter.returnType, |
| typeParameters: typeOrFunctionTypedParameter.typeParameters, |
| parameters: typeOrFunctionTypedParameter.parameters, |
| question: typeOrFunctionTypedParameter.question, |
| ); |
| } |
| } else { |
| var type = typeOrFunctionTypedParameter as TypeAnnotationImpl?; |
| if (superKeyword != null) { |
| assert(thisKeyword == null, |
| "Can't have both 'this' and 'super' in a parameter."); |
| if (keyword is KeywordToken && keyword.keyword == Keyword.VAR) { |
| handleRecoverableError( |
| templateExtraneousModifier.withArguments(keyword), |
| keyword, |
| keyword, |
| ); |
| } |
| node = SuperFormalParameterImpl( |
| comment: comment, |
| metadata: metadata, |
| covariantKeyword: covariantKeyword, |
| requiredKeyword: requiredKeyword, |
| keyword: keyword, |
| type: type, |
| superKeyword: superKeyword, |
| period: periodAfterThisOrSuper!, |
| name: name!.token, |
| typeParameters: null, |
| parameters: null, |
| question: null, |
| ); |
| } else if (thisKeyword != null) { |
| assert(superKeyword == null, |
| "Can't have both 'this' and 'super' in a parameter."); |
| node = FieldFormalParameterImpl( |
| comment: comment, |
| metadata: metadata, |
| covariantKeyword: covariantKeyword, |
| requiredKeyword: requiredKeyword, |
| keyword: keyword, |
| type: type, |
| thisKeyword: thisKeyword, |
| period: thisKeyword.next!, |
| name: name!.token, |
| typeParameters: null, |
| parameters: null, |
| question: null, |
| ); |
| } else { |
| node = SimpleFormalParameterImpl( |
| comment: comment, |
| metadata: metadata, |
| covariantKeyword: covariantKeyword, |
| requiredKeyword: requiredKeyword, |
| keyword: keyword, |
| type: type, |
| name: name?.token, |
| ); |
| } |
| } |
| |
| ParameterKind analyzerKind = _toAnalyzerParameterKind(kind); |
| FormalParameterImpl parameter = node; |
| if (analyzerKind != ParameterKind.REQUIRED) { |
| parameter = DefaultFormalParameterImpl( |
| parameter: node, |
| kind: analyzerKind, |
| separator: defaultValue?.separator, |
| defaultValue: defaultValue?.value, |
| ); |
| } else if (defaultValue != null) { |
| // An error is reported if a required parameter has a default value. |
| // Record it as named parameter for recovery. |
| parameter = DefaultFormalParameterImpl( |
| parameter: node, |
| kind: ParameterKind.NAMED, |
| separator: defaultValue.separator, |
| defaultValue: defaultValue.value, |
| ); |
| } |
| push(parameter); |
| } |
| |
| @override |
| void endFormalParameterDefaultValueExpression() { |
| debugEvent("FormalParameterDefaultValueExpression"); |
| } |
| |
| @override |
| void endFormalParameters(int count, Token leftParenthesis, |
| Token rightParenthesis, MemberKind kind) { |
| assert(optional('(', leftParenthesis)); |
| assert(optional(')', rightParenthesis)); |
| debugEvent("FormalParameters"); |
| |
| var rawParameters = popTypedList(count) ?? const <Object>[]; |
| var parameters = <FormalParameterImpl>[]; |
| Token? leftDelimiter; |
| Token? rightDelimiter; |
| for (Object raw in rawParameters) { |
| if (raw is _OptionalFormalParameters) { |
| parameters.addAll(raw.parameters ?? const []); |
| leftDelimiter = raw.leftDelimiter; |
| rightDelimiter = raw.rightDelimiter; |
| } else { |
| parameters.add(raw as FormalParameterImpl); |
| } |
| } |
| push( |
| FormalParameterListImpl( |
| leftParenthesis: leftParenthesis, |
| parameters: parameters, |
| leftDelimiter: leftDelimiter, |
| rightDelimiter: rightDelimiter, |
| rightParenthesis: rightParenthesis, |
| ), |
| ); |
| } |
| |
| @override |
| void endForStatement(Token endToken) { |
| debugEvent("ForStatement"); |
| var body = pop() as StatementImpl; |
| var forLoopParts = pop() as ForPartsImpl; |
| var leftParen = pop() as Token; |
| var forToken = pop() as Token; |
| |
| push( |
| ForStatementImpl( |
| awaitKeyword: null, |
| forKeyword: forToken, |
| leftParenthesis: leftParen, |
| forLoopParts: forLoopParts, |
| rightParenthesis: leftParen.endGroup!, |
| body: body, |
| ), |
| ); |
| } |
| |
| @override |
| void endForStatementBody(Token endToken) { |
| debugEvent("endForStatementBody"); |
| } |
| |
| @override |
| void endFunctionExpression(Token beginToken, Token endToken) { |
| // TODO(paulberry): set up scopes properly to resolve parameters and type |
| // variables. Note that this is tricky due to the handling of initializers |
| // in constructors, so the logic should be shared with BodyBuilder as much |
| // as possible. |
| debugEvent("FunctionExpression"); |
| |
| var body = pop() as FunctionBodyImpl; |
| var parameters = pop() as FormalParameterListImpl?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| push( |
| FunctionExpressionImpl( |
| typeParameters: typeParameters, |
| parameters: parameters, |
| body: body, |
| ), |
| ); |
| } |
| |
| @override |
| void endFunctionName( |
| Token beginToken, Token token, bool isFunctionExpression) { |
| debugEvent("FunctionName"); |
| } |
| |
| @override |
| void endFunctionType(Token functionToken, Token? questionMark) { |
| assert(optional('Function', functionToken)); |
| debugEvent("FunctionType"); |
| |
| var parameters = pop() as FormalParameterListImpl; |
| var returnType = pop() as TypeAnnotationImpl?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| push( |
| GenericFunctionTypeImpl( |
| returnType: returnType, |
| functionKeyword: functionToken, |
| typeParameters: typeParameters, |
| parameters: parameters, |
| question: questionMark, |
| ), |
| ); |
| } |
| |
| @override |
| void endFunctionTypedFormalParameter(Token nameToken, Token? question) { |
| debugEvent("FunctionTypedFormalParameter"); |
| |
| var formalParameters = pop() as FormalParameterListImpl; |
| var returnType = pop() as TypeAnnotationImpl?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| |
| // Create a temporary formal parameter that will be dissected later in |
| // [endFormalParameter]. |
| push( |
| FunctionTypedFormalParameterImpl( |
| comment: null, |
| metadata: null, |
| covariantKeyword: null, |
| requiredKeyword: null, |
| name: StringToken(TokenType.IDENTIFIER, '', 0), |
| returnType: returnType, |
| typeParameters: typeParameters, |
| parameters: formalParameters, |
| question: question, |
| ), |
| ); |
| } |
| |
| @override |
| void endHide(Token hideKeyword) { |
| assert(optional('hide', hideKeyword)); |
| debugEvent("Hide"); |
| |
| var hiddenNames = pop() as List<SimpleIdentifierImpl>; |
| push( |
| HideCombinatorImpl( |
| keyword: hideKeyword, |
| hiddenNames: hiddenNames, |
| ), |
| ); |
| } |
| |
| @override |
| void endIfControlFlow(Token token) { |
| var thenElement = pop() as CollectionElementImpl; |
| var condition = pop() as _ParenthesizedCondition; |
| var ifToken = pop() as Token; |
| push( |
| IfElementImpl( |
| ifKeyword: ifToken, |
| leftParenthesis: condition.leftParenthesis, |
| expression: condition.expression, |
| caseClause: condition.caseClause, |
| rightParenthesis: condition.rightParenthesis, |
| thenElement: thenElement, |
| elseKeyword: null, |
| elseElement: null, |
| ), |
| ); |
| } |
| |
| @override |
| void endIfElseControlFlow(Token token) { |
| var elseElement = pop() as CollectionElementImpl; |
| var elseToken = pop() as Token; |
| var thenElement = pop() as CollectionElementImpl; |
| var condition = pop() as _ParenthesizedCondition; |
| var ifToken = pop() as Token; |
| push( |
| IfElementImpl( |
| ifKeyword: ifToken, |
| leftParenthesis: condition.leftParenthesis, |
| expression: condition.expression, |
| caseClause: condition.caseClause, |
| rightParenthesis: condition.rightParenthesis, |
| thenElement: thenElement, |
| elseKeyword: elseToken, |
| elseElement: elseElement, |
| ), |
| ); |
| } |
| |
| @override |
| void endIfStatement(Token ifToken, Token? elseToken, Token endToken) { |
| assert(optional('if', ifToken)); |
| assert(optionalOrNull('else', elseToken)); |
| |
| var elsePart = popIfNotNull(elseToken) as StatementImpl?; |
| var thenPart = pop() as StatementImpl; |
| var condition = pop() as _ParenthesizedCondition; |
| push( |
| IfStatementImpl( |
| ifKeyword: ifToken, |
| leftParenthesis: condition.leftParenthesis, |
| expression: condition.expression, |
| caseClause: condition.caseClause, |
| rightParenthesis: condition.rightParenthesis, |
| thenStatement: thenPart, |
| elseKeyword: elseToken, |
| elseStatement: elsePart, |
| ), |
| ); |
| } |
| |
| @override |
| void endImplicitCreationExpression(Token token, Token openAngleBracket) { |
| debugEvent("ImplicitCreationExpression"); |
| |
| _handleInstanceCreation(null); |
| } |
| |
| @override |
| void endImport(Token importKeyword, Token? augmentToken, Token? semicolon) { |
| assert(optional('import', importKeyword)); |
| assert(optionalOrNull(';', semicolon)); |
| debugEvent("Import"); |
| |
| var combinators = pop() as List<CombinatorImpl>?; |
| var deferredKeyword = pop(NullValues.Deferred) as Token?; |
| var asKeyword = pop(NullValues.As) as Token?; |
| var prefix = pop(NullValues.Prefix) as SimpleIdentifierImpl?; |
| var configurations = pop() as List<ConfigurationImpl>?; |
| var uri = pop() as StringLiteralImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, importKeyword); |
| |
| if (!enableMacros) { |
| if (augmentToken != null) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.macros, |
| startToken: augmentToken, |
| ); |
| // Pretend that 'augment' didn't occur while this feature is incomplete. |
| augmentToken = null; |
| } |
| } |
| |
| directives.add( |
| ImportDirectiveImpl( |
| comment: comment, |
| metadata: metadata, |
| importKeyword: importKeyword, |
| uri: uri, |
| configurations: configurations, |
| deferredKeyword: deferredKeyword, |
| asKeyword: asKeyword, |
| prefix: prefix, |
| combinators: combinators, |
| semicolon: semicolon ?? Tokens.semicolon(), |
| ), |
| ); |
| } |
| |
| @override |
| void endInitializedIdentifier(Token nameToken) { |
| debugEvent("InitializedIdentifier"); |
| |
| var node = pop() as AstNodeImpl?; |
| VariableDeclarationImpl variable; |
| // TODO(paulberry): This seems kludgy. It would be preferable if we |
| // could respond to a "handleNoVariableInitializer" event by converting a |
| // SimpleIdentifier into a VariableDeclaration, and then when this code was |
| // reached, node would always be a VariableDeclaration. |
| if (node is VariableDeclarationImpl) { |
| variable = node; |
| } else if (node is SimpleIdentifierImpl) { |
| variable = VariableDeclarationImpl( |
| name: node.token, |
| equals: null, |
| initializer: null, |
| ); |
| } else { |
| internalProblem( |
| templateInternalProblemUnhandled.withArguments( |
| "${node.runtimeType}", "identifier"), |
| nameToken.charOffset, |
| uri); |
| } |
| push(variable); |
| } |
| |
| @override |
| void endInitializers(int count, Token colon, Token endToken) { |
| assert(optional(':', colon)); |
| debugEvent("Initializers"); |
| |
| var initializerObjects = popTypedList(count) ?? const []; |
| if (!isFullAst) return; |
| |
| push(colon); |
| |
| var initializers = <ConstructorInitializerImpl>[]; |
| for (Object initializerObject in initializerObjects) { |
| var initializer = buildInitializer(initializerObject); |
| if (initializer != null) { |
| initializers.add(initializer); |
| } else { |
| handleRecoverableError( |
| messageInvalidInitializer, |
| initializerObject is AstNodeImpl |
| ? initializerObject.beginToken |
| : colon, |
| initializerObject is AstNodeImpl |
| ? initializerObject.endToken |
| : colon); |
| } |
| } |
| |
| push(initializers); |
| } |
| |
| @override |
| void endInvalidAwaitExpression( |
| Token awaitKeyword, Token endToken, MessageCode errorCode) { |
| debugEvent("InvalidAwaitExpression"); |
| endAwaitExpression(awaitKeyword, endToken); |
| } |
| |
| @override |
| void endInvalidYieldStatement(Token yieldKeyword, Token? starToken, |
| Token endToken, MessageCode errorCode) { |
| debugEvent("InvalidYieldStatement"); |
| endYieldStatement(yieldKeyword, starToken, endToken); |
| } |
| |
| @override |
| void endIsOperatorType(Token asOperator) { |
| debugEvent("IsOperatorType"); |
| } |
| |
| @override |
| void endLabeledStatement(int labelCount) { |
| debugEvent("LabeledStatement"); |
| |
| var statement = pop() as StatementImpl; |
| var labels = popTypedList2<LabelImpl>(labelCount); |
| push( |
| LabeledStatementImpl( |
| labels: labels, |
| statement: statement, |
| ), |
| ); |
| } |
| |
| @override |
| void endLibraryAugmentation( |
| Token augmentKeyword, Token libraryKeyword, Token semicolon) { |
| // TODO(scheglov): remove this method |
| pop() as StringLiteralImpl; // uri |
| pop() as List<AnnotationImpl>?; // metadata |
| } |
| |
| @override |
| void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) { |
| assert(optional('library', libraryKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("LibraryName"); |
| |
| var libraryName = hasName ? pop() as List<SimpleIdentifierImpl>? : null; |
| |
| if (!hasName && !enableUnnamedLibraries) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.unnamed_libraries, |
| startToken: libraryKeyword, |
| ); |
| } |
| var name = libraryName == null |
| ? null |
| : LibraryIdentifierImpl( |
| components: libraryName, |
| ); |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, libraryKeyword); |
| directives.add( |
| LibraryDirectiveImpl( |
| comment: comment, |
| metadata: metadata, |
| libraryKeyword: libraryKeyword, |
| name: name, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void endLiteralString(int interpolationCount, Token endToken) { |
| debugEvent("endLiteralString"); |
| |
| if (interpolationCount == 0) { |
| var token = pop() as Token; |
| String value = unescapeString(token.lexeme, token, this); |
| push( |
| SimpleStringLiteralImpl( |
| literal: token, |
| value: value, |
| ), |
| ); |
| } else { |
| var parts = popTypedList(1 + interpolationCount * 2)!; |
| var first = parts.first as Token; |
| var last = parts.last as Token; |
| Quote quote = analyzeQuote(first.lexeme); |
| var elements = <InterpolationElementImpl>[]; |
| elements.add( |
| InterpolationStringImpl( |
| contents: first, |
| value: unescapeFirstStringPart(first.lexeme, quote, first, this), |
| ), |
| ); |
| for (int i = 1; i < parts.length - 1; i++) { |
| var part = parts[i]; |
| if (part is Token) { |
| elements.add( |
| InterpolationStringImpl( |
| contents: part, |
| value: unescape(part.lexeme, quote, part, this), |
| ), |
| ); |
| } else if (part is InterpolationExpressionImpl) { |
| elements.add(part); |
| } else { |
| internalProblem( |
| templateInternalProblemUnhandled.withArguments( |
| "${part.runtimeType}", "string interpolation"), |
| first.charOffset, |
| uri); |
| } |
| } |
| elements.add( |
| InterpolationStringImpl( |
| contents: last, |
| value: unescapeLastStringPart( |
| last.lexeme, quote, last, last.isSynthetic, this), |
| ), |
| ); |
| push( |
| StringInterpolationImpl( |
| elements: elements, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void endLiteralSymbol(Token hashToken, int tokenCount) { |
| assert(optional('#', hashToken)); |
| debugEvent("LiteralSymbol"); |
| |
| var components = popTypedList2<Token>(tokenCount); |
| push( |
| SymbolLiteralImpl( |
| poundSign: hashToken, |
| components: components, |
| ), |
| ); |
| } |
| |
| @override |
| void endLocalFunctionDeclaration(Token token) { |
| debugEvent("LocalFunctionDeclaration"); |
| var body = pop() as FunctionBodyImpl; |
| if (isFullAst) { |
| pop(); // constructor initializers |
| pop(); // separator before constructor initializers |
| } |
| var parameters = pop() as FormalParameterListImpl; |
| checkFieldFormalParameters(parameters); |
| var name = pop() as SimpleIdentifierImpl; |
| var returnType = pop() as TypeAnnotationImpl?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var metadata = pop(NullValues.Metadata) as List<AnnotationImpl>?; |
| var functionExpression = FunctionExpressionImpl( |
| typeParameters: typeParameters, |
| parameters: parameters, |
| body: body, |
| ); |
| var functionDeclaration = FunctionDeclarationImpl( |
| comment: null, |
| metadata: metadata, |
| augmentKeyword: null, |
| externalKeyword: null, |
| returnType: returnType, |
| propertyKeyword: null, |
| name: name.token, |
| functionExpression: functionExpression, |
| ); |
| push( |
| FunctionDeclarationStatementImpl( |
| functionDeclaration: functionDeclaration, |
| ), |
| ); |
| } |
| |
| @override |
| void endMember() { |
| debugEvent("Member"); |
| } |
| |
| @override |
| void endMetadata(Token atSign, Token? periodBeforeName, Token endToken) { |
| assert(optional('@', atSign)); |
| assert(optionalOrNull('.', periodBeforeName)); |
| debugEvent("Metadata"); |
| |
| var invocation = pop() as MethodInvocationImpl?; |
| var constructorName = |
| periodBeforeName != null ? pop() as SimpleIdentifierImpl : null; |
| var typeArguments = pop() as TypeArgumentListImpl?; |
| if (typeArguments != null && |
| !_featureSet.isEnabled(Feature.generic_metadata)) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.generic_metadata, |
| startToken: typeArguments.beginToken, |
| ); |
| } |
| var name = pop() as IdentifierImpl; |
| push( |
| AnnotationImpl( |
| atSign: atSign, |
| name: name, |
| typeArguments: typeArguments, |
| period: periodBeforeName, |
| constructorName: constructorName, |
| arguments: invocation?.argumentList, |
| ), |
| ); |
| } |
| |
| @override |
| void endMetadataStar(int count) { |
| debugEvent("MetadataStar"); |
| |
| push(popTypedList<AnnotationImpl>(count) ?? NullValues.Metadata); |
| } |
| |
| @override |
| void endMixinConstructor(Token? getOrSet, Token beginToken, Token beginParam, |
| Token? beginInitializers, Token endToken) { |
| debugEvent("MixinConstructor"); |
| |
| invalidNodes.add( |
| _buildConstructorDeclaration( |
| beginToken: beginToken, |
| endToken: endToken, |
| ), |
| ); |
| } |
| |
| @override |
| void endMixinDeclaration(Token beginToken, Token endToken) { |
| debugEvent("MixinDeclaration"); |
| |
| var builder = _classLikeBuilder as _MixinDeclarationBuilder; |
| declarations.add( |
| builder.build(), |
| ); |
| |
| _classLikeBuilder = null; |
| } |
| |
| @override |
| void endMixinFactoryMethod( |
| Token beginToken, Token factoryKeyword, Token endToken) { |
| debugEvent("MixinFactoryMethod"); |
| |
| invalidNodes.add( |
| _buildFactoryConstructorDeclaration( |
| beginToken: beginToken, |
| factoryKeyword: factoryKeyword, |
| endToken: endToken, |
| ), |
| ); |
| } |
| |
| @override |
| void endMixinFields( |
| Token? abstractToken, |
| Token? augmentToken, |
| Token? externalToken, |
| Token? staticToken, |
| Token? covariantToken, |
| Token? lateToken, |
| Token? varFinalOrConst, |
| int count, |
| Token beginToken, |
| Token endToken) { |
| endClassFields( |
| abstractToken, |
| augmentToken, |
| externalToken, |
| staticToken, |
| covariantToken, |
| lateToken, |
| varFinalOrConst, |
| count, |
| beginToken, |
| endToken); |
| } |
| |
| @override |
| void endMixinMethod(Token? getOrSet, Token beginToken, Token beginParam, |
| Token? beginInitializers, Token endToken) { |
| debugEvent("MixinMethod"); |
| endClassMethod( |
| getOrSet, beginToken, beginParam, beginInitializers, endToken); |
| } |
| |
| @override |
| void endNamedFunctionExpression(Token endToken) { |
| debugEvent("NamedFunctionExpression"); |
| var body = pop() as FunctionBodyImpl; |
| if (isFullAst) { |
| pop(); // constructor initializers |
| pop(); // separator before constructor initializers |
| } |
| var parameters = pop() as FormalParameterListImpl; |
| pop(); // name |
| pop(); // returnType |
| var typeParameters = pop() as TypeParameterListImpl?; |
| push( |
| FunctionExpressionImpl( |
| typeParameters: typeParameters, |
| parameters: parameters, |
| body: body, |
| ), |
| ); |
| } |
| |
| @override |
| void endNamedMixinApplication(Token beginToken, Token classKeyword, |
| Token equalsToken, Token? implementsKeyword, Token semicolon) { |
| assert(optional('class', classKeyword)); |
| assert(optionalOrNull('=', equalsToken)); |
| assert(optionalOrNull('implements', implementsKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("NamedMixinApplication"); |
| |
| ImplementsClauseImpl? implementsClause; |
| if (implementsKeyword != null) { |
| var interfaces = _popNamedTypeList( |
| errorCode: ParserErrorCode.EXPECTED_NAMED_TYPE_IMPLEMENTS, |
| ); |
| implementsClause = ImplementsClauseImpl( |
| implementsKeyword: implementsKeyword, |
| interfaces: interfaces, |
| ); |
| } |
| var withClause = pop(NullValues.WithClause) as WithClauseImpl; |
| var superclass = pop() as TypeAnnotationImpl; |
| if (superclass is! NamedTypeImpl) { |
| errorReporter.errorReporter?.atNode( |
| superclass, |
| ParserErrorCode.EXPECTED_NAMED_TYPE_EXTENDS, |
| ); |
| var beginToken = superclass.beginToken; |
| var endToken = superclass.endToken; |
| var currentToken = beginToken; |
| var count = 1; |
| while (currentToken != endToken) { |
| count++; |
| currentToken = currentToken.next!; |
| } |
| var nameToken = parser.rewriter.replaceNextTokensWithSyntheticToken( |
| beginToken.previous!, count, TokenType.IDENTIFIER); |
| superclass = NamedTypeImpl( |
| importPrefix: null, |
| name2: nameToken, |
| typeArguments: null, |
| question: null, |
| ); |
| } |
| var mixinKeyword = pop(NullValues.Token) as Token?; |
| var augmentKeyword = pop(NullValues.Token) as Token?; |
| var finalKeyword = pop(NullValues.Token) as Token?; |
| var interfaceKeyword = pop(NullValues.Token) as Token?; |
| var baseKeyword = pop(NullValues.Token) as Token?; |
| var sealedKeyword = pop(NullValues.Token) as Token?; |
| pop(NullValues.Token) as Token?; // macroKeyword |
| var modifiers = pop() as _Modifiers?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var name = pop() as SimpleIdentifierImpl; |
| var abstractKeyword = modifiers?.abstractKeyword; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, beginToken); |
| declarations.add( |
| ClassTypeAliasImpl( |
| comment: comment, |
| metadata: metadata, |
| typedefKeyword: classKeyword, |
| name: name.token, |
| typeParameters: typeParameters, |
| equals: equalsToken, |
| abstractKeyword: abstractKeyword, |
| sealedKeyword: sealedKeyword, |
| baseKeyword: baseKeyword, |
| interfaceKeyword: interfaceKeyword, |
| finalKeyword: finalKeyword, |
| augmentKeyword: augmentKeyword, |
| mixinKeyword: mixinKeyword, |
| superclass: superclass, |
| withClause: withClause, |
| implementsClause: implementsClause, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void endNewExpression(Token newKeyword) { |
| assert(optional('new', newKeyword)); |
| debugEvent("NewExpression"); |
| |
| _handleInstanceCreation(newKeyword); |
| } |
| |
| @override |
| void endOptionalFormalParameters( |
| int count, Token leftDelimiter, Token rightDelimiter, MemberKind kind) { |
| assert((optional('[', leftDelimiter) && optional(']', rightDelimiter)) || |
| (optional('{', leftDelimiter) && optional('}', rightDelimiter))); |
| debugEvent("OptionalFormalParameters"); |
| |
| push( |
| _OptionalFormalParameters( |
| popTypedList2<FormalParameterImpl>(count), |
| leftDelimiter, |
| rightDelimiter, |
| ), |
| ); |
| } |
| |
| @override |
| void endParenthesizedExpression(Token leftParenthesis) { |
| assert(optional('(', leftParenthesis)); |
| debugEvent("ParenthesizedExpression"); |
| |
| var expression = pop() as ExpressionImpl; |
| reportErrorIfSuper(expression); |
| |
| push( |
| ParenthesizedExpressionImpl( |
| leftParenthesis: leftParenthesis, |
| expression: expression, |
| rightParenthesis: leftParenthesis.endGroup!, |
| ), |
| ); |
| } |
| |
| @override |
| void endPart(Token partKeyword, Token semicolon) { |
| assert(optional('part', partKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("Part"); |
| |
| var configurations = pop() as List<ConfigurationImpl>?; |
| if (!enableEnhancedParts) { |
| var configuration = configurations?.firstOrNull; |
| if (configuration != null) { |
| _reportFeatureNotEnabled( |
| feature: Feature.enhanced_parts, |
| startToken: configuration.ifKeyword, |
| ); |
| configurations = []; |
| } |
| } |
| |
| var uri = pop() as StringLiteralImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, partKeyword); |
| directives.add( |
| PartDirectiveImpl( |
| comment: comment, |
| metadata: metadata, |
| partKeyword: partKeyword, |
| uri: uri, |
| configurations: configurations, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void endPartOf( |
| Token partKeyword, Token ofKeyword, Token semicolon, bool hasName) { |
| assert(optional('part', partKeyword)); |
| assert(optional('of', ofKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("PartOf"); |
| var libraryNameOrUri = pop(); |
| LibraryIdentifierImpl? name; |
| StringLiteralImpl? uri; |
| if (libraryNameOrUri is StringLiteralImpl) { |
| uri = libraryNameOrUri; |
| } else { |
| name = LibraryIdentifierImpl( |
| components: libraryNameOrUri as List<SimpleIdentifierImpl>, |
| ); |
| if (_featureSet.isEnabled(Feature.enhanced_parts)) { |
| errorReporter.errorReporter?.atNode( |
| name, |
| ParserErrorCode.PART_OF_NAME, |
| ); |
| } |
| } |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, partKeyword); |
| directives.add( |
| PartOfDirectiveImpl( |
| comment: comment, |
| metadata: metadata, |
| partKeyword: partKeyword, |
| ofKeyword: ofKeyword, |
| uri: uri, |
| libraryName: name, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void endPattern(Token token) { |
| debugEvent("Pattern"); |
| } |
| |
| @override |
| void endPatternGuard(Token when) { |
| debugEvent("PatternGuard"); |
| var expression = pop() as ExpressionImpl; |
| push( |
| WhenClauseImpl( |
| whenKeyword: when, |
| expression: expression, |
| ), |
| ); |
| } |
| |
| @override |
| void endPrimaryConstructor( |
| Token beginToken, Token? constKeyword, bool hasConstructorName) { |
| var formalParameterList = pop() as FormalParameterListImpl?; |
| if (formalParameterList == null) { |
| var extensionTypeName = beginToken.previous!; |
| formalParameterList = _syntheticFormalParameterList(extensionTypeName); |
| } |
| |
| var leftParenthesis = formalParameterList.leftParenthesis; |
| |
| RepresentationConstructorNameImpl? constructorName; |
| if (hasConstructorName) { |
| var nameIdentifier = pop() as SimpleIdentifierImpl; |
| constructorName = RepresentationConstructorNameImpl( |
| period: beginToken, |
| name: nameIdentifier.token, |
| ); |
| } |
| |
| List<AnnotationImpl> fieldMetadata; |
| TypeAnnotationImpl fieldType; |
| Token fieldName; |
| var firstFormalParameter = formalParameterList.parameters.firstOrNull; |
| if (firstFormalParameter is SimpleFormalParameterImpl) { |
| fieldMetadata = firstFormalParameter.metadata; |
| switch (firstFormalParameter.type) { |
| case var formalParameterType?: |
| fieldType = formalParameterType; |
| case null: |
| errorReporter.errorReporter?.atToken( |
| leftParenthesis.next!, |
| ParserErrorCode.EXPECTED_REPRESENTATION_TYPE, |
| ); |
| var typeNameToken = parser.rewriter.insertSyntheticIdentifier( |
| leftParenthesis, |
| ); |
| fieldType = NamedTypeImpl( |
| importPrefix: null, |
| name2: typeNameToken, |
| typeArguments: null, |
| question: null, |
| ); |
| } |
| if (firstFormalParameter.keyword case var keyword?) { |
| if (keyword.keyword != Keyword.CONST) { |
| errorReporter.errorReporter?.atToken( |
| keyword, |
| ParserErrorCode.REPRESENTATION_FIELD_MODIFIER, |
| ); |
| } |
| } |
| fieldName = firstFormalParameter.name!; |
| // Check for multiple fields. |
| var maybeComma = firstFormalParameter.endToken.next; |
| if (maybeComma != null && maybeComma.type == TokenType.COMMA) { |
| if (formalParameterList.parameters.length == 1) { |
| errorReporter.errorReporter?.atToken( |
| maybeComma, |
| ParserErrorCode.REPRESENTATION_FIELD_TRAILING_COMMA, |
| ); |
| } else { |
| errorReporter.errorReporter?.atToken( |
| maybeComma, |
| ParserErrorCode.MULTIPLE_REPRESENTATION_FIELDS, |
| ); |
| } |
| } |
| } else { |
| errorReporter.errorReporter?.atToken( |
| leftParenthesis.next!, |
| ParserErrorCode.EXPECTED_REPRESENTATION_FIELD, |
| ); |
| fieldMetadata = []; |
| var typeNameToken = parser.rewriter.insertSyntheticIdentifier( |
| leftParenthesis, |
| ); |
| fieldType = NamedTypeImpl( |
| importPrefix: null, |
| name2: typeNameToken, |
| typeArguments: null, |
| question: null, |
| ); |
| fieldName = parser.rewriter.insertSyntheticIdentifier( |
| typeNameToken, |
| ); |
| } |
| |
| push(constKeyword ?? const NullValue<Token>()); |
| |
| push( |
| RepresentationDeclarationImpl( |
| constructorName: constructorName, |
| leftParenthesis: leftParenthesis, |
| fieldMetadata: fieldMetadata, |
| fieldType: fieldType, |
| fieldName: fieldName, |
| rightParenthesis: formalParameterList.rightParenthesis, |
| ), |
| ); |
| } |
| |
| @override |
| void endRecordLiteral(Token leftParenthesis, int count, Token? constKeyword) { |
| debugEvent("RecordLiteral"); |
| |
| var fields = popTypedList<ExpressionImpl>(count) ?? const []; |
| var rightParenthesis = leftParenthesis.endGroup!; |
| |
| if (enableRecords) { |
| push( |
| RecordLiteralImpl( |
| constKeyword: constKeyword, |
| leftParenthesis: leftParenthesis, |
| fields: fields, |
| rightParenthesis: rightParenthesis, |
| ), |
| ); |
| } else { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.records, |
| startToken: leftParenthesis, |
| ); |
| |
| var expression = fields.firstOrNull; |
| expression ??= SimpleIdentifierImpl( |
| parser.rewriter.insertSyntheticIdentifier(leftParenthesis), |
| ); |
| |
| push( |
| ParenthesizedExpressionImpl( |
| leftParenthesis: leftParenthesis, |
| expression: expression, |
| rightParenthesis: rightParenthesis, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void endRecordType( |
| Token leftBracket, Token? questionMark, int count, bool hasNamedFields) { |
| debugEvent("RecordType"); |
| |
| RecordTypeAnnotationNamedFieldsImpl? namedFields; |
| var elements = popTypedList<Object>(count) ?? const []; |
| var last = elements.lastOrNull; |
| if (last is RecordTypeAnnotationNamedFieldsImpl) { |
| elements.removeLast(); |
| namedFields = last; |
| } |
| var positionalFields = <RecordTypeAnnotationPositionalFieldImpl>[]; |
| for (var elem in elements) { |
| positionalFields.add(elem as RecordTypeAnnotationPositionalFieldImpl); |
| } |
| |
| if (enableRecords) { |
| push( |
| RecordTypeAnnotationImpl( |
| leftParenthesis: leftBracket, |
| positionalFields: positionalFields, |
| namedFields: namedFields, |
| rightParenthesis: leftBracket.endGroup!, |
| question: questionMark, |
| ), |
| ); |
| } else { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.records, |
| startToken: leftBracket, |
| ); |
| |
| push( |
| NamedTypeImpl( |
| importPrefix: null, |
| name2: parser.rewriter.insertSyntheticIdentifier(leftBracket), |
| typeArguments: null, |
| question: questionMark, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void endRecordTypeEntry() { |
| debugEvent("RecordTypeEntry"); |
| |
| var name = pop() as SimpleIdentifierImpl?; |
| var type = pop() as TypeAnnotationImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| |
| push(RecordTypeAnnotationPositionalFieldImpl( |
| metadata: metadata, |
| type: type, |
| name: name?.token, |
| )); |
| } |
| |
| @override |
| void endRecordTypeNamedFields(int count, Token leftBracket) { |
| debugEvent("RecordTypeNamedFields"); |
| |
| var elements = |
| popTypedList<RecordTypeAnnotationPositionalFieldImpl>(count) ?? |
| const []; |
| var fields = <RecordTypeAnnotationNamedFieldImpl>[]; |
| for (var elem in elements) { |
| fields.add(RecordTypeAnnotationNamedFieldImpl( |
| metadata: elem.metadata, |
| type: elem.type, |
| name: elem.name!, |
| )); |
| } |
| push(RecordTypeAnnotationNamedFieldsImpl( |
| leftBracket: leftBracket, |
| fields: fields, |
| rightBracket: leftBracket.endGroup!, |
| )); |
| } |
| |
| @override |
| void endRedirectingFactoryBody(Token equalToken, Token endToken) { |
| assert(optional('=', equalToken)); |
| debugEvent("RedirectingFactoryBody"); |
| |
| var constructorName = pop() as ConstructorNameImpl; |
| var starToken = pop() as Token?; |
| var asyncToken = pop() as Token?; |
| push(_RedirectingFactoryBody( |
| asyncToken, starToken, equalToken, constructorName)); |
| } |
| |
| @override |
| void endRethrowStatement(Token rethrowToken, Token semicolon) { |
| assert(optional('rethrow', rethrowToken)); |
| assert(optional(';', semicolon)); |
| debugEvent("RethrowStatement"); |
| |
| var expression = RethrowExpressionImpl( |
| rethrowKeyword: rethrowToken, |
| ); |
| // TODO(scheglov): According to the specification, 'rethrow' is a statement. |
| push( |
| ExpressionStatementImpl( |
| expression: expression, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void endReturnStatement( |
| bool hasExpression, Token returnKeyword, Token semicolon) { |
| assert(optional('return', returnKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("ReturnStatement"); |
| |
| var expression = hasExpression ? pop() as ExpressionImpl : null; |
| push( |
| ReturnStatementImpl( |
| returnKeyword: returnKeyword, |
| expression: expression, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void endShow(Token showKeyword) { |
| assert(optional('show', showKeyword)); |
| debugEvent("Show"); |
| |
| var shownNames = pop() as List<SimpleIdentifierImpl>; |
| push( |
| ShowCombinatorImpl( |
| keyword: showKeyword, |
| shownNames: shownNames, |
| ), |
| ); |
| } |
| |
| @override |
| void endSwitchBlock(int caseCount, Token leftBracket, Token rightBracket) { |
| assert(optional('{', leftBracket)); |
| assert(optional('}', rightBracket)); |
| debugEvent("SwitchBlock"); |
| |
| var membersList = popTypedList2<List<SwitchMemberImpl>>(caseCount); |
| var members = membersList.flattenedToList; |
| |
| Set<String> labels = <String>{}; |
| for (var member in members) { |
| for (var label in member.labels) { |
| if (!labels.add(label.label.name)) { |
| handleRecoverableError( |
| templateDuplicateLabelInSwitchStatement |
| .withArguments(label.label.name), |
| label.beginToken, |
| label.beginToken); |
| } |
| } |
| } |
| |
| push(leftBracket); |
| push(members); |
| push(rightBracket); |
| } |
| |
| @override |
| void endSwitchCase( |
| int labelCount, |
| int expressionCount, |
| Token? defaultKeyword, |
| Token? colonAfterDefault, |
| int statementCount, |
| Token beginToken, |
| Token endToken) { |
| assert(optionalOrNull('default', defaultKeyword)); |
| assert(defaultKeyword == null |
| ? colonAfterDefault == null |
| : optional(':', colonAfterDefault!)); |
| debugEvent("SwitchCase"); |
| |
| var statements = popTypedList2<StatementImpl>(statementCount); |
| List<SwitchMemberImpl?> members; |
| |
| List<LabelImpl> popLabels() { |
| var labels = <LabelImpl>[]; |
| while (peek() is LabelImpl) { |
| labels.insert(0, pop() as LabelImpl); |
| --labelCount; |
| } |
| return labels; |
| } |
| |
| SwitchMemberImpl updateSwitchMember({ |
| required SwitchMemberImpl member, |
| List<LabelImpl>? labels, |
| List<StatementImpl>? statements, |
| }) { |
| if (member is SwitchCaseImpl) { |
| return SwitchCaseImpl( |
| labels: labels ?? member.labels, |
| keyword: member.keyword, |
| expression: member.expression, |
| colon: member.colon, |
| statements: statements ?? member.statements, |
| ); |
| } else if (member is SwitchDefaultImpl) { |
| return SwitchDefaultImpl( |
| labels: labels ?? member.labels, |
| keyword: member.keyword, |
| colon: member.colon, |
| statements: statements ?? member.statements, |
| ); |
| } else if (member is SwitchPatternCaseImpl) { |
| return SwitchPatternCaseImpl( |
| labels: labels ?? member.labels, |
| keyword: member.keyword, |
| guardedPattern: member.guardedPattern, |
| colon: member.colon, |
| statements: statements ?? member.statements, |
| ); |
| } else { |
| throw UnimplementedError('(${member.runtimeType}) $member'); |
| } |
| } |
| |
| if (labelCount == 0 && defaultKeyword == null) { |
| // Common situation: case with no default and no labels. |
| members = popTypedList2<SwitchMemberImpl>(expressionCount); |
| } else { |
| // Labels and case statements may be intertwined |
| if (defaultKeyword != null) { |
| var labels = popLabels(); |
| var member = SwitchDefaultImpl( |
| labels: labels, |
| keyword: defaultKeyword, |
| colon: colonAfterDefault!, |
| statements: <StatementImpl>[], |
| ); |
| members = List.filled(expressionCount + 1, null); |
| members[expressionCount] = member; |
| } else { |
| members = List.filled(expressionCount, null); |
| } |
| for (int index = expressionCount - 1; index >= 0; --index) { |
| var member = pop() as SwitchMemberImpl; |
| var labels = popLabels(); |
| members[index] = updateSwitchMember( |
| member: member, |
| labels: labels, |
| ); |
| } |
| assert(labelCount == 0); |
| } |
| |
| var members2 = members.nonNulls.toList(); |
| if (members2.isNotEmpty) { |
| members2.last = updateSwitchMember( |
| member: members2.last, |
| statements: statements, |
| ); |
| } |
| push(members2); |
| } |
| |
| @override |
| void endSwitchCaseWhenClause(Token token) { |
| debugEvent("SwitchCaseWhenClause"); |
| } |
| |
| @override |
| void endSwitchExpression(Token switchKeyword, Token endToken) { |
| assert(optional('switch', switchKeyword)); |
| debugEvent("SwitchExpression"); |
| |
| var rightBracket = pop() as Token; |
| var cases = pop() as List<SwitchExpressionCaseImpl>; |
| var leftBracket = pop() as Token; |
| var condition = pop() as _ParenthesizedCondition; |
| push( |
| SwitchExpressionImpl( |
| switchKeyword: switchKeyword, |
| leftParenthesis: condition.leftParenthesis, |
| expression: condition.expression, |
| rightParenthesis: condition.rightParenthesis, |
| leftBracket: leftBracket, |
| cases: cases, |
| rightBracket: rightBracket, |
| ), |
| ); |
| } |
| |
| @override |
| void endSwitchExpressionBlock( |
| int caseCount, Token leftBracket, Token rightBracket) { |
| assert(optional('{', leftBracket)); |
| assert(optional('}', rightBracket)); |
| debugEvent("SwitchExpressionBlock"); |
| |
| var cases = popTypedList2<SwitchExpressionCaseImpl>(caseCount); |
| |
| push(leftBracket); |
| push(cases); |
| push(rightBracket); |
| } |
| |
| @override |
| void endSwitchExpressionCase( |
| Token beginToken, Token? when, Token arrow, Token endToken) { |
| debugEvent("SwitchExpressionCase"); |
| var expression = pop() as ExpressionImpl; |
| WhenClauseImpl? whenClause; |
| if (when != null) { |
| var expression = pop() as ExpressionImpl; |
| whenClause = WhenClauseImpl(whenKeyword: when, expression: expression); |
| } |
| var pattern = pop() as DartPatternImpl; |
| push(SwitchExpressionCaseImpl( |
| guardedPattern: GuardedPatternImpl( |
| pattern: pattern, |
| whenClause: whenClause, |
| ), |
| arrow: arrow, |
| expression: expression)); |
| } |
| |
| @override |
| void endSwitchStatement(Token switchKeyword, Token endToken) { |
| assert(optional('switch', switchKeyword)); |
| debugEvent("SwitchStatement"); |
| |
| var rightBracket = pop() as Token; |
| var members = pop() as List<SwitchMemberImpl>; |
| var leftBracket = pop() as Token; |
| var condition = pop() as _ParenthesizedCondition; |
| push( |
| SwitchStatementImpl( |
| switchKeyword: switchKeyword, |
| leftParenthesis: condition.leftParenthesis, |
| expression: condition.expression, |
| rightParenthesis: condition.rightParenthesis, |
| leftBracket: leftBracket, |
| members: members, |
| rightBracket: rightBracket, |
| ), |
| ); |
| } |
| |
| @override |
| void endThenStatement(Token beginToken, Token endToken) { |
| debugEvent("endThenStatement"); |
| } |
| |
| @override |
| void endTopLevelDeclaration(Token endToken) { |
| debugEvent("TopLevelDeclaration"); |
| } |
| |
| @override |
| void endTopLevelFields( |
| Token? augmentToken, |
| Token? externalToken, |
| Token? staticToken, |
| Token? covariantToken, |
| Token? lateToken, |
| Token? varFinalOrConst, |
| int count, |
| Token beginToken, |
| Token semicolon) { |
| assert(optional(';', semicolon)); |
| debugEvent("TopLevelFields"); |
| |
| if (externalToken != null) { |
| if (lateToken != null) { |
| handleRecoverableError( |
| messageExternalLateField, externalToken, externalToken); |
| } |
| } |
| |
| var variables = popTypedList2<VariableDeclarationImpl>(count); |
| var type = pop() as TypeAnnotationImpl?; |
| var variableList = VariableDeclarationListImpl( |
| comment: null, |
| metadata: null, |
| lateKeyword: lateToken, |
| keyword: varFinalOrConst, |
| type: type, |
| variables: variables, |
| ); |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, beginToken); |
| declarations.add( |
| TopLevelVariableDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentToken, |
| externalKeyword: externalToken, |
| variableList: variableList, |
| semicolon: semicolon, |
| ), |
| ); |
| _enclosingDeclarationAugmentToken = null; |
| } |
| |
| @override |
| void endTopLevelMethod(Token beginToken, Token? getOrSet, Token endToken) { |
| // TODO(paulberry): set up scopes properly to resolve parameters and type |
| // variables. |
| assert(getOrSet == null || |
| optional('get', getOrSet) || |
| optional('set', getOrSet)); |
| debugEvent("TopLevelMethod"); |
| |
| var body = pop() as FunctionBodyImpl; |
| var parameters = pop() as FormalParameterListImpl?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var name = pop() as SimpleIdentifierImpl; |
| var returnType = pop() as TypeAnnotationImpl?; |
| var modifiers = pop() as _Modifiers?; |
| var augmentKeyword = modifiers?.augmentKeyword; |
| var externalKeyword = modifiers?.externalKeyword; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, beginToken); |
| declarations.add( |
| FunctionDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| externalKeyword: externalKeyword, |
| returnType: returnType, |
| propertyKeyword: getOrSet, |
| name: name.token, |
| functionExpression: FunctionExpressionImpl( |
| typeParameters: typeParameters, |
| parameters: parameters, |
| body: body, |
| ), |
| ), |
| ); |
| _enclosingDeclarationAugmentToken = null; |
| } |
| |
| @override |
| void endTryStatement( |
| int catchCount, Token tryKeyword, Token? finallyKeyword, Token endToken) { |
| assert(optional('try', tryKeyword)); |
| assert(optionalOrNull('finally', finallyKeyword)); |
| debugEvent("TryStatement"); |
| |
| var finallyBlock = popIfNotNull(finallyKeyword) as BlockImpl?; |
| var catchClauses = popTypedList2<CatchClauseImpl>(catchCount); |
| var body = pop() as BlockImpl; |
| push( |
| TryStatementImpl( |
| tryKeyword: tryKeyword, |
| body: body, |
| catchClauses: catchClauses, |
| finallyKeyword: finallyKeyword, |
| finallyBlock: finallyBlock, |
| ), |
| ); |
| } |
| |
| @override |
| void endTypeArguments(int count, Token leftBracket, Token rightBracket) { |
| assert(optional('<', leftBracket)); |
| assert(optional('>', rightBracket)); |
| debugEvent("TypeArguments"); |
| |
| var arguments = popTypedList2<TypeAnnotationImpl>(count); |
| push( |
| TypeArgumentListImpl( |
| leftBracket: leftBracket, |
| arguments: arguments, |
| rightBracket: rightBracket, |
| ), |
| ); |
| } |
| |
| @override |
| void endTypedef(Token? augmentToken, Token typedefKeyword, Token? equals, |
| Token semicolon) { |
| assert(optional('typedef', typedefKeyword)); |
| assert(optionalOrNull('=', equals)); |
| assert(optional(';', semicolon)); |
| debugEvent("FunctionTypeAlias"); |
| |
| if (equals == null) { |
| var parameters = pop() as FormalParameterListImpl; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var name = pop() as SimpleIdentifierImpl; |
| var returnType = pop() as TypeAnnotationImpl?; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, typedefKeyword); |
| declarations.add( |
| FunctionTypeAliasImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentToken, |
| typedefKeyword: typedefKeyword, |
| returnType: returnType, |
| name: name.token, |
| typeParameters: typeParameters, |
| parameters: parameters, |
| semicolon: semicolon, |
| ), |
| ); |
| } else { |
| var type = pop() as TypeAnnotationImpl; |
| var templateParameters = pop() as TypeParameterListImpl?; |
| var name = pop() as SimpleIdentifierImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, typedefKeyword); |
| if (type is! GenericFunctionTypeImpl && !enableNonFunctionTypeAliases) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.nonfunction_type_aliases, |
| startToken: equals, |
| ); |
| } |
| declarations.add( |
| GenericTypeAliasImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentToken, |
| typedefKeyword: typedefKeyword, |
| name: name.token, |
| typeParameters: templateParameters, |
| equals: equals, |
| type: type, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void endTypeList(int count) { |
| debugEvent("TypeList"); |
| push(popTypedList<TypeAnnotationImpl>(count) ?? NullValues.TypeList); |
| } |
| |
| @override |
| void endTypeVariable( |
| Token token, int index, Token? extendsOrSuper, Token? variance) { |
| debugEvent("TypeVariable"); |
| assert(extendsOrSuper == null || |
| optional('extends', extendsOrSuper) || |
| optional('super', extendsOrSuper)); |
| |
| // TODO(kallentu): Implement variance behaviour for the analyzer. |
| assert(variance == null || |
| optional('in', variance) || |
| optional('out', variance) || |
| optional('inout', variance)); |
| if (!enableVariance) { |
| reportVarianceModifierNotEnabled(variance); |
| } |
| |
| var bound = pop() as TypeAnnotationImpl?; |
| |
| // Peek to leave type parameters on top of stack. |
| var typeParameters = peek() as List<TypeParameterImpl>; |
| |
| typeParameters[index] |
| ..extendsKeyword = extendsOrSuper |
| ..bound = bound |
| ..varianceKeyword = variance; |
| } |
| |
| @override |
| void endTypeVariables(Token beginToken, Token endToken) { |
| assert(optional('<', beginToken)); |
| assert(optional('>', endToken)); |
| debugEvent("TypeVariables"); |
| |
| var typeParameters = pop() as List<TypeParameterImpl>; |
| push( |
| TypeParameterListImpl( |
| leftBracket: beginToken, |
| typeParameters: typeParameters, |
| rightBracket: endToken, |
| ), |
| ); |
| } |
| |
| @override |
| void endVariableInitializer(Token equals) { |
| assert(optionalOrNull('=', equals)); |
| debugEvent("VariableInitializer"); |
| |
| var initializer = pop() as ExpressionImpl; |
| var identifier = pop() as SimpleIdentifierImpl; |
| reportErrorIfSuper(initializer); |
| // TODO(ahe): Don't push initializers, instead install them. |
| push( |
| VariableDeclarationImpl( |
| name: identifier.token, |
| equals: equals, |
| initializer: initializer, |
| ), |
| ); |
| } |
| |
| @override |
| void endVariablesDeclaration(int count, Token? semicolon) { |
| assert(optionalOrNull(';', semicolon)); |
| debugEvent("VariablesDeclaration"); |
| |
| var variables = popTypedList2<VariableDeclarationImpl>(count); |
| var modifiers = pop(NullValues.Modifiers) as _Modifiers?; |
| var type = pop() as TypeAnnotationImpl?; |
| var keyword = modifiers?.finalConstOrVarKeyword; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, variables[0].beginToken); |
| // var comment = _findComment(metadata, |
| // variables[0].beginToken ?? type?.beginToken ?? modifiers.beginToken); |
| |
| // https://github.com/dart-lang/sdk/issues/53964 |
| if (semicolon != null && semicolon.isSynthetic) { |
| if (variables.singleOrNull case var variable?) { |
| if (type is NamedTypeImpl) { |
| var importPrefix = type.importPrefix; |
| if (importPrefix != null) { |
| // x.^ |
| // await y.foo(); |
| { |
| var awaitToken = type.name2; |
| if (awaitToken.type == Keyword.AWAIT) { |
| push( |
| ExpressionStatementImpl( |
| expression: PrefixedIdentifierImpl( |
| prefix: SimpleIdentifierImpl(importPrefix.name), |
| period: importPrefix.period, |
| identifier: SimpleIdentifierImpl( |
| parser.rewriter.insertSyntheticIdentifier( |
| importPrefix.period, |
| ), |
| ), |
| ), |
| semicolon: semicolon, |
| ), |
| ); |
| parser.rewriter.insertToken(semicolon, awaitToken); |
| parser.rewriter.insertToken(awaitToken, variable.name); |
| return; |
| } |
| } |
| // x.foo^ |
| // await y.bar(); |
| { |
| var awaitToken = variable.name; |
| if (awaitToken.type == Keyword.AWAIT || |
| awaitToken.type == TokenType.IDENTIFIER) { |
| // We see `x.foo await;`, where `;` is synthetic. |
| // It is followed by `y.bar()`. |
| // Insert a new `;`, and (unfortunately) drop `await;`. |
| type.name2.setNext(semicolon.next!); |
| var semicolon2 = parser.rewriter.insertSyntheticToken( |
| type.name2, |
| TokenType.SEMICOLON, |
| ); |
| push( |
| ExpressionStatementImpl( |
| expression: PrefixedIdentifierImpl( |
| prefix: SimpleIdentifierImpl(importPrefix.name), |
| period: importPrefix.period, |
| identifier: SimpleIdentifierImpl(type.name2), |
| ), |
| semicolon: semicolon2, |
| ), |
| ); |
| return; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| push( |
| VariableDeclarationStatementImpl( |
| variableList: VariableDeclarationListImpl( |
| comment: comment, |
| metadata: metadata, |
| lateKeyword: modifiers?.lateToken, |
| keyword: keyword, |
| type: type, |
| variables: variables, |
| ), |
| semicolon: semicolon ?? Tokens.semicolon(), |
| ), |
| ); |
| } |
| |
| @override |
| void endWhileStatement(Token whileKeyword, Token endToken) { |
| assert(optional('while', whileKeyword)); |
| debugEvent("WhileStatement"); |
| |
| var body = pop() as StatementImpl; |
| var condition = pop() as _ParenthesizedCondition; |
| push( |
| WhileStatementImpl( |
| whileKeyword: whileKeyword, |
| leftParenthesis: condition.leftParenthesis, |
| condition: condition.expression, |
| rightParenthesis: condition.rightParenthesis, |
| body: body, |
| ), |
| ); |
| } |
| |
| @override |
| void endWhileStatementBody(Token endToken) { |
| debugEvent("endWhileStatementBody"); |
| } |
| |
| @override |
| void endYieldStatement(Token yieldToken, Token? starToken, Token semicolon) { |
| assert(optional('yield', yieldToken)); |
| assert(optionalOrNull('*', starToken)); |
| assert(optional(';', semicolon)); |
| debugEvent("YieldStatement"); |
| |
| var expression = pop() as ExpressionImpl; |
| push( |
| YieldStatementImpl( |
| yieldKeyword: yieldToken, |
| star: starToken, |
| expression: expression, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void handleAdjacentStringLiterals(Token startToken, int literalCount) { |
| debugEvent("AdjacentStringLiterals"); |
| |
| var strings = popTypedList2<StringLiteralImpl>(literalCount); |
| push(AdjacentStringsImpl(strings: strings)); |
| } |
| |
| @override |
| void handleAsOperator(Token asOperator) { |
| assert(optional('as', asOperator)); |
| debugEvent("AsOperator"); |
| |
| var type = pop() as TypeAnnotationImpl; |
| var expression = pop() as ExpressionImpl; |
| reportErrorIfSuper(expression); |
| |
| push( |
| AsExpressionImpl( |
| expression: expression, |
| asOperator: asOperator, |
| type: type, |
| ), |
| ); |
| } |
| |
| @override |
| void handleAssignedVariablePattern(Token variable) { |
| debugEvent('AssignedVariablePattern'); |
| assert(_featureSet.isEnabled(Feature.patterns)); |
| assert(variable.lexeme != '_'); |
| push( |
| AssignedVariablePatternImpl( |
| name: variable, |
| ), |
| ); |
| } |
| |
| @override |
| void handleAssignmentExpression(Token token, Token endToken) { |
| assert(token.type.isAssignmentOperator); |
| debugEvent("AssignmentExpression"); |
| |
| var rhs = pop() as ExpressionImpl; |
| var lhs = pop() as ExpressionImpl; |
| if (!lhs.isAssignable) { |
| // TODO(danrubel): Update the BodyBuilder to report this error. |
| handleRecoverableError( |
| messageMissingAssignableSelector, lhs.beginToken, lhs.endToken); |
| } |
| reportErrorIfSuper(rhs); |
| push( |
| AssignmentExpressionImpl( |
| leftHandSide: lhs, |
| operator: token, |
| rightHandSide: rhs, |
| ), |
| ); |
| if (!enableTripleShift && token.type == TokenType.GT_GT_GT_EQ) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.triple_shift, |
| startToken: token, |
| ); |
| } |
| } |
| |
| @override |
| void handleAsyncModifier(Token? asyncToken, Token? starToken) { |
| assert(asyncToken == null || |
| optional('async', asyncToken) || |
| optional('sync', asyncToken)); |
| assert(optionalOrNull('*', starToken)); |
| debugEvent("AsyncModifier"); |
| |
| push(asyncToken ?? NullValues.FunctionBodyAsyncToken); |
| push(starToken ?? NullValues.FunctionBodyStarToken); |
| } |
| |
| @override |
| void handleAugmentSuperExpression( |
| Token augmentKeyword, Token superKeyword, IdentifierContext context) { |
| assert(optional('augment', augmentKeyword)); |
| assert(optional('super', superKeyword)); |
| debugEvent("AugmentSuperExpression"); |
| throw UnimplementedError('AstBuilder.handleAugmentSuperExpression'); |
| } |
| |
| @override |
| void handleBreakStatement( |
| bool hasTarget, Token breakKeyword, Token semicolon) { |
| assert(optional('break', breakKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("BreakStatement"); |
| |
| var label = hasTarget ? pop() as SimpleIdentifierImpl : null; |
| push( |
| BreakStatementImpl( |
| breakKeyword: breakKeyword, |
| label: label, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void handleCastPattern(Token asOperator) { |
| assert(optional('as', asOperator)); |
| debugEvent("CastPattern"); |
| |
| var type = pop() as TypeAnnotationImpl; |
| var pattern = pop() as DartPatternImpl; |
| push(CastPatternImpl(pattern: pattern, asToken: asOperator, type: type)); |
| } |
| |
| @override |
| void handleCatchBlock(Token? onKeyword, Token? catchKeyword, Token? comma) { |
| assert(optionalOrNull('on', onKeyword)); |
| assert(optionalOrNull('catch', catchKeyword)); |
| assert(optionalOrNull(',', comma)); |
| debugEvent("CatchBlock"); |
| |
| var body = pop() as BlockImpl; |
| var catchParameterList = |
| popIfNotNull(catchKeyword) as FormalParameterListImpl?; |
| var type = popIfNotNull(onKeyword) as TypeAnnotationImpl?; |
| Token? exception; |
| Token? stackTrace; |
| if (catchParameterList != null) { |
| var catchParameters = catchParameterList.parameters; |
| if (catchParameters.isNotEmpty) { |
| exception = catchParameters[0].name; |
| } |
| if (catchParameters.length > 1) { |
| stackTrace = catchParameters[1].name; |
| } |
| } |
| push( |
| CatchClauseImpl( |
| onKeyword: onKeyword, |
| exceptionType: type, |
| catchKeyword: catchKeyword, |
| leftParenthesis: catchParameterList?.leftParenthesis, |
| exceptionParameter: exception != null |
| ? CatchClauseParameterImpl( |
| name: exception, |
| ) |
| : null, |
| comma: comma, |
| stackTraceParameter: stackTrace != null |
| ? CatchClauseParameterImpl( |
| name: stackTrace, |
| ) |
| : null, |
| rightParenthesis: catchParameterList?.rightParenthesis, |
| body: body, |
| ), |
| ); |
| } |
| |
| @override |
| void handleClassExtends(Token? extendsKeyword, int typeCount) { |
| assert(extendsKeyword == null || extendsKeyword.isKeywordOrIdentifier); |
| debugEvent("ClassExtends"); |
| |
| // If more extends clauses was specified (parser has already issued an |
| // error) throw them away for now and pick the first one. |
| while (typeCount > 1) { |
| pop(); |
| typeCount--; |
| } |
| var supertype = pop() as TypeAnnotationImpl?; |
| if (supertype is NamedTypeImpl) { |
| push( |
| ExtendsClauseImpl( |
| extendsKeyword: extendsKeyword!, |
| superclass: supertype, |
| ), |
| ); |
| } else { |
| push(NullValues.ExtendsClause); |
| // TODO(brianwilkerson): Consider (a) extending `ExtendsClause` to accept |
| // any type annotation for recovery purposes, and (b) extending the |
| // parser to parse a generic function type at this location. |
| if (supertype != null) { |
| errorReporter.errorReporter?.atNode( |
| supertype, |
| ParserErrorCode.EXPECTED_NAMED_TYPE_EXTENDS, |
| ); |
| } |
| } |
| } |
| |
| @override |
| void handleClassHeader(Token begin, Token classKeyword, Token? nativeToken) { |
| assert(optional('class', classKeyword)); |
| assert(optionalOrNull('native', nativeToken)); |
| assert(_classLikeBuilder == null); |
| debugEvent("ClassHeader"); |
| |
| NativeClauseImpl? nativeClause; |
| if (nativeToken != null) { |
| nativeClause = NativeClauseImpl( |
| nativeKeyword: nativeToken, |
| name: nativeName, |
| ); |
| } |
| var implementsClause = |
| pop(NullValues.IdentifierList) as ImplementsClauseImpl?; |
| var withClause = pop(NullValues.WithClause) as WithClauseImpl?; |
| var extendsClause = pop(NullValues.ExtendsClause) as ExtendsClauseImpl?; |
| var mixinKeyword = pop(NullValues.Token) as Token?; |
| var augmentKeyword = pop(NullValues.Token) as Token?; |
| var finalKeyword = pop(NullValues.Token) as Token?; |
| var interfaceKeyword = pop(NullValues.Token) as Token?; |
| var baseKeyword = pop(NullValues.Token) as Token?; |
| var sealedKeyword = pop(NullValues.Token) as Token?; |
| var macroKeyword = pop(NullValues.Token) as Token?; |
| var modifiers = pop() as _Modifiers?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var name = pop() as SimpleIdentifierImpl; |
| var abstractKeyword = modifiers?.abstractKeyword; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, begin); |
| // leftBracket, members, and rightBracket |
| // are set in [endClassOrMixinBody]. |
| _classLikeBuilder = _ClassDeclarationBuilder( |
| comment: comment, |
| metadata: metadata, |
| abstractKeyword: abstractKeyword, |
| macroKeyword: macroKeyword, |
| sealedKeyword: sealedKeyword, |
| baseKeyword: baseKeyword, |
| interfaceKeyword: interfaceKeyword, |
| finalKeyword: finalKeyword, |
| augmentKeyword: augmentKeyword, |
| mixinKeyword: mixinKeyword, |
| classKeyword: classKeyword, |
| name: name.token, |
| typeParameters: typeParameters, |
| extendsClause: extendsClause, |
| withClause: withClause, |
| implementsClause: implementsClause, |
| nativeClause: nativeClause, |
| leftBracket: Tokens.openCurlyBracket(), |
| rightBracket: Tokens.closeCurlyBracket(), |
| ); |
| } |
| |
| @override |
| void handleClassNoWithClause() { |
| push(NullValues.WithClause); |
| } |
| |
| @override |
| void handleClassWithClause(Token withKeyword) { |
| assert(optional('with', withKeyword)); |
| var mixinTypes = _popNamedTypeList( |
| errorCode: ParserErrorCode.EXPECTED_NAMED_TYPE_WITH, |
| ); |
| push( |
| WithClauseImpl( |
| withKeyword: withKeyword, |
| mixinTypes: mixinTypes, |
| ), |
| ); |
| } |
| |
| @override |
| void handleConstFactory(Token constKeyword) { |
| debugEvent("ConstFactory"); |
| // TODO(kallentu): Removal of const factory error for const function feature |
| handleRecoverableError(messageConstFactory, constKeyword, constKeyword); |
| } |
| |
| @override |
| void handleContinueStatement( |
| bool hasTarget, Token continueKeyword, Token semicolon) { |
| assert(optional('continue', continueKeyword)); |
| assert(optional(';', semicolon)); |
| debugEvent("ContinueStatement"); |
| |
| var label = hasTarget ? pop() as SimpleIdentifierImpl : null; |
| push( |
| ContinueStatementImpl( |
| continueKeyword: continueKeyword, |
| label: label, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void handleDeclaredVariablePattern(Token? keyword, Token variable, |
| {required bool inAssignmentPattern}) { |
| debugEvent('DeclaredVariablePattern'); |
| assert(_featureSet.isEnabled(Feature.patterns)); |
| assert(variable.lexeme != '_'); |
| var type = pop() as TypeAnnotationImpl?; |
| |
| if (_enclosingDeclarationAugmentToken != null) { |
| if (variable.lexeme == 'augmented') { |
| errorReporter.errorReporter?.atToken( |
| variable, |
| ParserErrorCode.DECLARATION_NAMED_AUGMENTED_INSIDE_AUGMENTATION, |
| ); |
| } |
| } |
| |
| push( |
| DeclaredVariablePatternImpl( |
| keyword: keyword, |
| type: type, |
| name: variable, |
| ), |
| ); |
| } |
| |
| @override |
| void handleDotShorthandContext(Token token) { |
| debugEvent("DotShorthandContext"); |
| if (!enabledDotShorthands) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.dot_shorthands, |
| startToken: token, |
| ); |
| } |
| |
| var dotShorthand = pop() as ExpressionImpl; |
| if (dotShorthand is DotShorthandMixin) { |
| (dotShorthand as DotShorthandMixin).isDotShorthand = true; |
| } |
| // TODO(kallentu): Add this assert once we've applied the DotShorthandMixin |
| // on all possible expressions that can be a dot shorthand. |
| // } else { |
| // assert( |
| // false, |
| // "'$dotShorthand' must be a 'DotShorthandMixin' because we " |
| // "should only call 'handleDotShorthandContext' after parsing " |
| // "expressions that have a context type we can cache."); |
| // } |
| push(dotShorthand); |
| } |
| |
| @override |
| void handleDotShorthandHead(Token periodToken) { |
| debugEvent("DotShorthandHead"); |
| if (!enabledDotShorthands) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.dot_shorthands, |
| startToken: periodToken, |
| ); |
| } |
| |
| var operand = pop() as ExpressionImpl; |
| // TODO(kallentu): Handle property access case. |
| if (operand is MethodInvocationImpl) { |
| push(DotShorthandInvocationImpl( |
| period: periodToken, |
| memberName: operand.methodName, |
| typeArguments: operand.typeArguments, |
| argumentList: operand.argumentList, |
| )); |
| } else { |
| push(operand); |
| } |
| } |
| |
| @override |
| void handleDottedName(int count, Token firstIdentifier) { |
| assert(firstIdentifier.isIdentifier); |
| debugEvent("DottedName"); |
| |
| var components = popTypedList2<SimpleIdentifierImpl>(count); |
| push( |
| DottedNameImpl( |
| components: components, |
| ), |
| ); |
| } |
| |
| @override |
| void handleElseControlFlow(Token elseToken) { |
| push(elseToken); |
| } |
| |
| @override |
| void handleEmptyFunctionBody(Token semicolon) { |
| assert(optional(';', semicolon)); |
| debugEvent("EmptyFunctionBody"); |
| |
| // TODO(scheglov): Change the parser to not produce these modifiers. |
| pop(); // star |
| pop(); // async |
| push( |
| EmptyFunctionBodyImpl( |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void handleEmptyStatement(Token semicolon) { |
| assert(optional(';', semicolon)); |
| debugEvent("EmptyStatement"); |
| |
| push( |
| EmptyStatementImpl( |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void handleEnumElement(Token beginToken, Token? augmentToken) { |
| debugEvent("EnumElement"); |
| var tmpArguments = pop() as MethodInvocationImpl?; |
| var tmpConstructor = pop() as ConstructorNameImpl?; |
| var constant = pop() as EnumConstantDeclarationImpl; |
| |
| if (!enableEnhancedEnums && |
| (tmpArguments != null || |
| tmpConstructor != null && |
| (tmpConstructor.type.typeArguments != null || |
| tmpConstructor.name != null))) { |
| Token token = tmpArguments != null |
| ? tmpArguments.argumentList.beginToken |
| : tmpConstructor!.beginToken; |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.enhanced_enums, |
| startToken: token, |
| ); |
| } |
| |
| var argumentList = tmpArguments?.argumentList; |
| |
| TypeArgumentListImpl? typeArguments; |
| ConstructorSelectorImpl? constructorSelector; |
| if (tmpConstructor != null) { |
| typeArguments = tmpConstructor.type.typeArguments; |
| var constructorNamePeriod = tmpConstructor.period; |
| var constructorNameId = tmpConstructor.name; |
| if (constructorNamePeriod != null && constructorNameId != null) { |
| constructorSelector = ConstructorSelectorImpl( |
| period: constructorNamePeriod, |
| name: constructorNameId, |
| ); |
| } |
| } |
| |
| // Replace the constant to include arguments. |
| if (argumentList != null) { |
| constant = EnumConstantDeclarationImpl( |
| comment: constant.documentationComment, |
| metadata: constant.metadata, |
| augmentKeyword: augmentToken, |
| name: constant.name, |
| arguments: EnumConstantArgumentsImpl( |
| typeArguments: typeArguments, |
| constructorSelector: constructorSelector, |
| argumentList: argumentList, |
| ), |
| ); |
| } |
| |
| push(constant); |
| } |
| |
| @override |
| void handleEnumElements(Token elementsEndToken, int elementsCount) { |
| debugEvent("EnumElements"); |
| var builder = _classLikeBuilder as _EnumDeclarationBuilder; |
| |
| var constants = popTypedList2<EnumConstantDeclarationImpl>(elementsCount); |
| builder.constants.addAll(constants); |
| |
| if (optional(';', elementsEndToken)) { |
| builder.semicolon = elementsEndToken; |
| } |
| |
| if (!enableEnhancedEnums && optional(';', elementsEndToken)) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.enhanced_enums, |
| startToken: elementsEndToken, |
| ); |
| } |
| } |
| |
| @override |
| void handleEnumHeader( |
| Token? augmentToken, Token enumKeyword, Token leftBrace) { |
| assert(optional('enum', enumKeyword)); |
| assert(optional('{', leftBrace)); |
| debugEvent("EnumHeader"); |
| |
| var implementsClause = |
| pop(NullValues.IdentifierList) as ImplementsClauseImpl?; |
| var withClause = pop(NullValues.WithClause) as WithClauseImpl?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var name = pop() as SimpleIdentifierImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, enumKeyword); |
| |
| if (!enableEnhancedEnums && |
| (withClause != null || |
| implementsClause != null || |
| typeParameters != null)) { |
| var token = withClause != null |
| ? withClause.withKeyword |
| : implementsClause != null |
| ? implementsClause.implementsKeyword |
| : typeParameters!.beginToken; |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.enhanced_enums, |
| startToken: token, |
| ); |
| } |
| |
| _classLikeBuilder = _EnumDeclarationBuilder( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentToken, |
| enumKeyword: enumKeyword, |
| name: name.token, |
| typeParameters: typeParameters, |
| withClause: withClause, |
| implementsClause: implementsClause, |
| leftBracket: leftBrace, |
| semicolon: null, |
| rightBracket: leftBrace.endGroup!, |
| ); |
| } |
| |
| @override |
| void handleEnumNoWithClause() { |
| push(NullValues.WithClause); |
| } |
| |
| @override |
| void handleEnumWithClause(Token withKeyword) { |
| assert(optional('with', withKeyword)); |
| var mixinTypes = _popNamedTypeList( |
| errorCode: ParserErrorCode.EXPECTED_NAMED_TYPE_WITH, |
| ); |
| push( |
| WithClauseImpl( |
| withKeyword: withKeyword, |
| mixinTypes: mixinTypes, |
| ), |
| ); |
| } |
| |
| @override |
| void handleErrorToken(ErrorToken token) { |
| translateErrorToken(token, errorReporter.reportScannerError); |
| } |
| |
| @override |
| void handleExpressionFunctionBody(Token arrowToken, Token? semicolon) { |
| assert(optional('=>', arrowToken) || optional('=', arrowToken)); |
| assert(optionalOrNull(';', semicolon)); |
| debugEvent("ExpressionFunctionBody"); |
| |
| var expression = pop() as ExpressionImpl; |
| reportErrorIfSuper(expression); |
| var star = pop() as Token?; |
| var asyncKeyword = pop() as Token?; |
| if (parseFunctionBodies) { |
| push(ExpressionFunctionBodyImpl( |
| keyword: asyncKeyword, |
| star: star, |
| functionDefinition: arrowToken, |
| expression: expression, |
| semicolon: semicolon, |
| )); |
| } else { |
| push( |
| EmptyFunctionBodyImpl( |
| semicolon: semicolon!, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void handleExpressionStatement(Token beginToken, Token semicolon) { |
| assert(optional(';', semicolon)); |
| debugEvent("ExpressionStatement"); |
| var expression = pop() as ExpressionImpl; |
| reportErrorIfSuper(expression); |
| if (expression is SimpleIdentifierImpl && |
| expression.token.keyword?.isBuiltInOrPseudo == false) { |
| // This error is also reported by the body builder. |
| handleRecoverableError( |
| messageExpectedStatement, expression.beginToken, expression.endToken); |
| } |
| if (expression is AssignmentExpressionImpl) { |
| if (!expression.leftHandSide.isAssignable) { |
| // This error is also reported by the body builder. |
| handleRecoverableError( |
| messageIllegalAssignmentToNonAssignable, |
| expression.leftHandSide.beginToken, |
| expression.leftHandSide.endToken); |
| } |
| } |
| push( |
| ExpressionStatementImpl( |
| expression: expression, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void handleFinallyBlock(Token finallyKeyword) { |
| debugEvent("FinallyBlock"); |
| // The finally block is popped in "endTryStatement". |
| } |
| |
| @override |
| void handleForInitializerEmptyStatement(Token token) { |
| debugEvent("ForInitializerEmptyStatement"); |
| push(NullValues.Expression); |
| } |
| |
| @override |
| void handleForInitializerExpressionStatement(Token token, bool forIn) { |
| debugEvent("ForInitializerExpressionStatement"); |
| } |
| |
| @override |
| void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { |
| debugEvent("ForInitializerLocalVariableDeclaration"); |
| } |
| |
| @override |
| void handleForInitializerPatternVariableAssignment( |
| Token keyword, Token equals) { |
| var expression = pop() as ExpressionImpl; |
| var pattern = pop() as DartPatternImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| push(PatternVariableDeclarationImpl( |
| keyword: keyword, |
| pattern: pattern, |
| equals: equals, |
| expression: expression, |
| comment: null, |
| metadata: metadata)); |
| } |
| |
| @override |
| void handleForInLoopParts(Token? awaitToken, Token forToken, |
| Token leftParenthesis, Token? patternKeyword, Token inKeyword) { |
| assert(optionalOrNull('await', awaitToken)); |
| assert(optional('for', forToken)); |
| assert(optional('(', leftParenthesis)); |
| assert(optional('in', inKeyword) || optional(':', inKeyword)); |
| |
| var iterable = pop() as ExpressionImpl; |
| var variableOrDeclaration = pop()!; |
| reportErrorIfSuper(iterable); |
| |
| ForEachPartsImpl forLoopParts; |
| if (patternKeyword != null) { |
| var metadata = pop() as List<AnnotationImpl>?; |
| forLoopParts = ForEachPartsWithPatternImpl( |
| metadata: metadata, |
| keyword: patternKeyword, |
| pattern: variableOrDeclaration as DartPatternImpl, |
| inKeyword: inKeyword, |
| iterable: iterable); |
| } else if (variableOrDeclaration is VariableDeclarationStatementImpl) { |
| var variableList = variableOrDeclaration.variables; |
| forLoopParts = ForEachPartsWithDeclarationImpl( |
| loopVariable: DeclaredIdentifierImpl( |
| comment: variableList.documentationComment, |
| metadata: variableList.metadata, |
| keyword: variableList.keyword, |
| type: variableList.type, |
| name: variableList.variables.first.name, |
| ), |
| inKeyword: inKeyword, |
| iterable: iterable, |
| ); |
| } else { |
| if (variableOrDeclaration is! SimpleIdentifierImpl) { |
| // Parser has already reported the error. |
| if (!leftParenthesis.next!.isIdentifier) { |
| parser.rewriter.insertSyntheticIdentifier(leftParenthesis); |
| } |
| variableOrDeclaration = SimpleIdentifierImpl(leftParenthesis.next!); |
| } |
| forLoopParts = ForEachPartsWithIdentifierImpl( |
| identifier: variableOrDeclaration, |
| inKeyword: inKeyword, |
| iterable: iterable, |
| ); |
| } |
| |
| push(awaitToken ?? NullValues.AwaitToken); |
| push(forToken); |
| push(leftParenthesis); |
| push(forLoopParts); |
| } |
| |
| @override |
| void handleForLoopParts(Token forKeyword, Token leftParen, |
| Token leftSeparator, Token rightSeparator, int updateExpressionCount) { |
| assert(optional('for', forKeyword)); |
| assert(optional('(', leftParen)); |
| assert(optional(';', leftSeparator)); |
| assert(updateExpressionCount >= 0); |
| |
| var updates = popTypedList2<ExpressionImpl>(updateExpressionCount); |
| var conditionStatement = pop() as StatementImpl; |
| var initializerPart = pop(); |
| |
| for (var update in updates) { |
| reportErrorIfSuper(update); |
| } |
| |
| ExpressionImpl? condition; |
| Token rightSeparator; |
| if (conditionStatement is ExpressionStatementImpl) { |
| condition = conditionStatement.expression; |
| rightSeparator = conditionStatement.semicolon!; |
| } else { |
| rightSeparator = (conditionStatement as EmptyStatementImpl).semicolon; |
| } |
| |
| ForPartsImpl forLoopParts; |
| if (initializerPart is VariableDeclarationStatementImpl) { |
| forLoopParts = ForPartsWithDeclarationsImpl( |
| variableList: initializerPart.variables, |
| leftSeparator: leftSeparator, |
| condition: condition, |
| rightSeparator: rightSeparator, |
| updaters: updates, |
| ); |
| } else if (initializerPart is PatternVariableDeclarationImpl) { |
| forLoopParts = ForPartsWithPatternImpl( |
| variables: initializerPart, |
| leftSeparator: leftSeparator, |
| condition: condition, |
| rightSeparator: rightSeparator, |
| updaters: updates); |
| } else { |
| forLoopParts = ForPartsWithExpressionImpl( |
| initialization: initializerPart as ExpressionImpl?, |
| leftSeparator: leftSeparator, |
| condition: condition, |
| rightSeparator: rightSeparator, |
| updaters: updates, |
| ); |
| } |
| |
| push(forKeyword); |
| push(leftParen); |
| push(forLoopParts); |
| } |
| |
| @override |
| void handleFormalParameterWithoutValue(Token token) { |
| debugEvent("FormalParameterWithoutValue"); |
| |
| push(NullValues.ParameterDefaultValue); |
| } |
| |
| @override |
| void handleIdentifier(Token token, IdentifierContext context) { |
| assert(token.isKeywordOrIdentifier); |
| debugEvent("handleIdentifier"); |
| |
| if (context.inSymbol) { |
| push(token); |
| return; |
| } |
| |
| if (_enclosingDeclarationAugmentToken != null) { |
| if (token.lexeme == 'augmented') { |
| if (context.inDeclaration) { |
| errorReporter.errorReporter?.atToken( |
| token, |
| ParserErrorCode.DECLARATION_NAMED_AUGMENTED_INSIDE_AUGMENTATION, |
| ); |
| } else { |
| push( |
| AugmentedExpressionImpl( |
| augmentedKeyword: token, |
| ), |
| ); |
| return; |
| } |
| } |
| } |
| |
| var identifier = SimpleIdentifierImpl(token); |
| if (context.inLibraryOrPartOfDeclaration) { |
| if (!context.isContinuation) { |
| push([identifier]); |
| } else { |
| push(identifier); |
| } |
| } else if (context == IdentifierContext.enumValueDeclaration) { |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, token); |
| |
| Token? augmentKeyword; |
| if (token.previous case var previous?) { |
| if (optional('augment', previous)) { |
| augmentKeyword = previous; |
| } |
| } |
| |
| push( |
| EnumConstantDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| name: token, |
| arguments: null, |
| ), |
| ); |
| } else { |
| push(identifier); |
| } |
| } |
| |
| @override |
| void handleIdentifierList(int count) { |
| debugEvent("IdentifierList"); |
| |
| push( |
| popTypedList<SimpleIdentifierImpl>(count) ?? NullValues.IdentifierList); |
| } |
| |
| @override |
| void handleImplements(Token? implementsKeyword, int interfacesCount) { |
| assert(optionalOrNull('implements', implementsKeyword)); |
| debugEvent("Implements"); |
| |
| if (implementsKeyword != null) { |
| endTypeList(interfacesCount); |
| var interfaces = _popNamedTypeList( |
| errorCode: ParserErrorCode.EXPECTED_NAMED_TYPE_IMPLEMENTS, |
| ); |
| push( |
| ImplementsClauseImpl( |
| implementsKeyword: implementsKeyword, |
| interfaces: interfaces, |
| ), |
| ); |
| } else { |
| push(NullValues.IdentifierList); |
| } |
| } |
| |
| @override |
| void handleImportPrefix(Token? deferredKeyword, Token? asKeyword) { |
| assert(optionalOrNull('deferred', deferredKeyword)); |
| assert(optionalOrNull('as', asKeyword)); |
| debugEvent("ImportPrefix"); |
| |
| if (asKeyword == null) { |
| // If asKeyword is null, then no prefix has been pushed on the stack. |
| // Push a placeholder indicating that there is no prefix. |
| push(NullValues.Prefix); |
| push(NullValues.As); |
| } else { |
| push(asKeyword); |
| } |
| push(deferredKeyword ?? NullValues.Deferred); |
| } |
| |
| @override |
| void handleIndexedExpression( |
| Token? question, Token leftBracket, Token rightBracket) { |
| assert(optional('[', leftBracket) || optional('?.[', leftBracket)); |
| assert(optional(']', rightBracket)); |
| debugEvent("IndexedExpression"); |
| |
| var index = pop() as ExpressionImpl; |
| var target = pop() as ExpressionImpl?; |
| reportErrorIfSuper(index); |
| if (target == null) { |
| var receiver = pop() as CascadeExpressionImpl; |
| var token = peek() as Token; |
| push(receiver); |
| var expression = IndexExpressionImpl.forCascade( |
| period: token, |
| question: question, |
| leftBracket: leftBracket, |
| index: index, |
| rightBracket: rightBracket, |
| ); |
| assert(expression.isCascaded); |
| push(expression); |
| } else { |
| push( |
| IndexExpressionImpl.forTarget( |
| target: target, |
| question: question, |
| leftBracket: leftBracket, |
| index: index, |
| rightBracket: rightBracket, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void handleInterpolationExpression(Token leftBracket, Token? rightBracket) { |
| var expression = pop() as ExpressionImpl; |
| push( |
| InterpolationExpressionImpl( |
| leftBracket: leftBracket, |
| expression: expression, |
| rightBracket: rightBracket, |
| ), |
| ); |
| } |
| |
| @override |
| void handleInvalidExpression(Token token) { |
| debugEvent("InvalidExpression"); |
| } |
| |
| @override |
| void handleInvalidFunctionBody(Token leftBracket) { |
| assert(optional('{', leftBracket)); |
| assert(optional('}', leftBracket.endGroup!)); |
| debugEvent("InvalidFunctionBody"); |
| var block = BlockImpl( |
| leftBracket: leftBracket, |
| statements: [], |
| rightBracket: leftBracket.endGroup!, |
| ); |
| var star = pop() as Token?; |
| var asyncKeyword = pop() as Token?; |
| push( |
| BlockFunctionBodyImpl( |
| keyword: asyncKeyword, |
| star: star, |
| block: block, |
| ), |
| ); |
| } |
| |
| @override |
| void handleInvalidMember(Token endToken) { |
| debugEvent("InvalidMember"); |
| pop(); // metadata star |
| } |
| |
| @override |
| void handleInvalidOperatorName(Token operatorKeyword, Token token) { |
| assert(optional('operator', operatorKeyword)); |
| debugEvent("InvalidOperatorName"); |
| |
| push( |
| _OperatorName( |
| operatorKeyword, |
| SimpleIdentifierImpl(token), |
| ), |
| ); |
| } |
| |
| @override |
| void handleInvalidTopLevelBlock(Token token) { |
| // TODO(danrubel): Consider improved recovery by adding this block |
| // as part of a synthetic top level function. |
| pop(); // block |
| } |
| |
| @override |
| void handleInvalidTopLevelDeclaration(Token endToken) { |
| debugEvent("InvalidTopLevelDeclaration"); |
| |
| pop(); // metadata star |
| // TODO(danrubel): consider creating a AST node |
| // representing the invalid declaration to better support code completion, |
| // quick fixes, etc, rather than discarding the metadata and token |
| } |
| |
| @override |
| void handleInvalidTypeArguments(Token token) { |
| var invalidTypeArgs = pop() as TypeArgumentListImpl; |
| var node = pop(); |
| if (node is ConstructorNameImpl) { |
| push(_ConstructorNameWithInvalidTypeArgs(node, invalidTypeArgs)); |
| } else { |
| throw UnimplementedError( |
| 'node is an instance of ${node.runtimeType} in handleInvalidTypeArguments'); |
| } |
| } |
| |
| @override |
| void handleIsOperator(Token isOperator, Token? not) { |
| assert(optional('is', isOperator)); |
| assert(optionalOrNull('!', not)); |
| debugEvent("IsOperator"); |
| |
| var type = pop() as TypeAnnotationImpl; |
| var expression = pop() as ExpressionImpl; |
| reportErrorIfSuper(expression); |
| |
| push( |
| IsExpressionImpl( |
| expression: expression, |
| isOperator: isOperator, |
| notOperator: not, |
| type: type, |
| ), |
| ); |
| } |
| |
| @override |
| void handleLabel(Token colon) { |
| assert(optionalOrNull(':', colon)); |
| debugEvent("Label"); |
| |
| var name = pop() as SimpleIdentifierImpl; |
| push( |
| LabelImpl( |
| label: name, |
| colon: colon, |
| ), |
| ); |
| } |
| |
| @override |
| void handleListPattern(int count, Token leftBracket, Token rightBracket) { |
| assert(optional('[', leftBracket)); |
| assert(optional(']', rightBracket)); |
| debugEvent("ListPattern"); |
| |
| var elements = popTypedList2<ListPatternElementImpl>(count); |
| var typeArguments = pop() as TypeArgumentListImpl?; |
| push( |
| ListPatternImpl( |
| typeArguments: typeArguments, |
| leftBracket: leftBracket, |
| elements: elements, |
| rightBracket: rightBracket, |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralBool(Token token) { |
| bool value = boolFromToken(token); |
| debugEvent("LiteralBool"); |
| |
| push( |
| BooleanLiteralImpl( |
| literal: token, |
| value: value, |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralDouble(Token token) { |
| assert(token.type == TokenType.DOUBLE); |
| debugEvent("LiteralDouble"); |
| |
| push( |
| DoubleLiteralImpl( |
| literal: token, |
| value: double.parse(token.lexeme), |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralDoubleWithSeparators(Token token) { |
| assert(token.type == TokenType.DOUBLE_WITH_SEPARATORS); |
| debugEvent("LiteralDouble"); |
| |
| if (!_enableDigitSeparators) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.digit_separators, |
| startToken: token, |
| ); |
| } |
| |
| push( |
| DoubleLiteralImpl( |
| literal: token, |
| value: doubleFromToken(token, hasSeparators: true), |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralInt(Token token) { |
| assert(identical(token.kind, INT_TOKEN) || |
| identical(token.kind, HEXADECIMAL_TOKEN)); |
| debugEvent("LiteralInt"); |
| |
| push( |
| IntegerLiteralImpl( |
| literal: token, |
| value: intFromToken(token, hasSeparators: false), |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralIntWithSeparators(Token token) { |
| assert(identical(token.kind, INT_TOKEN) || |
| identical(token.kind, HEXADECIMAL_TOKEN)); |
| debugEvent("LiteralInt"); |
| |
| if (!_enableDigitSeparators) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.digit_separators, |
| startToken: token, |
| ); |
| } |
| |
| push( |
| IntegerLiteralImpl( |
| literal: token, |
| value: intFromToken(token, hasSeparators: true), |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralList( |
| int count, Token leftBracket, Token? constKeyword, Token rightBracket) { |
| assert(optional('[', leftBracket)); |
| assert(optionalOrNull('const', constKeyword)); |
| assert(optional(']', rightBracket)); |
| debugEvent("LiteralList"); |
| |
| var elements = popCollectionElements(count); |
| var typeArguments = pop() as TypeArgumentListImpl?; |
| |
| push( |
| ListLiteralImpl( |
| constKeyword: constKeyword, |
| typeArguments: typeArguments, |
| leftBracket: leftBracket, |
| elements: elements, |
| rightBracket: rightBracket, |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralMapEntry(Token colon, Token endToken, |
| {Token? nullAwareKeyToken, Token? nullAwareValueToken}) { |
| assert(optional(':', colon)); |
| debugEvent("LiteralMapEntry"); |
| |
| if (!enableNullAwareElements && |
| (nullAwareKeyToken != null || nullAwareValueToken != null)) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.null_aware_elements, |
| startToken: nullAwareKeyToken ?? nullAwareValueToken!, |
| ); |
| nullAwareKeyToken = null; |
| nullAwareValueToken = null; |
| } |
| |
| var value = pop() as ExpressionImpl; |
| var key = pop() as ExpressionImpl; |
| push( |
| MapLiteralEntryImpl( |
| keyQuestion: nullAwareKeyToken, |
| key: key, |
| separator: colon, |
| valueQuestion: nullAwareValueToken, |
| value: value, |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralNull(Token token) { |
| assert(optional('null', token)); |
| debugEvent("LiteralNull"); |
| |
| push( |
| NullLiteralImpl( |
| literal: token, |
| ), |
| ); |
| } |
| |
| @override |
| void handleLiteralSetOrMap( |
| int count, |
| Token leftBrace, |
| Token? constKeyword, |
| Token rightBrace, |
| // TODO(danrubel): hasSetEntry parameter exists for replicating existing |
| // behavior and will be removed once unified collection has been enabled |
| bool hasSetEntry, |
| ) { |
| var elements = popCollectionElements(count); |
| |
| var typeArguments = pop() as TypeArgumentListImpl?; |
| push( |
| SetOrMapLiteralImpl( |
| constKeyword: constKeyword, |
| typeArguments: typeArguments, |
| leftBracket: leftBrace, |
| elements: elements, |
| rightBracket: rightBrace, |
| ), |
| ); |
| } |
| |
| @override |
| void handleMapPattern(int count, Token leftBrace, Token rightBrace) { |
| debugEvent('MapPattern'); |
| |
| var elements = popTypedList2<MapPatternElementImpl>(count); |
| var typeArguments = pop() as TypeArgumentListImpl?; |
| push( |
| MapPatternImpl( |
| typeArguments: typeArguments, |
| leftBracket: leftBrace, |
| elements: elements, |
| rightBracket: rightBrace, |
| ), |
| ); |
| } |
| |
| @override |
| void handleMapPatternEntry(Token colon, Token endToken) { |
| assert(optional(':', colon)); |
| debugEvent("MapPatternEntry"); |
| |
| var value = pop() as DartPatternImpl; |
| var key = pop() as ExpressionImpl; |
| push(MapPatternEntryImpl(key: key, separator: colon, value: value)); |
| } |
| |
| @override |
| void handleMixinHeader(Token mixinKeyword) { |
| assert(optional('mixin', mixinKeyword)); |
| assert(_classLikeBuilder == null); |
| debugEvent("MixinHeader"); |
| |
| var implementsClause = |
| pop(NullValues.IdentifierList) as ImplementsClauseImpl?; |
| var onClause = pop(NullValues.IdentifierList) as MixinOnClauseImpl?; |
| var baseKeyword = pop(NullValues.Token) as Token?; |
| var augmentKeyword = pop(NullValues.Token) as Token?; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var name = pop() as SimpleIdentifierImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| |
| var begin = baseKeyword ?? mixinKeyword; |
| var comment = _findComment(metadata, begin); |
| |
| _classLikeBuilder = _MixinDeclarationBuilder( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| baseKeyword: baseKeyword, |
| mixinKeyword: mixinKeyword, |
| name: name.token, |
| typeParameters: typeParameters, |
| onClause: onClause, |
| implementsClause: implementsClause, |
| leftBracket: Tokens.openCurlyBracket(), |
| rightBracket: Tokens.closeCurlyBracket(), |
| ); |
| } |
| |
| @override |
| void handleMixinOn(Token? onKeyword, int typeCount) { |
| assert(onKeyword == null || onKeyword.isKeywordOrIdentifier); |
| debugEvent("MixinOn"); |
| |
| if (onKeyword != null) { |
| endTypeList(typeCount); |
| var onTypes = _popNamedTypeList( |
| errorCode: ParserErrorCode.EXPECTED_NAMED_TYPE_ON, |
| ); |
| push( |
| MixinOnClauseImpl( |
| onKeyword: onKeyword, |
| superclassConstraints: onTypes, |
| ), |
| ); |
| } else { |
| push(NullValues.IdentifierList); |
| } |
| } |
| |
| @override |
| void handleMixinWithClause(Token withKeyword) { |
| assert(optional('with', withKeyword)); |
| // This is an error case. An error has been issued already. |
| // Possibly the data could be used for help though. |
| _popNamedTypeList( |
| errorCode: ParserErrorCode.EXPECTED_NAMED_TYPE_WITH, |
| ); |
| } |
| |
| @override |
| void handleNamedArgument(Token colon) { |
| assert(optional(':', colon)); |
| debugEvent("NamedArgument"); |
| |
| var expression = pop() as ExpressionImpl; |
| |
| SimpleIdentifierImpl name; |
| var nameCandidate = pop(); |
| if (nameCandidate is AugmentedExpressionImpl) { |
| errorReporter.errorReporter?.atNode( |
| nameCandidate, |
| ParserErrorCode.INVALID_USE_OF_IDENTIFIER_AUGMENTED, |
| ); |
| name = SimpleIdentifierImpl(nameCandidate.augmentedKeyword); |
| } else { |
| name = nameCandidate as SimpleIdentifierImpl; |
| } |
| |
| push( |
| NamedExpressionImpl( |
| name: LabelImpl( |
| label: name, |
| colon: colon, |
| ), |
| expression: expression, |
| ), |
| ); |
| } |
| |
| @override |
| void handleNamedMixinApplicationWithClause(Token withKeyword) { |
| assert(optionalOrNull('with', withKeyword)); |
| var mixinTypes = _popNamedTypeList( |
| errorCode: ParserErrorCode.EXPECTED_NAMED_TYPE_WITH, |
| ); |
| push( |
| WithClauseImpl( |
| withKeyword: withKeyword, |
| mixinTypes: mixinTypes, |
| ), |
| ); |
| } |
| |
| @override |
| void handleNamedRecordField(Token colon) => handleNamedArgument(colon); |
| |
| @override |
| void handleNativeClause(Token nativeToken, bool hasName) { |
| debugEvent("NativeClause"); |
| |
| if (hasName) { |
| nativeName = pop() as StringLiteralImpl; |
| } else { |
| nativeName = null; |
| } |
| } |
| |
| @override |
| void handleNativeFunctionBody(Token nativeToken, Token semicolon) { |
| assert(optional('native', nativeToken)); |
| assert(optional(';', semicolon)); |
| debugEvent("NativeFunctionBody"); |
| |
| // TODO(danrubel): Change the parser to not produce these modifiers. |
| pop(); // star |
| pop(); // async |
| push( |
| NativeFunctionBodyImpl( |
| nativeKeyword: nativeToken, |
| stringLiteral: nativeName, |
| semicolon: semicolon, |
| ), |
| ); |
| } |
| |
| @override |
| void handleNewAsIdentifier(Token token) { |
| if (!enableConstructorTearoffs) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.constructor_tearoffs, |
| startToken: token, |
| ); |
| } |
| } |
| |
| @override |
| void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { |
| debugEvent("NoConstructorReferenceContinuationAfterTypeArguments"); |
| |
| push(NullValues.ConstructorReferenceContinuationAfterTypeArguments); |
| } |
| |
| @override |
| void handleNoFieldInitializer(Token token) { |
| debugEvent("NoFieldInitializer"); |
| |
| var name = pop() as SimpleIdentifierImpl; |
| push( |
| VariableDeclarationImpl( |
| name: name.token, |
| equals: null, |
| initializer: null, |
| ), |
| ); |
| } |
| |
| @override |
| void handleNoInitializers() { |
| debugEvent("NoInitializers"); |
| |
| if (!isFullAst) return; |
| push(NullValues.ConstructorInitializerSeparator); |
| push(NullValues.ConstructorInitializers); |
| } |
| |
| @override |
| void handleNonNullAssertExpression(Token bang) { |
| debugEvent('NonNullAssertExpression'); |
| |
| push( |
| PostfixExpressionImpl( |
| operand: pop() as ExpressionImpl, |
| operator: bang, |
| ), |
| ); |
| } |
| |
| @override |
| void handleNoPrimaryConstructor(Token token, Token? constKeyword) { |
| push(constKeyword ?? const NullValue<Token>()); |
| |
| push(const NullValue<RepresentationDeclarationImpl>()); |
| } |
| |
| @override |
| void handleNoTypeNameInConstructorReference(Token token) { |
| debugEvent("NoTypeNameInConstructorReference"); |
| var builder = _classLikeBuilder as _EnumDeclarationBuilder; |
| |
| push( |
| SimpleIdentifierImpl(builder.name), |
| ); |
| } |
| |
| @override |
| void handleNoVariableInitializer(Token token) { |
| debugEvent("NoVariableInitializer"); |
| } |
| |
| @override |
| void handleNullAssertPattern(Token bang) { |
| debugEvent("NullAssertPattern"); |
| push( |
| NullAssertPatternImpl( |
| pattern: pop() as DartPatternImpl, |
| operator: bang, |
| ), |
| ); |
| } |
| |
| @override |
| void handleNullAwareElement(Token nullAwareElement) { |
| debugEvent('NullAwareElement'); |
| if (!enableNullAwareElements) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.null_aware_elements, |
| startToken: nullAwareElement, |
| ); |
| } else { |
| var expression = pop() as ExpressionImpl; |
| push( |
| NullAwareElementImpl( |
| question: nullAwareElement, |
| value: expression, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void handleNullCheckPattern(Token question) { |
| debugEvent('NullCheckPattern'); |
| if (!_featureSet.isEnabled(Feature.patterns)) { |
| // TODO(paulberry): report the appropriate error |
| throw UnimplementedError('Patterns not enabled'); |
| } |
| push( |
| NullCheckPatternImpl( |
| pattern: pop() as DartPatternImpl, |
| operator: question, |
| ), |
| ); |
| } |
| |
| @override |
| void handleObjectPattern( |
| Token firstIdentifierToken, Token? dot, Token? secondIdentifierToken) { |
| debugEvent("ExtractorPattern"); |
| |
| var arguments = pop() as _ObjectPatternFields; |
| var typeArguments = pop() as TypeArgumentListImpl?; |
| |
| NamedTypeImpl namedType; |
| if (dot != null && secondIdentifierToken != null) { |
| namedType = NamedTypeImpl( |
| importPrefix: ImportPrefixReferenceImpl( |
| name: firstIdentifierToken, |
| period: dot, |
| ), |
| name2: secondIdentifierToken, |
| typeArguments: typeArguments, |
| question: null, |
| ); |
| } else { |
| namedType = NamedTypeImpl( |
| importPrefix: null, |
| name2: firstIdentifierToken, |
| typeArguments: typeArguments, |
| question: null, |
| ); |
| } |
| |
| push( |
| ObjectPatternImpl( |
| type: namedType, |
| leftParenthesis: arguments.leftParenthesis, |
| fields: arguments.fields, |
| rightParenthesis: arguments.rightParenthesis, |
| ), |
| ); |
| } |
| |
| @override |
| void handleObjectPatternFields(int count, Token beginToken, Token endToken) { |
| debugEvent("ExtractorPatternFields"); |
| var fields = popTypedList2<PatternFieldImpl>(count); |
| push(_ObjectPatternFields(beginToken, endToken, fields)); |
| } |
| |
| @override |
| void handleOperator(Token operatorToken) { |
| assert(operatorToken.isUserDefinableOperator); |
| debugEvent("Operator"); |
| |
| push(operatorToken); |
| } |
| |
| @override |
| void handleOperatorName(Token operatorKeyword, Token token) { |
| assert(optional('operator', operatorKeyword)); |
| assert(token.type.isUserDefinableOperator); |
| debugEvent("OperatorName"); |
| |
| push( |
| _OperatorName( |
| operatorKeyword, |
| SimpleIdentifierImpl(token), |
| ), |
| ); |
| } |
| |
| @override |
| void handleParenthesizedCondition( |
| Token leftParenthesis, Token? case_, Token? when) { |
| ExpressionImpl condition; |
| CaseClauseImpl? caseClause; |
| if (case_ != null) { |
| var whenClause = when != null ? pop() as WhenClauseImpl : null; |
| var pattern = pop() as DartPatternImpl; |
| caseClause = CaseClauseImpl( |
| caseKeyword: case_, |
| guardedPattern: GuardedPatternImpl( |
| pattern: pattern, |
| whenClause: whenClause, |
| ), |
| ); |
| } |
| condition = pop() as ExpressionImpl; |
| reportErrorIfSuper(condition); |
| push(_ParenthesizedCondition(leftParenthesis, condition, caseClause)); |
| } |
| |
| @override |
| void handleParenthesizedPattern(Token leftParenthesis) { |
| assert(optional('(', leftParenthesis)); |
| debugEvent("ParenthesizedPattern"); |
| |
| var pattern = pop() as DartPatternImpl; |
| push(ParenthesizedPatternImpl( |
| leftParenthesis: leftParenthesis, |
| pattern: pattern, |
| rightParenthesis: leftParenthesis.endGroup!)); |
| } |
| |
| @override |
| void handlePatternAssignment(Token equals) { |
| var expression = pop() as ExpressionImpl; |
| var pattern = pop() as DartPatternImpl; |
| push(PatternAssignmentImpl( |
| pattern: pattern, equals: equals, expression: expression)); |
| } |
| |
| @override |
| void handlePatternField(Token? colon) { |
| debugEvent("PatternField"); |
| |
| var pattern = pop() as DartPatternImpl; |
| PatternFieldNameImpl? fieldName; |
| if (colon != null) { |
| var name = (pop() as SimpleIdentifierImpl?)?.token; |
| fieldName = PatternFieldNameImpl(name: name, colon: colon); |
| } |
| push(PatternFieldImpl(name: fieldName, pattern: pattern)); |
| } |
| |
| @override |
| void handlePatternVariableDeclarationStatement( |
| Token keyword, Token equals, Token semicolon) { |
| var expression = pop() as ExpressionImpl; |
| var pattern = pop() as DartPatternImpl; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, keyword); |
| push(PatternVariableDeclarationStatementImpl( |
| declaration: PatternVariableDeclarationImpl( |
| keyword: keyword, |
| pattern: pattern, |
| equals: equals, |
| expression: expression, |
| comment: comment, |
| metadata: metadata), |
| semicolon: semicolon)); |
| } |
| |
| @override |
| void handleQualified(Token period) { |
| assert(optional('.', period)); |
| |
| var identifier = pop() as SimpleIdentifierImpl; |
| var prefix = pop(); |
| if (prefix is List) { |
| // We're just accumulating components into a list. |
| prefix.add(identifier); |
| push(prefix); |
| } else if (prefix is SimpleIdentifierImpl) { |
| // TODO(paulberry): resolve [identifier]. Note that BodyBuilder handles |
| // this situation using SendAccessGenerator. |
| push( |
| PrefixedIdentifierImpl( |
| prefix: prefix, |
| period: period, |
| identifier: identifier, |
| ), |
| ); |
| } else { |
| // TODO(paulberry): implement. |
| logEvent('Qualified with >1 dot'); |
| } |
| } |
| |
| @override |
| void handleRecordPattern(Token token, int count) { |
| debugEvent("RecordPattern"); |
| |
| var fields = popTypedList2<PatternFieldImpl>(count); |
| push( |
| RecordPatternImpl( |
| leftParenthesis: token, |
| fields: fields, |
| rightParenthesis: token.endGroup!, |
| ), |
| ); |
| } |
| |
| @override |
| void handleRecoverableError( |
| Message message, Token startToken, Token endToken) { |
| // TODO(danrubel): Ignore this error until we deprecate `native` support. |
| if (message == messageNativeClauseShouldBeAnnotation && allowNativeClause) { |
| return; |
| } else if (message.code == codeBuiltInIdentifierInDeclaration) { |
| // Allow e.g. 'class Function' in sdk. |
| if (isDartLibrary) return; |
| } |
| debugEvent("Error: ${message.problemMessage}"); |
| if (message.code.analyzerCodes == null && startToken is ErrorToken) { |
| translateErrorToken(startToken, errorReporter.reportScannerError); |
| } else { |
| int offset = startToken.offset; |
| int length = endToken.end - offset; |
| addProblem(message, offset, length); |
| } |
| } |
| |
| @override |
| void handleRecoverDeclarationHeader(DeclarationHeaderKind kind) { |
| debugEvent("RecoverClassHeader"); |
| |
| var implementsClause = |
| pop(NullValues.IdentifierList) as ImplementsClauseImpl?; |
| var withClause = pop(NullValues.WithClause) as WithClauseImpl?; |
| var extendsClause = pop(NullValues.ExtendsClause) as ExtendsClauseImpl?; |
| switch (kind) { |
| case DeclarationHeaderKind.Class: |
| var declaration = _classLikeBuilder as _ClassDeclarationBuilder; |
| if (extendsClause != null) { |
| if (declaration.extendsClause?.superclass == null) { |
| declaration.extendsClause = extendsClause; |
| } |
| } |
| if (withClause != null) { |
| var existingClause = declaration.withClause; |
| if (existingClause == null) { |
| declaration.withClause = withClause; |
| } else { |
| declaration.withClause = WithClauseImpl( |
| withKeyword: existingClause.withKeyword, |
| mixinTypes: [ |
| ...existingClause.mixinTypes, |
| ...withClause.mixinTypes, |
| ], |
| ); |
| } |
| } |
| if (implementsClause != null) { |
| var existingClause = declaration.implementsClause; |
| if (existingClause == null) { |
| declaration.implementsClause = implementsClause; |
| } else { |
| declaration.implementsClause = ImplementsClauseImpl( |
| implementsKeyword: existingClause.implementsKeyword, |
| interfaces: [ |
| ...existingClause.interfaces, |
| ...implementsClause.interfaces, |
| ], |
| ); |
| } |
| } |
| case DeclarationHeaderKind.ExtensionType: |
| // TODO(scheglov): Support header recovery on extension type |
| // declaration. |
| } |
| } |
| |
| @override |
| void handleRecoverImport(Token? semicolon) { |
| assert(optionalOrNull(';', semicolon)); |
| debugEvent("RecoverImport"); |
| |
| var combinators = pop() as List<CombinatorImpl>?; |
| var deferredKeyword = pop(NullValues.Deferred) as Token?; |
| var asKeyword = pop(NullValues.As) as Token?; |
| var prefix = pop(NullValues.Prefix) as SimpleIdentifierImpl?; |
| var configurations = pop() as List<ConfigurationImpl>?; |
| |
| var directive = directives.last; |
| switch (directive) { |
| case ImportDirectiveImpl(): |
| // TODO(scheglov): This code would be easier if we used one object. |
| var mergedAsKeyword = directive.asKeyword; |
| var mergedPrefix = directive.prefix; |
| if (directive.asKeyword == null && asKeyword != null) { |
| mergedAsKeyword = asKeyword; |
| mergedPrefix = prefix; |
| } |
| |
| directives.last = ImportDirectiveImpl( |
| comment: directive.documentationComment, |
| metadata: directive.metadata, |
| importKeyword: directive.importKeyword, |
| uri: directive.uri, |
| configurations: [ |
| ...directive.configurations, |
| ...?configurations, |
| ], |
| deferredKeyword: directive.deferredKeyword ?? deferredKeyword, |
| asKeyword: mergedAsKeyword, |
| prefix: mergedPrefix, |
| combinators: [ |
| ...directive.combinators, |
| ...?combinators, |
| ], |
| semicolon: semicolon ?? directive.semicolon, |
| ); |
| default: |
| throw UnimplementedError('${directive.runtimeType}'); |
| } |
| } |
| |
| @override |
| void handleRecoverMixinHeader() { |
| var builder = _classLikeBuilder as _MixinDeclarationBuilder; |
| var implementsClause = |
| pop(NullValues.IdentifierList) as ImplementsClauseImpl?; |
| var onClause = pop(NullValues.IdentifierList) as MixinOnClauseImpl?; |
| |
| if (onClause != null) { |
| var existingClause = builder.onClause; |
| if (existingClause == null) { |
| builder.onClause = onClause; |
| } else { |
| builder.onClause = MixinOnClauseImpl( |
| onKeyword: existingClause.onKeyword, |
| superclassConstraints: [ |
| ...existingClause.superclassConstraints, |
| ...onClause.superclassConstraints, |
| ], |
| ); |
| } |
| } |
| if (implementsClause != null) { |
| var existingClause = builder.implementsClause; |
| if (existingClause == null) { |
| builder.implementsClause = implementsClause; |
| } else { |
| builder.implementsClause = ImplementsClauseImpl( |
| implementsKeyword: implementsClause.implementsKeyword, |
| interfaces: [ |
| ...existingClause.interfaces, |
| ...implementsClause.interfaces, |
| ], |
| ); |
| } |
| } |
| } |
| |
| @override |
| void handleRelationalPattern(Token token) { |
| debugEvent("RelationalPattern"); |
| push(RelationalPatternImpl( |
| operator: token, operand: pop() as ExpressionImpl)); |
| } |
| |
| @override |
| void handleRestPattern(Token dots, {required bool hasSubPattern}) { |
| var subPattern = hasSubPattern ? pop() as DartPatternImpl : null; |
| push(RestPatternElementImpl(operator: dots, pattern: subPattern)); |
| } |
| |
| @override |
| void handleScript(Token token) { |
| assert(identical(token.type, TokenType.SCRIPT_TAG)); |
| debugEvent("Script"); |
| |
| scriptTag = ScriptTagImpl( |
| scriptTag: token, |
| ); |
| } |
| |
| @override |
| void handleSend(Token beginToken, Token endToken) { |
| debugEvent("Send"); |
| |
| var arguments = pop() as MethodInvocationImpl?; |
| var typeArguments = pop() as TypeArgumentListImpl?; |
| if (arguments != null) { |
| doInvocation(typeArguments, arguments); |
| } else { |
| doPropertyGet(); |
| } |
| } |
| |
| @override |
| void handleSpreadExpression(Token spreadToken) { |
| var expression = pop() as ExpressionImpl; |
| push( |
| SpreadElementImpl( |
| spreadOperator: spreadToken, |
| expression: expression, |
| ), |
| ); |
| } |
| |
| @override |
| void handleStringPart(Token literalString) { |
| assert(identical(literalString.kind, STRING_TOKEN)); |
| debugEvent("StringPart"); |
| |
| push(literalString); |
| } |
| |
| @override |
| void handleSuperExpression(Token superKeyword, IdentifierContext context) { |
| assert(optional('super', superKeyword)); |
| debugEvent("SuperExpression"); |
| push( |
| SuperExpressionImpl( |
| superKeyword: superKeyword, |
| ), |
| ); |
| } |
| |
| @override |
| void handleSwitchCaseNoWhenClause(Token token) { |
| debugEvent("SwitchCaseNoWhenClause"); |
| } |
| |
| @override |
| void handleSwitchExpressionCasePattern(Token token) { |
| debugEvent("SwitchExpressionCasePattern"); |
| } |
| |
| @override |
| void handleSymbolVoid(Token voidKeyword) { |
| assert(optional('void', voidKeyword)); |
| debugEvent("SymbolVoid"); |
| |
| push(voidKeyword); |
| } |
| |
| @override |
| void handleThisExpression(Token thisKeyword, IdentifierContext context) { |
| assert(optional('this', thisKeyword)); |
| debugEvent("ThisExpression"); |
| |
| push( |
| ThisExpressionImpl( |
| thisKeyword: thisKeyword, |
| ), |
| ); |
| } |
| |
| @override |
| void handleThrowExpression(Token throwToken, Token endToken) { |
| assert(optional('throw', throwToken)); |
| debugEvent("ThrowExpression"); |
| |
| push( |
| ThrowExpressionImpl( |
| throwKeyword: throwToken, |
| expression: pop() as ExpressionImpl, |
| ), |
| ); |
| } |
| |
| @override |
| void handleType(Token beginToken, Token? question) { |
| debugEvent("Type"); |
| |
| var arguments = pop() as TypeArgumentListImpl?; |
| |
| IdentifierImpl name; |
| var nameCandidate = pop(); |
| if (nameCandidate is AugmentedExpressionImpl) { |
| errorReporter.errorReporter?.atNode( |
| nameCandidate, |
| ParserErrorCode.INVALID_USE_OF_IDENTIFIER_AUGMENTED, |
| ); |
| name = SimpleIdentifierImpl(nameCandidate.augmentedKeyword); |
| } else { |
| name = nameCandidate as IdentifierImpl; |
| } |
| |
| push( |
| name.toNamedType( |
| typeArguments: arguments, |
| question: question, |
| ), |
| ); |
| } |
| |
| @override |
| void handleTypeArgumentApplication(Token openAngleBracket) { |
| var typeArguments = pop() as TypeArgumentListImpl; |
| var receiver = pop() as ExpressionImpl; |
| if (!enableConstructorTearoffs) { |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.constructor_tearoffs, |
| startToken: typeArguments.leftBracket, |
| endToken: typeArguments.rightBracket, |
| ); |
| } |
| reportErrorIfSuper(receiver); |
| push( |
| FunctionReferenceImpl( |
| function: receiver, |
| typeArguments: typeArguments, |
| ), |
| ); |
| } |
| |
| @override |
| void handleTypeVariablesDefined(Token token, int count) { |
| debugEvent("handleTypeVariablesDefined"); |
| assert(count > 0); |
| push(popTypedList<TypeParameterImpl>(count)); |
| } |
| |
| @override |
| void handleUnaryPostfixAssignmentExpression(Token operator) { |
| assert(operator.type.isUnaryPostfixOperator); |
| debugEvent("UnaryPostfixAssignmentExpression"); |
| |
| var expression = pop() as ExpressionImpl; |
| if (!expression.isAssignable) { |
| // This error is also reported by the body builder. |
| handleRecoverableError( |
| messageIllegalAssignmentToNonAssignable, operator, operator); |
| } |
| push( |
| PostfixExpressionImpl( |
| operand: expression, |
| operator: operator, |
| ), |
| ); |
| } |
| |
| @override |
| void handleUnaryPrefixAssignmentExpression(Token operator) { |
| assert(operator.type.isUnaryPrefixOperator); |
| debugEvent("UnaryPrefixAssignmentExpression"); |
| |
| var expression = pop() as ExpressionImpl; |
| if (!expression.isAssignable) { |
| // This error is also reported by the body builder. |
| handleRecoverableError(messageMissingAssignableSelector, |
| expression.endToken, expression.endToken); |
| } |
| push( |
| PrefixExpressionImpl( |
| operator: operator, |
| operand: expression, |
| ), |
| ); |
| } |
| |
| @override |
| void handleUnaryPrefixExpression(Token operator) { |
| assert(operator.type.isUnaryPrefixOperator); |
| debugEvent("UnaryPrefixExpression"); |
| |
| var operand = pop() as ExpressionImpl; |
| if (!(operator.type == TokenType.MINUS || |
| operator.type == TokenType.TILDE)) { |
| reportErrorIfSuper(operand); |
| } |
| |
| push( |
| PrefixExpressionImpl( |
| operator: operator, |
| operand: operand, |
| ), |
| ); |
| } |
| |
| @override |
| void handleValuedFormalParameter( |
| Token equals, Token token, FormalParameterKind kind) { |
| assert(optional('=', equals) || optional(':', equals)); |
| debugEvent("ValuedFormalParameter"); |
| |
| var value = pop() as ExpressionImpl; |
| push(_ParameterDefaultValue(equals, value)); |
| } |
| |
| @override |
| void handleVoidKeyword(Token voidKeyword) { |
| assert(optional('void', voidKeyword)); |
| debugEvent("VoidKeyword"); |
| |
| // TODO(paulberry): is this sufficient, or do we need to hook the "void" |
| // keyword up to an element? |
| handleIdentifier(voidKeyword, IdentifierContext.typeReference); |
| handleNoTypeArguments(voidKeyword); |
| handleType(voidKeyword, null); |
| } |
| |
| @override |
| void handleVoidKeywordWithTypeArguments(Token voidKeyword) { |
| assert(optional('void', voidKeyword)); |
| debugEvent("VoidKeywordWithTypeArguments"); |
| var arguments = pop() as TypeArgumentListImpl; |
| |
| // TODO(paulberry): is this sufficient, or do we need to hook the "void" |
| // keyword up to an element? |
| handleIdentifier(voidKeyword, IdentifierContext.typeReference); |
| push(arguments); |
| handleType(voidKeyword, null); |
| } |
| |
| @override |
| void handleWildcardPattern(Token? keyword, Token wildcard) { |
| debugEvent('WildcardPattern'); |
| assert(_featureSet.isEnabled(Feature.patterns)); |
| // Note: if `default` appears in a switch expression, parser error recovery |
| // treats it as a wildcard pattern. |
| assert(wildcard.lexeme == '_' || wildcard.lexeme == 'default'); |
| var type = pop() as TypeAnnotationImpl?; |
| push( |
| WildcardPatternImpl( |
| keyword: keyword, |
| type: type, |
| name: wildcard, |
| ), |
| ); |
| } |
| |
| @override |
| Never internalProblem(Message message, int charOffset, Uri uri) { |
| throw UnsupportedError(message.problemMessage); |
| } |
| |
| /// Return `true` if [token] is either `null` or is the symbol or keyword |
| /// [value]. |
| bool optionalOrNull(String value, Token? token) { |
| return token == null || identical(value, token.stringValue); |
| } |
| |
| /// Parses the comment references in a sequence of comment tokens where |
| /// [dartdoc] is the first token in the sequence. |
| @visibleForTesting |
| CommentImpl parseDocComment(Token dartdoc) { |
| // Build and return the comment. |
| return DocCommentBuilder( |
| parser, |
| errorReporter.errorReporter, |
| uri, |
| _featureSet, |
| _languageVersion, |
| _lineInfo, |
| dartdoc, |
| ).build(); |
| } |
| |
| List<CollectionElementImpl> popCollectionElements(int count) { |
| // TODO(scheglov): Not efficient. |
| var elements = <CollectionElementImpl>[]; |
| for (int index = count - 1; index >= 0; --index) { |
| var element = pop(); |
| elements.add(element as CollectionElementImpl); |
| } |
| return elements.reversed.toList(); |
| } |
| |
| List? popList(int n, List list) { |
| if (n == 0) return null; |
| return stack.popList(n, list, null); |
| } |
| |
| List<T>? popTypedList<T extends Object>(int count) { |
| if (count == 0) return null; |
| assert(stack.length >= count); |
| |
| var tailList = List<T?>.filled(count, null, growable: true); |
| stack.popList(count, tailList, null); |
| return tailList.nonNulls.toList(); |
| } |
| |
| // TODO(scheglov): This is probably not optimal. |
| List<T> popTypedList2<T>(int count) { |
| var result = <T>[]; |
| for (var i = 0; i < count; i++) { |
| var element = stack.pop(null) as T; |
| result.add(element); |
| } |
| return result.reversed.toList(); |
| } |
| |
| void reportErrorIfNullableType(Token? questionMark) { |
| if (questionMark != null) { |
| assert(optional('?', questionMark)); |
| _reportFeatureNotEnabled( |
| feature: ExperimentalFeatures.non_nullable, |
| startToken: questionMark, |
| ); |
| } |
| } |
| |
| void reportErrorIfSuper(ExpressionImpl expression) { |
| if (expression is SuperExpressionImpl) { |
| // This error is also reported by the body builder. |
| handleRecoverableError(messageMissingAssignableSelector, |
| expression.beginToken, expression.endToken); |
| } |
| } |
| |
| ConstructorDeclarationImpl _buildConstructorDeclaration({ |
| required Token beginToken, |
| required Token endToken, |
| }) { |
| var bodyObject = pop(); |
| var initializers = (pop() as List<ConstructorInitializerImpl>?) ?? const []; |
| var separator = pop() as Token?; |
| var parameters = pop() as FormalParameterListImpl; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var name = pop(); |
| pop(); // return type |
| var modifiers = pop() as _Modifiers?; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, beginToken); |
| |
| ConstructorNameImpl? redirectedConstructor; |
| FunctionBodyImpl body; |
| if (bodyObject is FunctionBodyImpl) { |
| body = bodyObject; |
| } else if (bodyObject is _RedirectingFactoryBody) { |
| separator = bodyObject.equalToken; |
| redirectedConstructor = bodyObject.constructorName; |
| body = EmptyFunctionBodyImpl( |
| semicolon: endToken, |
| ); |
| } else { |
| internalProblem( |
| templateInternalProblemUnhandled.withArguments( |
| "${bodyObject.runtimeType}", "bodyObject"), |
| beginToken.charOffset, |
| uri); |
| } |
| |
| SimpleIdentifierImpl prefixOrName; |
| Token? period; |
| SimpleIdentifierImpl? nameOrNull; |
| if (name is SimpleIdentifierImpl) { |
| prefixOrName = name; |
| } else if (name is PrefixedIdentifierImpl) { |
| prefixOrName = name.prefix; |
| period = name.period; |
| nameOrNull = name.identifier; |
| } else if (name is _OperatorName) { |
| prefixOrName = name.name; |
| } else { |
| throw UnimplementedError( |
| 'name is an instance of ${name.runtimeType} in endClassConstructor'); |
| } |
| |
| if (typeParameters != null) { |
| // Outline builder also reports this error message. |
| handleRecoverableError(messageConstructorWithTypeParameters, |
| typeParameters.beginToken, typeParameters.endToken); |
| } |
| if (modifiers?.constKeyword != null && |
| (body.length > 1 || body.beginToken.lexeme != ';')) { |
| // This error is also reported in BodyBuilder.finishFunction |
| Token bodyToken = body.beginToken; |
| // Token bodyToken = body.beginToken ?? modifiers.constKeyword; |
| handleRecoverableError( |
| messageConstConstructorWithBody, bodyToken, bodyToken); |
| } |
| |
| if (modifiers?.externalKeyword != null) { |
| for (var formalParameter in parameters.parameters) { |
| var notDefault = formalParameter.notDefault; |
| if (notDefault is FieldFormalParameterImpl) { |
| errorReporter.errorReporter?.atToken( |
| notDefault.thisKeyword, |
| ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_FIELD_INITIALIZERS, |
| ); |
| } |
| } |
| } |
| |
| var constructor = ConstructorDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: modifiers?.augmentKeyword, |
| externalKeyword: modifiers?.externalKeyword, |
| constKeyword: modifiers?.finalConstOrVarKeyword, |
| factoryKeyword: null, |
| returnType: SimpleIdentifierImpl(prefixOrName.token), |
| period: period, |
| name: nameOrNull?.token, |
| parameters: parameters, |
| separator: separator, |
| initializers: initializers, |
| redirectedConstructor: redirectedConstructor, |
| body: body, |
| ); |
| return constructor; |
| } |
| |
| ConstructorDeclarationImpl _buildFactoryConstructorDeclaration({ |
| required Token beginToken, |
| required Token factoryKeyword, |
| required Token endToken, |
| }) { |
| FunctionBodyImpl body; |
| Token? separator; |
| ConstructorNameImpl? redirectedConstructor; |
| var bodyObject = pop(); |
| if (bodyObject is FunctionBodyImpl) { |
| body = bodyObject; |
| } else if (bodyObject is _RedirectingFactoryBody) { |
| separator = bodyObject.equalToken; |
| redirectedConstructor = bodyObject.constructorName; |
| body = EmptyFunctionBodyImpl( |
| semicolon: endToken, |
| ); |
| } else { |
| internalProblem( |
| templateInternalProblemUnhandled.withArguments( |
| "${bodyObject.runtimeType}", "bodyObject"), |
| beginToken.charOffset, |
| uri); |
| } |
| |
| var parameters = pop() as FormalParameterListImpl; |
| var typeParameters = pop() as TypeParameterListImpl?; |
| var constructorName = pop() as IdentifierImpl; |
| var modifiers = pop() as _Modifiers?; |
| var metadata = pop() as List<AnnotationImpl>?; |
| var comment = _findComment(metadata, beginToken); |
| |
| if (typeParameters != null) { |
| // TODO(danrubel): Update OutlineBuilder to report this error message. |
| handleRecoverableError(messageConstructorWithTypeParameters, |
| typeParameters.beginToken, typeParameters.endToken); |
| } |
| |
| // Decompose the preliminary ConstructorName into the type name and |
| // the actual constructor name. |
| SimpleIdentifierImpl returnType; |
| Token? period; |
| Token? nameToken; |
| IdentifierImpl typeName = constructorName; |
| if (typeName is SimpleIdentifierImpl) { |
| returnType = typeName; |
| } else if (typeName is PrefixedIdentifierImpl) { |
| returnType = typeName.prefix; |
| period = typeName.period; |
| nameToken = typeName.identifier.token; |
| } else { |
| throw UnimplementedError(); |
| } |
| |
| var constructor = ConstructorDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: modifiers?.augmentKeyword, |
| externalKeyword: modifiers?.externalKeyword, |
| constKeyword: modifiers?.finalConstOrVarKeyword, |
| factoryKeyword: factoryKeyword, |
| returnType: SimpleIdentifierImpl(returnType.token), |
| period: period, |
| name: nameToken, |
| parameters: parameters, |
| separator: separator, |
| initializers: null, |
| redirectedConstructor: redirectedConstructor, |
| body: body, |
| ); |
| return constructor; |
| } |
| |
| CommentImpl? _findComment( |
| List<AnnotationImpl>? metadata, Token tokenAfterMetadata) { |
| // Find the dartdoc tokens. |
| var dartdoc = parser.findDartDoc(tokenAfterMetadata); |
| if (dartdoc == null) { |
| if (metadata == null) { |
| return null; |
| } |
| int index = metadata.length; |
| while (true) { |
| if (index == 0) { |
| return null; |
| } |
| --index; |
| dartdoc = parser.findDartDoc(metadata[index].beginToken); |
| if (dartdoc != null) { |
| break; |
| } |
| } |
| } |
| |
| return parseDocComment(dartdoc); |
| } |
| |
| void _handleInstanceCreation(Token? token) { |
| var arguments = pop() as MethodInvocationImpl; |
| ConstructorNameImpl constructorName; |
| TypeArgumentListImpl? typeArguments; |
| var object = pop(); |
| if (object is _ConstructorNameWithInvalidTypeArgs) { |
| constructorName = object.name; |
| typeArguments = object.invalidTypeArgs; |
| } else { |
| constructorName = object as ConstructorNameImpl; |
| } |
| push( |
| InstanceCreationExpressionImpl( |
| keyword: token, |
| constructorName: constructorName, |
| argumentList: arguments.argumentList, |
| typeArguments: typeArguments, |
| ), |
| ); |
| } |
| |
| List<NamedTypeImpl> _popNamedTypeList({ |
| required ErrorCode errorCode, |
| }) { |
| var types = pop() as List<TypeAnnotationImpl>; |
| var namedTypes = <NamedTypeImpl>[]; |
| for (var type in types) { |
| if (type is NamedTypeImpl) { |
| namedTypes.add(type); |
| } else { |
| errorReporter.errorReporter?.atNode( |
| type, |
| errorCode, |
| ); |
| } |
| } |
| return namedTypes; |
| } |
| |
| void _reportFeatureNotEnabled({ |
| required ExperimentalFeature feature, |
| required Token startToken, |
| Token? endToken, |
| }) { |
| var requiredVersion = |
| feature.releaseVersion ?? ExperimentStatus.currentVersion; |
| handleRecoverableError( |
| templateExperimentNotEnabled.withArguments( |
| feature.enableString, |
| _versionAsString(requiredVersion), |
| ), |
| startToken, |
| endToken ?? startToken, |
| ); |
| } |
| |
| ArgumentListImpl _syntheticArgumentList(Token precedingToken) { |
| var left = parser.rewriter.insertParens(precedingToken, false); |
| var right = left.endGroup!; |
| return ArgumentListImpl( |
| leftParenthesis: left, |
| arguments: [], |
| rightParenthesis: right, |
| ); |
| } |
| |
| FormalParameterListImpl _syntheticFormalParameterList(Token precedingToken) { |
| var left = parser.rewriter.insertParens(precedingToken, false); |
| var right = left.endGroup!; |
| return FormalParameterListImpl( |
| leftParenthesis: left, |
| parameters: [], |
| leftDelimiter: null, |
| rightDelimiter: null, |
| rightParenthesis: right, |
| ); |
| } |
| |
| SimpleIdentifierImpl _tmpSimpleIdentifier() { |
| return SimpleIdentifierImpl( |
| StringToken(TokenType.STRING, '__tmp', -1), |
| ); |
| } |
| |
| ParameterKind _toAnalyzerParameterKind(FormalParameterKind type) { |
| switch (type) { |
| case FormalParameterKind.requiredPositional: |
| return ParameterKind.REQUIRED; |
| case FormalParameterKind.requiredNamed: |
| return ParameterKind.NAMED_REQUIRED; |
| case FormalParameterKind.optionalNamed: |
| return ParameterKind.NAMED; |
| case FormalParameterKind.optionalPositional: |
| return ParameterKind.POSITIONAL; |
| } |
| } |
| |
| static String _versionAsString(Version version) { |
| return '${version.major}.${version.minor}.${version.patch}'; |
| } |
| } |
| |
| class _ClassDeclarationBuilder extends _ClassLikeDeclarationBuilder { |
| final Token? augmentKeyword; |
| final Token? abstractKeyword; |
| final Token? macroKeyword; |
| final Token? sealedKeyword; |
| final Token? baseKeyword; |
| final Token? interfaceKeyword; |
| final Token? finalKeyword; |
| final Token? mixinKeyword; |
| final Token classKeyword; |
| final Token name; |
| ExtendsClauseImpl? extendsClause; |
| WithClauseImpl? withClause; |
| ImplementsClauseImpl? implementsClause; |
| final NativeClauseImpl? nativeClause; |
| |
| _ClassDeclarationBuilder({ |
| required super.comment, |
| required super.metadata, |
| required super.typeParameters, |
| required super.leftBracket, |
| required super.rightBracket, |
| required this.augmentKeyword, |
| required this.abstractKeyword, |
| required this.macroKeyword, |
| required this.sealedKeyword, |
| required this.baseKeyword, |
| required this.interfaceKeyword, |
| required this.finalKeyword, |
| required this.mixinKeyword, |
| required this.classKeyword, |
| required this.name, |
| required this.extendsClause, |
| required this.withClause, |
| required this.implementsClause, |
| required this.nativeClause, |
| }); |
| |
| ClassDeclarationImpl build() { |
| return ClassDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| abstractKeyword: abstractKeyword, |
| macroKeyword: macroKeyword, |
| sealedKeyword: sealedKeyword, |
| baseKeyword: baseKeyword, |
| interfaceKeyword: interfaceKeyword, |
| finalKeyword: finalKeyword, |
| mixinKeyword: mixinKeyword, |
| classKeyword: classKeyword, |
| name: name, |
| typeParameters: typeParameters, |
| extendsClause: extendsClause, |
| withClause: withClause, |
| implementsClause: implementsClause, |
| nativeClause: nativeClause, |
| leftBracket: leftBracket, |
| members: members, |
| rightBracket: rightBracket, |
| ); |
| } |
| } |
| |
| class _ClassLikeDeclarationBuilder { |
| final CommentImpl? comment; |
| final List<AnnotationImpl>? metadata; |
| final TypeParameterListImpl? typeParameters; |
| |
| Token leftBracket; |
| final List<ClassMemberImpl> members = []; |
| Token rightBracket; |
| |
| _ClassLikeDeclarationBuilder({ |
| required this.comment, |
| required this.metadata, |
| required this.typeParameters, |
| required this.leftBracket, |
| required this.rightBracket, |
| }); |
| } |
| |
| class _ConstructorNameWithInvalidTypeArgs { |
| final ConstructorNameImpl name; |
| final TypeArgumentListImpl invalidTypeArgs; |
| |
| _ConstructorNameWithInvalidTypeArgs(this.name, this.invalidTypeArgs); |
| } |
| |
| class _EnumDeclarationBuilder extends _ClassLikeDeclarationBuilder { |
| final Token? augmentKeyword; |
| final Token enumKeyword; |
| final Token name; |
| final WithClauseImpl? withClause; |
| final ImplementsClauseImpl? implementsClause; |
| final List<EnumConstantDeclarationImpl> constants = []; |
| Token? semicolon; |
| |
| _EnumDeclarationBuilder({ |
| required super.comment, |
| required super.metadata, |
| required super.typeParameters, |
| required super.leftBracket, |
| required super.rightBracket, |
| required this.augmentKeyword, |
| required this.enumKeyword, |
| required this.name, |
| required this.withClause, |
| required this.implementsClause, |
| required this.semicolon, |
| }); |
| |
| EnumDeclarationImpl build() { |
| return EnumDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| enumKeyword: enumKeyword, |
| name: name, |
| typeParameters: typeParameters, |
| withClause: withClause, |
| implementsClause: implementsClause, |
| leftBracket: leftBracket, |
| constants: constants, |
| semicolon: semicolon, |
| members: members, |
| rightBracket: rightBracket, |
| ); |
| } |
| } |
| |
| class _ExtensionDeclarationBuilder extends _ClassLikeDeclarationBuilder { |
| final Token? augmentKeyword; |
| final Token extensionKeyword; |
| final Token? name; |
| |
| _ExtensionDeclarationBuilder({ |
| required super.comment, |
| required super.metadata, |
| required super.typeParameters, |
| required super.leftBracket, |
| required super.rightBracket, |
| required this.augmentKeyword, |
| required this.extensionKeyword, |
| required this.name, |
| }); |
| |
| ExtensionDeclarationImpl build({ |
| required Token? typeKeyword, |
| required ExtensionOnClauseImpl? onClause, |
| }) { |
| return ExtensionDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| extensionKeyword: extensionKeyword, |
| typeKeyword: typeKeyword, |
| name: name, |
| typeParameters: typeParameters, |
| onClause: onClause, |
| leftBracket: leftBracket, |
| members: members, |
| rightBracket: rightBracket, |
| ); |
| } |
| } |
| |
| class _ExtensionTypeDeclarationBuilder extends _ClassLikeDeclarationBuilder { |
| final Token? augmentKeyword; |
| final Token extensionKeyword; |
| final Token name; |
| |
| _ExtensionTypeDeclarationBuilder({ |
| required super.comment, |
| required super.metadata, |
| required super.typeParameters, |
| required super.leftBracket, |
| required super.rightBracket, |
| required this.augmentKeyword, |
| required this.extensionKeyword, |
| required this.name, |
| }); |
| |
| ExtensionTypeDeclarationImpl build({ |
| required Token typeKeyword, |
| required Token? constKeyword, |
| required RepresentationDeclarationImpl representation, |
| required ImplementsClauseImpl? implementsClause, |
| }) { |
| return ExtensionTypeDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| extensionKeyword: extensionKeyword, |
| typeKeyword: typeKeyword, |
| constKeyword: constKeyword, |
| name: name, |
| typeParameters: typeParameters, |
| representation: representation, |
| implementsClause: implementsClause, |
| leftBracket: leftBracket, |
| members: members, |
| rightBracket: rightBracket, |
| ); |
| } |
| } |
| |
| class _MixinDeclarationBuilder extends _ClassLikeDeclarationBuilder { |
| final Token? augmentKeyword; |
| final Token? baseKeyword; |
| final Token mixinKeyword; |
| final Token name; |
| MixinOnClauseImpl? onClause; |
| ImplementsClauseImpl? implementsClause; |
| |
| _MixinDeclarationBuilder({ |
| required super.comment, |
| required super.metadata, |
| required super.typeParameters, |
| required super.leftBracket, |
| required super.rightBracket, |
| required this.augmentKeyword, |
| required this.baseKeyword, |
| required this.mixinKeyword, |
| required this.name, |
| required this.onClause, |
| required this.implementsClause, |
| }); |
| |
| MixinDeclarationImpl build() { |
| return MixinDeclarationImpl( |
| comment: comment, |
| metadata: metadata, |
| augmentKeyword: augmentKeyword, |
| baseKeyword: baseKeyword, |
| mixinKeyword: mixinKeyword, |
| name: name, |
| typeParameters: typeParameters, |
| onClause: onClause, |
| implementsClause: implementsClause, |
| leftBracket: leftBracket, |
| members: members, |
| rightBracket: rightBracket, |
| ); |
| } |
| } |
| |
| /// Data structure placed on the stack to represent a non-empty sequence |
| /// of modifiers. |
| class _Modifiers { |
| Token? abstractKeyword; |
| Token? augmentKeyword; |
| Token? externalKeyword; |
| Token? finalConstOrVarKeyword; |
| Token? staticKeyword; |
| Token? covariantKeyword; |
| Token? requiredToken; |
| Token? lateToken; |
| |
| /// Return the token that is lexically first. |
| Token? get beginToken { |
| Token? firstToken; |
| for (Token? token in [ |
| abstractKeyword, |
| externalKeyword, |
| finalConstOrVarKeyword, |
| staticKeyword, |
| covariantKeyword, |
| requiredToken, |
| lateToken, |
| ]) { |
| if (firstToken == null) { |
| firstToken = token; |
| } else if (token != null) { |
| if (token.offset < firstToken.offset) { |
| firstToken = token; |
| } |
| } |
| } |
| return firstToken; |
| } |
| |
| /// Return the `const` keyword or `null`. |
| Token? get constKeyword { |
| return identical('const', finalConstOrVarKeyword?.lexeme) |
| ? finalConstOrVarKeyword |
| : null; |
| } |
| } |
| |
| /// Temporary representation of the fields of an extractor used internally by |
| /// the [AstBuilder]. |
| class _ObjectPatternFields { |
| final Token leftParenthesis; |
| final Token rightParenthesis; |
| final List<PatternFieldImpl> fields; |
| |
| _ObjectPatternFields( |
| this.leftParenthesis, this.rightParenthesis, this.fields); |
| } |
| |
| /// Data structure placed on the stack to represent the keyword "operator" |
| /// followed by a token. |
| class _OperatorName { |
| final Token operatorKeyword; |
| final SimpleIdentifierImpl name; |
| |
| _OperatorName(this.operatorKeyword, this.name); |
| } |
| |
| /// Data structure placed on the stack as a container for optional parameters. |
| class _OptionalFormalParameters { |
| final List<FormalParameterImpl>? parameters; |
| final Token leftDelimiter; |
| final Token rightDelimiter; |
| |
| _OptionalFormalParameters( |
| this.parameters, this.leftDelimiter, this.rightDelimiter); |
| } |
| |
| /// Data structure placed on the stack to represent the default parameter |
| /// value with the separator token. |
| class _ParameterDefaultValue { |
| final Token separator; |
| final ExpressionImpl value; |
| |
| _ParameterDefaultValue(this.separator, this.value); |
| } |
| |
| /// Data structure placed on the stack to represent the parenthesized condition |
| /// part of an if-statement, if-control-flow, switch-statement, while-statement, |
| /// or do-while-statement. |
| class _ParenthesizedCondition { |
| final Token leftParenthesis; |
| final ExpressionImpl expression; |
| final CaseClauseImpl? caseClause; |
| |
| _ParenthesizedCondition( |
| this.leftParenthesis, this.expression, this.caseClause); |
| |
| Token get rightParenthesis => leftParenthesis.endGroup!; |
| } |
| |
| /// Data structure placed on stack to represent the redirected constructor. |
| class _RedirectingFactoryBody { |
| final Token? asyncKeyword; |
| final Token? starKeyword; |
| final Token equalToken; |
| final ConstructorNameImpl constructorName; |
| |
| _RedirectingFactoryBody(this.asyncKeyword, this.starKeyword, this.equalToken, |
| this.constructorName); |
| } |