Update AstBuilder to build spread collection AST structures

Change-Id: Ifde5047933d810bdda77fe1b46eb6f69b7eabc5a
Reviewed-on: https://dart-review.googlesource.com/c/90082
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
This commit is contained in:
danrubel
2019-01-18 00:05:30 +00:00
committed by commit-bot@chromium.org
parent b10f179608
commit 2faab1d4c0
3 changed files with 275 additions and 39 deletions
+1 -1
View File
@@ -5142,7 +5142,7 @@ abstract class ListLiteral extends TypedLiteral {
*
* listLiteral ::=
* 'const'? ('<' [TypeAnnotation] '>')?
* '[' ([CollectionLiteralElement] ','?)? ']'
* '[' ([CollectionElement] ','?)? ']'
*
* This is the class that is used to represent a list literal when either the
* 'control-flow-collections' or 'spread-collections' experiments are enabled.
+66 -23
View File
@@ -279,9 +279,12 @@ class AstBuilder extends StackListener {
@override
void handleSpreadExpression(Token spreadToken) {
// TODO(danrubel): generate new AST structure
handleRecoverableError(templateUnexpectedToken.withArguments(spreadToken),
spreadToken, spreadToken);
if (enableSpreadCollections) {
push(ast.spreadElement(spreadOperator: spreadToken, expression: pop()));
} else {
handleRecoverableError(templateUnexpectedToken.withArguments(spreadToken),
spreadToken, spreadToken);
}
}
void handleStringJuxtaposition(int literalCount) {
@@ -865,10 +868,22 @@ class AstBuilder extends StackListener {
assert(optional(']', rightBracket));
debugEvent("LiteralList");
List<Expression> expressions = popTypedList(count);
TypeArgumentList typeArguments = pop();
push(ast.listLiteral(
constKeyword, typeArguments, leftBracket, expressions, rightBracket));
if (enableSpreadCollections) {
List<CollectionElement> elements = popTypedList(count);
TypeArgumentList typeArguments = pop();
push(ast.listLiteral2(
constKeyword: constKeyword,
typeArguments: typeArguments,
leftBracket: leftBracket,
elements: elements,
rightBracket: rightBracket,
));
} else {
List<Expression> expressions = popTypedList(count);
TypeArgumentList typeArguments = pop();
push(ast.listLiteral(
constKeyword, typeArguments, leftBracket, expressions, rightBracket));
}
}
void handleAsyncModifier(Token asyncToken, Token starToken) {
@@ -927,10 +942,23 @@ class AstBuilder extends StackListener {
assert(optional('}', rightBracket));
debugEvent("LiteralSet");
List<Expression> entries = popTypedList(count) ?? <Expression>[];
TypeArgumentList typeArguments = pop();
push(ast.setLiteral(
constKeyword, typeArguments, leftBracket, entries, rightBracket));
if (enableSpreadCollections) {
List<CollectionElement> elements =
popTypedList(count) ?? <CollectionElement>[];
TypeArgumentList typeArguments = pop();
push(ast.setLiteral2(
constKeyword: constKeyword,
typeArguments: typeArguments,
leftBracket: leftBracket,
elements: elements,
rightBracket: rightBracket,
));
} else {
List<Expression> entries = popTypedList(count) ?? <Expression>[];
TypeArgumentList typeArguments = pop();
push(ast.setLiteral(
constKeyword, typeArguments, leftBracket, entries, rightBracket));
}
}
void handleLiteralMap(
@@ -940,19 +968,34 @@ class AstBuilder extends StackListener {
assert(optional('}', rightBracket));
debugEvent("LiteralMap");
// TODO(danrubel): Revise once spread collection AST structures
// are in place. For now, drop those on the floor
// as error(s) have already been reported in handleSpreadExpression.
List<MapLiteralEntry> entries = <MapLiteralEntry>[];
popTypedList(count)?.forEach((entry) {
if (entry is MapLiteralEntry) {
entries.add(entry);
}
});
if (enableSpreadCollections) {
List<MapElement> entries = <MapElement>[];
popTypedList(count)?.forEach((entry) {
if (entry is MapElement) {
entries.add(entry);
}
});
TypeArgumentList typeArguments = pop();
push(ast.mapLiteral(
constKeyword, typeArguments, leftBracket, entries, rightBracket));
TypeArgumentList typeArguments = pop();
push(ast.mapLiteral2(
constKeyword: constKeyword,
typeArguments: typeArguments,
leftBracket: leftBracket,
entries: entries,
rightBracket: rightBracket,
));
} else {
List<MapLiteralEntry> entries = <MapLiteralEntry>[];
popTypedList(count)?.forEach((entry) {
if (entry is MapLiteralEntry) {
entries.add(entry);
}
});
TypeArgumentList typeArguments = pop();
push(ast.mapLiteral(
constKeyword, typeArguments, leftBracket, entries, rightBracket));
}
}
void handleLiteralMapEntry(Token colon, Token endToken) {
@@ -40,6 +40,7 @@ main() {
defineReflectiveTests(NNBDParserTest_Fasta);
defineReflectiveTests(RecoveryParserTest_Fasta);
defineReflectiveTests(SimpleParserTest_Fasta);
defineReflectiveTests(CollectionLiteralParserTest);
defineReflectiveTests(StatementParserTest_Fasta);
defineReflectiveTests(TopLevelParserTest_Fasta);
});
@@ -104,6 +105,196 @@ class ClassMemberParserTest_Fasta extends FastaParserTestCase
}
}
/**
* Tests of the fasta parser based on [ExpressionParserTestMixin].
*/
@reflectiveTest
class CollectionLiteralParserTest extends FastaParserTestCase {
Expression parseCollectionLiteral(String source,
{List<ErrorCode> codes,
List<ExpectedError> errors,
int expectedEndOffset}) {
return parseExpression(source,
codes: codes,
errors: errors,
expectedEndOffset: expectedEndOffset,
parseSetLiterals: true,
parseSpreadCollections: true);
}
void test_listLiteral_spread() {
ListLiteral2 list = parseCollectionLiteral('[1, ...[2]]');
expect(list.elements, hasLength(2));
IntegerLiteral first = list.elements[0];
expect(first.value, 1);
SpreadElement element = list.elements[1];
expect(element.spreadOperator.lexeme, '...');
ListLiteral2 spreadExpression = element.expression;
expect(spreadExpression.elements, hasLength(1));
}
void test_listLiteral_spreadQ() {
ListLiteral2 list = parseCollectionLiteral('[1, ...?[2]]');
expect(list.elements, hasLength(2));
IntegerLiteral first = list.elements[0];
expect(first.value, 1);
SpreadElement element = list.elements[1];
expect(element.spreadOperator.lexeme, '...?');
ListLiteral2 spreadExpression = element.expression;
expect(spreadExpression.elements, hasLength(1));
}
void test_mapLiteral_spread() {
MapLiteral2 map = parseCollectionLiteral('{1: 2, ...{3: 4}}');
expect(map.constKeyword, isNull);
expect(map.typeArguments, isNull);
expect(map.entries, hasLength(2));
SpreadElement element = map.entries[1];
expect(element.spreadOperator.lexeme, '...');
MapLiteral2 spreadExpression = element.expression;
expect(spreadExpression.entries, hasLength(1));
}
void test_mapLiteral_spreadQ() {
MapLiteral2 map = parseCollectionLiteral('{1: 2, ...?{3: 4}}');
expect(map.constKeyword, isNull);
expect(map.typeArguments, isNull);
expect(map.entries, hasLength(2));
SpreadElement element = map.entries[1];
expect(element.spreadOperator.lexeme, '...?');
MapLiteral2 spreadExpression = element.expression;
expect(spreadExpression.entries, hasLength(1));
}
void test_mapLiteral_spread_typed() {
MapLiteral2 map = parseCollectionLiteral('<int, int>{...{3: 4}}');
expect(map.constKeyword, isNull);
expect(map.typeArguments.arguments, hasLength(2));
expect(map.entries, hasLength(1));
SpreadElement element = map.entries[0];
expect(element.spreadOperator.lexeme, '...');
MapLiteral2 spreadExpression = element.expression;
expect(spreadExpression.entries, hasLength(1));
}
void test_mapLiteral_spreadQ_typed() {
MapLiteral2 map = parseCollectionLiteral('<int, int>{...?{3: 4}}');
expect(map.constKeyword, isNull);
expect(map.typeArguments.arguments, hasLength(2));
expect(map.entries, hasLength(1));
SpreadElement element = map.entries[0];
expect(element.spreadOperator.lexeme, '...?');
MapLiteral2 spreadExpression = element.expression;
expect(spreadExpression.entries, hasLength(1));
}
void test_mapLiteral_spread2_typed() {
MapLiteral2 map = parseCollectionLiteral('<int, int>{1: 2, ...{3: 4}}');
expect(map.constKeyword, isNull);
expect(map.typeArguments.arguments, hasLength(2));
expect(map.entries, hasLength(2));
SpreadElement element = map.entries[1];
expect(element.spreadOperator.lexeme, '...');
MapLiteral2 spreadExpression = element.expression;
expect(spreadExpression.entries, hasLength(1));
}
void test_mapLiteral_spreadQ2_typed() {
MapLiteral2 map = parseCollectionLiteral('<int, int>{1: 2, ...?{3: 4}}');
expect(map.constKeyword, isNull);
expect(map.typeArguments.arguments, hasLength(2));
expect(map.entries, hasLength(2));
SpreadElement element = map.entries[1];
expect(element.spreadOperator.lexeme, '...?');
MapLiteral2 spreadExpression = element.expression;
expect(spreadExpression.entries, hasLength(1));
}
void test_setLiteral_spread2() {
SetLiteral2 set = parseCollectionLiteral('{3, ...[4]}');
expect(set.constKeyword, isNull);
expect(set.typeArguments, isNull);
expect(set.elements, hasLength(2));
IntegerLiteral value = set.elements[0];
expect(value.value, 3);
SpreadElement element = set.elements[1];
expect(element.spreadOperator.lexeme, '...');
ListLiteral2 spreadExpression = element.expression;
expect(spreadExpression.elements, hasLength(1));
}
void test_setLiteral_spread2Q() {
SetLiteral2 set = parseCollectionLiteral('{3, ...?[4]}');
expect(set.constKeyword, isNull);
expect(set.typeArguments, isNull);
expect(set.elements, hasLength(2));
IntegerLiteral value = set.elements[0];
expect(value.value, 3);
SpreadElement element = set.elements[1];
expect(element.spreadOperator.lexeme, '...?');
ListLiteral2 spreadExpression = element.expression;
expect(spreadExpression.elements, hasLength(1));
}
void test_setLiteral_spread_typed() {
SetLiteral2 set = parseCollectionLiteral('<int>{...[3]}');
expect(set.constKeyword, isNull);
expect(set.typeArguments, isNotNull);
expect(set.elements, hasLength(1));
SpreadElement element = set.elements[0];
expect(element.spreadOperator.lexeme, '...');
ListLiteral2 spreadExpression = element.expression;
expect(spreadExpression.elements, hasLength(1));
}
void test_setLiteral_spreadQ_typed() {
SetLiteral2 set = parseCollectionLiteral('<int>{...?[3]}');
expect(set.constKeyword, isNull);
expect(set.typeArguments, isNotNull);
expect(set.elements, hasLength(1));
SpreadElement element = set.elements[0];
expect(element.spreadOperator.lexeme, '...?');
ListLiteral2 spreadExpression = element.expression;
expect(spreadExpression.elements, hasLength(1));
}
void test_setOrMapLiteral_spread() {
MapLiteral2 map = parseCollectionLiteral('{...{3: 4}}');
expect(map.constKeyword, isNull);
expect(map.typeArguments, isNull);
expect(map.entries, hasLength(1));
SpreadElement element = map.entries[0];
expect(element.spreadOperator.lexeme, '...');
MapLiteral2 spreadExpression = element.expression;
expect(spreadExpression.entries, hasLength(1));
}
void test_setOrMapLiteral_spreadQ() {
MapLiteral2 map = parseCollectionLiteral('{...?{3: 4}}');
expect(map.constKeyword, isNull);
expect(map.typeArguments, isNull);
expect(map.entries, hasLength(1));
SpreadElement element = map.entries[0];
expect(element.spreadOperator.lexeme, '...?');
MapLiteral2 spreadExpression = element.expression;
expect(spreadExpression.entries, hasLength(1));
}
}
/**
* Tests of the fasta parser based on [ComplexParserTestMixin].
*/
@@ -261,7 +452,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_listLiteral_spread() {
// TODO(danrubel): Revise this test once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
ListLiteral list = parseExpression('[1, ...[2]]', errors: [
expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 3),
]);
@@ -273,7 +464,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_listLiteral_spreadQ() {
// TODO(danrubel): Revise this test once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
ListLiteral list = parseExpression('[1, ...?[2]]', errors: [
expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 4),
]);
@@ -352,7 +543,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_mapLiteral_spread() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
MapLiteral map = parseExpression('{1: 2, ...{3: 4}}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 3)]);
@@ -362,7 +553,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_mapLiteral_spreadQ() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
MapLiteral map = parseExpression('{1: 2, ...?{3: 4}}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 4)]);
@@ -372,7 +563,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_mapLiteral_spread_typed() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
MapLiteral map = parseExpression('<int, int>{...{3: 4}}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 11, 3)]);
@@ -382,7 +573,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_mapLiteral_spreadQ_typed() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
MapLiteral map = parseExpression('<int, int>{...?{3: 4}}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 11, 4)]);
@@ -392,7 +583,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_mapLiteral_spread2_typed() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
MapLiteral map = parseExpression('<int, int>{1: 2, ...{3: 4}}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 17, 3)]);
@@ -402,7 +593,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_mapLiteral_spreadQ2_typed() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
MapLiteral map = parseExpression('<int, int>{1: 2, ...?{3: 4}}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 17, 4)]);
@@ -471,7 +662,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_setLiteral_spread2() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
SetLiteral set = parseExpression('{3, ...[4]}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 3)]);
@@ -485,7 +676,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_setLiteral_spread2Q() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
SetLiteral set = parseExpression('{3, ...?[4]}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 4)]);
@@ -499,7 +690,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_setLiteral_spread_typed() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
SetLiteral set = parseExpression('<int>{...[3]}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 6, 3)]);
@@ -511,7 +702,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_setLiteral_spreadQ_typed() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
SetLiteral set = parseExpression('<int>{...?[3]}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 6, 4)]);
@@ -534,7 +725,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_setOrMapLiteral_spread() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
MapLiteral set = parseExpression('{...{3: 4}}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 1, 3)]);
@@ -544,7 +735,7 @@ class ExpressionParserTest_Fasta extends FastaParserTestCase
}
void test_setOrMapLiteral_spreadQ() {
// TODO(danrubel): Revise this once AST supports new syntax
// TODO(danrubel): Remove this once spread_collections is enabled by default
MapLiteral set = parseExpression('{...?{3: 4}}',
parseSetLiterals: true,
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 1, 4)]);
@@ -810,9 +1001,11 @@ class FastaParserTestCase
{List<ErrorCode> codes,
List<ExpectedError> errors,
int expectedEndOffset,
bool parseSetLiterals = false}) {
bool parseSetLiterals = false,
bool parseSpreadCollections = false}) {
createParser(source, expectedEndOffset: expectedEndOffset);
_parserProxy.fastaParser.enableSetLiterals = parseSetLiterals;
_parserProxy.astBuilder.enableSpreadCollections = parseSpreadCollections;
Expression result = _parserProxy.parseExpression2();
assertErrors(codes: codes, errors: errors);
return result;