| Index: compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| diff --git a/compiler/java/com/google/dart/compiler/parser/DartParser.java b/compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| index d0615c55e8b46dfa1b49f6f694aaf87f4ca7cfa8..7ff83e9f8421b7a6cb725d59fba1a1a61d21df63 100644
|
| --- a/compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| +++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java
|
| @@ -28,6 +28,7 @@ import com.google.dart.compiler.ast.DartCascadeExpression;
|
| import com.google.dart.compiler.ast.DartCase;
|
| import com.google.dart.compiler.ast.DartCatchBlock;
|
| import com.google.dart.compiler.ast.DartClass;
|
| +import com.google.dart.compiler.ast.DartClassTypeAlias;
|
| import com.google.dart.compiler.ast.DartConditional;
|
| import com.google.dart.compiler.ast.DartContinueStatement;
|
| import com.google.dart.compiler.ast.DartDeclaration;
|
| @@ -351,7 +352,7 @@ public class DartParser extends CompletionHooksParserBase {
|
| } else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
|
| && (peek(1).equals(Token.IDENTIFIER) || peek(1).equals(Token.VOID))) {
|
| consume(Token.IDENTIFIER);
|
| - node = done(parseFunctionTypeAlias());
|
| + node = done(parseTypeAlias());
|
| } else if (looksLikeDirective()) {
|
| reportErrorWithoutAdvancing(ParserErrorCode.DIRECTIVE_OUT_OF_ORDER);
|
| metadata = parseDirectives(unit, metadata);
|
| @@ -977,22 +978,62 @@ public class DartParser extends CompletionHooksParserBase {
|
|
|
| // Parse the extends and implements clauses.
|
| DartTypeNode superType = null;
|
| + int withOffset = -1;
|
| int implementsOffset = -1;
|
| + List<DartTypeNode> mixins = null;
|
| List<DartTypeNode> interfaces = null;
|
| if (isParsingInterface) {
|
| if (optional(Token.EXTENDS)) {
|
| interfaces = parseTypeAnnotationList();
|
| }
|
| } else {
|
| - if (optional(Token.EXTENDS)) {
|
| - superType = parseTypeAnnotation();
|
| + boolean foundClause = true;
|
| + while (foundClause) {
|
| + if (optional(Token.EXTENDS)) {
|
| + if (mixins != null) {
|
| + reportErrorAtPosition(withOffset, withOffset + "with".length(),
|
| + ParserErrorCode.WITH_BEFORE_EXTENDS);
|
| + }
|
| + if (interfaces != null) {
|
| + reportErrorAtPosition(implementsOffset, implementsOffset + "implements".length(),
|
| + ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS);
|
| + }
|
| + if (superType == null) {
|
| + superType = parseTypeAnnotation();
|
| + } else {
|
| + reportError(position(), ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES);
|
| + parseTypeAnnotation();
|
| + }
|
| + } else if (optional(Token.WITH)) {
|
| + if (mixins == null) {
|
| + withOffset = position();
|
| + mixins = parseTypeAnnotationList();
|
| + if (interfaces != null) {
|
| + reportErrorAtPosition(implementsOffset, implementsOffset + "implements".length(),
|
| + ParserErrorCode.IMPLEMENTS_BEFORE_WITH);
|
| + }
|
| + } else {
|
| + reportError(position(), ParserErrorCode.MULTIPLE_WITH_CLAUSES);
|
| + parseTypeAnnotationList();
|
| + }
|
| + } else if (optionalPseudoKeyword(IMPLEMENTS_KEYWORD)) {
|
| + if (interfaces == null) {
|
| + implementsOffset = position();
|
| + interfaces = parseTypeAnnotationList();
|
| + } else {
|
| + reportError(position(), ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES);
|
| + parseTypeAnnotationList();
|
| + }
|
| + } else {
|
| + foundClause = false;
|
| + }
|
| }
|
| - if (optionalPseudoKeyword(IMPLEMENTS_KEYWORD)) {
|
| - implementsOffset = position();
|
| - interfaces = parseTypeAnnotationList();
|
| + if (mixins != null && superType == null) {
|
| + reportErrorAtPosition(withOffset, withOffset + "with".length(),
|
| + ParserErrorCode.WITH_WITHOUT_EXTENDS);
|
| }
|
| }
|
| -
|
| +
|
| // Deal with factory clause for interfaces.
|
| DartParameterizedTypeNode defaultClass = null;
|
| int defaultTokenOffset = -1;
|
| @@ -1036,13 +1077,13 @@ public class DartParser extends CompletionHooksParserBase {
|
| }
|
|
|
| if (isParsingInterface) {
|
| - return done(new DartClass(tokenOffset, tokenLength, name, superType, implementsOffset,
|
| - interfaces, defaultTokenOffset, openBraceOffset, closeBraceOffset, members,
|
| - typeParameters, defaultClass));
|
| + return done(new DartClass(tokenOffset, tokenLength, name, null, superType, implementsOffset,
|
| + interfaces, mixins, defaultTokenOffset, openBraceOffset, closeBraceOffset, members,
|
| + typeParameters, defaultClass, true, Modifiers.NONE));
|
| } else {
|
| return done(new DartClass(tokenOffset, tokenLength, name, nativeName, superType,
|
| - implementsOffset, interfaces, defaultTokenOffset, openBraceOffset, closeBraceOffset,
|
| - members, typeParameters, modifiers));
|
| + implementsOffset, interfaces, mixins, defaultTokenOffset, openBraceOffset,
|
| + closeBraceOffset, members, typeParameters, null, false, modifiers));
|
| }
|
| }
|
|
|
| @@ -1148,37 +1189,128 @@ public class DartParser extends CompletionHooksParserBase {
|
| }
|
|
|
| /**
|
| + * Parse a type alias.
|
| + *
|
| + * <pre>
|
| + * typeAlias ::=
|
| + * 'typedef' typeAliasBody
|
| + *
|
| + * typeAliasBody ::=
|
| + * classTypeAlias
|
| + * | functionTypeAlias
|
| + *
|
| + * classTypeAlias ::=
|
| + * identifier typeParameters? '=' 'abstract'? mixinApplication
|
| + *
|
| + * mixinApplication ::=
|
| + * qualified withClause implementsClause? ';'
|
| + *
|
| + * functionTypeAlias ::=
|
| + * functionPrefix typeParameterList? formalParameterList ';'
|
| + *
|
| + * functionPrefix ::=
|
| + * returnType? name
|
| + * </pre>
|
| + *
|
| + * @return the type alias that was parsed
|
| + */
|
| + private DartNodeWithMetadata parseTypeAlias() {
|
| + if (match(Token.IDENTIFIER)) {
|
| + Token next = peek(1);
|
| + if (next == Token.LT) {
|
| + int offset = skipTypeArguments(1, new DepthCounter());
|
| + next = peek(offset);
|
| + if (next != null && next == Token.ASSIGN) {
|
| + return parseClassTypeAlias();
|
| + }
|
| + } else if (next == Token.ASSIGN) {
|
| + return parseClassTypeAlias();
|
| + }
|
| + }
|
| + return parseFunctionTypeAlias();
|
| + }
|
| +
|
| + /**
|
| + * Parse a class type alias.
|
| + *
|
| + * <pre>
|
| + * classTypeAlias ::=
|
| + * identifier typeParameters? '=' 'abstract'? mixinApplication
|
| + *
|
| + * mixinApplication ::=
|
| + * type withClause implementsClause? ';'
|
| + * </pre>
|
| + *
|
| + * @return the class type alias that was parsed
|
| + */
|
| + private DartClassTypeAlias parseClassTypeAlias() {
|
| + beginClassTypeInterface();
|
| +
|
| + Modifiers modifiers = Modifiers.NONE;
|
| + if (optionalPseudoKeyword(ABSTRACT_KEYWORD)) {
|
| + modifiers = modifiers.makeAbstract();
|
| + }
|
| +
|
| + DartIdentifier name = parseIdentifier();
|
| + if (PSEUDO_KEYWORDS_SET.contains(name.getName())) {
|
| + reportError(name, ParserErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
|
| + }
|
| + List<DartTypeParameter> typeParameters = parseTypeParametersOpt();
|
| +
|
| + expect(Token.ASSIGN);
|
| +
|
| + DartTypeNode superType = parseTypeAnnotation();
|
| +
|
| + List<DartTypeNode> mixins = null;
|
| + if (optional(Token.WITH)) {
|
| + mixins = parseTypeAnnotationList();
|
| + }
|
| +
|
| + List<DartTypeNode> interfaces = null;
|
| + if (optionalPseudoKeyword(IMPLEMENTS_KEYWORD)) {
|
| + interfaces = parseTypeAnnotationList();
|
| + }
|
| +
|
| + expect(Token.SEMICOLON);
|
| + return done(new DartClassTypeAlias(name, typeParameters, modifiers, superType, mixins,
|
| + interfaces));
|
| + }
|
| +
|
| + /**
|
| + * Parse a function type alias.
|
| + *
|
| * <pre>
|
| - * functionTypeAlias
|
| - * : TYPEDEF functionPrefix typeParameters?
|
| - * formalParameterList ';'
|
| + * functionTypeAlias ::=
|
| + * functionPrefix typeParameterList? formalParameterList ';'
|
| *
|
| - * functionPrefix
|
| - * : returnType? identifier
|
| + * functionPrefix ::=
|
| + * returnType? name
|
| * </pre>
|
| + *
|
| + * @return the function type alias that was parsed
|
| */
|
| private DartFunctionTypeAlias parseFunctionTypeAlias() {
|
| beginFunctionTypeInterface();
|
| -
|
| +
|
| DartTypeNode returnType = null;
|
| if (peek(0) == Token.VOID) {
|
| returnType = parseVoidType();
|
| } else if (!isFunctionTypeAliasName()) {
|
| returnType = parseTypeAnnotation();
|
| }
|
| -
|
| +
|
| DartIdentifier name = parseIdentifier();
|
| if (PSEUDO_KEYWORDS_SET.contains(name.getName())) {
|
| reportError(name, ParserErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
|
| }
|
| -
|
| +
|
| List<DartTypeParameter> typeParameters = parseTypeParametersOpt();
|
| FormalParameters params = parseFormalParameterList();
|
| expect(Token.SEMICOLON);
|
| validateNoDefaultParameterValues(
|
| params.val,
|
| ParserErrorCode.DEFAULT_VALUE_CAN_NOT_BE_SPECIFIED_IN_TYPEDEF);
|
| -
|
| +
|
| return done(new DartFunctionTypeAlias(name, returnType, params.val, typeParameters));
|
| }
|
|
|
|
|