| Index: frog/leg/scanner/parser.dart
|
| ===================================================================
|
| --- frog/leg/scanner/parser.dart (revision 5925)
|
| +++ frog/leg/scanner/parser.dart (working copy)
|
| @@ -1,1592 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -/**
|
| - * An event generating parser of Dart programs. This parser expects
|
| - * all tokens in a linked list.
|
| - */
|
| -class Parser {
|
| - final Listener listener;
|
| - bool mayParseFunctionExpressions = true;
|
| -
|
| - Parser(Listener this.listener);
|
| -
|
| - void parseUnit(Token token) {
|
| - while (token.kind !== EOF_TOKEN) {
|
| - token = parseTopLevelDeclaration(token);
|
| - }
|
| - }
|
| -
|
| - Token parseTopLevelDeclaration(Token token) {
|
| - final String value = token.stringValue;
|
| - if (value === 'interface') {
|
| - return parseInterface(token);
|
| - } else if ((value === 'abstract') || (value === 'class')) {
|
| - return parseClass(token);
|
| - } else if (value === 'typedef') {
|
| - return parseNamedFunctionAlias(token);
|
| - } else if (value === '#') {
|
| - return parseScriptTags(token);
|
| - } else {
|
| - return parseTopLevelMember(token);
|
| - }
|
| - }
|
| -
|
| - Token parseInterface(Token token) {
|
| - Token interfaceKeyword = token;
|
| - listener.beginInterface(token);
|
| - token = parseIdentifier(token.next);
|
| - token = parseTypeVariablesOpt(token);
|
| - int supertypeCount = 0;
|
| - Token extendsKeyword = null;
|
| - if (optional('extends', token)) {
|
| - extendsKeyword = token;
|
| - do {
|
| - token = parseType(token.next);
|
| - ++supertypeCount;
|
| - } while (optional(',', token));
|
| - }
|
| - token = parseDefaultClauseOpt(token);
|
| - token = parseInterfaceBody(token);
|
| - listener.endInterface(supertypeCount, interfaceKeyword,
|
| - extendsKeyword, token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseInterfaceBody(Token token) {
|
| - return parseClassBody(token);
|
| - }
|
| -
|
| - Token parseNamedFunctionAlias(Token token) {
|
| - Token typedefKeyword = token;
|
| - listener.beginFunctionTypeAlias(token);
|
| - token = parseReturnTypeOpt(token.next);
|
| - token = parseIdentifier(token);
|
| - token = parseTypeVariablesOpt(token);
|
| - token = parseFormalParameters(token);
|
| - listener.endFunctionTypeAlias(typedefKeyword, token);
|
| - return expect(';', token);
|
| - }
|
| -
|
| - Token parseReturnTypeOpt(Token token) {
|
| - if (token.stringValue === 'void') {
|
| - listener.handleVoidKeyword(token);
|
| - return token.next;
|
| - } else {
|
| - return parseTypeOpt(token);
|
| - }
|
| - }
|
| -
|
| - Token parseFormalParameters(Token token) {
|
| - Token begin = token;
|
| - listener.beginFormalParameters(begin);
|
| - expect('(', token);
|
| - int parameterCount = 0;
|
| - if (optional(')', token.next)) {
|
| - listener.endFormalParameters(parameterCount, begin, token.next);
|
| - return token.next.next;
|
| - }
|
| - do {
|
| - ++parameterCount;
|
| - token = token.next;
|
| - if (optional('[', token)) {
|
| - token = parseOptionalFormalParameters(token);
|
| - break;
|
| - }
|
| - token = parseFormalParameter(token);
|
| - } while (optional(',', token));
|
| - listener.endFormalParameters(parameterCount, begin, token);
|
| - return expect(')', token);
|
| - }
|
| -
|
| - Token parseFormalParameter(Token token) {
|
| - listener.beginFormalParameter(token);
|
| - token = parseModifiers(token);
|
| - // TODO(ahe): Validate that there are formal parameters if void.
|
| - token = parseReturnTypeOpt(token);
|
| - Token thisKeyword = null;
|
| - 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);
|
| - }
|
| - token = parseIdentifier(token);
|
| - if (optional('(', token)) {
|
| - token = parseFormalParameters(token);
|
| - listener.handleFunctionTypedFormalParameter(token);
|
| - }
|
| - if (optional('=', token)) {
|
| - // TODO(ahe): Validate that these are only used for optional parameters.
|
| - Token equal = token;
|
| - token = parseExpression(token.next);
|
| - listener.handleValuedFormalParameter(equal, token);
|
| - }
|
| - listener.endFormalParameter(token, thisKeyword);
|
| - return token;
|
| - }
|
| -
|
| - Token parseOptionalFormalParameters(Token token) {
|
| - Token begin = token;
|
| - listener.beginOptionalFormalParameters(begin);
|
| - assert(optional('[', token));
|
| - int parameterCount = 0;
|
| - do {
|
| - token = token.next;
|
| - token = parseFormalParameter(token);
|
| - ++parameterCount;
|
| - } while (optional(',', token));
|
| - listener.endOptionalFormalParameters(parameterCount, begin, token);
|
| - return expect(']', token);
|
| - }
|
| -
|
| - Token parseTypeOpt(Token token) {
|
| - String value = token.stringValue;
|
| - if (value === 'var') return parseType(token);
|
| - if (value !== 'this') {
|
| - Token peek = peekAfterType(token);
|
| - if (isIdentifier(peek) || optional('this', peek)) {
|
| - return parseType(token);
|
| - }
|
| - }
|
| - listener.handleNoType(token);
|
| - return token;
|
| - }
|
| -
|
| - bool isIdentifier(Token token) {
|
| - final kind = token.kind;
|
| - if (kind === IDENTIFIER_TOKEN) return true;
|
| - if (kind === KEYWORD_TOKEN) return token.value.isPseudo;
|
| - return false;
|
| - }
|
| -
|
| - Token parseDefaultClauseOpt(Token token) {
|
| - if (isDefaultKeyword(token)) {
|
| - // TODO(ahe): Remove support for 'factory' in this position.
|
| - Token defaultKeyword = token;
|
| - listener.beginDefaultClause(defaultKeyword);
|
| - token = parseIdentifier(token.next);
|
| - token = parseQualifiedRestOpt(token);
|
| - token = parseTypeVariablesOpt(token);
|
| - listener.endDefaultClause(defaultKeyword);
|
| - } else {
|
| - listener.handleNoDefaultClause(token);
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parseQualifiedRestOpt(Token token) {
|
| - if (optional('.', token)) {
|
| - Token period = token;
|
| - token = parseIdentifier(token.next);
|
| - listener.handleQualified(period);
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - bool isDefaultKeyword(Token token) {
|
| - String value = token.stringValue;
|
| - if (value === 'default') return true;
|
| - if (value === 'factory') {
|
| - listener.recoverableError("expected 'default'", token: token);
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - Token skipBlock(Token token) {
|
| - if (!optional('{', token)) {
|
| - return listener.expectedBlockToSkip(token);
|
| - }
|
| - BeginGroupToken beginGroupToken = token;
|
| - assert(beginGroupToken.endGroup === null ||
|
| - beginGroupToken.endGroup.kind === $CLOSE_CURLY_BRACKET);
|
| - return beginGroupToken.endGroup;
|
| - }
|
| -
|
| - Token parseClass(Token token) {
|
| - Token begin = token;
|
| - listener.beginClassDeclaration(token);
|
| - if (optional('abstract', token)) {
|
| - // TODO(ahe): Notify listener about abstract modifier.
|
| - token = token.next;
|
| - }
|
| - token = parseIdentifier(token.next);
|
| - token = parseTypeVariablesOpt(token);
|
| - Token extendsKeyword;
|
| - if (optional('extends', token)) {
|
| - extendsKeyword = token;
|
| - token = parseType(token.next);
|
| - } else {
|
| - extendsKeyword = null;
|
| - listener.handleNoType(token);
|
| - }
|
| - Token implementsKeyword;
|
| - int interfacesCount = 0;
|
| - if (optional('implements', token)) {
|
| - do {
|
| - token = parseType(token.next);
|
| - ++interfacesCount;
|
| - } while (optional(',', token));
|
| - }
|
| - token = parseClassBody(token);
|
| - listener.endClassDeclaration(interfacesCount, begin, extendsKeyword,
|
| - implementsKeyword, token);
|
| - return token.next;
|
| - }
|
| -
|
| -
|
| - Token parseStringPart(Token token) {
|
| - if (token.kind === STRING_TOKEN) {
|
| - listener.handleStringPart(token);
|
| - return token.next;
|
| - } else {
|
| - return listener.expected('string', token);
|
| - }
|
| - }
|
| -
|
| - Token parseIdentifier(Token token) {
|
| - if (isIdentifier(token)) {
|
| - listener.handleIdentifier(token);
|
| - } else {
|
| - listener.expectedIdentifier(token);
|
| - }
|
| - return token.next;
|
| - }
|
| -
|
| - Token expect(String string, Token token) {
|
| - if (string !== token.stringValue) {
|
| - if (string === '>') {
|
| - if (token.stringValue === '>>') {
|
| - Token gt = new Token(GT_INFO, token.charOffset + 1);
|
| - gt.next = token.next;
|
| - return gt;
|
| - } else if (token.stringValue === '>>>') {
|
| - Token gtgt = new Token(GT_GT_INFO, token.charOffset + 1);
|
| - gtgt.next = token.next;
|
| - return gtgt;
|
| - }
|
| - }
|
| - return listener.expected(string, token);
|
| - }
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseTypeVariable(Token token) {
|
| - listener.beginTypeVariable(token);
|
| - token = parseIdentifier(token);
|
| - if (optional('extends', token)) {
|
| - token = parseType(token.next);
|
| - } else {
|
| - listener.handleNoType(token);
|
| - }
|
| - listener.endTypeVariable(token);
|
| - return token;
|
| - }
|
| -
|
| - bool optional(String value, Token token) => value === token.stringValue;
|
| -
|
| - bool notEofOrValue(String value, Token token) {
|
| - return token.kind !== EOF_TOKEN && value !== token.stringValue;
|
| - }
|
| -
|
| - Token parseType(Token token) {
|
| - Token begin = token;
|
| - if (isIdentifier(token)) {
|
| - token = parseIdentifier(token);
|
| - token = parseQualifiedRestOpt(token);
|
| - } else {
|
| - token = listener.expectedType(token);
|
| - }
|
| - token = parseTypeArgumentsOpt(token);
|
| - listener.endType(begin, token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseTypeArgumentsOpt(Token token) {
|
| - return parseStuff(token,
|
| - (t) => listener.beginTypeArguments(t),
|
| - (t) => parseType(t),
|
| - (c, bt, et) => listener.endTypeArguments(c, bt, et),
|
| - (t) => listener.handleNoTypeArguments(t));
|
| - }
|
| -
|
| - Token parseTypeVariablesOpt(Token token) {
|
| - return parseStuff(token,
|
| - (t) => listener.beginTypeVariables(t),
|
| - (t) => parseTypeVariable(t),
|
| - (c, bt, et) => listener.endTypeVariables(c, bt, et),
|
| - (t) => listener.handleNoTypeVariables(t));
|
| - }
|
| -
|
| - // TODO(ahe): Clean this up.
|
| - Token parseStuff(Token token, Function beginStuff, Function stuffParser,
|
| - Function endStuff, Function handleNoStuff) {
|
| - if (optional('<', token)) {
|
| - Token begin = token;
|
| - beginStuff(begin);
|
| - int count = 0;
|
| - do {
|
| - token = stuffParser(token.next);
|
| - ++count;
|
| - } while (optional(',', token));
|
| - endStuff(count, begin, token);
|
| - return expect('>', token);
|
| - }
|
| - handleNoStuff(token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseTopLevelMember(Token token) {
|
| - Token start = token;
|
| - listener.beginTopLevelMember(token);
|
| - token = parseModifiers(token);
|
| - Token getOrSet = findGetOrSet(token);
|
| - if (token === getOrSet) token = token.next;
|
| - Token peek = peekAfterType(token);
|
| - if (isIdentifier(peek)) {
|
| - // Skip type.
|
| - token = peek;
|
| - }
|
| - if (token === getOrSet) token = token.next;
|
| - token = parseIdentifier(token);
|
| - bool isField;
|
| - while (true) {
|
| - // Loop to allow the listener to rewrite the token stream for
|
| - // error handling.
|
| - final String value = token.stringValue;
|
| - if (value === '(') {
|
| - isField = false;
|
| - break;
|
| - } else if ((value === '=') || (value === ';') || (value === ',')) {
|
| - isField = true;
|
| - break;
|
| - } else {
|
| - token = listener.unexpected(token);
|
| - if (token.kind === EOF_TOKEN) {
|
| - // TODO(ahe): This is a hack. It would be better to tell the
|
| - // listener more explicitly that it must pop an identifier.
|
| - listener.endTopLevelFields(1, start, token);
|
| - return token;
|
| - }
|
| - }
|
| - }
|
| - if (isField) {
|
| - int fieldCount = 1;
|
| - token = parseVariableInitializerOpt(token);
|
| - while (optional(',', token)) {
|
| - token = parseIdentifier(token.next);
|
| - token = parseVariableInitializerOpt(token);
|
| - ++fieldCount;
|
| - }
|
| - expectSemicolon(token);
|
| - listener.endTopLevelFields(fieldCount, start, token);
|
| - } else {
|
| - token = parseFormalParameters(token);
|
| - token = parseFunctionBody(token, false);
|
| - listener.endTopLevelMethod(start, getOrSet, token);
|
| - }
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseVariableInitializerOpt(Token token) {
|
| - if (optional('=', token)) {
|
| - Token assignment = token;
|
| - listener.beginInitializer(token);
|
| - token = parseExpression(token.next);
|
| - listener.endInitializer(assignment);
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parseInitializersOpt(Token token) {
|
| - if (optional(':', token)) {
|
| - return parseInitializers(token);
|
| - } else {
|
| - listener.handleNoInitializers();
|
| - return token;
|
| - }
|
| - }
|
| -
|
| - Token parseInitializers(Token token) {
|
| - Token begin = token;
|
| - listener.beginInitializers(begin);
|
| - expect(':', token);
|
| - int count = 0;
|
| - bool old = mayParseFunctionExpressions;
|
| - mayParseFunctionExpressions = false;
|
| - do {
|
| - token = parseExpression(token.next);
|
| - ++count;
|
| - } while (optional(',', token));
|
| - mayParseFunctionExpressions = old;
|
| - listener.endInitializers(count, begin, token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseScriptTags(Token token) {
|
| - Token begin = token;
|
| - listener.beginScriptTag(token);
|
| - token = parseIdentifier(token.next);
|
| - token = expect('(', token);
|
| - token = parseLiteralStringOrRecoverExpression(token);
|
| - bool hasPrefix = false;
|
| - if (optional(',', token)) {
|
| - hasPrefix = true;
|
| - token = parseIdentifier(token.next);
|
| - token = expect(':', token);
|
| - token = parseLiteralStringOrRecoverExpression(token);
|
| - }
|
| - token = expect(')', token);
|
| - listener.endScriptTag(hasPrefix, begin, token);
|
| - return expectSemicolon(token);
|
| - }
|
| -
|
| - Token parseLiteralStringOrRecoverExpression(Token token) {
|
| - if (token.kind === STRING_TOKEN) {
|
| - return parseLiteralString(token);
|
| - } else {
|
| - listener.recoverableError("unexpected", token: token);
|
| - return parseExpression(token);
|
| - }
|
| - }
|
| -
|
| - Token expectSemicolon(Token token) {
|
| - return expect(';', token);
|
| - }
|
| -
|
| - Token parseModifier(Token token) {
|
| - assert(('final' === token.stringValue) ||
|
| - ('var' === token.stringValue) ||
|
| - ('const' === token.stringValue) ||
|
| - ('abstract' === token.stringValue) ||
|
| - ('static' === token.stringValue));
|
| - listener.handleModifier(token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseModifiers(Token token) {
|
| - int count = 0;
|
| - while (token.kind === KEYWORD_TOKEN) {
|
| - final String value = token.stringValue;
|
| - if (('final' !== value) &&
|
| - ('var' !== value) &&
|
| - ('const' !== value) &&
|
| - ('abstract' !== value) &&
|
| - ('static' !== value))
|
| - break;
|
| - token = parseModifier(token);
|
| - count++;
|
| - }
|
| - listener.handleModifiers(count);
|
| - return token;
|
| - }
|
| -
|
| - Token peekAfterType(Token token) {
|
| - // TODO(ahe): Also handle var?
|
| - if ('void' !== token.stringValue && !isIdentifier(token)) {
|
| - listener.unexpected(token);
|
| - }
|
| - // We are looking at "identifier ...".
|
| - Token peek = token.next;
|
| - if (peek.kind === PERIOD_TOKEN) {
|
| - if (isIdentifier(peek.next)) {
|
| - // Look past a library prefix.
|
| - peek = peek.next.next;
|
| - }
|
| - }
|
| - // We are looking at "qualified ...".
|
| - if (peek.kind === LT_TOKEN) {
|
| - // Possibly generic type.
|
| - // We are looking at "qualified '<'".
|
| - BeginGroupToken beginGroupToken = peek;
|
| - Token gtToken = beginGroupToken.endGroup;
|
| - if (gtToken !== null) {
|
| - // We are looking at "qualified '<' ... '>' ...".
|
| - return gtToken.next;
|
| - }
|
| - }
|
| - return peek;
|
| - }
|
| -
|
| - Token parseClassBody(Token token) {
|
| - Token begin = token;
|
| - listener.beginClassBody(token);
|
| - if (!optional('{', token)) {
|
| - token = listener.expectedClassBody(token);
|
| - }
|
| - token = token.next;
|
| - int count = 0;
|
| - while (notEofOrValue('}', token)) {
|
| - token = parseMember(token);
|
| - ++count;
|
| - }
|
| - listener.endClassBody(count, begin, token);
|
| - return token;
|
| - }
|
| -
|
| - bool isGetOrSet(Token token) {
|
| - final String value = token.stringValue;
|
| - return (value === 'get') || (value === 'set');
|
| - }
|
| -
|
| - Token findGetOrSet(Token token) {
|
| - if (isGetOrSet(token)) {
|
| - if (optional('<', token.next)) {
|
| - // For example: get<T> ...
|
| - final Token peek = peekAfterType(token);
|
| - if (isGetOrSet(peek) && isIdentifier(peek.next)) {
|
| - // For example: get<T> get identifier
|
| - return peek;
|
| - }
|
| - } else {
|
| - // For example: get ...
|
| - if (isGetOrSet(token.next) && isIdentifier(token.next.next)) {
|
| - // For example: get get identifier
|
| - return token.next;
|
| - } else {
|
| - // For example: get identifier
|
| - return token;
|
| - }
|
| - }
|
| - } else if (token.stringValue !== 'operator') {
|
| - final Token peek = peekAfterType(token);
|
| - if (isGetOrSet(peek) && isIdentifier(peek.next)) {
|
| - // type? get identifier
|
| - return peek;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - Token parseMember(Token token) {
|
| - if (optional('factory', token)) {
|
| - return parseFactoryMethod(token);
|
| - }
|
| - Token start = token;
|
| - listener.beginMember(token);
|
| - token = parseModifiers(token);
|
| - Token getOrSet = findGetOrSet(token);
|
| - if (token === getOrSet) token = token.next;
|
| - Token peek = peekAfterType(token);
|
| - if (isIdentifier(peek) && token.stringValue !== 'operator') {
|
| - // Skip type.
|
| - token = peek;
|
| - }
|
| - if (token === getOrSet) token = token.next;
|
| - if (optional('operator', token)) {
|
| - token = parseOperatorName(token);
|
| - } else {
|
| - token = parseIdentifier(token);
|
| - }
|
| - bool isField;
|
| - while (true) {
|
| - // Loop to allow the listener to rewrite the token stream for
|
| - // error handling.
|
| - final String value = token.stringValue;
|
| - if ((value === '(') || (value === '.')) {
|
| - isField = false;
|
| - break;
|
| - } else if ((value === '=') || (value === ';') || (value === ',')) {
|
| - isField = true;
|
| - break;
|
| - } else {
|
| - token = listener.unexpected(token);
|
| - if (token.kind === EOF_TOKEN) {
|
| - // TODO(ahe): This is a hack, see parseTopLevelMember.
|
| - listener.endFields(1, start, token);
|
| - return token;
|
| - }
|
| - }
|
| - }
|
| - if (isField) {
|
| - int fieldCount = 1;
|
| - token = parseVariableInitializerOpt(token);
|
| - if (getOrSet !== null) {
|
| - listener.recoverableError("unexpected", token: getOrSet);
|
| - }
|
| - while (optional(',', token)) {
|
| - // TODO(ahe): Count these.
|
| - token = parseIdentifier(token.next);
|
| - token = parseVariableInitializerOpt(token);
|
| - ++fieldCount;
|
| - }
|
| - expectSemicolon(token);
|
| - listener.endFields(fieldCount, start, token);
|
| - } else {
|
| - token = parseQualifiedRestOpt(token);
|
| - token = parseFormalParameters(token);
|
| - token = parseInitializersOpt(token);
|
| - token = parseFunctionBody(token, false);
|
| - listener.endMethod(getOrSet, start, token);
|
| - }
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseFactoryMethod(Token token) {
|
| - assert(optional('factory', token));
|
| - Token factoryKeyword = token;
|
| - listener.beginFactoryMethod(factoryKeyword);
|
| - token = token.next; // Skip 'factory'.
|
| - token = parseIdentifier(token);
|
| - token = parseQualifiedRestOpt(token);
|
| - token = parseTypeVariablesOpt(token);
|
| - Token period = null;
|
| - if (optional('.', token)) {
|
| - period = token;
|
| - token = parseIdentifier(token.next);
|
| - }
|
| - token = parseFormalParameters(token);
|
| - token = parseFunctionBody(token, false);
|
| - listener.endFactoryMethod(factoryKeyword, period, token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseOperatorName(Token token) {
|
| - assert(optional('operator', token));
|
| - if (isUserDefinableOperator(token.next.stringValue)) {
|
| - Token operator = token;
|
| - token = token.next;
|
| - listener.handleOperatorName(operator, token);
|
| - return token.next;
|
| - } else {
|
| - return parseIdentifier(token);
|
| - }
|
| - }
|
| -
|
| - Token parseFunction(Token token, Token getOrSet) {
|
| - listener.beginFunction(token);
|
| - token = parseModifiers(token);
|
| - if (getOrSet === token) token = token.next;
|
| - token = parseReturnTypeOpt(token);
|
| - if (getOrSet === token) token = token.next;
|
| - listener.beginFunctionName(token);
|
| - if (optional('operator', token)) {
|
| - token = parseOperatorName(token);
|
| - } else {
|
| - token = parseIdentifier(token);
|
| - }
|
| - token = parseQualifiedRestOpt(token);
|
| - listener.endFunctionName(token);
|
| - token = parseFormalParameters(token);
|
| - token = parseInitializersOpt(token);
|
| - token = parseFunctionBody(token, false);
|
| - listener.endFunction(getOrSet, token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseUnamedFunction(Token token) {
|
| - listener.beginUnamedFunction(token);
|
| - token = parseFormalParameters(token);
|
| - bool isBlock = optional('{', token);
|
| - token = parseFunctionBody(token, true);
|
| - listener.endUnamedFunction(token);
|
| - return isBlock ? token.next : token;
|
| - }
|
| -
|
| - Token parseFunctionDeclaration(Token token) {
|
| - listener.beginFunctionDeclaration(token);
|
| - token = parseFunction(token, null);
|
| - listener.endFunctionDeclaration(token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseFunctionExpression(Token token) {
|
| - listener.beginFunction(token);
|
| - listener.handleModifiers(0);
|
| - token = parseReturnTypeOpt(token);
|
| - listener.beginFunctionName(token);
|
| - token = parseIdentifier(token);
|
| - listener.endFunctionName(token);
|
| - token = parseFormalParameters(token);
|
| - listener.handleNoInitializers();
|
| - bool isBlock = optional('{', token);
|
| - token = parseFunctionBody(token, true);
|
| - listener.endFunction(null, token);
|
| - return isBlock ? token.next : token;
|
| - }
|
| -
|
| - Token parseFunctionBody(Token token, bool isExpression) {
|
| - if (optional(';', token)) {
|
| - listener.endFunctionBody(0, null, token);
|
| - return token;
|
| - } else if (optional('=>', token)) {
|
| - Token begin = token;
|
| - token = parseExpression(token.next);
|
| - if (!isExpression) {
|
| - expectSemicolon(token);
|
| - listener.endReturnStatement(true, begin, token);
|
| - } else {
|
| - listener.endReturnStatement(true, begin, null);
|
| - }
|
| - return token;
|
| - }
|
| - Token begin = token;
|
| - int statementCount = 0;
|
| - listener.beginFunctionBody(begin);
|
| - if (!optional('{', token)) {
|
| - return listener.expectedFunctionBody(token);
|
| - } else {
|
| - token = token.next;
|
| - }
|
| - while (notEofOrValue('}', token)) {
|
| - token = parseStatement(token);
|
| - ++statementCount;
|
| - }
|
| - listener.endFunctionBody(statementCount, begin, token);
|
| - expect('}', token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseStatement(Token token) {
|
| - final value = token.stringValue;
|
| - if (token.kind === IDENTIFIER_TOKEN) {
|
| - return parseExpressionStatementOrDeclaration(token);
|
| - } else if (value === '{') {
|
| - return parseBlock(token);
|
| - } else if (value === 'return') {
|
| - return parseReturnStatement(token);
|
| - } else if (value === 'var' || value === 'final') {
|
| - return parseVariablesDeclaration(token);
|
| - } else if (value === 'if') {
|
| - return parseIfStatement(token);
|
| - } else if (value === 'for') {
|
| - return parseForStatement(token);
|
| - } else if (value === 'throw') {
|
| - return parseThrowStatement(token);
|
| - } else if (value === 'void') {
|
| - return parseExpressionStatementOrDeclaration(token);
|
| - } else if (value === 'while') {
|
| - return parseWhileStatement(token);
|
| - } else if (value === 'do') {
|
| - return parseDoWhileStatement(token);
|
| - } else if (value === 'try') {
|
| - return parseTryStatement(token);
|
| - } else if (value === 'switch') {
|
| - return parseSwitchStatement(token);
|
| - } else if (value === 'break') {
|
| - return parseBreakStatement(token);
|
| - } else if (value === 'continue') {
|
| - return parseContinueStatement(token);
|
| - } else if (value === ';') {
|
| - return parseEmptyStatement(token);
|
| - } else {
|
| - return parseExpressionStatement(token);
|
| - }
|
| - }
|
| -
|
| - Token parseReturnStatement(Token token) {
|
| - Token begin = token;
|
| - listener.beginReturnStatement(begin);
|
| - assert('return' === token.stringValue);
|
| - token = token.next;
|
| - if (optional(';', token)) {
|
| - listener.endReturnStatement(false, begin, token);
|
| - } else {
|
| - token = parseExpression(token);
|
| - listener.endReturnStatement(true, begin, token);
|
| - }
|
| - return expectSemicolon(token);
|
| - }
|
| -
|
| - Token peekIdentifierAfterType(Token token) {
|
| - Token peek = peekAfterType(token);
|
| - if (peek !== null && isIdentifier(peek)) {
|
| - // We are looking at "type identifier".
|
| - return peek;
|
| - } else {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - Token parseExpressionStatementOrDeclaration(Token token) {
|
| - assert(isIdentifier(token) || token.stringValue === 'void');
|
| - Token identifier = peekIdentifierAfterType(token);
|
| - if (identifier !== null) {
|
| - assert(isIdentifier(identifier));
|
| - Token afterId = identifier.next;
|
| - int afterIdKind = afterId.kind;
|
| - if (afterIdKind === EQ_TOKEN ||
|
| - afterIdKind === SEMICOLON_TOKEN ||
|
| - afterIdKind === COMMA_TOKEN) {
|
| - // We are looking at "type identifier" followed by '=', ';', ','.
|
| - return parseVariablesDeclaration(token);
|
| - } else if (afterIdKind === OPEN_PAREN_TOKEN) {
|
| - // We are looking at "type identifier '('".
|
| - BeginGroupToken beginParen = afterId;
|
| - Token endParen = beginParen.endGroup;
|
| - Token afterParens = endParen.next;
|
| - if (optional('{', afterParens) || optional('=>', afterParens)) {
|
| - // We are looking at "type identifier '(' ... ')'" followed
|
| - // by '=>' or '{'.
|
| - return parseFunctionDeclaration(token);
|
| - }
|
| - }
|
| - // Fall-through to expression statement.
|
| - } else {
|
| - if (optional(':', token.next)) {
|
| - return parseLabeledStatement(token);
|
| - } else if (optional('(', token.next)) {
|
| - BeginGroupToken begin = token.next;
|
| - String afterParens = begin.endGroup.next.stringValue;
|
| - if (afterParens === '{' || afterParens === '=>') {
|
| - return parseFunctionDeclaration(token);
|
| - }
|
| - }
|
| - }
|
| - return parseExpressionStatement(token);
|
| - }
|
| -
|
| - Token parseLabeledStatement(Token token) {
|
| - listener.beginLabeledStatement(token);
|
| - token = parseIdentifier(token);
|
| - Token colon = token;
|
| - token = expect(':', token);
|
| - token = parseStatement(token);
|
| - listener.endLabeledStatement(colon);
|
| - return token;
|
| - }
|
| -
|
| - Token parseExpressionStatement(Token token) {
|
| - listener.beginExpressionStatement(token);
|
| - token = parseExpression(token);
|
| - listener.endExpressionStatement(token);
|
| - return expectSemicolon(token);
|
| - }
|
| -
|
| - Token parseExpression(Token token) {
|
| - return parsePrecedenceExpression(token, 2);
|
| - }
|
| -
|
| - Token parseConditionalExpressionRest(Token token) {
|
| - assert(optional('?', token));
|
| - Token question = token;
|
| - token = parseExpression(token.next);
|
| - Token colon = token;
|
| - token = expect(':', token);
|
| - token = parseExpression(token);
|
| - listener.handleConditionalExpression(question, colon);
|
| - return token;
|
| - }
|
| -
|
| - Token parsePrecedenceExpression(Token token, int precedence) {
|
| - assert(precedence >= 2);
|
| - assert(precedence <= POSTFIX_PRECEDENCE);
|
| - token = parseUnaryExpression(token);
|
| - PrecedenceInfo info = token.info;
|
| - int tokenLevel = info.precedence;
|
| - for (int level = tokenLevel; level >= precedence; --level) {
|
| - while (tokenLevel === level) {
|
| - Token operator = token;
|
| - if (tokenLevel === ASSIGNMENT_PRECEDENCE) {
|
| - // Right associative, so we recurse at the same precedence
|
| - // level.
|
| - token = parsePrecedenceExpression(token.next, level);
|
| - listener.handleAssignmentExpression(operator);
|
| - } else if (tokenLevel === POSTFIX_PRECEDENCE) {
|
| - if (info === PERIOD_INFO) {
|
| - // Left associative, so we recurse at the next higher
|
| - // precedence level. However, POSTFIX_PRECEDENCE is the
|
| - // highest level, so we just call parseUnaryExpression
|
| - // directly.
|
| - token = parseUnaryExpression(token.next);
|
| - listener.handleBinaryExpression(operator);
|
| - } else if ((info === OPEN_PAREN_INFO) ||
|
| - (info === OPEN_SQUARE_BRACKET_INFO)) {
|
| - token = parseArgumentOrIndexStar(token);
|
| - } else if ((info === PLUS_PLUS_INFO) ||
|
| - (info === MINUS_MINUS_INFO)) {
|
| - listener.handleUnaryPostfixAssignmentExpression(token);
|
| - token = token.next;
|
| - } else {
|
| - token = listener.unexpected(token);
|
| - }
|
| - } else if (info === IS_INFO) {
|
| - token = parseIsOperatorRest(token);
|
| - } else if (info === QUESTION_INFO) {
|
| - token = parseConditionalExpressionRest(token);
|
| - } else {
|
| - // Left associative, so we recurse at the next higher
|
| - // precedence level.
|
| - token = parsePrecedenceExpression(token.next, level + 1);
|
| - listener.handleBinaryExpression(operator);
|
| - }
|
| - info = token.info;
|
| - tokenLevel = info.precedence;
|
| - }
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parseUnaryExpression(Token token) {
|
| - String value = token.stringValue;
|
| - // Prefix:
|
| - if (value === '+') {
|
| - // Dart only allows "prefix plus" as an initial part of a
|
| - // decimal literal. We scan it as a separate token and let
|
| - // the parser listener combine it with the digits.
|
| - Token next = token.next;
|
| - if (next.charOffset === token.charOffset + 1) {
|
| - if (next.kind === INT_TOKEN) {
|
| - listener.handleLiteralInt(token);
|
| - return next.next;
|
| - }
|
| - if (next.kind === DOUBLE_TOKEN) {
|
| - listener.handleLiteralDouble(token);
|
| - return next.next;
|
| - }
|
| - }
|
| - listener.recoverableError("Unexpected token '+'", token: token);
|
| - return parsePrecedenceExpression(next, POSTFIX_PRECEDENCE);
|
| - } else if ((value === '!') ||
|
| - (value === '-') ||
|
| - (value === '~')) {
|
| - Token operator = token;
|
| - // Right associative, so we recurse at the same precedence
|
| - // level.
|
| - token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE);
|
| - listener.handleUnaryPrefixExpression(operator);
|
| - } else if ((value === '++') || value === '--') {
|
| - // TODO(ahe): Validate this is used correctly.
|
| - Token operator = token;
|
| - // Right associative, so we recurse at the same precedence
|
| - // level.
|
| - token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE);
|
| - listener.handleUnaryPrefixAssignmentExpression(operator);
|
| - } else {
|
| - token = parsePrimary(token);
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parseArgumentOrIndexStar(Token token) {
|
| - while (true) {
|
| - if (optional('[', token)) {
|
| - Token openSquareBracket = token;
|
| - bool old = mayParseFunctionExpressions;
|
| - mayParseFunctionExpressions = true;
|
| - token = parseExpression(token.next);
|
| - mayParseFunctionExpressions = old;
|
| - listener.handleIndexedExpression(openSquareBracket, token);
|
| - token = expect(']', token);
|
| - } else if (optional('(', token)) {
|
| - token = parseArguments(token);
|
| - listener.endSend(token);
|
| - } else {
|
| - break;
|
| - }
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parsePrimary(Token token) {
|
| - final kind = token.kind;
|
| - if (kind === IDENTIFIER_TOKEN) {
|
| - return parseSendOrFunctionLiteral(token);
|
| - } else if (kind === INT_TOKEN || kind === HEXADECIMAL_TOKEN) {
|
| - return parseLiteralInt(token);
|
| - } else if (kind === DOUBLE_TOKEN) {
|
| - return parseLiteralDouble(token);
|
| - } else if (kind === STRING_TOKEN) {
|
| - return parseLiteralString(token);
|
| - } else if (kind === KEYWORD_TOKEN) {
|
| - final value = token.stringValue;
|
| - if ((value === 'true') || (value === 'false')) {
|
| - return parseLiteralBool(token);
|
| - } else if (value === 'null') {
|
| - return parseLiteralNull(token);
|
| - } else if (value === 'this') {
|
| - return parseThisExpression(token);
|
| - } else if (value === 'super') {
|
| - return parseSuperExpression(token);
|
| - } else if (value === 'new') {
|
| - return parseNewExpression(token);
|
| - } else if (value === 'const') {
|
| - return parseConstExpression(token);
|
| - } else if (value === 'void') {
|
| - return parseFunctionExpression(token);
|
| - } else if (isIdentifier(token)) {
|
| - return parseSendOrFunctionLiteral(token);
|
| - } else {
|
| - return listener.expectedExpression(token);
|
| - }
|
| - } else if (kind === OPEN_PAREN_TOKEN) {
|
| - return parseParenthesizedExpressionOrFunctionLiteral(token);
|
| - } else if ((kind === LT_TOKEN) ||
|
| - (kind === OPEN_SQUARE_BRACKET_TOKEN) ||
|
| - (kind === OPEN_CURLY_BRACKET_TOKEN) ||
|
| - token.stringValue === '[]') {
|
| - return parseLiteralListOrMap(token);
|
| - } else {
|
| - return listener.expectedExpression(token);
|
| - }
|
| - }
|
| -
|
| - Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
|
| - BeginGroupToken beginGroup = token;
|
| - int kind = beginGroup.endGroup.next.kind;
|
| - if (mayParseFunctionExpressions &&
|
| - (kind === FUNCTION_TOKEN || kind === OPEN_CURLY_BRACKET_TOKEN)) {
|
| - return parseUnamedFunction(token);
|
| - } else {
|
| - bool old = mayParseFunctionExpressions;
|
| - mayParseFunctionExpressions = true;
|
| - token = parseParenthesizedExpression(token);
|
| - mayParseFunctionExpressions = old;
|
| - return token;
|
| - }
|
| - }
|
| -
|
| - Token parseParenthesizedExpression(Token token) {
|
| - BeginGroupToken begin = token;
|
| - token = expect('(', token);
|
| - token = parseExpression(token);
|
| - if (begin.endGroup !== token) {
|
| - listener.unexpected(token);
|
| - token = begin.endGroup;
|
| - }
|
| - listener.handleParenthesizedExpression(begin);
|
| - return expect(')', token);
|
| - }
|
| -
|
| - Token parseThisExpression(Token token) {
|
| - listener.handleThisExpression(token);
|
| - token = token.next;
|
| - if (optional('(', token)) {
|
| - // Constructor forwarding.
|
| - token = parseArguments(token);
|
| - listener.endSend(token);
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parseSuperExpression(Token token) {
|
| - listener.handleSuperExpression(token);
|
| - token = token.next;
|
| - if (optional('(', token)) {
|
| - // Super constructor.
|
| - token = parseArguments(token);
|
| - listener.endSend(token);
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parseLiteralListOrMap(Token token) {
|
| - Token constKeyword = null;
|
| - if (optional('const', token)) {
|
| - constKeyword = token;
|
| - token = token.next;
|
| - }
|
| - token = parseTypeArgumentsOpt(token);
|
| - Token beginToken = token;
|
| - int count = 0;
|
| - if (optional('{', token)) {
|
| - bool old = mayParseFunctionExpressions;
|
| - mayParseFunctionExpressions = true;
|
| - do {
|
| - if (optional('}', token.next)) {
|
| - token = token.next;
|
| - break;
|
| - }
|
| - token = parseMapLiteralEntry(token.next);
|
| - ++count;
|
| - } while (optional(',', token));
|
| - mayParseFunctionExpressions = old;
|
| - listener.handleLiteralMap(count, beginToken, constKeyword, token);
|
| - return expect('}', token);
|
| - } else if (optional('[', token)) {
|
| - bool old = mayParseFunctionExpressions;
|
| - mayParseFunctionExpressions = true;
|
| - do {
|
| - if (optional(']', token.next)) {
|
| - token = token.next;
|
| - break;
|
| - }
|
| - token = parseExpression(token.next);
|
| - ++count;
|
| - } while (optional(',', token));
|
| - mayParseFunctionExpressions = old;
|
| - listener.handleLiteralList(count, beginToken, constKeyword, token);
|
| - return expect(']', token);
|
| - } else if (optional('[]', token)) {
|
| - listener.handleLiteralList(0, token, constKeyword, token);
|
| - return token.next;
|
| - } else {
|
| - listener.unexpected(token);
|
| - }
|
| - }
|
| -
|
| - Token parseMapLiteralEntry(Token token) {
|
| - listener.beginLiteralMapEntry(token);
|
| - // Assume the listener rejects non-string keys.
|
| - token = parseExpression(token);
|
| - Token colon = token;
|
| - token = expect(':', token);
|
| - token = parseExpression(token);
|
| - listener.endLiteralMapEntry(colon, token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseSendOrFunctionLiteral(Token token) {
|
| - if (!mayParseFunctionExpressions) return parseSend(token);
|
| - Token peek = peekAfterType(token);
|
| - if (peek.kind === IDENTIFIER_TOKEN && isFunctionDeclaration(peek.next)) {
|
| - return parseFunctionExpression(token);
|
| - } else if (isFunctionDeclaration(token.next)) {
|
| - return parseFunctionExpression(token);
|
| - } else {
|
| - return parseSend(token);
|
| - }
|
| - }
|
| -
|
| - bool isFunctionDeclaration(Token token) {
|
| - if (optional('(', token)) {
|
| - BeginGroupToken begin = token;
|
| - String afterParens = begin.endGroup.next.stringValue;
|
| - if (afterParens === '{' || afterParens === '=>') {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - Token parseNewExpression(Token token) {
|
| - Token newKeyword = token;
|
| - token = expect('new', token);
|
| - token = parseType(token);
|
| - bool named = false;
|
| - if (optional('.', token)) {
|
| - named = true;
|
| - token = parseIdentifier(token.next);
|
| - }
|
| - if (optional('(', token)) {
|
| - token = parseArguments(token);
|
| - } else {
|
| - listener.handleNoArguments(token);
|
| - token = listener.unexpected(token);
|
| - }
|
| - listener.handleNewExpression(newKeyword, named);
|
| - return token;
|
| - }
|
| -
|
| - Token parseConstExpression(Token token) {
|
| - Token constKeyword = token;
|
| - token = expect('const', token);
|
| - final String value = token.stringValue;
|
| - if ((value === '<') ||
|
| - (value === '[') ||
|
| - (value === '[]') ||
|
| - (value === '{')) {
|
| - return parseLiteralListOrMap(constKeyword);
|
| - }
|
| - token = parseType(token);
|
| - bool named = false;
|
| - if (optional('.', token)) {
|
| - named = true;
|
| - token = parseIdentifier(token.next);
|
| - }
|
| - expect('(', token);
|
| - token = parseArguments(token);
|
| - listener.handleConstExpression(constKeyword, named);
|
| - return token;
|
| - }
|
| -
|
| - Token parseLiteralInt(Token token) {
|
| - listener.handleLiteralInt(token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseLiteralDouble(Token token) {
|
| - listener.handleLiteralDouble(token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseLiteralString(Token token) {
|
| - token = parseSingleLiteralString(token);
|
| - int count = 1;
|
| - while (token.kind === STRING_TOKEN) {
|
| - token = parseSingleLiteralString(token);
|
| - count++;
|
| - }
|
| - if (count > 1) {
|
| - listener.handleStringJuxtaposition(count);
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parseSingleLiteralString(Token token) {
|
| - listener.beginLiteralString(token);
|
| - token = token.next;
|
| - int interpolationCount = 0;
|
| - while (optional('\${', token)) {
|
| - token = token.next;
|
| - token = parseExpression(token);
|
| - token = expect('}', token);
|
| - token = parseStringPart(token);
|
| - ++interpolationCount;
|
| - }
|
| - listener.endLiteralString(interpolationCount);
|
| - return token;
|
| - }
|
| -
|
| - Token parseLiteralBool(Token token) {
|
| - listener.handleLiteralBool(token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseLiteralNull(Token token) {
|
| - listener.handleLiteralNull(token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseSend(Token token) {
|
| - listener.beginSend(token);
|
| - token = parseIdentifier(token);
|
| - token = parseArgumentsOpt(token);
|
| - listener.endSend(token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseArgumentsOpt(Token token) {
|
| - if (!optional('(', token)) {
|
| - listener.handleNoArguments(token);
|
| - return token;
|
| - } else {
|
| - return parseArguments(token);
|
| - }
|
| - }
|
| -
|
| - Token parseArguments(Token token) {
|
| - Token begin = token;
|
| - listener.beginArguments(begin);
|
| - assert('(' === token.stringValue);
|
| - int argumentCount = 0;
|
| - if (optional(')', token.next)) {
|
| - listener.endArguments(argumentCount, begin, token.next);
|
| - return token.next.next;
|
| - }
|
| - bool old = mayParseFunctionExpressions;
|
| - mayParseFunctionExpressions = true;
|
| - do {
|
| - Token colon = null;
|
| - if (optional(':', token.next.next)) {
|
| - token = parseIdentifier(token.next);
|
| - colon = token;
|
| - }
|
| - token = parseExpression(token.next);
|
| - if (colon !== null) listener.handleNamedArgument(colon);
|
| - ++argumentCount;
|
| - } while (optional(',', token));
|
| - mayParseFunctionExpressions = old;
|
| - listener.endArguments(argumentCount, begin, token);
|
| - return expect(')', token);
|
| - }
|
| -
|
| - Token parseIsOperatorRest(Token token) {
|
| - assert(optional('is', token));
|
| - Token operator = token;
|
| - Token not = null;
|
| - if (optional('!', token.next)) {
|
| - token = token.next;
|
| - not = token;
|
| - }
|
| - token = parseType(token.next);
|
| - listener.handleIsOperator(operator, not, token);
|
| - if (optional('is', token)) {
|
| - // The is-operator cannot be chained, but it can take part of
|
| - // expressions like: foo is Foo || foo is Bar.
|
| - listener.unexpected(token);
|
| - }
|
| - return token;
|
| - }
|
| -
|
| - Token parseVariablesDeclaration(Token token) {
|
| - token = parseVariablesDeclarationNoSemicolon(token);
|
| - return expectSemicolon(token);
|
| - }
|
| -
|
| - Token parseVariablesDeclarationNoSemicolon(Token token) {
|
| - int count = 1;
|
| - listener.beginVariablesDeclaration(token);
|
| - token = parseModifiers(token);
|
| - token = parseTypeOpt(token);
|
| - token = parseOptionallyInitializedIdentifier(token);
|
| - while (optional(',', token)) {
|
| - token = parseOptionallyInitializedIdentifier(token.next);
|
| - ++count;
|
| - }
|
| - listener.endVariablesDeclaration(count, token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseOptionallyInitializedIdentifier(Token token) {
|
| - listener.beginInitializedIdentifier(token);
|
| - token = parseIdentifier(token);
|
| - token = parseVariableInitializerOpt(token);
|
| - listener.endInitializedIdentifier();
|
| - return token;
|
| - }
|
| -
|
| - Token parseIfStatement(Token token) {
|
| - Token ifToken = token;
|
| - listener.beginIfStatement(ifToken);
|
| - token = expect('if', token);
|
| - token = parseParenthesizedExpression(token);
|
| - token = parseStatement(token);
|
| - Token elseToken = null;
|
| - if (optional('else', token)) {
|
| - elseToken = token;
|
| - token = parseStatement(token.next);
|
| - }
|
| - listener.endIfStatement(ifToken, elseToken);
|
| - return token;
|
| - }
|
| -
|
| - Token parseForStatement(Token token) {
|
| - Token forToken = token;
|
| - listener.beginForStatement(forToken);
|
| - token = expect('for', token);
|
| - token = expect('(', token);
|
| - token = parseVariablesDeclarationOrExpressionOpt(token);
|
| - if (optional('in', token)) {
|
| - return parseForInRest(forToken, token);
|
| - } else {
|
| - return parseForRest(forToken, token);
|
| - }
|
| - }
|
| -
|
| - Token parseVariablesDeclarationOrExpressionOpt(Token token) {
|
| - final String value = token.stringValue;
|
| - if (value === ';') {
|
| - listener.handleNoExpression(token);
|
| - return token;
|
| - } else if ((value === 'var') || (value === 'final')) {
|
| - return parseVariablesDeclarationNoSemicolon(token);
|
| - }
|
| - Token identifier = peekIdentifierAfterType(token);
|
| - if (identifier !== null) {
|
| - assert(isIdentifier(identifier));
|
| - Token afterId = identifier.next;
|
| - int afterIdKind = afterId.kind;
|
| - if (afterIdKind === EQ_TOKEN || afterIdKind === SEMICOLON_TOKEN ||
|
| - afterIdKind === COMMA_TOKEN || optional('in', afterId)) {
|
| - return parseVariablesDeclarationNoSemicolon(token);
|
| - }
|
| - }
|
| - return parseExpression(token);
|
| - }
|
| -
|
| - Token parseForRest(Token forToken, Token token) {
|
| - token = expectSemicolon(token);
|
| - if (optional(';', token)) {
|
| - token = parseEmptyStatement(token);
|
| - } else {
|
| - token = parseExpressionStatement(token);
|
| - }
|
| - int expressionCount = 0;
|
| - while (true) {
|
| - if (optional(')', token)) break;
|
| - token = parseExpression(token);
|
| - ++expressionCount;
|
| - if (optional(',', token)) {
|
| - token = token.next;
|
| - } else {
|
| - break;
|
| - }
|
| - }
|
| - token = expect(')', token);
|
| - token = parseStatement(token);
|
| - listener.endForStatement(expressionCount, forToken, token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseForInRest(Token forToken, Token token) {
|
| - assert(optional('in', token));
|
| - Token inKeyword = token;
|
| - token = parseExpression(token.next);
|
| - token = expect(')', token);
|
| - token = parseStatement(token);
|
| - listener.endForInStatement(forToken, inKeyword, token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseWhileStatement(Token token) {
|
| - Token whileToken = token;
|
| - listener.beginWhileStatement(whileToken);
|
| - token = expect('while', token);
|
| - token = parseParenthesizedExpression(token);
|
| - token = parseStatement(token);
|
| - listener.endWhileStatement(whileToken, token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseDoWhileStatement(Token token) {
|
| - Token doToken = token;
|
| - listener.beginDoWhileStatement(doToken);
|
| - token = expect('do', token);
|
| - token = parseStatement(token);
|
| - Token whileToken = token;
|
| - token = expect('while', token);
|
| - token = parseParenthesizedExpression(token);
|
| - listener.endDoWhileStatement(doToken, whileToken, token);
|
| - return expectSemicolon(token);
|
| - }
|
| -
|
| - Token parseBlock(Token token) {
|
| - Token begin = token;
|
| - listener.beginBlock(begin);
|
| - int statementCount = 0;
|
| - token = expect('{', token);
|
| - while (notEofOrValue('}', token)) {
|
| - token = parseStatement(token);
|
| - ++statementCount;
|
| - }
|
| - listener.endBlock(statementCount, begin, token);
|
| - return expect('}', token);
|
| - }
|
| -
|
| - Token parseThrowStatement(Token token) {
|
| - Token throwToken = token;
|
| - listener.beginThrowStatement(throwToken);
|
| - token = expect('throw', token);
|
| - if (optional(';', token)) {
|
| - listener.endRethrowStatement(throwToken, token);
|
| - return token.next;
|
| - } else {
|
| - token = parseExpression(token);
|
| - listener.endThrowStatement(throwToken, token);
|
| - return expectSemicolon(token);
|
| - }
|
| - }
|
| -
|
| - Token parseTryStatement(Token token) {
|
| - assert(optional('try', token));
|
| - Token tryKeyword = token;
|
| - listener.beginTryStatement(tryKeyword);
|
| - token = parseBlock(token.next);
|
| - int catchCount = 0;
|
| - while (optional('catch', token)) {
|
| - Token catchKeyword = token;
|
| - // TODO(ahe): Validate the "parameters".
|
| - token = parseFormalParameters(token.next);
|
| - token = parseBlock(token);
|
| - ++catchCount;
|
| - listener.handleCatchBlock(catchKeyword);
|
| - }
|
| - Token finallyKeyword = null;
|
| - if (optional('finally', token)) {
|
| - finallyKeyword = token;
|
| - token = parseBlock(token.next);
|
| - listener.handleFinallyBlock(finallyKeyword);
|
| - }
|
| - listener.endTryStatement(catchCount, tryKeyword, finallyKeyword);
|
| - return token;
|
| - }
|
| -
|
| - Token parseSwitchStatement(Token token) {
|
| - assert(optional('switch', token));
|
| - Token switchKeyword = token;
|
| - listener.beginSwitchStatement(switchKeyword);
|
| - token = parseParenthesizedExpression(token.next);
|
| - token = parseSwitchBlock(token);
|
| - listener.endSwitchStatement(switchKeyword, token);
|
| - return token.next;
|
| - }
|
| -
|
| - Token parseSwitchBlock(Token token) {
|
| - Token begin = token;
|
| - listener.beginSwitchBlock(begin);
|
| - token = expect('{', token);
|
| - int caseCount = 0;
|
| - while (token.kind !== EOF_TOKEN) {
|
| - if (optional('}', token)) {
|
| - break;
|
| - }
|
| - token = parseSwitchCase(token);
|
| - ++caseCount;
|
| - }
|
| - listener.endSwitchBlock(caseCount, begin, token);
|
| - expect('}', token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseSwitchCase(Token token) {
|
| - Token begin = token;
|
| - Token defaultKeyword = null;
|
| - Token label = null;
|
| - // First an optional label.
|
| - if (isIdentifier(token)) {
|
| - label = token;
|
| - token = parseIdentifier(token);
|
| - token = expect(':', token);
|
| - }
|
| - // Then one or more case expressions, the last of which may be
|
| - // 'default' instead.
|
| - int expressionCount = 0;
|
| - String value = token.stringValue;
|
| - do {
|
| - if (value === 'default') {
|
| - defaultKeyword = token;
|
| - token = expect(':', token.next);
|
| - break;
|
| - }
|
| - token = expect('case', token);
|
| - token = parseExpression(token);
|
| - token = expect(':', token);
|
| - expressionCount++;
|
| - value = token.stringValue;
|
| - } while (value === 'case' || value === 'default');
|
| - // Finally zero or more statements.
|
| - int statementCount = 0;
|
| - while (token.kind !== EOF_TOKEN) {
|
| - String value;
|
| - if (isIdentifier(token) && optional(':', token.next)) {
|
| - // Skip label.
|
| - value = token.next.next.stringValue;
|
| - } else {
|
| - value = token.stringValue;
|
| - }
|
| - if (value === 'case' || value === 'default' || value === '}') {
|
| - break;
|
| - } else {
|
| - token = parseStatement(token);
|
| - ++statementCount;
|
| - }
|
| - }
|
| - listener.handleSwitchCase(label, expressionCount, defaultKeyword,
|
| - statementCount, begin, token);
|
| - return token;
|
| - }
|
| -
|
| - Token parseBreakStatement(Token token) {
|
| - assert(optional('break', token));
|
| - Token breakKeyword = token;
|
| - token = token.next;
|
| - bool hasTarget = false;
|
| - if (isIdentifier(token)) {
|
| - token = parseIdentifier(token);
|
| - hasTarget = true;
|
| - }
|
| - listener.handleBreakStatement(hasTarget, breakKeyword, token);
|
| - return expectSemicolon(token);
|
| - }
|
| -
|
| - Token parseContinueStatement(Token token) {
|
| - assert(optional('continue', token));
|
| - Token continueKeyword = token;
|
| - token = token.next;
|
| - bool hasTarget = false;
|
| - if (isIdentifier(token)) {
|
| - token = parseIdentifier(token);
|
| - hasTarget = true;
|
| - }
|
| - listener.handleContinueStatement(hasTarget, continueKeyword, token);
|
| - return expectSemicolon(token);
|
| - }
|
| -
|
| - Token parseEmptyStatement(Token token) {
|
| - listener.handleEmptyStatement(token);
|
| - return expectSemicolon(token);
|
| - }
|
| -}
|
|
|