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 95e0a349fe4f63cc8566741f510b5435aee687ab..ac0ebd3ee5644a37bd296c494213a620fcab5663 100644 |
--- a/pkg/analyzer/lib/src/generated/parser.dart |
+++ b/pkg/analyzer/lib/src/generated/parser.dart |
@@ -6206,7 +6206,7 @@ class Parser { |
*/ |
ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) { |
Token exportKeyword = _expectKeyword(Keyword.EXPORT); |
- StringLiteral libraryUri = parseStringLiteral(); |
+ StringLiteral libraryUri = _parseUri(); |
List<Combinator> combinators = _parseCombinators(); |
Token semicolon = _expectSemicolon(); |
return new ExportDirective( |
@@ -6903,7 +6903,7 @@ class Parser { |
*/ |
ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) { |
Token importKeyword = _expectKeyword(Keyword.IMPORT); |
- StringLiteral libraryUri = parseStringLiteral(); |
+ StringLiteral libraryUri = _parseUri(); |
Token deferredToken = null; |
Token asToken = null; |
SimpleIdentifier prefix = null; |
@@ -7764,7 +7764,7 @@ class Parser { |
libraryName, |
semicolon); |
} |
- StringLiteral partUri = parseStringLiteral(); |
+ StringLiteral partUri = _parseUri(); |
Token semicolon = _expect(TokenType.SEMICOLON); |
return new PartDirective( |
commentAndMetadata.comment, |
@@ -8622,6 +8622,58 @@ class Parser { |
} |
/** |
+ * Parse a string literal representing a URI. |
+ */ |
+ StringLiteral _parseUri() { |
+ bool iskeywordAfterUri(Token token) => |
+ token.lexeme == Keyword.AS.syntax || |
+ token.lexeme == _HIDE || |
+ token.lexeme == _SHOW; |
+ if (!_matches(TokenType.STRING) && |
+ !_matches(TokenType.SEMICOLON) && |
+ !iskeywordAfterUri(_currentToken)) { |
+ // Attempt to recover in the case where the URI was not enclosed in |
+ // quotes. |
+ Token token = _currentToken; |
+ while ((_tokenMatchesIdentifier(token) && !iskeywordAfterUri(token)) || |
+ _tokenMatches(token, TokenType.COLON) || |
+ _tokenMatches(token, TokenType.SLASH) || |
+ _tokenMatches(token, TokenType.PERIOD) || |
+ _tokenMatches(token, TokenType.PERIOD_PERIOD) || |
+ _tokenMatches(token, TokenType.PERIOD_PERIOD_PERIOD) || |
+ _tokenMatches(token, TokenType.INT) || |
+ _tokenMatches(token, TokenType.DOUBLE)) { |
+ token = token.next; |
+ } |
+ if (_tokenMatches(token, TokenType.SEMICOLON) || |
+ iskeywordAfterUri(token)) { |
+ Token endToken = token.previous; |
+ token = _currentToken; |
+ int endOffset = token.end; |
+ StringBuffer buffer = new StringBuffer(); |
+ buffer.write(token.lexeme); |
+ while (token != endToken) { |
+ token = token.next; |
+ if (token.offset != endOffset || token.precedingComments != null) { |
+ return parseStringLiteral(); |
+ } |
+ buffer.write(token.lexeme); |
+ endOffset = token.end; |
+ } |
+ String value = buffer.toString(); |
+ Token newToken = |
+ new StringToken(TokenType.STRING, "'$value'", _currentToken.offset); |
+ _reportErrorForToken( |
+ ParserErrorCode.NON_STRING_LITERAL_AS_URI, |
+ newToken); |
+ _currentToken = endToken.next; |
+ return new SimpleStringLiteral(newToken, value); |
+ } |
+ } |
+ return parseStringLiteral(); |
+ } |
+ |
+ /** |
* Parse a variable declaration. |
* |
* <pre> |
@@ -10478,6 +10530,12 @@ class ParserErrorCode extends ErrorCode { |
'NON_PART_OF_DIRECTIVE_IN_PART', |
"The part-of directive must be the only directive in a part"); |
+ static const ParserErrorCode NON_STRING_LITERAL_AS_URI = |
+ const ParserErrorCode( |
+ 'NON_STRING_LITERAL_AS_URI', |
+ "The URI must be a string literal", |
+ "Enclose the URI in either single or double quotes."); |
+ |
static const ParserErrorCode NON_USER_DEFINABLE_OPERATOR = |
const ParserErrorCode( |
'NON_USER_DEFINABLE_OPERATOR', |