mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 00:45:16 +00:00
parse nested control flow collection entries
Change-Id: Id50c0a53a51f076dd75dd5bc13a694663449bc83 Reviewed-on: https://dart-review.googlesource.com/c/91400 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
213cfdc85e
commit
09e6a689c2
|
@ -1121,6 +1121,11 @@ class HighlightsTestSupport extends AbstractAnalysisTest {
|
|||
}
|
||||
|
||||
void processNotification(Notification notification) {
|
||||
if (notification.event == SERVER_NOTIFICATION_ERROR) {
|
||||
print('SERVER_NOTIFICATION_ERROR: ${notification.toJson()}');
|
||||
_resultsAvailable.complete(null);
|
||||
fail('SERVER_NOTIFICATION_ERROR');
|
||||
}
|
||||
if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) {
|
||||
var params = new AnalysisHighlightsParams.fromNotification(notification);
|
||||
if (params.file == testFile) {
|
||||
|
|
|
@ -971,6 +971,11 @@ class HighlightsTestSupport extends AbstractAnalysisTest {
|
|||
}
|
||||
|
||||
void processNotification(Notification notification) {
|
||||
if (notification.event == SERVER_NOTIFICATION_ERROR) {
|
||||
print('SERVER_NOTIFICATION_ERROR: ${notification.toJson()}');
|
||||
_resultsAvailable.complete(null);
|
||||
fail('SERVER_NOTIFICATION_ERROR');
|
||||
}
|
||||
if (notification.event == ANALYSIS_NOTIFICATION_HIGHLIGHTS) {
|
||||
var params = new AnalysisHighlightsParams.fromNotification(notification);
|
||||
if (params.file == testFile) {
|
||||
|
|
|
@ -7987,7 +7987,7 @@ class LocalVariableInfo {
|
|||
|
||||
abstract class MapElementImpl extends AstNodeImpl implements MapElement {}
|
||||
|
||||
class MapForElementImpl extends CollectionElementImpl
|
||||
class MapForElementImpl extends MapElementImpl
|
||||
with ForMixin
|
||||
implements MapForElement {
|
||||
/**
|
||||
|
|
|
@ -3288,28 +3288,28 @@ class _ForControlFlowInfo implements _EntryInfo {
|
|||
this.forLoopParts, this.rightParenthesis, this.entry);
|
||||
|
||||
@override
|
||||
CollectionElement asCollectionElement(AstFactory ast) {
|
||||
return ast.collectionForElement(
|
||||
awaitKeyword: awaitToken,
|
||||
forKeyword: forKeyword,
|
||||
leftParenthesis: leftParenthesis,
|
||||
forLoopParts: forLoopParts,
|
||||
rightParenthesis: rightParenthesis,
|
||||
body: entry,
|
||||
);
|
||||
}
|
||||
CollectionElement asCollectionElement(AstFactory ast) =>
|
||||
ast.collectionForElement(
|
||||
awaitKeyword: awaitToken,
|
||||
forKeyword: forKeyword,
|
||||
leftParenthesis: leftParenthesis,
|
||||
forLoopParts: forLoopParts,
|
||||
rightParenthesis: rightParenthesis,
|
||||
body: entry is _EntryInfo
|
||||
? entry.asCollectionElement(ast)
|
||||
: entry as CollectionElement,
|
||||
);
|
||||
|
||||
@override
|
||||
MapElement asMapElement(AstFactory ast) {
|
||||
return ast.mapForElement(
|
||||
awaitKeyword: awaitToken,
|
||||
forKeyword: forKeyword,
|
||||
leftParenthesis: leftParenthesis,
|
||||
forLoopParts: forLoopParts,
|
||||
rightParenthesis: rightParenthesis,
|
||||
body: entry,
|
||||
);
|
||||
}
|
||||
MapElement asMapElement(AstFactory ast) => ast.mapForElement(
|
||||
awaitKeyword: awaitToken,
|
||||
forKeyword: forKeyword,
|
||||
leftParenthesis: leftParenthesis,
|
||||
forLoopParts: forLoopParts,
|
||||
rightParenthesis: rightParenthesis,
|
||||
body:
|
||||
entry is _EntryInfo ? entry.asMapElement(ast) : entry as MapElement,
|
||||
);
|
||||
}
|
||||
|
||||
class _IfControlFlowInfo implements _EntryInfo {
|
||||
|
|
|
@ -148,6 +148,34 @@ class CollectionLiteralParserTest extends FastaParserTestCase {
|
|||
expect(iterable.name, 'list');
|
||||
}
|
||||
|
||||
void test_listLiteral_forIf() {
|
||||
ListLiteral2 list = parseCollectionLiteral(
|
||||
'[1, await for (var x in list) if (c) 2]',
|
||||
inAsync: true,
|
||||
);
|
||||
expect(list.elements, hasLength(2));
|
||||
IntegerLiteral first = list.elements[0];
|
||||
expect(first.value, 1);
|
||||
|
||||
CollectionForElement second = list.elements[1];
|
||||
expect(second.awaitKeyword, isNotNull);
|
||||
expect(second.forKeyword.isKeyword, isTrue);
|
||||
expect(second.leftParenthesis.lexeme, '(');
|
||||
expect(second.rightParenthesis.lexeme, ')');
|
||||
ForEachPartsWithDeclaration forLoopParts = second.forLoopParts;
|
||||
DeclaredIdentifier forLoopVar = forLoopParts.loopVariable;
|
||||
expect(forLoopVar.identifier.name, 'x');
|
||||
expect(forLoopParts.inKeyword, isNotNull);
|
||||
SimpleIdentifier iterable = forLoopParts.iterable;
|
||||
expect(iterable.name, 'list');
|
||||
|
||||
CollectionIfElement body = second.body;
|
||||
SimpleIdentifier condition = body.condition;
|
||||
expect(condition.name, 'c');
|
||||
IntegerLiteral thenElement = body.thenElement;
|
||||
expect(thenElement.value, 2);
|
||||
}
|
||||
|
||||
void test_listLiteral_forSpread() {
|
||||
ListLiteral2 list =
|
||||
parseCollectionLiteral('[1, for (int x = 0; x < 10; ++x) ...[2]]');
|
||||
|
@ -200,6 +228,46 @@ class CollectionLiteralParserTest extends FastaParserTestCase {
|
|||
expect(elseElement.value, 5);
|
||||
}
|
||||
|
||||
void test_listLiteral_ifElseFor() {
|
||||
ListLiteral2 list =
|
||||
parseCollectionLiteral('[1, if (true) 2 else for (a in b) 5]');
|
||||
expect(list.elements, hasLength(2));
|
||||
IntegerLiteral first = list.elements[0];
|
||||
expect(first.value, 1);
|
||||
|
||||
CollectionIfElement second = list.elements[1];
|
||||
BooleanLiteral condition = second.condition;
|
||||
expect(condition.value, isTrue);
|
||||
IntegerLiteral thenElement = second.thenElement;
|
||||
expect(thenElement.value, 2);
|
||||
|
||||
CollectionForElement elseElement = second.elseElement;
|
||||
ForEachPartsWithIdentifier forLoopParts = elseElement.forLoopParts;
|
||||
expect(forLoopParts.identifier.name, 'a');
|
||||
|
||||
IntegerLiteral forValue = elseElement.body;
|
||||
expect(forValue.value, 5);
|
||||
}
|
||||
|
||||
void test_listLiteral_ifFor() {
|
||||
ListLiteral2 list = parseCollectionLiteral('[1, if (true) for (a in b) 2]');
|
||||
expect(list.elements, hasLength(2));
|
||||
IntegerLiteral first = list.elements[0];
|
||||
expect(first.value, 1);
|
||||
|
||||
CollectionIfElement second = list.elements[1];
|
||||
BooleanLiteral condition = second.condition;
|
||||
expect(condition.value, isTrue);
|
||||
|
||||
CollectionForElement thenElement = second.thenElement;
|
||||
ForEachPartsWithIdentifier forLoopParts = thenElement.forLoopParts;
|
||||
expect(forLoopParts.identifier.name, 'a');
|
||||
|
||||
IntegerLiteral forValue = thenElement.body;
|
||||
expect(forValue.value, 2);
|
||||
expect(second.elseElement, isNull);
|
||||
}
|
||||
|
||||
void test_listLiteral_ifSpread() {
|
||||
ListLiteral2 list = parseCollectionLiteral('[1, if (true) ...[2]]');
|
||||
expect(list.elements, hasLength(2));
|
||||
|
@ -275,6 +343,35 @@ class CollectionLiteralParserTest extends FastaParserTestCase {
|
|||
expect(iterable.name, 'list');
|
||||
}
|
||||
|
||||
void test_mapLiteral_forIf() {
|
||||
MapLiteral2 map = parseCollectionLiteral(
|
||||
'{1:7, await for (y in list) if (c) 2:3}',
|
||||
inAsync: true);
|
||||
expect(map.entries, hasLength(2));
|
||||
MapLiteralEntry first = map.entries[0];
|
||||
IntegerLiteral firstValue = first.value;
|
||||
expect(firstValue.value, 7);
|
||||
|
||||
MapForElement second = map.entries[1];
|
||||
expect(second.awaitKeyword, isNotNull);
|
||||
expect(second.forKeyword.isKeyword, isTrue);
|
||||
expect(second.leftParenthesis.lexeme, '(');
|
||||
expect(second.rightParenthesis.lexeme, ')');
|
||||
ForEachPartsWithIdentifier forLoopParts = second.forLoopParts;
|
||||
SimpleIdentifier forLoopVar = forLoopParts.identifier;
|
||||
expect(forLoopVar.name, 'y');
|
||||
expect(forLoopParts.inKeyword, isNotNull);
|
||||
SimpleIdentifier iterable = forLoopParts.iterable;
|
||||
expect(iterable.name, 'list');
|
||||
|
||||
MapIfElement body = second.body;
|
||||
SimpleIdentifier condition = body.condition;
|
||||
expect(condition.name, 'c');
|
||||
MapLiteralEntry thenElement = body.thenElement;
|
||||
IntegerLiteral thenValue = thenElement.value;
|
||||
expect(thenValue.value, 3);
|
||||
}
|
||||
|
||||
void test_mapLiteral_forSpread() {
|
||||
MapLiteral2 map =
|
||||
parseCollectionLiteral('{1:7, for (x = 0; x < 10; ++x) ...{2:3}}');
|
||||
|
@ -334,6 +431,52 @@ class CollectionLiteralParserTest extends FastaParserTestCase {
|
|||
expect(elseElementValue.value, 6);
|
||||
}
|
||||
|
||||
void test_mapLiteral_ifElseFor() {
|
||||
MapLiteral2 map =
|
||||
parseCollectionLiteral('{1:1, if (true) 2:4 else for (c in d) 5:6}');
|
||||
expect(map.entries, hasLength(2));
|
||||
MapLiteralEntry first = map.entries[0];
|
||||
IntegerLiteral firstValue = first.value;
|
||||
expect(firstValue.value, 1);
|
||||
|
||||
MapIfElement second = map.entries[1];
|
||||
BooleanLiteral condition = second.condition;
|
||||
expect(condition.value, isTrue);
|
||||
MapLiteralEntry thenElement = second.thenElement;
|
||||
IntegerLiteral thenElementValue = thenElement.value;
|
||||
expect(thenElementValue.value, 4);
|
||||
|
||||
MapForElement elseElement = second.elseElement;
|
||||
ForEachPartsWithIdentifier forLoopParts = elseElement.forLoopParts;
|
||||
expect(forLoopParts.identifier.name, 'c');
|
||||
|
||||
MapLiteralEntry body = elseElement.body;
|
||||
IntegerLiteral bodyValue = body.value;
|
||||
expect(bodyValue.value, 6);
|
||||
}
|
||||
|
||||
void test_mapLiteral_ifFor() {
|
||||
MapLiteral2 map =
|
||||
parseCollectionLiteral('{1:1, if (true) for (a in b) 2:4}');
|
||||
expect(map.entries, hasLength(2));
|
||||
MapLiteralEntry first = map.entries[0];
|
||||
IntegerLiteral firstValue = first.value;
|
||||
expect(firstValue.value, 1);
|
||||
|
||||
MapIfElement second = map.entries[1];
|
||||
BooleanLiteral condition = second.condition;
|
||||
expect(condition.value, isTrue);
|
||||
|
||||
MapForElement thenElement = second.thenElement;
|
||||
ForEachPartsWithIdentifier forLoopParts = thenElement.forLoopParts;
|
||||
expect(forLoopParts.identifier.name, 'a');
|
||||
|
||||
MapLiteralEntry body = thenElement.body;
|
||||
IntegerLiteral thenElementValue = body.value;
|
||||
expect(thenElementValue.value, 4);
|
||||
expect(second.elseElement, isNull);
|
||||
}
|
||||
|
||||
void test_mapLiteral_ifSpread() {
|
||||
MapLiteral2 map = parseCollectionLiteral('{1:1, if (true) ...{2:4}}');
|
||||
expect(map.entries, hasLength(2));
|
||||
|
|
|
@ -925,9 +925,7 @@ class ConstantVisitorWithFlowControlAndSpreadCollectionsTest
|
|||
|
||||
bool get enableNewAnalysisDriver => true;
|
||||
|
||||
@failingTest
|
||||
test_listLiteral_nested() async {
|
||||
// Fails because we're not yet parsing nested elements.
|
||||
CompilationUnit compilationUnit = await resolveSource('''
|
||||
const c = [1, if (1 > 0) if (2 > 1) 2, 3];
|
||||
''');
|
||||
|
@ -1082,9 +1080,7 @@ const c = {'a' : 1, ...{'b' : 2, 'c' : 3}, 'd' : 4};
|
|||
value.values.map((e) => e.toIntValue()), unorderedEquals([1, 2, 3, 4]));
|
||||
}
|
||||
|
||||
@failingTest
|
||||
test_setLiteral_nested() async {
|
||||
// Fails because we're not yet parsing nested elements.
|
||||
CompilationUnit compilationUnit = await resolveSource('''
|
||||
const c = {1, if (1 > 0) if (2 > 1) 2, 3};
|
||||
''');
|
||||
|
|
|
@ -49,9 +49,8 @@ LiteralEntryInfo computeLiteralEntry(Token token) {
|
|||
Token next = token.next;
|
||||
if (optional('if', next)) {
|
||||
return ifCondition;
|
||||
} else if (optional('for', next)) {
|
||||
return new ForCondition();
|
||||
} else if (optional('await', next) && optional('for', next.next)) {
|
||||
} else if (optional('for', next) ||
|
||||
(optional('await', next) && optional('for', next.next))) {
|
||||
return new ForCondition();
|
||||
} else if (optional('...', next) || optional('...?', next)) {
|
||||
return spreadOperator;
|
||||
|
|
|
@ -57,10 +57,20 @@ class ForCondition extends LiteralEntryInfo {
|
|||
@override
|
||||
LiteralEntryInfo computeNext(Token token) {
|
||||
Token next = token.next;
|
||||
if (optional('...', next) || optional('...?', next)) {
|
||||
if (optional('for', next) ||
|
||||
(optional('await', next) && optional('for', next.next))) {
|
||||
return new Nested(
|
||||
new ForCondition(),
|
||||
inStyle ? const ForInComplete() : const ForComplete(),
|
||||
);
|
||||
} else if (optional('if', next)) {
|
||||
return new Nested(
|
||||
ifCondition,
|
||||
inStyle ? const ForInComplete() : const ForComplete(),
|
||||
);
|
||||
} else if (optional('...', next) || optional('...?', next)) {
|
||||
return inStyle ? const ForInSpread() : const ForSpread();
|
||||
}
|
||||
// TODO(danrubel): nested control flow structures
|
||||
return inStyle ? const ForInEntry() : const ForEntry();
|
||||
}
|
||||
}
|
||||
|
@ -144,10 +154,14 @@ class IfCondition extends LiteralEntryInfo {
|
|||
@override
|
||||
LiteralEntryInfo computeNext(Token token) {
|
||||
Token next = token.next;
|
||||
if (optional('...', next) || optional('...?', next)) {
|
||||
if (optional('for', next) ||
|
||||
(optional('await', next) && optional('for', next.next))) {
|
||||
return new Nested(new ForCondition(), const IfComplete());
|
||||
} else if (optional('if', next)) {
|
||||
return new Nested(ifCondition, const IfComplete());
|
||||
} else if (optional('...', next) || optional('...?', next)) {
|
||||
return const IfSpread();
|
||||
}
|
||||
// TODO(danrubel): nested control flow structures
|
||||
return const IfEntry();
|
||||
}
|
||||
}
|
||||
|
@ -158,12 +172,7 @@ class IfSpread extends SpreadOperator {
|
|||
const IfSpread();
|
||||
|
||||
@override
|
||||
LiteralEntryInfo computeNext(Token token) {
|
||||
if (optional('else', token.next)) {
|
||||
return const IfElse();
|
||||
}
|
||||
return const IfComplete();
|
||||
}
|
||||
LiteralEntryInfo computeNext(Token token) => const IfComplete();
|
||||
}
|
||||
|
||||
/// A step for parsing a literal list, set, or map entry
|
||||
|
@ -172,11 +181,23 @@ class IfEntry extends LiteralEntryInfo {
|
|||
const IfEntry() : super(true);
|
||||
|
||||
@override
|
||||
LiteralEntryInfo computeNext(Token token) {
|
||||
if (optional('else', token.next)) {
|
||||
return const IfElse();
|
||||
LiteralEntryInfo computeNext(Token token) => const IfComplete();
|
||||
}
|
||||
|
||||
class IfComplete extends LiteralEntryInfo {
|
||||
const IfComplete() : super(false);
|
||||
|
||||
@override
|
||||
Token parse(Token token, Parser parser) {
|
||||
if (!optional('else', token.next)) {
|
||||
parser.listener.endIfControlFlow(token);
|
||||
}
|
||||
return const IfComplete();
|
||||
return token;
|
||||
}
|
||||
|
||||
@override
|
||||
LiteralEntryInfo computeNext(Token token) {
|
||||
return optional('else', token.next) ? const IfElse() : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,10 +217,14 @@ class IfElse extends LiteralEntryInfo {
|
|||
LiteralEntryInfo computeNext(Token token) {
|
||||
assert(optional('else', token));
|
||||
Token next = token.next;
|
||||
if (optional('...', next) || optional('...?', next)) {
|
||||
if (optional('for', next) ||
|
||||
(optional('await', next) && optional('for', next.next))) {
|
||||
return new Nested(new ForCondition(), const IfElseComplete());
|
||||
} else if (optional('if', next)) {
|
||||
return new Nested(ifCondition, const IfElseComplete());
|
||||
} else if (optional('...', next) || optional('...?', next)) {
|
||||
return const ElseSpread();
|
||||
}
|
||||
// TODO(danrubel): nested control flow structures
|
||||
return const ElseEntry();
|
||||
}
|
||||
}
|
||||
|
@ -222,16 +247,6 @@ class ElseEntry extends LiteralEntryInfo {
|
|||
}
|
||||
}
|
||||
|
||||
class IfComplete extends LiteralEntryInfo {
|
||||
const IfComplete() : super(false);
|
||||
|
||||
@override
|
||||
Token parse(Token token, Parser parser) {
|
||||
parser.listener.endIfControlFlow(token);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
class IfElseComplete extends LiteralEntryInfo {
|
||||
const IfElseComplete() : super(false);
|
||||
|
||||
|
@ -255,3 +270,22 @@ class SpreadOperator extends LiteralEntryInfo {
|
|||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
class Nested extends LiteralEntryInfo {
|
||||
LiteralEntryInfo nestedStep;
|
||||
final LiteralEntryInfo lastStep;
|
||||
|
||||
Nested(this.nestedStep, this.lastStep) : super(false);
|
||||
|
||||
@override
|
||||
bool get hasEntry => nestedStep.hasEntry;
|
||||
|
||||
@override
|
||||
Token parse(Token token, Parser parser) => nestedStep.parse(token, parser);
|
||||
|
||||
@override
|
||||
LiteralEntryInfo computeNext(Token token) {
|
||||
nestedStep = nestedStep.computeNext(token);
|
||||
return nestedStep != null ? this : lastStep;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,143 @@ class CollectionElementTest {
|
|||
);
|
||||
}
|
||||
|
||||
test_forForFor() {
|
||||
parseEntry(
|
||||
'before for (var i = 0; i < 10; ++i) for (x in y) for (var a in [6]) 2',
|
||||
[
|
||||
// for (var i = 0; i < 10; ++i)
|
||||
'beginForControlFlow null for',
|
||||
'beginMetadataStar var',
|
||||
'endMetadataStar 0',
|
||||
'handleNoTypeArguments var',
|
||||
'beginVariablesDeclaration i var',
|
||||
'handleIdentifier i localVariableDeclaration',
|
||||
'beginInitializedIdentifier i',
|
||||
'beginVariableInitializer =',
|
||||
'handleLiteralInt 0',
|
||||
'endVariableInitializer =',
|
||||
'endInitializedIdentifier i',
|
||||
'endVariablesDeclaration 1 null',
|
||||
'handleForInitializerLocalVariableDeclaration 0',
|
||||
'handleIdentifier i expression',
|
||||
'handleNoTypeArguments <',
|
||||
'handleNoArguments <',
|
||||
'handleSend i <',
|
||||
'beginBinaryExpression <',
|
||||
'handleLiteralInt 10',
|
||||
'endBinaryExpression <',
|
||||
'handleExpressionStatement ;',
|
||||
'handleIdentifier i expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend i )',
|
||||
'handleUnaryPrefixAssignmentExpression ++',
|
||||
'handleForInitializerExpressionStatement for ( ; 1',
|
||||
// nested for (x in y)
|
||||
'beginForControlFlow null for',
|
||||
'handleIdentifier x expression',
|
||||
'handleNoTypeArguments in',
|
||||
'handleNoArguments in',
|
||||
'handleSend x in',
|
||||
'handleForInitializerExpressionStatement x',
|
||||
'beginForInExpression y',
|
||||
'handleIdentifier y expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend y )',
|
||||
'endForInExpression )',
|
||||
'handleForInLoopParts null for ( in',
|
||||
// nested for (var a in [6])
|
||||
'beginForControlFlow null for',
|
||||
'beginMetadataStar var',
|
||||
'endMetadataStar 0',
|
||||
'handleNoTypeArguments var',
|
||||
'beginVariablesDeclaration a var',
|
||||
'handleIdentifier a localVariableDeclaration',
|
||||
'beginInitializedIdentifier a',
|
||||
'handleNoVariableInitializer in',
|
||||
'endInitializedIdentifier a',
|
||||
'endVariablesDeclaration 1 null',
|
||||
'handleForInitializerLocalVariableDeclaration a',
|
||||
'beginForInExpression [',
|
||||
'handleNoTypeArguments [',
|
||||
'handleLiteralInt 6',
|
||||
'handleLiteralList 1, [, null, ]',
|
||||
'endForInExpression )',
|
||||
'handleForInLoopParts null for ( in',
|
||||
// entry
|
||||
'handleLiteralInt 2',
|
||||
// end nested for
|
||||
'endForInControlFlow 2',
|
||||
// end nested for
|
||||
'endForInControlFlow 2',
|
||||
// end for
|
||||
'endForControlFlow 2',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_forIfForElse() {
|
||||
parseEntry(
|
||||
'before await for (var x in y) if (a) for (b in c) 2 else 7',
|
||||
[
|
||||
// await for (var x in y)
|
||||
'beginForControlFlow await for',
|
||||
'beginMetadataStar var',
|
||||
'endMetadataStar 0',
|
||||
'handleNoTypeArguments var',
|
||||
'beginVariablesDeclaration x var',
|
||||
'handleIdentifier x localVariableDeclaration',
|
||||
'beginInitializedIdentifier x',
|
||||
'handleNoVariableInitializer in',
|
||||
'endInitializedIdentifier x',
|
||||
'endVariablesDeclaration 1 null',
|
||||
'handleForInitializerLocalVariableDeclaration x',
|
||||
'beginForInExpression y',
|
||||
'handleIdentifier y expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend y )',
|
||||
'endForInExpression )',
|
||||
'handleForInLoopParts await for ( in',
|
||||
// nested if (a)
|
||||
'beginIfControlFlow if',
|
||||
'handleIdentifier a expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend a )',
|
||||
'handleParenthesizedCondition (',
|
||||
// nested for (b in c)
|
||||
'beginForControlFlow null for',
|
||||
'handleIdentifier b expression',
|
||||
'handleNoTypeArguments in',
|
||||
'handleNoArguments in',
|
||||
'handleSend b in',
|
||||
'handleForInitializerExpressionStatement b',
|
||||
'beginForInExpression c',
|
||||
'handleIdentifier c expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend c )',
|
||||
'endForInExpression )',
|
||||
'handleForInLoopParts null for ( in',
|
||||
// for-if-for-entry
|
||||
'handleLiteralInt 2',
|
||||
// end nested for
|
||||
'endForInControlFlow 2',
|
||||
// nested else
|
||||
'handleElseControlFlow else',
|
||||
// nested if-else-entry
|
||||
'handleLiteralInt 7',
|
||||
// end nested else
|
||||
'endIfElseControlFlow 7',
|
||||
// end for
|
||||
'endForInControlFlow 7',
|
||||
],
|
||||
inAsync: true,
|
||||
);
|
||||
}
|
||||
|
||||
test_forIn() {
|
||||
parseEntry(
|
||||
'before await for (var x in y) 2',
|
||||
|
@ -219,6 +356,99 @@ class CollectionElementTest {
|
|||
);
|
||||
}
|
||||
|
||||
test_ifFor() {
|
||||
parseEntry(
|
||||
'before if (true) for (x in y) 2',
|
||||
[
|
||||
// if (true)
|
||||
'beginIfControlFlow if',
|
||||
'handleLiteralBool true',
|
||||
'handleParenthesizedCondition (',
|
||||
// nested for (x in y)
|
||||
'beginForControlFlow null for',
|
||||
'handleIdentifier x expression',
|
||||
'handleNoTypeArguments in',
|
||||
'handleNoArguments in',
|
||||
'handleSend x in',
|
||||
'handleForInitializerExpressionStatement x',
|
||||
'beginForInExpression y',
|
||||
'handleIdentifier y expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend y )',
|
||||
'endForInExpression )',
|
||||
'handleForInLoopParts null for ( in',
|
||||
// if-for-entry
|
||||
'handleLiteralInt 2',
|
||||
// end nested for
|
||||
'endForInControlFlow 2',
|
||||
// end if
|
||||
'endIfControlFlow 2',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_ifForElseIfFor() {
|
||||
parseEntry(
|
||||
'before if (true) for (a in b) 2 else if (c) for (d in e) 5',
|
||||
[
|
||||
// if (true)
|
||||
'beginIfControlFlow if',
|
||||
'handleLiteralBool true',
|
||||
'handleParenthesizedCondition (',
|
||||
// nested for (a in b)
|
||||
'beginForControlFlow null for',
|
||||
'handleIdentifier a expression',
|
||||
'handleNoTypeArguments in',
|
||||
'handleNoArguments in',
|
||||
'handleSend a in',
|
||||
'handleForInitializerExpressionStatement a',
|
||||
'beginForInExpression b',
|
||||
'handleIdentifier b expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend b )',
|
||||
'endForInExpression )',
|
||||
'handleForInLoopParts null for ( in',
|
||||
// if-for-entry
|
||||
'handleLiteralInt 2',
|
||||
// end nested for
|
||||
'endForInControlFlow 2',
|
||||
// else
|
||||
'handleElseControlFlow else',
|
||||
// nested if (c)
|
||||
'beginIfControlFlow if',
|
||||
'handleIdentifier c expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend c )',
|
||||
'handleParenthesizedCondition (',
|
||||
// nested for (d in e)
|
||||
'beginForControlFlow null for',
|
||||
'handleIdentifier d expression',
|
||||
'handleNoTypeArguments in',
|
||||
'handleNoArguments in',
|
||||
'handleSend d in',
|
||||
'handleForInitializerExpressionStatement d',
|
||||
'beginForInExpression e',
|
||||
'handleIdentifier e expression',
|
||||
'handleNoTypeArguments )',
|
||||
'handleNoArguments )',
|
||||
'handleSend e )',
|
||||
'endForInExpression )',
|
||||
'handleForInLoopParts null for ( in',
|
||||
// else-if-for-entry
|
||||
'handleLiteralInt 5',
|
||||
// end nested for
|
||||
'endForInControlFlow 5',
|
||||
// end nested if
|
||||
'endIfControlFlow 5',
|
||||
// end else
|
||||
'endIfElseControlFlow 5',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_ifSpreadQ() {
|
||||
parseEntry(
|
||||
'before if (true) ...?[2]',
|
||||
|
|
Loading…
Reference in a new issue