mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 16:35:01 +00:00
Unnamed libraries
Fixes https://github.com/dart-lang/language/issues/1073 Spec: https://github.com/dart-lang/language/blob/master/accepted/future-releases/unnamed-libraries/feature-specification.md This work allows library directives without a name. Every single one would look like this: ``` library; ``` :) it was a little anti-climactic implementing a non-feature like this, but there it is. The affordance for a library directive without a name is guarded by an experiment flag, `--unnamed-libraries`. Change-Id: I8612238359e88d6082f7e89d0d0fc624fdb45273 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/257490 Commit-Queue: Samuel Rawlins <srawlins@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Kevin Moore <kevmoo@google.com>
This commit is contained in:
parent
948eb70c02
commit
51114fca8a
|
@ -973,8 +973,8 @@ class ForwardingListener implements Listener {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
listener?.endLibraryName(libraryKeyword, semicolon);
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
listener?.endLibraryName(libraryKeyword, semicolon, hasName);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -968,7 +968,7 @@ class Listener implements UnescapeErrorListener {
|
|||
/// Handle the end of a library directive. Substructures:
|
||||
/// - Metadata
|
||||
/// - Library name (a qualified identifier)
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
logEvent("LibraryName");
|
||||
}
|
||||
|
||||
|
|
|
@ -654,17 +654,23 @@ class Parser {
|
|||
|
||||
/// ```
|
||||
/// libraryDirective:
|
||||
/// 'library' qualified ';'
|
||||
/// 'library' qualified? ';'
|
||||
/// ;
|
||||
/// ```
|
||||
Token parseLibraryName(Token libraryKeyword) {
|
||||
assert(optional('library', libraryKeyword));
|
||||
listener.beginUncategorizedTopLevelDeclaration(libraryKeyword);
|
||||
listener.beginLibraryName(libraryKeyword);
|
||||
Token token = parseQualified(libraryKeyword, IdentifierContext.libraryName,
|
||||
IdentifierContext.libraryNameContinuation);
|
||||
token = ensureSemicolon(token);
|
||||
listener.endLibraryName(libraryKeyword, token);
|
||||
Token token = libraryKeyword.next!;
|
||||
bool hasName = !optional(';', token);
|
||||
if (hasName) {
|
||||
token = parseQualified(libraryKeyword, IdentifierContext.libraryName,
|
||||
IdentifierContext.libraryNameContinuation);
|
||||
token = ensureSemicolon(token);
|
||||
} else {
|
||||
token = ensureSemicolon(libraryKeyword);
|
||||
}
|
||||
listener.endLibraryName(libraryKeyword, token, hasName);
|
||||
return token;
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ void sendAnalysisNotificationOverrides(
|
|||
String? _computeLibraryName(CompilationUnit unit) {
|
||||
for (var directive in unit.directives) {
|
||||
if (directive is LibraryDirective) {
|
||||
return directive.name.name;
|
||||
return directive.name2?.name;
|
||||
}
|
||||
}
|
||||
for (var directive in unit.directives) {
|
||||
|
|
|
@ -432,12 +432,9 @@ class KytheDartVisitor extends GeneralizingAstVisitor<void> with OutputUtils {
|
|||
}
|
||||
}
|
||||
|
||||
var start = 0;
|
||||
var end = 0;
|
||||
if (libraryDirective != null) {
|
||||
start = libraryDirective.name.offset;
|
||||
end = libraryDirective.name.end;
|
||||
}
|
||||
final libraryName = libraryDirective?.name2;
|
||||
final start = libraryName?.offset ?? 0;
|
||||
final end = libraryName?.end ?? 0;
|
||||
|
||||
// package node
|
||||
var packageVName = addNodeAndFacts(schema.PACKAGE_KIND,
|
||||
|
|
|
@ -871,7 +871,7 @@ class CodeShapeDataCollector extends RecursiveAstVisitor<void> {
|
|||
_visitChildren(node, {
|
||||
'documentationComment': node.documentationComment,
|
||||
'metadata': node.metadata,
|
||||
'name': node.name,
|
||||
'name': node.name2,
|
||||
});
|
||||
super.visitLibraryDirective(node);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,9 @@ abstract class Feature {
|
|||
static final nonfunction_type_aliases =
|
||||
ExperimentalFeatures.nonfunction_type_aliases;
|
||||
|
||||
/// Feature information for unnamed libraries.
|
||||
static final unnamedLibraries = ExperimentalFeatures.unnamed_libraries;
|
||||
|
||||
/// Feature information for variance.
|
||||
static final variance = ExperimentalFeatures.variance;
|
||||
|
||||
|
|
|
@ -3334,7 +3334,7 @@ abstract class LibraryAugmentationDirective implements UriBasedDirective {
|
|||
/// A library directive.
|
||||
///
|
||||
/// libraryDirective ::=
|
||||
/// [Annotation] 'library' [Identifier] ';'
|
||||
/// [Annotation] 'library' [LibraryIdentifier]? ';'
|
||||
///
|
||||
/// Clients may not extend, implement or mix-in this class.
|
||||
abstract class LibraryDirective implements Directive {
|
||||
|
@ -3342,8 +3342,12 @@ abstract class LibraryDirective implements Directive {
|
|||
Token get libraryKeyword;
|
||||
|
||||
/// Return the name of the library being defined.
|
||||
@Deprecated('Use name2')
|
||||
LibraryIdentifier get name;
|
||||
|
||||
/// Return the name of the library being defined.
|
||||
LibraryIdentifier? get name2;
|
||||
|
||||
/// Return the semicolon terminating the directive.
|
||||
Token get semicolon;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ final _knownFeatures = <String, ExperimentalFeature>{
|
|||
EnableString.super_parameters: ExperimentalFeatures.super_parameters,
|
||||
EnableString.test_experiment: ExperimentalFeatures.test_experiment,
|
||||
EnableString.triple_shift: ExperimentalFeatures.triple_shift,
|
||||
EnableString.unnamed_libraries: ExperimentalFeatures.unnamed_libraries,
|
||||
EnableString.value_class: ExperimentalFeatures.value_class,
|
||||
EnableString.variance: ExperimentalFeatures.variance,
|
||||
};
|
||||
|
@ -110,6 +111,9 @@ class EnableString {
|
|||
/// String to enable the experiment "triple-shift"
|
||||
static const String triple_shift = 'triple-shift';
|
||||
|
||||
/// String to enable the experiment "unnamed-libraries"
|
||||
static const String unnamed_libraries = 'unnamed-libraries';
|
||||
|
||||
/// String to enable the experiment "value-class"
|
||||
static const String value_class = 'value-class';
|
||||
|
||||
|
@ -333,8 +337,18 @@ class ExperimentalFeatures {
|
|||
releaseVersion: Version.parse('2.14.0'),
|
||||
);
|
||||
|
||||
static final value_class = ExperimentalFeature(
|
||||
static final unnamed_libraries = ExperimentalFeature(
|
||||
index: 21,
|
||||
enableString: EnableString.unnamed_libraries,
|
||||
isEnabledByDefault: IsEnabledByDefault.unnamed_libraries,
|
||||
isExpired: IsExpired.unnamed_libraries,
|
||||
documentation: 'Unnamed libraries',
|
||||
experimentalReleaseVersion: null,
|
||||
releaseVersion: null,
|
||||
);
|
||||
|
||||
static final value_class = ExperimentalFeature(
|
||||
index: 22,
|
||||
enableString: EnableString.value_class,
|
||||
isEnabledByDefault: IsEnabledByDefault.value_class,
|
||||
isExpired: IsExpired.value_class,
|
||||
|
@ -344,7 +358,7 @@ class ExperimentalFeatures {
|
|||
);
|
||||
|
||||
static final variance = ExperimentalFeature(
|
||||
index: 22,
|
||||
index: 23,
|
||||
enableString: EnableString.variance,
|
||||
isEnabledByDefault: IsEnabledByDefault.variance,
|
||||
isExpired: IsExpired.variance,
|
||||
|
@ -420,6 +434,9 @@ class IsEnabledByDefault {
|
|||
/// Default state of the experiment "triple-shift"
|
||||
static const bool triple_shift = true;
|
||||
|
||||
/// Default state of the experiment "unnamed-libraries"
|
||||
static const bool unnamed_libraries = false;
|
||||
|
||||
/// Default state of the experiment "value-class"
|
||||
static const bool value_class = false;
|
||||
|
||||
|
@ -494,6 +511,9 @@ class IsExpired {
|
|||
/// Expiration status of the experiment "triple-shift"
|
||||
static const bool triple_shift = true;
|
||||
|
||||
/// Expiration status of the experiment "unnamed-libraries"
|
||||
static const bool unnamed_libraries = false;
|
||||
|
||||
/// Expiration status of the experiment "value-class"
|
||||
static const bool value_class = false;
|
||||
|
||||
|
@ -574,6 +594,10 @@ mixin _CurrentState {
|
|||
/// Current state for the flag "triple-shift"
|
||||
bool get triple_shift => isEnabled(ExperimentalFeatures.triple_shift);
|
||||
|
||||
/// Current state for the flag "unnamed-libraries"
|
||||
bool get unnamed_libraries =>
|
||||
isEnabled(ExperimentalFeatures.unnamed_libraries);
|
||||
|
||||
/// Current state for the flag "value-class"
|
||||
bool get value_class => isEnabled(ExperimentalFeatures.value_class);
|
||||
|
||||
|
|
|
@ -872,7 +872,7 @@ class FileState {
|
|||
}
|
||||
} else if (directive is LibraryDirective) {
|
||||
libraryDirective = UnlinkedLibraryDirective(
|
||||
name: directive.name.name,
|
||||
name: directive.name2?.name,
|
||||
);
|
||||
} else if (directive is PartDirective) {
|
||||
parts.add(
|
||||
|
|
|
@ -704,7 +704,7 @@ class LibraryAnalyzer {
|
|||
directive.element = containerElement;
|
||||
} else if (directive is LibraryDirectiveImpl) {
|
||||
directive.element = containerElement;
|
||||
libraryNameNode = directive.name;
|
||||
libraryNameNode = directive.name2;
|
||||
} else if (directive is PartDirectiveImpl) {
|
||||
if (containerKind is LibraryFileKind &&
|
||||
containerElement is LibraryElementImpl) {
|
||||
|
|
|
@ -181,7 +181,7 @@ class UnlinkedLibraryAugmentationDirective {
|
|||
}
|
||||
|
||||
class UnlinkedLibraryDirective {
|
||||
final String name;
|
||||
final String? name;
|
||||
|
||||
UnlinkedLibraryDirective({
|
||||
required this.name,
|
||||
|
@ -191,12 +191,12 @@ class UnlinkedLibraryDirective {
|
|||
SummaryDataReader reader,
|
||||
) {
|
||||
return UnlinkedLibraryDirective(
|
||||
name: reader.readStringUtf8(),
|
||||
name: reader.readOptionalStringUtf8(),
|
||||
);
|
||||
}
|
||||
|
||||
void write(BufferedSink sink) {
|
||||
sink.writeStringUtf8(name);
|
||||
sink.writeOptionalStringUtf8(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7804,7 +7804,7 @@ class LibraryDirectiveImpl extends DirectiveImpl implements LibraryDirective {
|
|||
Token libraryKeyword;
|
||||
|
||||
/// The name of the library being defined.
|
||||
LibraryIdentifierImpl _name;
|
||||
LibraryIdentifierImpl? _name;
|
||||
|
||||
/// The semicolon terminating the directive.
|
||||
@override
|
||||
|
@ -7817,7 +7817,7 @@ class LibraryDirectiveImpl extends DirectiveImpl implements LibraryDirective {
|
|||
required super.comment,
|
||||
required super.metadata,
|
||||
required this.libraryKeyword,
|
||||
required LibraryIdentifierImpl name,
|
||||
required LibraryIdentifierImpl? name,
|
||||
required this.semicolon,
|
||||
}) : _name = name {
|
||||
_becomeParentOf(_name);
|
||||
|
@ -7830,16 +7830,20 @@ class LibraryDirectiveImpl extends DirectiveImpl implements LibraryDirective {
|
|||
Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
|
||||
|
||||
@override
|
||||
LibraryIdentifierImpl get name => _name;
|
||||
@Deprecated('Use name2')
|
||||
LibraryIdentifierImpl get name => _name!;
|
||||
|
||||
set name(LibraryIdentifier name) {
|
||||
_name = _becomeParentOf(name as LibraryIdentifierImpl);
|
||||
set name(LibraryIdentifier? name) {
|
||||
_name = _becomeParentOf(name as LibraryIdentifierImpl?);
|
||||
}
|
||||
|
||||
@override
|
||||
LibraryIdentifierImpl? get name2 => _name;
|
||||
|
||||
@override
|
||||
ChildEntities get _childEntities => super._childEntities
|
||||
..addToken('libraryKeyword', libraryKeyword)
|
||||
..addNode('name', name)
|
||||
..addNode('name', name2)
|
||||
..addToken('semicolon', semicolon);
|
||||
|
||||
@override
|
||||
|
@ -7848,7 +7852,7 @@ class LibraryDirectiveImpl extends DirectiveImpl implements LibraryDirective {
|
|||
@override
|
||||
void visitChildren(AstVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
_name.accept(visitor);
|
||||
_name?.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -793,7 +793,7 @@ class ToSourceVisitor implements AstVisitor<void> {
|
|||
void visitLibraryDirective(LibraryDirective node) {
|
||||
_visitNodeList(node.metadata, separator: ' ', suffix: ' ');
|
||||
sink.write('library ');
|
||||
_visitNode(node.name);
|
||||
_visitNode(node.name2);
|
||||
sink.write(';');
|
||||
}
|
||||
|
||||
|
|
|
@ -915,7 +915,7 @@ class AstComparator implements AstVisitor<bool> {
|
|||
node.documentationComment, other.documentationComment) &&
|
||||
_isEqualNodeLists(node.metadata, other.metadata) &&
|
||||
isEqualTokens(node.libraryKeyword, other.libraryKeyword) &&
|
||||
isEqualNodes(node.name, other.name) &&
|
||||
isEqualNodes(node.name2, other.name2) &&
|
||||
isEqualTokens(node.semicolon, other.semicolon);
|
||||
}
|
||||
|
||||
|
@ -2780,7 +2780,7 @@ class NodeReplacer extends ThrowingAstVisitor<bool> {
|
|||
|
||||
@override
|
||||
bool visitLibraryDirective(covariant LibraryDirectiveImpl node) {
|
||||
if (identical(node.name, _oldNode)) {
|
||||
if (identical(node.name2, _oldNode)) {
|
||||
node.name = _newNode as LibraryIdentifier;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -141,6 +141,9 @@ class AstBuilder extends StackListener {
|
|||
/// `true` if records are enabled
|
||||
final bool enableRecords;
|
||||
|
||||
/// `true` if unnamed-library behavior is enabled
|
||||
final bool enableUnnamedLibraries;
|
||||
|
||||
final FeatureSet _featureSet;
|
||||
|
||||
final LineInfo _lineInfo;
|
||||
|
@ -163,6 +166,8 @@ class AstBuilder extends StackListener {
|
|||
enableEnhancedEnums = _featureSet.isEnabled(Feature.enhanced_enums),
|
||||
enableMacros = _featureSet.isEnabled(Feature.macros),
|
||||
enableRecords = _featureSet.isEnabled(Feature.records),
|
||||
enableUnnamedLibraries =
|
||||
_featureSet.isEnabled(Feature.unnamedLibraries),
|
||||
uri = uri ?? fileUri;
|
||||
|
||||
@override
|
||||
|
@ -2131,13 +2136,20 @@ class AstBuilder extends StackListener {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
assert(optional('library', libraryKeyword));
|
||||
assert(optional(';', semicolon));
|
||||
debugEvent("LibraryName");
|
||||
|
||||
var libraryName = pop() as List<SimpleIdentifier>;
|
||||
var name = ast.libraryIdentifier(libraryName);
|
||||
var libraryName = hasName ? pop() as List<SimpleIdentifier>? : null;
|
||||
|
||||
if (!hasName && !enableUnnamedLibraries) {
|
||||
_reportFeatureNotEnabled(
|
||||
feature: ExperimentalFeatures.unnamed_libraries,
|
||||
startToken: libraryKeyword,
|
||||
);
|
||||
}
|
||||
var name = libraryName == null ? null : ast.libraryIdentifier(libraryName);
|
||||
var metadata = pop() as List<Annotation>?;
|
||||
var comment = _findComment(metadata, libraryKeyword);
|
||||
directives.add(
|
||||
|
|
|
@ -399,17 +399,20 @@ class AstTestFactory {
|
|||
astFactory.labeledStatement(labels, statement);
|
||||
|
||||
static LibraryDirectiveImpl libraryDirective(
|
||||
List<Annotation> metadata, LibraryIdentifier libraryName) =>
|
||||
List<Annotation> metadata, LibraryIdentifier? libraryName) =>
|
||||
LibraryDirectiveImpl(
|
||||
comment: null,
|
||||
metadata: metadata,
|
||||
libraryKeyword: TokenFactory.tokenFromKeyword(Keyword.LIBRARY),
|
||||
name: libraryName as LibraryIdentifierImpl,
|
||||
name: libraryName as LibraryIdentifierImpl?,
|
||||
semicolon: TokenFactory.tokenFromType(TokenType.SEMICOLON),
|
||||
);
|
||||
|
||||
static LibraryDirectiveImpl libraryDirective2(String libraryName) =>
|
||||
libraryDirective(<Annotation>[], libraryIdentifier2([libraryName]));
|
||||
static LibraryDirectiveImpl libraryDirective2(String? libraryName) =>
|
||||
libraryDirective(
|
||||
<Annotation>[],
|
||||
libraryName == null ? null : libraryIdentifier2([libraryName]),
|
||||
);
|
||||
|
||||
static LibraryIdentifierImpl libraryIdentifier(
|
||||
List<SimpleIdentifier> components) =>
|
||||
|
|
|
@ -670,7 +670,7 @@ class AstTextPrinter extends ThrowingAstVisitor<void> {
|
|||
void visitLibraryDirective(LibraryDirective node) {
|
||||
_directive(node);
|
||||
_token(node.libraryKeyword);
|
||||
node.name.accept(this);
|
||||
node.name2?.accept(this);
|
||||
_token(node.semicolon);
|
||||
}
|
||||
|
||||
|
|
|
@ -1423,8 +1423,11 @@ class _InformativeDataWriter {
|
|||
for (var directive in unit.directives) {
|
||||
firstDirective ??= directive;
|
||||
if (directive is LibraryDirective) {
|
||||
nameOffset = directive.name.offset;
|
||||
nameLength = directive.name.length;
|
||||
final libraryName = directive.name2;
|
||||
if (libraryName != null) {
|
||||
nameOffset = libraryName.offset;
|
||||
nameLength = libraryName.length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -760,9 +760,12 @@ class LibraryBuilder {
|
|||
var nameLength = 0;
|
||||
for (final directive in libraryUnitNode.directives) {
|
||||
if (directive is ast.LibraryDirective) {
|
||||
name = directive.name.components.map((e) => e.name).join('.');
|
||||
nameOffset = directive.name.offset;
|
||||
nameLength = directive.name.length;
|
||||
final nameIdentifier = directive.name2;
|
||||
if (nameIdentifier != null) {
|
||||
name = nameIdentifier.components.map((e) => e.name).join('.');
|
||||
nameOffset = nameIdentifier.offset;
|
||||
nameLength = nameIdentifier.length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2172,12 +2172,6 @@ class Wrong<T> {
|
|||
expect(parameter.name, isNotNull);
|
||||
}
|
||||
|
||||
void test_missingNameInLibraryDirective() {
|
||||
CompilationUnit unit = parseCompilationUnit("library;",
|
||||
errors: [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 7, 1)]);
|
||||
expect(unit, isNotNull);
|
||||
}
|
||||
|
||||
void test_missingNameInPartOfDirective() {
|
||||
CompilationUnit unit = parseCompilationUnit("part of;",
|
||||
errors: [expectedError(ParserErrorCode.EXPECTED_STRING_LITERAL, 7, 1)]);
|
||||
|
@ -2837,6 +2831,18 @@ main() {
|
|||
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 1)]);
|
||||
}
|
||||
|
||||
void test_unnamedLibraryDirective() {
|
||||
CompilationUnit unit = parseCompilationUnit("library;",
|
||||
errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 0, 7)]);
|
||||
expect(unit, isNotNull);
|
||||
}
|
||||
|
||||
void test_unnamedLibraryDirective_enabled() {
|
||||
CompilationUnit unit = parseCompilationUnit("library;",
|
||||
featureSet: FeatureSets.latestWithExperiments);
|
||||
expect(unit, isNotNull);
|
||||
}
|
||||
|
||||
void test_unterminatedString_at_eof() {
|
||||
// Although the "unterminated string" error message is produced by the
|
||||
// scanner, we need to verify that the parser can handle the tokens
|
||||
|
|
|
@ -1021,9 +1021,9 @@ class ForwardingTestListener extends ForwardingListener {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
end('LibraryName');
|
||||
super.endLibraryName(libraryKeyword, semicolon);
|
||||
super.endLibraryName(libraryKeyword, semicolon, hasName);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -63,13 +63,13 @@ class SimpleParserTest extends FastaParserTestCase {
|
|||
return classDecl.implementsClause!;
|
||||
}
|
||||
|
||||
LibraryIdentifier parseLibraryIdentifier(String name) {
|
||||
LibraryIdentifier? parseLibraryIdentifier(String name) {
|
||||
createParser('library $name;');
|
||||
CompilationUnit unit = parser.parseCompilationUnit2();
|
||||
expect(unit, isNotNull);
|
||||
expect(unit.directives, hasLength(1));
|
||||
var directive = unit.directives[0] as LibraryDirective;
|
||||
return directive.name;
|
||||
return directive.name2;
|
||||
}
|
||||
|
||||
/// Parse the given [content] as a sequence of statements by enclosing it in a
|
||||
|
@ -1468,7 +1468,7 @@ void main() {final c = C<int, int Function(String)>();}
|
|||
|
||||
void test_parseLibraryIdentifier_builtin() {
|
||||
String name = "deferred";
|
||||
LibraryIdentifier identifier = parseLibraryIdentifier(name);
|
||||
LibraryIdentifier identifier = parseLibraryIdentifier(name)!;
|
||||
expectNotNullIfNoErrors(identifier);
|
||||
assertNoErrors();
|
||||
expect(identifier.name, name);
|
||||
|
@ -1484,7 +1484,7 @@ void main() {final c = C<int, int Function(String)>();}
|
|||
|
||||
void test_parseLibraryIdentifier_multiple() {
|
||||
String name = "a.b.c";
|
||||
LibraryIdentifier identifier = parseLibraryIdentifier(name);
|
||||
LibraryIdentifier identifier = parseLibraryIdentifier(name)!;
|
||||
expectNotNullIfNoErrors(identifier);
|
||||
assertNoErrors();
|
||||
expect(identifier.name, name);
|
||||
|
@ -1492,7 +1492,7 @@ void main() {final c = C<int, int Function(String)>();}
|
|||
|
||||
void test_parseLibraryIdentifier_pseudo() {
|
||||
String name = "await";
|
||||
LibraryIdentifier identifier = parseLibraryIdentifier(name);
|
||||
LibraryIdentifier identifier = parseLibraryIdentifier(name)!;
|
||||
expectNotNullIfNoErrors(identifier);
|
||||
assertNoErrors();
|
||||
expect(identifier.name, name);
|
||||
|
@ -1501,7 +1501,7 @@ void main() {final c = C<int, int Function(String)>();}
|
|||
|
||||
void test_parseLibraryIdentifier_single() {
|
||||
String name = "a";
|
||||
LibraryIdentifier identifier = parseLibraryIdentifier(name);
|
||||
LibraryIdentifier identifier = parseLibraryIdentifier(name)!;
|
||||
expectNotNullIfNoErrors(identifier);
|
||||
assertNoErrors();
|
||||
expect(identifier.name, name);
|
||||
|
|
|
@ -1121,32 +1121,32 @@ Function(int, String) v;
|
|||
expect(directive, TypeMatcher<LibraryDirective>());
|
||||
var libraryDirective = directive as LibraryDirective;
|
||||
expect(libraryDirective.libraryKeyword, isNotNull);
|
||||
expect(libraryDirective.name, isNotNull);
|
||||
expect(libraryDirective.name2, isNotNull);
|
||||
expect(libraryDirective.semicolon, isNotNull);
|
||||
}
|
||||
|
||||
void test_parseDirective_library_1_component() {
|
||||
createParser("library a;");
|
||||
var lib = parseFullDirective() as LibraryDirective;
|
||||
expect(lib.name.components, hasLength(1));
|
||||
expect(lib.name.components[0].name, 'a');
|
||||
expect(lib.name2!.components, hasLength(1));
|
||||
expect(lib.name2!.components[0].name, 'a');
|
||||
}
|
||||
|
||||
void test_parseDirective_library_2_components() {
|
||||
createParser("library a.b;");
|
||||
var lib = parseFullDirective() as LibraryDirective;
|
||||
expect(lib.name.components, hasLength(2));
|
||||
expect(lib.name.components[0].name, 'a');
|
||||
expect(lib.name.components[1].name, 'b');
|
||||
expect(lib.name2!.components, hasLength(2));
|
||||
expect(lib.name2!.components[0].name, 'a');
|
||||
expect(lib.name2!.components[1].name, 'b');
|
||||
}
|
||||
|
||||
void test_parseDirective_library_3_components() {
|
||||
createParser("library a.b.c;");
|
||||
var lib = parseFullDirective() as LibraryDirective;
|
||||
expect(lib.name.components, hasLength(3));
|
||||
expect(lib.name.components[0].name, 'a');
|
||||
expect(lib.name.components[1].name, 'b');
|
||||
expect(lib.name.components[2].name, 'c');
|
||||
expect(lib.name2!.components, hasLength(3));
|
||||
expect(lib.name2!.components[0].name, 'a');
|
||||
expect(lib.name2!.components[1].name, 'b');
|
||||
expect(lib.name2!.components[2].name, 'c');
|
||||
}
|
||||
|
||||
void test_parseDirective_library_annotation() {
|
||||
|
@ -1157,7 +1157,7 @@ Function(int, String) v;
|
|||
expect(directive, TypeMatcher<LibraryDirective>());
|
||||
var libraryDirective = directive as LibraryDirective;
|
||||
expect(libraryDirective.libraryKeyword, isNotNull);
|
||||
expect(libraryDirective.name, isNotNull);
|
||||
expect(libraryDirective.name2, isNotNull);
|
||||
expect(libraryDirective.semicolon, isNotNull);
|
||||
expect(libraryDirective.metadata, hasLength(1));
|
||||
expect(libraryDirective.metadata[0].name.name, 'A');
|
||||
|
@ -1172,12 +1172,18 @@ Function(int, String) v;
|
|||
expect(directive, TypeMatcher<LibraryDirective>());
|
||||
var libraryDirective = directive as LibraryDirective;
|
||||
expect(libraryDirective.libraryKeyword, isNotNull);
|
||||
expect(libraryDirective.name, isNotNull);
|
||||
expect(libraryDirective.name2, isNotNull);
|
||||
expect(libraryDirective.semicolon, isNotNull);
|
||||
expect(libraryDirective.metadata, hasLength(1));
|
||||
expect(libraryDirective.metadata[0].name.name, 'A');
|
||||
}
|
||||
|
||||
void test_parseDirective_library_unnamed() {
|
||||
createParser("library;");
|
||||
var lib = parseFullDirective() as LibraryDirective;
|
||||
expect(lib.name2, isNull);
|
||||
}
|
||||
|
||||
void test_parseDirective_library_withDocumentationComment() {
|
||||
createParser('/// Doc\nlibrary l;');
|
||||
var directive = parseFullDirective() as LibraryDirective;
|
||||
|
@ -1904,7 +1910,7 @@ enum E {
|
|||
expect(directive, isNotNull);
|
||||
assertNoErrors();
|
||||
expect(directive.libraryKeyword, isNotNull);
|
||||
expect(directive.name, isNotNull);
|
||||
expect(directive.name2, isNotNull);
|
||||
expect(directive.semicolon, isNotNull);
|
||||
}
|
||||
|
||||
|
|
|
@ -1238,7 +1238,7 @@ library foo;
|
|||
destination: node,
|
||||
source: node,
|
||||
childAccessors: [
|
||||
(node) => node.name,
|
||||
(node) => node.name2!,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -638,6 +638,13 @@ void f() {}
|
|||
_assertSource("", AstTestFactory.compilationUnit());
|
||||
}
|
||||
|
||||
void test_visitCompilationUnit_libraryWithoutName() {
|
||||
_assertSource(
|
||||
"library ;",
|
||||
AstTestFactory.compilationUnit3([AstTestFactory.libraryDirective2(null)]),
|
||||
);
|
||||
}
|
||||
|
||||
void test_visitCompilationUnit_script() {
|
||||
_assertSource(
|
||||
"!#/bin/dartvm", AstTestFactory.compilationUnit5("!#/bin/dartvm"));
|
||||
|
|
|
@ -748,6 +748,42 @@ LibraryAugmentationDirective
|
|||
''');
|
||||
}
|
||||
|
||||
void test_library_with_name() {
|
||||
var parseResult = parseStringWithErrors(r'''
|
||||
library name.and.dots;
|
||||
''');
|
||||
parseResult.assertNoErrors();
|
||||
|
||||
var node = parseResult.findNode.library('library');
|
||||
assertParsedNodeText(node, r'''
|
||||
LibraryDirective
|
||||
libraryKeyword: library
|
||||
name: LibraryIdentifier
|
||||
components
|
||||
SimpleIdentifier
|
||||
token: name
|
||||
SimpleIdentifier
|
||||
token: and
|
||||
SimpleIdentifier
|
||||
token: dots
|
||||
semicolon: ;
|
||||
''');
|
||||
}
|
||||
|
||||
void test_library_without_name() {
|
||||
var parseResult = parseStringWithErrors(r'''
|
||||
library;
|
||||
''');
|
||||
parseResult.assertNoErrors();
|
||||
|
||||
var node = parseResult.findNode.library('library');
|
||||
assertParsedNodeText(node, r'''
|
||||
LibraryDirective
|
||||
libraryKeyword: library
|
||||
semicolon: ;
|
||||
''');
|
||||
}
|
||||
|
||||
void test_mixin_implementsClause_recordType() {
|
||||
var parseResult = parseStringWithErrors(r'''
|
||||
class C {}
|
||||
|
|
|
@ -32,6 +32,11 @@ class FeatureSets {
|
|||
flags: [],
|
||||
);
|
||||
|
||||
static final FeatureSet language_2_19 = FeatureSet.fromEnableFlags2(
|
||||
sdkLanguageVersion: Version.parse('2.19.0'),
|
||||
flags: [],
|
||||
);
|
||||
|
||||
static final FeatureSet latest = FeatureSet.latestLanguageVersion();
|
||||
|
||||
static final FeatureSet latestWithExperiments = FeatureSet.fromEnableFlags2(
|
||||
|
@ -43,6 +48,7 @@ class FeatureSets {
|
|||
EnableString.named_arguments_anywhere,
|
||||
EnableString.records,
|
||||
EnableString.super_parameters,
|
||||
EnableString.unnamed_libraries,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
@ -328,9 +328,11 @@ class MiniAstBuilder extends StackListener {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
debugEvent("LibraryName");
|
||||
pop(); // Library name
|
||||
if (hasName) {
|
||||
pop(); // Library name
|
||||
}
|
||||
pop(); // Metadata
|
||||
pop(); // Comment
|
||||
}
|
||||
|
|
|
@ -399,7 +399,7 @@ class _DartNavigationComputerVisitor extends RecursiveAstVisitor<void> {
|
|||
|
||||
@override
|
||||
void visitLibraryDirective(LibraryDirective node) {
|
||||
computer._addRegionForNode(node.name, node.element2);
|
||||
computer._addRegionForNode(node.name2, node.element2);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -227,6 +227,14 @@ class ExperimentalFlag {
|
|||
experimentEnabledVersion: const Version(2, 14),
|
||||
experimentReleasedVersion: const Version(2, 14));
|
||||
|
||||
static const ExperimentalFlag unnamedLibraries = const ExperimentalFlag(
|
||||
name: 'unnamed-libraries',
|
||||
isEnabledByDefault: false,
|
||||
isExpired: false,
|
||||
enabledVersion: const Version(2, 19),
|
||||
experimentEnabledVersion: const Version(2, 19),
|
||||
experimentReleasedVersion: const Version(2, 19));
|
||||
|
||||
static const ExperimentalFlag valueClass = const ExperimentalFlag(
|
||||
name: 'value-class',
|
||||
isEnabledByDefault: false,
|
||||
|
@ -378,6 +386,10 @@ class GlobalFeatures {
|
|||
GlobalFeature get tripleShift =>
|
||||
_tripleShift ??= _computeGlobalFeature(ExperimentalFlag.tripleShift);
|
||||
|
||||
GlobalFeature? _unnamedLibraries;
|
||||
GlobalFeature get unnamedLibraries => _unnamedLibraries ??=
|
||||
_computeGlobalFeature(ExperimentalFlag.unnamedLibraries);
|
||||
|
||||
GlobalFeature? _valueClass;
|
||||
GlobalFeature get valueClass =>
|
||||
_valueClass ??= _computeGlobalFeature(ExperimentalFlag.valueClass);
|
||||
|
@ -515,6 +527,11 @@ class LibraryFeatures {
|
|||
_tripleShift ??= globalFeatures._computeLibraryFeature(
|
||||
ExperimentalFlag.tripleShift, canonicalUri, libraryVersion);
|
||||
|
||||
LibraryFeature? _unnamedLibraries;
|
||||
LibraryFeature get unnamedLibraries =>
|
||||
_unnamedLibraries ??= globalFeatures._computeLibraryFeature(
|
||||
ExperimentalFlag.unnamedLibraries, canonicalUri, libraryVersion);
|
||||
|
||||
LibraryFeature? _valueClass;
|
||||
LibraryFeature get valueClass =>
|
||||
_valueClass ??= globalFeatures._computeLibraryFeature(
|
||||
|
@ -572,6 +589,8 @@ ExperimentalFlag? parseExperimentalFlag(String flag) {
|
|||
return ExperimentalFlag.testExperiment;
|
||||
case "triple-shift":
|
||||
return ExperimentalFlag.tripleShift;
|
||||
case "unnamed-libraries":
|
||||
return ExperimentalFlag.unnamedLibraries;
|
||||
case "value-class":
|
||||
return ExperimentalFlag.valueClass;
|
||||
case "variance":
|
||||
|
@ -619,6 +638,8 @@ final Map<ExperimentalFlag, bool> defaultExperimentalFlags = {
|
|||
ExperimentalFlag.testExperiment:
|
||||
ExperimentalFlag.testExperiment.isEnabledByDefault,
|
||||
ExperimentalFlag.tripleShift: ExperimentalFlag.tripleShift.isEnabledByDefault,
|
||||
ExperimentalFlag.unnamedLibraries:
|
||||
ExperimentalFlag.unnamedLibraries.isEnabledByDefault,
|
||||
ExperimentalFlag.valueClass: ExperimentalFlag.valueClass.isEnabledByDefault,
|
||||
ExperimentalFlag.variance: ExperimentalFlag.variance.isEnabledByDefault,
|
||||
};
|
||||
|
|
|
@ -1309,7 +1309,7 @@ class _MacroListener implements Listener {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
_unexpected();
|
||||
}
|
||||
|
||||
|
|
|
@ -438,9 +438,11 @@ class DietListener extends StackListenerImpl {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
debugEvent("endLibraryName");
|
||||
pop(); // Name.
|
||||
if (hasName) {
|
||||
pop(); // Name.
|
||||
}
|
||||
pop(); // Annotations.
|
||||
}
|
||||
|
||||
|
|
|
@ -832,14 +832,20 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
debugEvent("endLibraryName");
|
||||
popCharOffset();
|
||||
Object? name = pop();
|
||||
Object? name = null;
|
||||
if (hasName) {
|
||||
popCharOffset();
|
||||
name = pop();
|
||||
}
|
||||
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
|
||||
if (name is! ParserRecovery) {
|
||||
if (name != null && name is! ParserRecovery) {
|
||||
libraryBuilder.name =
|
||||
flattenName(name!, offsetForToken(libraryKeyword), uri);
|
||||
flattenName(name, offsetForToken(libraryKeyword), uri);
|
||||
} else {
|
||||
reportIfNotEnabled(
|
||||
libraryFeatures.unnamedLibraries, semicolon.charOffset, noLength);
|
||||
}
|
||||
libraryBuilder.metadata = metadata;
|
||||
}
|
||||
|
|
|
@ -1275,9 +1275,9 @@ abstract class AbstractParserAstListener implements Listener {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
LibraryNameEnd data = new LibraryNameEnd(ParserAstType.END,
|
||||
libraryKeyword: libraryKeyword, semicolon: semicolon);
|
||||
libraryKeyword: libraryKeyword, semicolon: semicolon, hasName: hasName);
|
||||
seen(data);
|
||||
}
|
||||
|
||||
|
@ -4960,15 +4960,19 @@ class LibraryNameBegin extends ParserAstNode {
|
|||
class LibraryNameEnd extends ParserAstNode {
|
||||
final Token libraryKeyword;
|
||||
final Token semicolon;
|
||||
final bool hasName;
|
||||
|
||||
LibraryNameEnd(ParserAstType type,
|
||||
{required this.libraryKeyword, required this.semicolon})
|
||||
{required this.libraryKeyword,
|
||||
required this.semicolon,
|
||||
required this.hasName})
|
||||
: super("LibraryName", type);
|
||||
|
||||
@override
|
||||
Map<String, Object?> get deprecatedArguments => {
|
||||
"libraryKeyword": libraryKeyword,
|
||||
"semicolon": semicolon,
|
||||
"hasName": hasName,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -768,7 +768,7 @@ class TextualOutlineListener extends Listener {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
unsortableElementStartToChunk[libraryKeyword] =
|
||||
new _LibraryNameChunk(libraryKeyword, semicolon);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ beginCompilationUnit(library)
|
|||
beginLibraryName(library)
|
||||
handleRecoverableError(Message[ExpectedIdentifierButGotKeyword, 'enum' can't be used as an identifier because it's a keyword., Try renaming this to be an identifier that isn't a keyword., {lexeme: enum}], enum, enum)
|
||||
handleIdentifier(enum, libraryName)
|
||||
endLibraryName(library, ;)
|
||||
endLibraryName(library, ;, true)
|
||||
endTopLevelDeclaration(main)
|
||||
beginMetadataStar(main)
|
||||
endMetadataStar(0)
|
||||
|
|
|
@ -16,7 +16,7 @@ parseUnit(library)
|
|||
listener: handleRecoverableError(Message[ExpectedIdentifierButGotKeyword, 'enum' can't be used as an identifier because it's a keyword., Try renaming this to be an identifier that isn't a keyword., {lexeme: enum}], enum, enum)
|
||||
listener: handleIdentifier(enum, libraryName)
|
||||
ensureSemicolon(enum)
|
||||
listener: endLibraryName(library, ;)
|
||||
listener: endLibraryName(library, ;, true)
|
||||
listener: endTopLevelDeclaration(main)
|
||||
parseTopLevelDeclarationImpl(;, Instance of 'DirectiveContext')
|
||||
parseMetadataStar(;)
|
||||
|
|
|
@ -1387,11 +1387,11 @@ class ParserTestListener implements Listener {
|
|||
}
|
||||
|
||||
@override
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon) {
|
||||
void endLibraryName(Token libraryKeyword, Token semicolon, bool hasName) {
|
||||
indent--;
|
||||
seen(libraryKeyword);
|
||||
seen(semicolon);
|
||||
doPrint('endLibraryName(' '$libraryKeyword, ' '$semicolon)');
|
||||
doPrint('endLibraryName(' '$libraryKeyword, ' '$semicolon, ' '$hasName)');
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
# dart pkg/analyzer/tool/experiments/generate.dart
|
||||
#
|
||||
# Also, pkg/analyzer/lib/src/dart/analysis/driver.dart will need a bump in
|
||||
# DATA_VERSION if making changes that changes previous flags' "index", e.g.
|
||||
# if adding a new flag that doesn't happen to be lexicographically last.
|
||||
# DATA_VERSION if making changes that change the "index" of any previous flags,
|
||||
# e.g. if adding a new flag that doesn't happen to be lexicographically last.
|
||||
#
|
||||
# kernel:
|
||||
# pkg/front_end/tool/fasta generate-experimental-flags
|
||||
|
@ -134,6 +134,9 @@ features:
|
|||
patterns:
|
||||
help: "Patterns"
|
||||
|
||||
unnamed-libraries:
|
||||
help: "Unnamed libraries"
|
||||
|
||||
# Experiment flag only used for testing.
|
||||
test-experiment:
|
||||
help: >-
|
||||
|
|
Loading…
Reference in a new issue