Skip to content

Commit 86e5463

Browse files
scheglovCommit Queue
authored andcommitted
Parts. Support for parsing and (not) reporting errors.
Change-Id: I4f352b7cc0c782eba96cd63e5b4a605657fd5c5c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/375541 Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 726fc33 commit 86e5463

File tree

14 files changed

+604
-84
lines changed

14 files changed

+604
-84
lines changed

pkg/_fe_analyzer_shared/lib/src/parser/directive_context.dart

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,15 @@ import '../scanner/token.dart';
77
import 'parser_impl.dart';
88

99
class DirectiveContext {
10+
/// Whether the `enhanced-parts` feature is enabled.
11+
final bool enableFeatureEnhancedParts;
12+
1013
DirectiveState state = DirectiveState.Unknown;
1114

15+
DirectiveContext({
16+
required this.enableFeatureEnhancedParts,
17+
});
18+
1219
void checkScriptTag(Parser parser, Token token) {
1320
if (state == DirectiveState.Unknown) {
1421
state = DirectiveState.Script;
@@ -26,32 +33,42 @@ class DirectiveContext {
2633
}
2734

2835
void checkExport(Parser parser, Token token) {
29-
if (state.index <= DirectiveState.ImportAndExport.index) {
30-
state = DirectiveState.ImportAndExport;
31-
return;
32-
}
33-
// Recovery
34-
if (state == DirectiveState.Part) {
35-
parser.reportRecoverableError(token, messageExportAfterPart);
36-
} else if (state == DirectiveState.PartOf) {
37-
parser.reportRecoverableError(token, messageNonPartOfDirectiveInPart);
38-
} else {
39-
parser.reportRecoverableError(token, messageDirectiveAfterDeclaration);
36+
switch (state) {
37+
case DirectiveState.Unknown:
38+
case DirectiveState.Script:
39+
case DirectiveState.Library:
40+
case DirectiveState.ImportAndExport:
41+
state = DirectiveState.ImportAndExport;
42+
case DirectiveState.Part:
43+
parser.reportRecoverableError(token, messageExportAfterPart);
44+
case DirectiveState.PartOf:
45+
if (enableFeatureEnhancedParts) {
46+
state = DirectiveState.ImportAndExport;
47+
} else {
48+
parser.reportRecoverableError(token, messageNonPartOfDirectiveInPart);
49+
}
50+
case DirectiveState.Declarations:
51+
parser.reportRecoverableError(token, messageDirectiveAfterDeclaration);
4052
}
4153
}
4254

4355
void checkImport(Parser parser, Token token) {
44-
if (state.index <= DirectiveState.ImportAndExport.index) {
45-
state = DirectiveState.ImportAndExport;
46-
return;
47-
}
48-
// Recovery
49-
if (state == DirectiveState.Part) {
50-
parser.reportRecoverableError(token, messageImportAfterPart);
51-
} else if (state == DirectiveState.PartOf) {
52-
parser.reportRecoverableError(token, messageNonPartOfDirectiveInPart);
53-
} else {
54-
parser.reportRecoverableError(token, messageDirectiveAfterDeclaration);
56+
switch (state) {
57+
case DirectiveState.Unknown:
58+
case DirectiveState.Script:
59+
case DirectiveState.Library:
60+
case DirectiveState.ImportAndExport:
61+
state = DirectiveState.ImportAndExport;
62+
case DirectiveState.Part:
63+
parser.reportRecoverableError(token, messageImportAfterPart);
64+
case DirectiveState.PartOf:
65+
if (enableFeatureEnhancedParts) {
66+
state = DirectiveState.ImportAndExport;
67+
} else {
68+
parser.reportRecoverableError(token, messageNonPartOfDirectiveInPart);
69+
}
70+
case DirectiveState.Declarations:
71+
parser.reportRecoverableError(token, messageDirectiveAfterDeclaration);
5572
}
5673
}
5774

@@ -71,15 +88,21 @@ class DirectiveContext {
7188
}
7289

7390
void checkPart(Parser parser, Token token) {
74-
if (state.index <= DirectiveState.Part.index) {
75-
state = DirectiveState.Part;
76-
return;
77-
}
78-
// Recovery
79-
if (state == DirectiveState.PartOf) {
80-
parser.reportRecoverableError(token, messageNonPartOfDirectiveInPart);
81-
} else {
82-
parser.reportRecoverableError(token, messageDirectiveAfterDeclaration);
91+
switch (state) {
92+
case DirectiveState.Unknown:
93+
case DirectiveState.Script:
94+
case DirectiveState.Library:
95+
case DirectiveState.ImportAndExport:
96+
case DirectiveState.Part:
97+
state = DirectiveState.Part;
98+
case DirectiveState.PartOf:
99+
if (enableFeatureEnhancedParts) {
100+
state = DirectiveState.ImportAndExport;
101+
} else {
102+
parser.reportRecoverableError(token, messageNonPartOfDirectiveInPart);
103+
}
104+
case DirectiveState.Declarations:
105+
parser.reportRecoverableError(token, messageDirectiveAfterDeclaration);
83106
}
84107
}
85108

pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,14 @@ class Parser {
338338
/// [parsePrimaryPattern] and [parsePattern].
339339
bool isLastPatternAllowedInsideUnaryPattern = false;
340340

341+
/// Whether the `enhanced-parts` feature is enabled.
342+
final bool enableFeatureEnhancedParts;
343+
341344
Parser(
342345
this.listener, {
343346
this.useImplicitCreationExpression = true,
344347
this.allowPatterns = false,
348+
this.enableFeatureEnhancedParts = false,
345349
}) : assert(listener != null); // ignore:unnecessary_null_comparison
346350

347351
/// Executes [callback]; however if `this` is the `TestParser` (from
@@ -401,7 +405,9 @@ class Parser {
401405

402406
listener.beginCompilationUnit(token);
403407
int count = 0;
404-
DirectiveContext directiveState = new DirectiveContext();
408+
DirectiveContext directiveState = new DirectiveContext(
409+
enableFeatureEnhancedParts: enableFeatureEnhancedParts,
410+
);
405411
token = syntheticPreviousToken(token);
406412
if (identical(token.next!.type, TokenType.SCRIPT_TAG)) {
407413
directiveState.checkScriptTag(this, token.next!);
@@ -448,7 +454,9 @@ class Parser {
448454
Token parseDirectives(Token token) {
449455
listener.beginCompilationUnit(token);
450456
int count = 0;
451-
DirectiveContext directiveState = new DirectiveContext();
457+
DirectiveContext directiveState = new DirectiveContext(
458+
enableFeatureEnhancedParts: enableFeatureEnhancedParts,
459+
);
452460
token = syntheticPreviousToken(token);
453461
while (!token.next!.isEof) {
454462
final Token start = token.next!;
@@ -1227,13 +1235,14 @@ class Parser {
12271235

12281236
/// ```
12291237
/// partDirective:
1230-
/// 'part' uri ';'
1238+
/// 'part' uri ('if' '(' test ')' uri)* ';'
12311239
/// ;
12321240
/// ```
12331241
Token parsePart(Token partKeyword) {
12341242
assert(optional('part', partKeyword));
12351243
listener.beginPart(partKeyword);
12361244
Token token = ensureLiteralString(partKeyword);
1245+
token = parseConditionalUriStar(token);
12371246
token = ensureSemicolon(token);
12381247
listener.endPart(partKeyword, token);
12391248
return token;

pkg/analyzer/lib/src/dart/ast/ast.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13256,6 +13256,9 @@ final class ParenthesizedPatternImpl extends DartPatternImpl
1325613256
/// partDirective ::=
1325713257
/// [Annotation] 'part' [StringLiteral] ';'
1325813258
abstract final class PartDirective implements UriBasedDirective {
13259+
/// The configurations that control which file is actually included.
13260+
NodeList<Configuration> get configurations;
13261+
1325913262
@override
1326013263
PartElement? get element;
1326113264

@@ -13271,6 +13274,9 @@ final class PartDirectiveImpl extends UriBasedDirectiveImpl
1327113274
@override
1327213275
final Token partKeyword;
1327313276

13277+
@override
13278+
final NodeListImpl<ConfigurationImpl> configurations = NodeListImpl._();
13279+
1327413280
@override
1327513281
final Token semicolon;
1327613282

@@ -13283,8 +13289,11 @@ final class PartDirectiveImpl extends UriBasedDirectiveImpl
1328313289
required super.metadata,
1328413290
required this.partKeyword,
1328513291
required super.uri,
13292+
required List<ConfigurationImpl>? configurations,
1328613293
required this.semicolon,
13287-
});
13294+
}) {
13295+
this.configurations._initialize(this, configurations);
13296+
}
1328813297

1328913298
@override
1329013299
PartElementImpl? get element {
@@ -13301,6 +13310,7 @@ final class PartDirectiveImpl extends UriBasedDirectiveImpl
1330113310
ChildEntities get _childEntities => super._childEntities
1330213311
..addToken('partKeyword', partKeyword)
1330313312
..addNode('uri', uri)
13313+
..addNodeList('configurations', configurations)
1330413314
..addToken('semicolon', semicolon);
1330513315

1330613316
@override

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,6 +2779,18 @@ class AstBuilder extends StackListener {
27792779
assert(optional(';', semicolon));
27802780
debugEvent("Part");
27812781

2782+
var configurations = pop() as List<ConfigurationImpl>?;
2783+
if (!enableEnhancedParts) {
2784+
var configuration = configurations?.firstOrNull;
2785+
if (configuration != null) {
2786+
_reportFeatureNotEnabled(
2787+
feature: Feature.enhanced_parts,
2788+
startToken: configuration.ifKeyword,
2789+
);
2790+
configurations = [];
2791+
}
2792+
}
2793+
27822794
var uri = pop() as StringLiteralImpl;
27832795
var metadata = pop() as List<AnnotationImpl>?;
27842796
var comment = _findComment(metadata, partKeyword);
@@ -2788,6 +2800,7 @@ class AstBuilder extends StackListener {
27882800
metadata: metadata,
27892801
partKeyword: partKeyword,
27902802
uri: uri,
2803+
configurations: configurations,
27912804
semicolon: semicolon,
27922805
),
27932806
);

pkg/analyzer/lib/src/generated/parser.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class Parser {
4141
fastaParser = fasta.Parser(
4242
astBuilder,
4343
allowPatterns: featureSet.isEnabled(Feature.patterns),
44+
enableFeatureEnhancedParts: featureSet.isEnabled(Feature.enhanced_parts),
4445
);
4546
astBuilder.parser = fastaParser;
4647
astBuilder.allowNativeClause = allowNativeClause;

pkg/analyzer/lib/src/test_utilities/find_node.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ class FindNode {
140140

141141
ParenthesizedExpression get singleParenthesizedExpression => _single();
142142

143+
PartDirective get singlePartDirective => _single();
144+
143145
PatternAssignment get singlePatternAssignment => _single();
144146

145147
PatternVariableDeclaration get singlePatternVariableDeclaration => _single();

pkg/analyzer/test/generated/error_parser_test.dart

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -926,13 +926,6 @@ class Foo {
926926
]);
927927
}
928928

929-
void test_exportDirectiveAfterPartDirective() {
930-
parseCompilationUnit("part 'a.dart'; export 'b.dart';", errors: [
931-
expectedError(
932-
ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, 15, 6)
933-
]);
934-
}
935-
936929
void test_externalAfterConst() {
937930
createParser('const external C();');
938931
ClassMember member = parser.parseClassMember('C');
@@ -1394,13 +1387,6 @@ class Wrong<T> {
13941387
errors: [expectedError(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, 31, 4)]);
13951388
}
13961389

1397-
void test_importDirectiveAfterPartDirective() {
1398-
parseCompilationUnit("part 'a.dart'; import 'b.dart';", errors: [
1399-
expectedError(
1400-
ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, 15, 6)
1401-
]);
1402-
}
1403-
14041390
void test_initializedVariableInForEach() {
14051391
var statement = parseStatement('for (int a = 0 in foo) {}');
14061392
expectNotNullIfNoErrors(statement);
@@ -2377,21 +2363,6 @@ class Wrong<T> {
23772363
expect(unit, isNotNull);
23782364
}
23792365

2380-
void test_nonPartOfDirectiveInPart_after() {
2381-
parseCompilationUnit("part of l; part 'f.dart';", errors: [
2382-
expectedError(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, 11, 4)
2383-
]);
2384-
}
2385-
2386-
void test_nonPartOfDirectiveInPart_before() {
2387-
// TODO(brianwilkerson): Remove codes when highlighting is fixed.
2388-
parseCompilationUnit("part 'f.dart'; part of m;", codes: [
2389-
ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART
2390-
], errors: [
2391-
expectedError(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, 0, 4)
2392-
]);
2393-
}
2394-
23952366
void test_nonUserDefinableOperator() {
23962367
createParser('operator +=(int x) => x + 1;');
23972368
ClassMember member = parser.parseClassMember('C');

pkg/analyzer/test/generated/parser_test_base.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ class FastaParserTestCase
396396
fasta.Parser parser = fasta.Parser(
397397
astBuilder,
398398
allowPatterns: featureSet!.isEnabled(Feature.patterns),
399+
enableFeatureEnhancedParts: featureSet!.isEnabled(Feature.enhanced_parts),
399400
);
400401
astBuilder.parser = parser;
401402
astBuilder.allowNativeClause = allowNativeClause;

0 commit comments

Comments
 (0)