| Index: pkg/compiler/lib/src/parser/parser.dart
|
| diff --git a/pkg/compiler/lib/src/parser/parser.dart b/pkg/compiler/lib/src/parser/parser.dart
|
| index fa4ac4b05de8f8543bd6b9cf3bbe627d00d99685..0ef9cb8373d292e82d3f55ef70d7bd8d86addb3b 100644
|
| --- a/pkg/compiler/lib/src/parser/parser.dart
|
| +++ b/pkg/compiler/lib/src/parser/parser.dart
|
| @@ -362,21 +362,12 @@ class Parser {
|
|
|
| Token parseTypedef(Token token) {
|
| Token typedefKeyword = token;
|
| - listener.beginTypedef(token);
|
| - Token equals;
|
| - if (optional('=', peekAfterNominalType(token.next))) {
|
| - token = parseIdentifier(token.next);
|
| - token = parseTypeVariablesOpt(token);
|
| - equals = token;
|
| - token = expect('=', token);
|
| - token = parseType(token);
|
| - } else {
|
| - token = parseReturnTypeOpt(token.next);
|
| - token = parseIdentifier(token);
|
| - token = parseTypeVariablesOpt(token);
|
| - token = parseFormalParameters(token);
|
| - }
|
| - listener.endTypedef(typedefKeyword, equals, token);
|
| + listener.beginFunctionTypeAlias(token);
|
| + token = parseReturnTypeOpt(token.next);
|
| + token = parseIdentifier(token);
|
| + token = parseTypeVariablesOpt(token);
|
| + token = parseFormalParameters(token);
|
| + listener.endFunctionTypeAlias(typedefKeyword, token);
|
| return expect(';', token);
|
| }
|
|
|
| @@ -407,11 +398,7 @@ class Parser {
|
| }
|
| }
|
|
|
| - /// Parses the formal parameter list of a function.
|
| - ///
|
| - /// If [inFunctionType] is true, then the names may be omitted (except for
|
| - /// named arguments). If it is false, then the types may be omitted.
|
| - Token parseFormalParameters(Token token, {bool inFunctionType: false}) {
|
| + Token parseFormalParameters(Token token) {
|
| Token begin = token;
|
| listener.beginFormalParameters(begin);
|
| expect('(', token);
|
| @@ -424,23 +411,19 @@ class Parser {
|
| ++parameterCount;
|
| String value = token.stringValue;
|
| if (identical(value, '[')) {
|
| - token = parseOptionalFormalParameters(
|
| - token, false, inFunctionType: inFunctionType);
|
| + token = parseOptionalFormalParameters(token, false);
|
| break;
|
| } else if (identical(value, '{')) {
|
| - token = parseOptionalFormalParameters(
|
| - token, true, inFunctionType: inFunctionType);
|
| + token = parseOptionalFormalParameters(token, true);
|
| break;
|
| }
|
| - token = parseFormalParameter(token, FormalParameterType.REQUIRED,
|
| - inFunctionType: inFunctionType);
|
| + token = parseFormalParameter(token, FormalParameterType.REQUIRED);
|
| } while (optional(',', token));
|
| listener.endFormalParameters(parameterCount, begin, token);
|
| return expect(')', token);
|
| }
|
|
|
| - Token parseFormalParameter(Token token, FormalParameterType type,
|
| - {bool inFunctionType}) {
|
| + Token parseFormalParameter(Token token, FormalParameterType type) {
|
| token = parseMetadataStar(token, forParameter: true);
|
| listener.beginFormalParameter(token);
|
|
|
| @@ -453,41 +436,24 @@ class Parser {
|
| token = token.next;
|
| }
|
| token = parseModifiers(token);
|
| - bool isNamedParameter = type == FormalParameterType.NAMED;
|
| -
|
| + // TODO(ahe): Validate that there are formal parameters if void.
|
| + token = parseReturnTypeOpt(token);
|
| Token thisKeyword = null;
|
| - if (inFunctionType && isNamedParameter) {
|
| - token = parseType(token);
|
| - token = parseIdentifier(token);
|
| - } else if (inFunctionType) {
|
| - token = parseType(token);
|
| - if (token.isIdentifier()) {
|
| - token = parseIdentifier(token);
|
| - } else {
|
| - listener.handleNoName(token);
|
| - }
|
| - } else {
|
| - token = parseReturnTypeOpt(token);
|
| - if (optional('this', token)) {
|
| - thisKeyword = token;
|
| - token = expect('.', token.next);
|
| - }
|
| - token = parseIdentifier(token);
|
| + if (optional('this', token)) {
|
| + thisKeyword = token;
|
| + // TODO(ahe): Validate field initializers are only used in
|
| + // constructors, and not for function-typed arguments.
|
| + token = expect('.', token.next);
|
| }
|
| -
|
| - // Generalized function types don't allow inline function types.
|
| - // The following isn't allowed:
|
| - // int Function(int bar(String x)).
|
| - if (!inFunctionType) {
|
| - if (optional('(', token)) {
|
| - listener.handleNoTypeVariables(token);
|
| - token = parseFormalParameters(token);
|
| - listener.handleFunctionTypedFormalParameter(token);
|
| - } else if (optional('<', token)) {
|
| - token = parseTypeVariablesOpt(token);
|
| - token = parseFormalParameters(token);
|
| - listener.handleFunctionTypedFormalParameter(token);
|
| - }
|
| + token = parseIdentifier(token);
|
| + if (optional('(', token)) {
|
| + listener.handleNoTypeVariables(token);
|
| + token = parseFormalParameters(token);
|
| + listener.handleFunctionTypedFormalParameter(token);
|
| + } else if (optional('<', token)) {
|
| + token = parseTypeVariablesOpt(token);
|
| + token = parseFormalParameters(token);
|
| + listener.handleFunctionTypedFormalParameter(token);
|
| }
|
| String value = token.stringValue;
|
| if ((identical('=', value)) || (identical(':', value))) {
|
| @@ -507,8 +473,7 @@ class Parser {
|
| return token;
|
| }
|
|
|
| - Token parseOptionalFormalParameters(Token token, bool isNamed,
|
| - {bool inFunctionType}) {
|
| + Token parseOptionalFormalParameters(Token token, bool isNamed) {
|
| Token begin = token;
|
| listener.beginOptionalFormalParameters(begin);
|
| assert((isNamed && optional('{', token)) || optional('[', token));
|
| @@ -522,8 +487,7 @@ class Parser {
|
| }
|
| var type =
|
| isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
|
| - token =
|
| - parseFormalParameter(token, type, inFunctionType: inFunctionType);
|
| + token = parseFormalParameter(token, type);
|
| ++parameterCount;
|
| } while (optional(',', token));
|
| if (parameterCount == 0) {
|
| @@ -542,10 +506,6 @@ class Parser {
|
| }
|
|
|
| Token parseTypeOpt(Token token) {
|
| - if (isGeneralizedFunctionType(token)) {
|
| - // Function type without return type.
|
| - return parseType(token);
|
| - }
|
| Token peek = peekAfterIfType(token);
|
| if (peek != null && (peek.isIdentifier() || optional('this', peek))) {
|
| return parseType(token);
|
| @@ -710,7 +670,7 @@ class Parser {
|
| token = token.next;
|
| }
|
| Token classKeyword = token;
|
| - var isMixinApplication = optional('=', peekAfterNominalType(token.next));
|
| + var isMixinApplication = optional('=', peekAfterType(token.next));
|
| if (isMixinApplication) {
|
| listener.beginNamedMixinApplication(begin);
|
| } else {
|
| @@ -751,7 +711,7 @@ class Parser {
|
| Token extendsKeyword;
|
| if (optional('extends', token)) {
|
| extendsKeyword = token;
|
| - if (optional('with', peekAfterNominalType(token.next))) {
|
| + if (optional('with', peekAfterType(token.next))) {
|
| token = parseMixinApplication(token.next);
|
| } else {
|
| token = parseType(token.next);
|
| @@ -849,53 +809,16 @@ class Parser {
|
| !identical(value, token.stringValue);
|
| }
|
|
|
| - bool isGeneralizedFunctionType(Token token) {
|
| - // TODO(floitsch): don't use string comparison, but the keyword-state
|
| - // table is currently not set up to deal with upper-case characters.
|
| - return (optional('<', token.next) || optional('(', token.next)) &&
|
| - token.value == "Function";
|
| - }
|
| -
|
| Token parseType(Token token) {
|
| Token begin = token;
|
| - if (isGeneralizedFunctionType(token)) {
|
| - // A function type without return type.
|
| - // Push the non-existing return type first. The loop below will
|
| - // generate the full type.
|
| - listener.handleNoType(token);
|
| + if (isValidTypeReference(token)) {
|
| + token = parseIdentifier(token);
|
| + token = parseQualifiedRestOpt(token);
|
| } else {
|
| - if (isValidTypeReference(token)) {
|
| - token = parseIdentifier(token);
|
| - token = parseQualifiedRestOpt(token);
|
| - } else {
|
| - token = listener.expectedType(token);
|
| - }
|
| - token = parseTypeArgumentsOpt(token);
|
| - listener.endType(begin, token);
|
| - }
|
| -
|
| - // While we see a `Function(` treat the pushed type as return type.
|
| - // For example: `int Function() Function(int) Function(String x)`.
|
| - while (isGeneralizedFunctionType(token)) {
|
| - token = parseFunctionType(token);
|
| + token = listener.expectedType(token);
|
| }
|
| - return token;
|
| - }
|
| -
|
| - /// Parses a generalized function type.
|
| - ///
|
| - /// The return type must already be pushed.
|
| - Token parseFunctionType(Token token) {
|
| - // TODO(floitsch): don't use string comparison, but the keyword-state
|
| - // table is currently not set up to deal with upper-case characters.
|
| - if (token.value != "Function") {
|
| - return listener.expected("Function", token);
|
| - }
|
| - Token functionToken = token;
|
| - token = token.next;
|
| - token = parseTypeVariablesOpt(token);
|
| - token = parseFormalParameters(token, inFunctionType: true);
|
| - listener.endFunctionType(functionToken, token);
|
| + token = parseTypeArgumentsOpt(token);
|
| + listener.endType(begin, token);
|
| return token;
|
| }
|
|
|
| @@ -1252,55 +1175,26 @@ class Parser {
|
| hasName = true;
|
| }
|
| identifiers = identifiers.prepend(token);
|
| -
|
| - if (!isGeneralizedFunctionType(token)) {
|
| - // Read a potential return type.
|
| - if (isValidTypeReference(token)) {
|
| - // type ...
|
| - if (optional('.', token.next)) {
|
| - // type '.' ...
|
| - if (token.next.next.isIdentifier()) {
|
| - // type '.' identifier
|
| - token = token.next.next;
|
| - }
|
| - }
|
| - if (optional('<', token.next)) {
|
| - if (token.next is BeginGroupToken) {
|
| - BeginGroupToken beginGroup = token.next;
|
| - if (beginGroup.endGroup == null) {
|
| - listener.unmatched(beginGroup);
|
| - }
|
| - token = beginGroup.endGroup;
|
| - }
|
| + if (isValidTypeReference(token)) {
|
| + // type ...
|
| + if (optional('.', token.next)) {
|
| + // type '.' ...
|
| + if (token.next.next.isIdentifier()) {
|
| + // type '.' identifier
|
| + token = token.next.next;
|
| }
|
| }
|
| - token = token.next;
|
| - }
|
| - while (isGeneralizedFunctionType(token)) {
|
| - token = token.next;
|
| - if (optional('<', token)) {
|
| - if (token is BeginGroupToken) {
|
| - BeginGroupToken beginGroup = token;
|
| + if (optional('<', token.next)) {
|
| + if (token.next is BeginGroupToken) {
|
| + BeginGroupToken beginGroup = token.next;
|
| if (beginGroup.endGroup == null) {
|
| listener.unmatched(beginGroup);
|
| }
|
| - token = beginGroup.endGroup.next;
|
| - }
|
| - }
|
| - if (!optional('(', token)) {
|
| - if (optional(';', token)) {
|
| - listener.recoverableError(token, "expected '('");
|
| + token = beginGroup.endGroup;
|
| }
|
| - token = listener.unexpected(token);
|
| - }
|
| - if (token is BeginGroupToken) {
|
| - BeginGroupToken beginGroup = token;
|
| - if (beginGroup.endGroup == null) {
|
| - listener.unmatched(beginGroup);
|
| - }
|
| - token = beginGroup.endGroup.next;
|
| }
|
| }
|
| + token = token.next;
|
| }
|
| return const Link<Token>();
|
| }
|
| @@ -1398,31 +1292,11 @@ class Parser {
|
|
|
| /**
|
| * Returns the first token after the type starting at [token].
|
| - *
|
| * This method assumes that [token] is an identifier (or void).
|
| * Use [peekAfterIfType] if [token] isn't known to be an identifier.
|
| */
|
| Token peekAfterType(Token token) {
|
| // We are looking at "identifier ...".
|
| - Token peek = token;
|
| - if (!isGeneralizedFunctionType(token)) {
|
| - peek = peekAfterNominalType(token);
|
| - }
|
| -
|
| - // We might have just skipped over the return value of the function type.
|
| - // Check again, if we are now at a function type position.
|
| - while (isGeneralizedFunctionType(peek)) {
|
| - peek = peekAfterFunctionType(peek);
|
| - }
|
| - return peek;
|
| - }
|
| -
|
| - /**
|
| - * Returns the first token after the nominal type starting at [token].
|
| - *
|
| - * This method assumes that [token] is an identifier (or void).
|
| - */
|
| - Token peekAfterNominalType(Token token) {
|
| Token peek = token.next;
|
| if (identical(peek.kind, PERIOD_TOKEN)) {
|
| if (peek.next.isIdentifier()) {
|
| @@ -1438,57 +1312,13 @@ class Parser {
|
| Token gtToken = beginGroupToken.endGroup;
|
| if (gtToken != null) {
|
| // We are looking at "qualified '<' ... '>' ...".
|
| - peek = gtToken.next;
|
| + return gtToken.next;
|
| }
|
| }
|
| return peek;
|
| }
|
|
|
| /**
|
| - * Returns the first token after the function type starting at [token].
|
| - *
|
| - * The token must be at the `Function` token position. That is, the return
|
| - * type must have already been skipped.
|
| - *
|
| - * This function only skips over one function type syntax.
|
| - * If necessary, this function must be called multiple times.
|
| - *
|
| - * Example:
|
| - * ```
|
| - * int Function() Function<T>(int)
|
| - * ^ ^
|
| - * A call to this function must be at one of the `Function` tokens.
|
| - * If `token` pointed to the first `Function` token, then the returned
|
| - * token points to the second `Function` token.
|
| - */
|
| - Token peekAfterFunctionType(Token token) {
|
| - // Possible inputs are:
|
| - // Function( ... )
|
| - // Function< ... >( ... )
|
| -
|
| - Token peek = token.next; // Skip over the Function token.
|
| - // If there is a generic argument to the function, skip over that one first.
|
| - if (identical(peek.kind, LT_TOKEN)) {
|
| - BeginGroupToken beginGroupToken = peek;
|
| - Token closeToken = beginGroupToken.endGroup;
|
| - if (closeToken != null) {
|
| - peek = closeToken.next;
|
| - }
|
| - }
|
| -
|
| - // Now we just need to skip over the formals.
|
| - expect('(', peek);
|
| -
|
| - BeginGroupToken beginGroupToken = peek;
|
| - Token closeToken = beginGroupToken.endGroup;
|
| - if (closeToken != null) {
|
| - peek = closeToken.next;
|
| - }
|
| -
|
| - return peek;
|
| - }
|
| -
|
| - /**
|
| * If [token] is the start of a type, returns the token after that type.
|
| * If [token] is not the start of a type, null is returned.
|
| */
|
|
|