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

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

Issue 2342383002: Initial support for the NNBD proposal (Closed)
Patch Set: 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
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..c75ad60930f018501fab853d9cb962195001ce93 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,14 +2088,31 @@ 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);
}
/**
+ * 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 parseFunction(Parser parser) {
scheglov 2016/09/16 15:29:38 The name looks like this function will parse a fun
Brian Wilkerson 2016/09/16 15:47:35 Yes it does. :-) I've renamed it to 'parseOperatio
+ parser.parseExpressionWithoutCascade();
+ }
+
+ Token token = _skip(_currentToken.next, parseFunction);
+ if (token == null || !_tokenMatches(token, TokenType.COLON)) {
+ return false;
+ }
+ token = _skip(token.next, parseFunction);
scheglov 2016/09/16 15:29:38 Out of curiosity - what is an example when just se
Brian Wilkerson 2016/09/16 15:47:35 I'm concerned about cases like if (foo is Bar?
+ return token != null;
+ }
+
+ /**
* Advance to the next token in the token stream.
*/
void _advance() {
@@ -3507,7 +3549,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 +4622,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 +6259,7 @@ class Parser {
TypeName _parseOptionalTypeNameComment() {
if (_injectGenericCommentTypeAssign()) {
- return _parseTypeName();
+ return _parseTypeName(false);
}
return null;
}
@@ -6555,7 +6597,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 +6605,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 +7044,7 @@ class Parser {
TypeName exceptionType = null;
if (_matchesString(_ON)) {
onKeyword = getAndAdvance();
- exceptionType = parseTypeName();
+ exceptionType = parseTypeName(false);
}
Token catchKeyword = null;
Token leftParenthesis = null;
@@ -7092,7 +7134,7 @@ class Parser {
return _parseFunctionTypeAlias(commentAndMetadata, keyword);
}
- TypeName _parseTypeName() {
+ TypeName _parseTypeName(bool inExpression) {
Identifier typeName;
if (_matchesIdentifier()) {
typeName = _parsePrefixedIdentifierUnchecked();
@@ -7104,7 +7146,50 @@ 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);
+ }
+
+ /**
+ * Execute the given [parseFunction] 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, parseFunction(Parser parser)) {
+ // TODO(brianwilkerson) We need to create a copy of the token stream from
+ // the current token onward so that token re-writes don't change the
+ // behavior of the current parser.
+ BooleanErrorListener listener = new BooleanErrorListener();
+ Parser parser = new Parser(_source, listener);
+ parser._currentToken = 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 {
+ parseFunction(parser);
+ } catch (exception) {
+ return null;
+ }
+ if (listener.errorReported) {
+ return null;
+ }
+ return parser._currentToken;
}
/**

Powered by Google App Engine
This is Rietveld 408576698