diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index cac9f75e2ee..c877c6f9773 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -125,6 +125,7 @@ module ts { Unterminated_template_literal: { code: 1160, category: DiagnosticCategory.Error, key: "Unterminated template literal." }, Unterminated_regular_expression_literal: { code: 1161, category: DiagnosticCategory.Error, key: "Unterminated regular expression literal." }, An_object_member_cannot_be_declared_optional: { code: 1162, category: DiagnosticCategory.Error, key: "An object member cannot be declared optional." }, + yield_expression_must_be_contained_within_a_generator_declaration: { code: 1163, category: DiagnosticCategory.Error, key: "'yield' expression must be contained_within a generator declaration." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index adf1bf041cf..5ee797482a9 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -491,6 +491,10 @@ "category": "Error", "code": 1162 }, + "'yield' expression must be contained_within a generator declaration.": { + "category": "Error", + "code": 1163 + }, "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a7dff2ea809..88f4a9b4adb 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -977,30 +977,6 @@ module ts { return func(); } - function enterGeneratorParameterContextAnd(func: () => T): T { - if (generatorParameterContext) { - // no need to do anything special if we're already in the [GeneratorParameter] context - return func(); - } - - setGeneratorParameterContext(true); - var result = func(); - setGeneratorParameterContext(false); - return result; - } - - function exitGeneratorParameterContextAnd(func: () => T): T { - if (generatorParameterContext) { - setGeneratorParameterContext(false); - var result = func(); - setGeneratorParameterContext(true); - return result; - } - - // no need to do anything special if we're not in the [GeneratorParameter] context - return func(); - } - function getLineStarts(): number[] { return lineStarts || (lineStarts = computeLineStarts(sourceText)); } @@ -1126,7 +1102,17 @@ module ts { } function isIdentifier(): boolean { - return token === SyntaxKind.Identifier || (strictModeContext ? token > SyntaxKind.LastFutureReservedWord : token > SyntaxKind.LastReservedWord); + if (token === SyntaxKind.Identifier) { + return true; + } + + // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is + // considered a keyword and is not an identifier. + if (token === SyntaxKind.YieldKeyword && yieldContext) { + return false; + } + + return strictModeContext ? token > SyntaxKind.LastFutureReservedWord : token > SyntaxKind.LastReservedWord; } function parseExpected(t: SyntaxKind): boolean { @@ -1247,7 +1233,7 @@ module ts { function parseAnyContextualModifier(): boolean { return isModifier(token) && tryParse(() => { nextToken(); - return token === SyntaxKind.OpenBracketToken || isPropertyName(); + return token === SyntaxKind.OpenBracketToken || token === SyntaxKind.AsteriskToken || isPropertyName(); }); } @@ -1268,7 +1254,7 @@ module ts { return lookAhead(isClassMemberStart); case ParsingContext.EnumMembers: case ParsingContext.ObjectLiteralMembers: - return isPropertyName(); + return token === SyntaxKind.AsteriskToken || isPropertyName(); case ParsingContext.BaseTypeReferences: return isIdentifier() && ((token !== SyntaxKind.ExtendsKeyword && token !== SyntaxKind.ImplementsKeyword) || !lookAhead(() => (nextToken(), isIdentifier()))); case ParsingContext.VariableDeclarations: @@ -1460,12 +1446,13 @@ module ts { return result; } - function parseBracketedList(kind: ParsingContext, parseElement: () => T, startToken: SyntaxKind, endToken: SyntaxKind): NodeArray { - if (parseExpected(startToken)) { + function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray { + if (parseExpected(open)) { var result = parseDelimitedList(kind, parseElement); - parseExpected(endToken); + parseExpected(close); return result; } + return createMissingList(); } @@ -1637,7 +1624,15 @@ module ts { if (parseOptional(SyntaxKind.DotDotDotToken)) { node.flags |= NodeFlags.Rest; } - node.name = parseIdentifier(); + + // SingleNameBinding[Yield,GeneratorParameter] : See 13.2.3 + // [+GeneratorParameter]BindingIdentifier[Yield]Initializer[In]opt + // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt + + node.name = generatorParameterContext + ? enterYieldContextAnd(parseIdentifier) + : parseIdentifier(); + if (node.name.kind === SyntaxKind.Missing && node.flags === 0 && isModifier(token)) { // in cases like // 'use strict' @@ -1654,7 +1649,9 @@ module ts { node.flags |= NodeFlags.QuestionMark; } node.type = parseParameterType(); - node.initializer = parseInitializer(/*inParameter*/ true); + node.initializer = generatorParameterContext + ? exitYieldContextAnd(parseParameterInitializer) + : parseParameterInitializer(); // Do not check for initializers in an ambient context for parameters. This is not // a grammar error because the grammar allows arbitrary call signatures in @@ -1667,18 +1664,28 @@ module ts { return finishNode(node); } - function parseSignature(kind: SyntaxKind, returnToken: SyntaxKind, returnTokenRequired: boolean): ParsedSignature { + function parseParameterInitializer() { + return parseInitializer(/*inParameter*/ true); + } + + function parseSignature(kind: SyntaxKind, returnToken: SyntaxKind, returnTokenRequired: boolean, isGenerator: boolean): ParsedSignature { var signature = {}; - fillSignature(kind, returnToken, returnTokenRequired, signature); + fillSignature(kind, returnToken, returnTokenRequired, isGenerator, signature); return signature; } - function fillSignature(kind: SyntaxKind, returnToken: SyntaxKind, returnTokenRequired: boolean, signature: ParsedSignature): void { + function fillSignature( + kind: SyntaxKind, + returnToken: SyntaxKind, + returnTokenRequired: boolean, + isGenerator: boolean, + signature: ParsedSignature): void { + if (kind === SyntaxKind.ConstructSignature) { parseExpected(SyntaxKind.NewKeyword); } signature.typeParameters = parseTypeParameters(); - signature.parameters = parseParameterList(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken); + signature.parameters = parseParameterList(/*yieldContext:*/ isGenerator, /*generatorParameterContext:*/ isGenerator); if (returnTokenRequired) { parseExpected(returnToken); @@ -1691,13 +1698,43 @@ module ts { // Because we use this for index signatures as well, we sometimes use // parentheses, and sometimes use brackets. - function parseParameterList(startDelimiter: SyntaxKind, endDelimiter: SyntaxKind) { - return parseBracketedList(ParsingContext.Parameters, parseParameter, startDelimiter, endDelimiter); + function parseParameterList(_yieldContext: boolean, _generatorParameterContext: boolean) { + // FormalParameters[Yield,GeneratorParameter] : + // ... + // + // FormalParameter[Yield,GeneratorParameter] : + // BindingElement[?Yield, ?GeneratorParameter] + // + // BindingElement[Yield, GeneratorParameter ] : See 13.2.3 + // SingleNameBinding[?Yield, ?GeneratorParameter] + // [+GeneratorParameter]BindingPattern[?Yield, GeneratorParameter]Initializer[In]opt + // [~GeneratorParameter]BindingPattern[?Yield]Initializer[In, ?Yield]opt + // + // SingleNameBinding[Yield, GeneratorParameter] : See 13.2.3 + // [+GeneratorParameter]BindingIdentifier[Yield]Initializer[In]opt + // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt + if (parseExpected(SyntaxKind.OpenParenToken)) { + var savedYieldContext = yieldContext; + var savedGeneratorParameterContext = generatorParameterContext; + + setYieldContext(_yieldContext); + setGeneratorParameterContext(_generatorParameterContext); + + var result = parseDelimitedList(ParsingContext.Parameters, parseParameter); + parseExpected(SyntaxKind.CloseParenToken); + + setYieldContext(savedYieldContext); + setGeneratorParameterContext(savedGeneratorParameterContext); + + return result; + } + + return createMissingList(); } function parseSignatureMember(kind: SyntaxKind, returnToken: SyntaxKind): SignatureDeclaration { var node = createNode(kind); - fillSignature(kind, returnToken, /* returnTokenRequired */ false, node); + fillSignature(kind, returnToken, /* returnTokenRequired */ false, /*isGenerator:*/ false, node); parseSemicolon(); return finishNode(node); } @@ -1705,7 +1742,7 @@ module ts { function parseIndexSignatureMember(fullStart: number, modifiers: ModifiersArray): SignatureDeclaration { var node = createNode(SyntaxKind.IndexSignature, fullStart); setModifiers(node, modifiers); - node.parameters = parseParameterList(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); node.type = parseTypeAnnotation(); parseSemicolon(); return finishNode(node) @@ -1723,7 +1760,11 @@ module ts { var method = createNode(SyntaxKind.Method, fullStart); method.name = name; method.flags = flags; - fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, method); + + // Method signatues don't exist in expression contexts. So they have neither + // [Yield] nor [GeneratorParameter] + fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ false, method); + parseSemicolon(); return finishNode(method); } @@ -1806,7 +1847,7 @@ module ts { function parseFunctionType(typeKind: SyntaxKind): SignatureDeclaration { var node = createNode(typeKind); fillSignature(typeKind === SyntaxKind.FunctionType ? SyntaxKind.CallSignature : SyntaxKind.ConstructSignature, - SyntaxKind.EqualsGreaterThanToken, /* returnTokenRequired */ true, node); + SyntaxKind.EqualsGreaterThanToken, /* returnTokenRequired */ true, /*isGenerator:*/ false, node); return finishNode(node); } @@ -1926,6 +1967,23 @@ module ts { } function parseType(): TypeNode { + // The rules about 'yield' only apply to actual code/expression contexts. They don't + // apply to 'type' contexts. So we disable these parameters here before moving on. + var savedYieldContext = yieldContext; + var savedGeneratorParameterContext = generatorParameterContext; + + setYieldContext(false); + setGeneratorParameterContext(false); + + var result = parseTypeWorker(); + + setYieldContext(savedYieldContext); + setGeneratorParameterContext(savedGeneratorParameterContext); + + return result; + } + + function parseTypeWorker(): TypeNode { if (isStartOfFunctionType()) { return parseFunctionType(SyntaxKind.FunctionType); } @@ -1970,6 +2028,10 @@ module ts { case SyntaxKind.MinusMinusToken: case SyntaxKind.LessThanToken: case SyntaxKind.Identifier: + case SyntaxKind.YieldKeyword: + // Yield always starts an expression. Either it is an identifier (in which case + // it is definitely an expression). Or it's a keyword (either because we're in + // a generator, or in strict mode (or both)) and it started a yield expression. return true; default: return isIdentifier(); @@ -2018,18 +2080,22 @@ module ts { } function parseAssignmentExpression(): Expression { - // Augmented by TypeScript: - // - // AssignmentExpression[in]: - // 1) ConditionalExpression[in] - // 2) LeftHandSideExpression = AssignmentExpression[in] - // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[in] - // 4) ArrowFunctionExpression <-- added by TypeScript + // AssignmentExpression[in,yield]: + // 1) ConditionalExpression[?in,?yield] + // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] + // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield] + // 4) ArrowFunctionExpression[?in,?yield] + // 5) [+Yield] YieldExpression[?In] // // Note: for ease of implementation we treat productions '2' and '3' as the same thing. // (i.e. they're both BinaryExpressions with an assignment operator in it). - // First, check if we have an arrow function (production '4') that starts with a parenthesized + // First, do the simple check if we have a YieldExpression (production '5'). + if (isYieldExpression()) { + return parseYieldExpression(); + } + + // Then, check if we have an arrow function (production '4') that starts with a parenthesized // parameter list. If we do, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done // with AssignmentExpression if we see one. @@ -2062,6 +2128,66 @@ module ts { return expr; } + function isYieldExpression(): boolean { + if (token === SyntaxKind.YieldKeyword) { + // If we have a 'yield' keyword, and htis is a context where yield expressions are + // allowed, then definitely parse out a yield expression. + if (yieldContext) { + return true; + } + + if (strictModeContext) { + // If we're in strict mode, then 'yield' is a keyword, could only ever start + // a yield expression. + return true; + } + + // We're in a context where 'yield expr' is not allowed. However, if we can + // definitely tell that the user was trying to parse a 'yield expr' and not + // just a normal expr that start with a 'yield' identifier, then parse out + // a 'yield expr'. We can then report an error later that they are only + // allowed in generator expressions. + // + // for example, if we see 'yield(foo)', then we'll have to treat that as an + // invocation expression of something called 'yield'. However, if we have + // 'yield foo' then that is not legal as a normal expression, so we can + // definitely recognize this as a yield expression. + // + // for now we just check if the next token is an identifier. More heuristics + // can be added here later as necessary. We just need to make sure that we + // don't accidently consume something legal. + return lookAhead(() => { + nextToken(); + return !scanner.hasPrecedingLineBreak() && isIdentifier(); + }); + } + + return false; + } + + function parseYieldExpression(): YieldExpression { + var node = createNode(SyntaxKind.YieldExpression); + + // YieldExpression[In] : + // yield + // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] + // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] + nextToken(); + + if (!scanner.hasPrecedingLineBreak() && + (token === SyntaxKind.AsteriskToken || isStartOfExpression())) { + parseOptional(SyntaxKind.AsteriskToken); + + node.expression = parseAssignmentExpression(); + return finishNode(node); + } + else { + // if the next token is not on the same line as yield. or we don't have an '*' or + // the start of an expressin, then this is just a simple "yield" expression. + return finishNode(node); + } + } + function parseSimpleArrowFunctionExpression(identifier: Identifier): Expression { Debug.assert(token === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); parseExpected(SyntaxKind.EqualsGreaterThanToken); @@ -2091,7 +2217,8 @@ module ts { var pos = getNodePos(); if (triState === Tristate.True) { - var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false); + // Arrow function are never generators. + var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ false); // If we have an arrow, then try to parse the body. // Even if not, try to parse if we have an opening brace, just in case we're in an error state. @@ -2194,7 +2321,8 @@ module ts { function tryParseSignatureIfArrowOrBraceFollows(): ParsedSignature { return tryParse(() => { - var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false); + // Arrow functions are never generators. + var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ false); // Parsing a signature isn't enough. // Parenthesized arrow signatures often look like other valid expressions. @@ -2216,7 +2344,7 @@ module ts { var body: Node; if (token === SyntaxKind.OpenBraceToken) { - body = parseFunctionBlock(/* ignoreMissingOpenBrace */ false); + body = parseFunctionBlock(/*allowYield:*/ false, /* ignoreMissingOpenBrace */ false); } else if (isStatement(/* inErrorRecovery */ true) && !isStartOfExpressionStatement() && token !== SyntaxKind.FunctionKeyword) { // Check if we got a plain statement (i.e. no expression-statements, no functions expressions/declarations) @@ -2233,7 +2361,7 @@ module ts { // up preemptively closing the containing construct. // // Note: even when 'ignoreMissingOpenBrace' is passed as true, parseBody will still error. - body = parseFunctionBlock(/* ignoreMissingOpenBrace */ true); + body = parseFunctionBlock(/*allowYield:*/ false, /* ignoreMissingOpenBrace */ true); } else { body = parseAssignmentExpression(); @@ -2575,15 +2703,17 @@ module ts { function parsePropertyAssignment(): Declaration { var nodePos = scanner.getStartPos(); + var isGenerator = parseOptional(SyntaxKind.AsteriskToken); var tokenIsIdentifier = isIdentifier(); var nameToken = token; var propertyName = parsePropertyName(); var node: Declaration; - if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { + if (isGenerator || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { node = createNode(SyntaxKind.PropertyAssignment, nodePos); node.name = propertyName; - var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false); - var body = parseFunctionBlock(/* ignoreMissingOpenBrace */ false); + var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ isGenerator); + + var body = parseFunctionBlock(isGenerator, /* ignoreMissingOpenBrace */ false); // do not propagate property name as name for function expression // for scenarios like // var x = 1; @@ -2640,14 +2770,25 @@ module ts { } function parseFunctionExpression(): FunctionExpression { + // GeneratorExpression : + // function * BindingIdentifier[Yield]opt (FormalParameters[Yield, GeneratorParameter]) { GeneratorBody[Yield] } + // FunctionExpression: + // function BindingIdentifieropt(FormalParameters) { FunctionBody } + var pos = getNodePos(); parseExpected(SyntaxKind.FunctionKeyword); - var name = isIdentifier() ? parseIdentifier() : undefined; - var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false); - var body = parseFunctionBlock(/* ignoreMissingOpenBrace */ false); + var isGenerator = parseOptional(SyntaxKind.AsteriskToken); + var name = isGenerator ? enterYieldContextAnd(parseOptionalIdentifier) : parseOptionalIdentifier(); + var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ isGenerator); + + var body = parseFunctionBlock(/*allowYield:*/ isGenerator, /* ignoreMissingOpenBrace */ false); return makeFunctionExpression(SyntaxKind.FunctionExpression, pos, name, sig, body); } + function parseOptionalIdentifier() { + return isIdentifier() ? parseIdentifier() : undefined; + } + function makeFunctionExpression(kind: SyntaxKind, pos: number, name: Identifier, sig: ParsedSignature, body: Node): FunctionExpression { var node = createNode(kind, pos); node.name = name; @@ -2682,10 +2823,15 @@ module ts { return finishNode(node); } - function parseFunctionBlock(ignoreMissingOpenBrace: boolean): Block { + function parseFunctionBlock(allowYield: boolean, ignoreMissingOpenBrace: boolean): Block { + var savedYieldContext = yieldContext; + setYieldContext(allowYield); + var block = parseBlock(ignoreMissingOpenBrace, /*checkForStrictMode*/ true); block.kind = SyntaxKind.FunctionBlock; + setYieldContext(savedYieldContext); + return block; } @@ -3050,9 +3196,9 @@ module ts { } } - function parseFunctionBlockOrSemicolon(): Block { + function parseFunctionBlockOrSemicolon(isGenerator: boolean): Block { if (token === SyntaxKind.OpenBraceToken) { - return parseFunctionBlock(/* ignoreMissingOpenBrace */ false); + return parseFunctionBlock(isGenerator, /* ignoreMissingOpenBrace */ false); } if (canParseSemicolon()) { @@ -3111,9 +3257,10 @@ module ts { var node = createNode(SyntaxKind.FunctionDeclaration, fullStart); setModifiers(node, modifiers); parseExpected(SyntaxKind.FunctionKeyword); + var isGenerator = parseOptional(SyntaxKind.AsteriskToken); node.name = parseIdentifier(); - fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, node); - node.body = parseFunctionBlockOrSemicolon(); + fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ isGenerator, node); + node.body = parseFunctionBlockOrSemicolon(isGenerator); return finishNode(node); } @@ -3121,12 +3268,13 @@ module ts { var node = createNode(SyntaxKind.Constructor, pos); setModifiers(node, modifiers); parseExpected(SyntaxKind.ConstructorKeyword); - fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, node); - node.body = parseFunctionBlockOrSemicolon(); + fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ false, node); + node.body = parseFunctionBlockOrSemicolon(/*isGenerator:*/ false); return finishNode(node); } function parsePropertyMemberDeclaration(fullStart: number, modifiers: ModifiersArray): Declaration { + var isGenerator = parseOptional(SyntaxKind.AsteriskToken); var name = parsePropertyName(); var flags = modifiers ? modifiers.flags : 0; if (parseOptional(SyntaxKind.QuestionToken)) { @@ -3135,15 +3283,15 @@ module ts { flags |= NodeFlags.QuestionMark; } - if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { + if (isGenerator || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { var method = createNode(SyntaxKind.Method, fullStart); setModifiers(method, modifiers); if (flags) { method.flags = flags; } method.name = name; - fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, method); - method.body = parseFunctionBlockOrSemicolon(); + fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ isGenerator, method); + method.body = parseFunctionBlockOrSemicolon(isGenerator); return finishNode(method); } else { @@ -3164,8 +3312,8 @@ module ts { var node = createNode(kind, fullStart); setModifiers(node, modifiers); node.name = parsePropertyName(); - fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, node); - node.body = parseFunctionBlockOrSemicolon(); + fillSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false, /*isGenerator:*/ false, node); + node.body = parseFunctionBlockOrSemicolon(/*isGenerator:*/ false); return finishNode(node); } @@ -3178,6 +3326,10 @@ module ts { nextToken(); } + if (token === SyntaxKind.AsteriskToken) { + return true; + } + // Try to get the first property-like token following all modifiers. // This can either be an identifier or the 'get' or 'set' keywords. if (isPropertyName()) { @@ -3254,7 +3406,7 @@ module ts { if (token === SyntaxKind.ConstructorKeyword) { return parseConstructorDeclaration(fullStart, modifiers); } - if (token >= SyntaxKind.Identifier || token === SyntaxKind.StringLiteral || token === SyntaxKind.NumericLiteral) { + if (token >= SyntaxKind.Identifier || token === SyntaxKind.StringLiteral || token === SyntaxKind.NumericLiteral || token === SyntaxKind.AsteriskToken) { return parsePropertyMemberDeclaration(fullStart, modifiers); } if (token === SyntaxKind.OpenBracketToken) { @@ -3273,12 +3425,26 @@ module ts { node.typeParameters = parseTypeParameters(); // TODO(jfreeman): Parse arbitrary sequence of heritage clauses and error for order and duplicates - node.baseType = parseOptional(SyntaxKind.ExtendsKeyword) ? parseTypeReference() : undefined; + + // ClassTail[Yield,GeneratorParameter] : See 14.5 + // [~GeneratorParameter]ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } + // [+GeneratorParameter] ClassHeritageopt { ClassBodyopt } + + node.baseType = generatorParameterContext + ? exitYieldContextAnd(parseClassBaseType) + : parseClassBaseType(); + if (parseOptional(SyntaxKind.ImplementsKeyword)) { node.implementedTypes = parseDelimitedList(ParsingContext.BaseTypeReferences, parseTypeReference); } if (parseExpected(SyntaxKind.OpenBraceToken)) { - node.members = parseList(ParsingContext.ClassMembers, /*checkForStrictMode*/ false, parseClassMemberDeclaration); + // ClassTail[Yield,GeneratorParameter] : See 14.5 + // [~GeneratorParameter]ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } + // [+GeneratorParameter] ClassHeritageopt { ClassBodyopt } + + node.members = generatorParameterContext + ? exitYieldContextAnd(parseClassMembers) + : parseClassMembers(); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -3287,6 +3453,14 @@ module ts { return finishNode(node); } + function parseClassMembers() { + return parseList(ParsingContext.ClassMembers, /*checkForStrictMode*/ false, parseClassMemberDeclaration); + } + + function parseClassBaseType(): TypeReferenceNode { + return parseOptional(SyntaxKind.ExtendsKeyword) ? parseTypeReference() : undefined; + } + function parseInterfaceDeclaration(fullStart: number, modifiers: ModifiersArray): InterfaceDeclaration { var node = createNode(SyntaxKind.InterfaceDeclaration, fullStart); setModifiers(node, modifiers); @@ -3725,7 +3899,6 @@ module ts { return checkCallOrNewExpression(node); case SyntaxKind.EnumDeclaration: return checkEnumDeclaration(node); - case SyntaxKind.Parameter: return checkParameter(node); case SyntaxKind.BinaryExpression: return checkBinaryExpression(node); case SyntaxKind.CatchBlock: return checkCatchBlock(node); case SyntaxKind.ClassDeclaration: return checkClassDeclaration(node); @@ -3744,6 +3917,7 @@ module ts { case SyntaxKind.ModuleDeclaration: return checkModuleDeclaration(node); case SyntaxKind.ObjectLiteral: return checkObjectLiteral(node); case SyntaxKind.NumericLiteral: return checkNumericLiteral(node); + case SyntaxKind.Parameter: return checkParameter(node); case SyntaxKind.PostfixOperator: return checkPostfixOperator(node); case SyntaxKind.PrefixOperator: return checkPrefixOperator(node); case SyntaxKind.Property: return checkProperty(node); @@ -3760,6 +3934,7 @@ module ts { case SyntaxKind.VariableDeclaration: return checkVariableDeclaration(node); case SyntaxKind.VariableStatement: return checkVariableStatement(node); case SyntaxKind.WithStatement: return checkWithStatement(node); + case SyntaxKind.YieldExpression: return checkYieldExpression(node); } } @@ -4740,6 +4915,12 @@ module ts { return grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode); } } + + function checkYieldExpression(node: YieldExpression): boolean { + if (!(node.parserContextFlags & ParserContextFlags.ParsedInYieldContext)) { + return grammarErrorOnFirstToken(node, Diagnostics.yield_expression_must_be_contained_within_a_generator_declaration); + } + } } export function createProgram(rootNames: string[], options: CompilerOptions, host: CompilerHost): Program { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8539ac8fc83..68d74385c03 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -183,6 +183,7 @@ module ts { ConditionalExpression, TemplateExpression, TemplateSpan, + YieldExpression, OmittedExpression, // Element Block, @@ -291,7 +292,7 @@ module ts { flags: NodeFlags; // Specific context the parser was in when this node was created. Normally undefined. // Only set when the parser was in some interesting context (like async/yield). - parserContextFlags?: NodeFlags; + parserContextFlags?: ParserContextFlags; id?: number; // Unique id (used to look up NodeLinks) parent?: Node; // Parent node (initialized by binding) symbol?: Symbol; // Symbol declared by node (initialized by binding) @@ -438,6 +439,10 @@ module ts { operator: SyntaxKind; operand: Expression; } + + export interface YieldExpression extends Expression { + expression: Expression; + } export interface BinaryExpression extends Expression { left: Expression;