Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Unified Diff: pkg/analyzer/lib/src/generated/parser.dart

Issue 2342383002: Initial support for the NNBD proposal (Closed)
Patch Set: Addressed comments and added tests Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analyzer/lib/src/dart/ast/utilities.dart ('k') | pkg/analyzer/test/generated/parser_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/generated/parser.dart
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index cb2a41218b94e69df3cb937443cced98691977ad..67ba79a053a2cb1522715718cbd6e42b1683b797 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -90,7 +90,7 @@ Map<String, MethodTrampoline> methodTable_Parser = <String, MethodTrampoline>{
'parseTypeArgumentList_0': new MethodTrampoline(
0, (Parser target) => target.parseTypeArgumentList()),
'parseTypeName_0':
- new MethodTrampoline(0, (Parser target) => target.parseTypeName()),
+ new MethodTrampoline(0, (Parser target) => target.parseTypeName(false)),
'parseTypeParameter_0':
new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()),
'parseTypeParameterList_0': new MethodTrampoline(
@@ -683,6 +683,12 @@ class Parser {
bool _enableAssertInitializer = false;
/**
+ * A flag indicating whether the parser is to parse the non-nullable modifier
+ * in type names.
+ */
+ bool _enableNnbd = false;
+
+ /**
* A flag indicating whether the parser is to parse the async support.
*/
bool _parseAsync = true;
@@ -764,6 +770,20 @@ class Parser {
}
/**
+ * Return `true` if the parser is to parse the non-nullable modifier in type
+ * names.
+ */
+ bool get enableNnbd => _enableNnbd;
+
+ /**
+ * Set whether the parser is to parse the non-nullable modifier in type names
+ * to match the given [enable] flag.
+ */
+ void set enableNnbd(bool enable) {
+ _enableNnbd = enable;
+ }
+
+ /**
* Return `true` if the current token is the first token of a return type that
* is followed by an identifier, possibly followed by a list of type
* parameters, followed by a left-parenthesis. This is used by
@@ -1521,7 +1541,7 @@ class Parser {
* type ('.' identifier)?
*/
ConstructorName parseConstructorName() {
- TypeName type = parseTypeName();
+ TypeName type = parseTypeName(false);
Token period = null;
SimpleIdentifier name = null;
if (_matches(TokenType.PERIOD)) {
@@ -1637,7 +1657,7 @@ class Parser {
*/
ExtendsClause parseExtendsClause() {
Token keyword = getAndAdvance();
- TypeName superclass = parseTypeName();
+ TypeName superclass = parseTypeName(false);
return new ExtendsClause(keyword, superclass);
}
@@ -1718,9 +1738,9 @@ class Parser {
ImplementsClause parseImplementsClause() {
Token keyword = getAndAdvance();
List<TypeName> interfaces = <TypeName>[];
- interfaces.add(parseTypeName());
+ interfaces.add(parseTypeName(false));
while (_optional(TokenType.COMMA)) {
- interfaces.add(parseTypeName());
+ interfaces.add(parseTypeName(false));
}
return new ImplementsClause(keyword, interfaces);
}
@@ -1822,13 +1842,18 @@ class Parser {
_reportErrorForToken(
ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
}
+ Token question = null;
+ if (enableNnbd && _matches(TokenType.QUESTION)) {
+ question = getAndAdvance();
+ }
return new FunctionTypedFormalParameter(
commentAndMetadata.comment,
commentAndMetadata.metadata,
holder.type,
new SimpleIdentifier(identifier.token, isDeclaration: true),
typeParameters,
- parameters);
+ parameters,
+ question: question);
} else {
return new FieldFormalParameter(
commentAndMetadata.comment,
@@ -1901,7 +1926,7 @@ class Parser {
if (_currentToken.keyword == Keyword.VOID) {
return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
} else {
- return parseTypeName();
+ return parseTypeName(false);
}
}
@@ -1991,9 +2016,9 @@ class Parser {
*/
TypeArgumentList parseTypeArgumentList() {
Token leftBracket = getAndAdvance();
- List<TypeName> arguments = <TypeName>[parseTypeName()];
+ List<TypeName> arguments = <TypeName>[parseTypeName(false)];
while (_optional(TokenType.COMMA)) {
- arguments.add(parseTypeName());
+ arguments.add(parseTypeName(false));
}
Token rightBracket = _expectGt();
return new TypeArgumentList(leftBracket, arguments, rightBracket);
@@ -2005,8 +2030,8 @@ class Parser {
* type ::=
* qualified typeArguments?
*/
- TypeName parseTypeName() {
- TypeName realType = _parseTypeName();
+ TypeName parseTypeName(bool inExpression) {
+ TypeName realType = _parseTypeName(inExpression);
// If this is followed by a generic method type comment, allow the comment
// type to replace the real type name.
// TODO(jmesserly): this feels like a big hammer. Can we restrict it to
@@ -2026,7 +2051,7 @@ class Parser {
SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
if (_matchesKeyword(Keyword.EXTENDS)) {
Token keyword = getAndAdvance();
- TypeName bound = parseTypeName();
+ TypeName bound = parseTypeName(false);
return new TypeParameter(commentAndMetadata.comment,
commentAndMetadata.metadata, name, keyword, bound);
}
@@ -2063,9 +2088,9 @@ class Parser {
*/
WithClause parseWithClause() {
Token withKeyword = getAndAdvance();
- List<TypeName> types = <TypeName>[parseTypeName()];
+ List<TypeName> types = <TypeName>[parseTypeName(false)];
while (_optional(TokenType.COMMA)) {
- types.add(parseTypeName());
+ types.add(parseTypeName(false));
}
return new WithClause(withKeyword, types);
}
@@ -2101,6 +2126,30 @@ class Parser {
}
/**
+ * Clone all token starting from the given [token] up to the end of the token
+ * stream, and return the first token in the new token stream.
+ */
+ Token _cloneTokens(Token token) {
+ if (token == null) {
+ return null;
+ }
+ token = token is CommentToken ? token.parent : token;
+ Token head = new Token(TokenType.EOF, -1);
+ head.setNext(head);
+ Token current = head;
+ while (token.type != TokenType.EOF) {
+ Token clone = token.copy();
+ current.setNext(clone);
+ current = clone;
+ token = token.next;
+ }
+ Token tail = new Token(TokenType.EOF, 0);
+ tail.setNext(tail);
+ current.setNext(tail);
+ return head.next;
+ }
+
+ /**
* Return the content of a string with the given literal representation. The
* [lexeme] is the literal representation of the string. The flag [isFirst] is
* `true` if this is the first token in a string literal. The flag [isLast] is
@@ -2497,6 +2546,23 @@ class Parser {
}
/**
+ * Return `true` if the current token could be the question mark in a
+ * condition expression. The current token is assumed to be a question mark.
+ */
+ bool _isConditionalOperator() {
+ void parseOperation(Parser parser) {
+ parser.parseExpressionWithoutCascade();
+ }
+
+ Token token = _skip(_currentToken.next, parseOperation);
+ if (token == null || !_tokenMatches(token, TokenType.COLON)) {
+ return false;
+ }
+ token = _skip(token.next, parseOperation);
+ return token != null;
+ }
+
+ /**
* Return `true` if the current token appears to be the beginning of a
* function declaration.
*/
@@ -3507,7 +3573,7 @@ class Parser {
SimpleIdentifier className,
TypeParameterList typeParameters) {
Token equals = _expect(TokenType.EQ);
- TypeName superclass = parseTypeName();
+ TypeName superclass = parseTypeName(false);
WithClause withClause = null;
if (_matchesKeyword(Keyword.WITH)) {
withClause = parseWithClause();
@@ -4580,7 +4646,7 @@ class Parser {
if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
keywordToken = getAndAdvance();
if (_isTypedIdentifier(_currentToken)) {
- type = parseTypeName();
+ type = parseTypeName(false);
} else {
// Support `final/*=T*/ x;`
type = _parseOptionalTypeNameComment();
@@ -6217,7 +6283,7 @@ class Parser {
TypeName _parseOptionalTypeNameComment() {
if (_injectGenericCommentTypeAssign()) {
- return _parseTypeName();
+ return _parseTypeName(false);
}
return null;
}
@@ -6555,7 +6621,7 @@ class Parser {
Keyword keyword = _currentToken.keyword;
if (keyword == Keyword.AS) {
Token asOperator = getAndAdvance();
- return new AsExpression(expression, asOperator, parseTypeName());
+ return new AsExpression(expression, asOperator, parseTypeName(true));
} else if (keyword == Keyword.IS) {
Token isOperator = getAndAdvance();
Token notOperator = null;
@@ -6563,7 +6629,7 @@ class Parser {
notOperator = getAndAdvance();
}
return new IsExpression(
- expression, isOperator, notOperator, parseTypeName());
+ expression, isOperator, notOperator, parseTypeName(true));
} else if (_currentToken.type.isRelationalOperator) {
Token operator = getAndAdvance();
return new BinaryExpression(
@@ -7002,7 +7068,7 @@ class Parser {
TypeName exceptionType = null;
if (_matchesString(_ON)) {
onKeyword = getAndAdvance();
- exceptionType = parseTypeName();
+ exceptionType = parseTypeName(false);
}
Token catchKeyword = null;
Token leftParenthesis = null;
@@ -7092,7 +7158,7 @@ class Parser {
return _parseFunctionTypeAlias(commentAndMetadata, keyword);
}
- TypeName _parseTypeName() {
+ TypeName _parseTypeName(bool inExpression) {
Identifier typeName;
if (_matchesIdentifier()) {
typeName = _parsePrefixedIdentifierUnchecked();
@@ -7104,7 +7170,13 @@ class Parser {
_reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME);
}
TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- return new TypeName(typeName, typeArguments);
+ Token question = null;
+ if (enableNnbd && _matches(TokenType.QUESTION)) {
+ if (!inExpression || !_isConditionalOperator()) {
+ question = getAndAdvance();
+ }
+ }
+ return new TypeName(typeName, typeArguments, question: question);
}
/**
@@ -7516,6 +7588,40 @@ class Parser {
}
/**
+ * Execute the given [parseOperation] in a temporary parser whose current
+ * token has been set to the given [startToken]. If the parse does not
+ * generate any errors or exceptions, then return the token following the
+ * matching portion of the token stream. Otherwise, return `null`.
+ *
+ * Note: This is an extremely inefficient way of testing whether the tokens in
+ * the token stream match a given production. It should not be used for
+ * production code.
+ */
+ Token _skip(Token startToken, parseOperation(Parser parser)) {
+ BooleanErrorListener listener = new BooleanErrorListener();
+ Parser parser = new Parser(_source, listener);
+ parser._currentToken = _cloneTokens(startToken);
+ parser._enableAssertInitializer = _enableAssertInitializer;
+ parser._enableNnbd = _enableNnbd;
+ parser._inAsync = _inAsync;
+ parser._inGenerator = _inGenerator;
+ parser._inInitializer = _inInitializer;
+ parser._inLoop = _inLoop;
+ parser._inSwitch = _inSwitch;
+ parser._parseAsync = _parseAsync;
+ parser._parseFunctionBodies = _parseFunctionBodies;
+ try {
+ parseOperation(parser);
+ } catch (exception) {
+ return null;
+ }
+ if (listener.errorReported) {
+ return null;
+ }
+ return parser._currentToken;
+ }
+
+ /**
* Skips a block with all containing blocks.
*/
void _skipBlock() {
« no previous file with comments | « pkg/analyzer/lib/src/dart/ast/utilities.dart ('k') | pkg/analyzer/test/generated/parser_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698