Add support for parsing yield expressions.

Conflicts:
	src/services/syntax/SyntaxGenerator.js.map
This commit is contained in:
Cyrus Najmabadi 2014-11-11 18:50:19 -08:00
parent 6895efc7c5
commit 7ab80d260e
16 changed files with 279 additions and 80 deletions

View File

@ -96,6 +96,7 @@ module TypeScript {
Type_expected: "Type expected.",
Template_literal_cannot_be_used_as_an_element_name: "Template literal cannot be used as an element name.",
Computed_property_names_cannot_be_used_here: "Computed property names cannot be used here.",
yield_expression_must_be_contained_within_a_generator_declaration: "'yield' expression must be contained within a generator declaration.",
Duplicate_identifier_0: "Duplicate identifier '{0}'.",
The_name_0_does_not_exist_in_the_current_scope: "The name '{0}' does not exist in the current scope.",
The_name_0_does_not_refer_to_a_value: "The name '{0}' does not refer to a value.",

View File

@ -98,6 +98,7 @@ module TypeScript {
"Type expected.": { "code": 1110, "category": DiagnosticCategory.Error },
"Template literal cannot be used as an element name.": { "code": 1111, "category": DiagnosticCategory.Error },
"Computed property names cannot be used here.": { "code": 1112, "category": DiagnosticCategory.Error },
"'yield' expression must be contained within a generator declaration.": { "code": 1113, "category": DiagnosticCategory.Error },
"Duplicate identifier '{0}'.": { "code": 2000, "category": DiagnosticCategory.Error },
"The name '{0}' does not exist in the current scope.": { "code": 2001, "category": DiagnosticCategory.Error },
"The name '{0}' does not refer to a value.": { "code": 2002, "category": DiagnosticCategory.Error },

View File

@ -379,6 +379,10 @@
"category": "Error",
"code": 1112
},
"'yield' expression must be contained within a generator declaration.": {
"category": "Error",
"code": 1113
},
"Duplicate identifier '{0}'.": {
"category": "Error",
"code": 2000

View File

@ -599,30 +599,31 @@ var TypeScript;
SyntaxKind[SyntaxKind["OmittedExpression"] = 187] = "OmittedExpression";
SyntaxKind[SyntaxKind["TemplateExpression"] = 188] = "TemplateExpression";
SyntaxKind[SyntaxKind["TemplateAccessExpression"] = 189] = "TemplateAccessExpression";
SyntaxKind[SyntaxKind["VariableDeclaration"] = 190] = "VariableDeclaration";
SyntaxKind[SyntaxKind["VariableDeclarator"] = 191] = "VariableDeclarator";
SyntaxKind[SyntaxKind["ArgumentList"] = 192] = "ArgumentList";
SyntaxKind[SyntaxKind["ParameterList"] = 193] = "ParameterList";
SyntaxKind[SyntaxKind["TypeArgumentList"] = 194] = "TypeArgumentList";
SyntaxKind[SyntaxKind["TypeParameterList"] = 195] = "TypeParameterList";
SyntaxKind[SyntaxKind["HeritageClause"] = 196] = "HeritageClause";
SyntaxKind[SyntaxKind["EqualsValueClause"] = 197] = "EqualsValueClause";
SyntaxKind[SyntaxKind["CaseSwitchClause"] = 198] = "CaseSwitchClause";
SyntaxKind[SyntaxKind["DefaultSwitchClause"] = 199] = "DefaultSwitchClause";
SyntaxKind[SyntaxKind["ElseClause"] = 200] = "ElseClause";
SyntaxKind[SyntaxKind["CatchClause"] = 201] = "CatchClause";
SyntaxKind[SyntaxKind["FinallyClause"] = 202] = "FinallyClause";
SyntaxKind[SyntaxKind["TemplateClause"] = 203] = "TemplateClause";
SyntaxKind[SyntaxKind["TypeParameter"] = 204] = "TypeParameter";
SyntaxKind[SyntaxKind["Constraint"] = 205] = "Constraint";
SyntaxKind[SyntaxKind["SimplePropertyAssignment"] = 206] = "SimplePropertyAssignment";
SyntaxKind[SyntaxKind["FunctionPropertyAssignment"] = 207] = "FunctionPropertyAssignment";
SyntaxKind[SyntaxKind["Parameter"] = 208] = "Parameter";
SyntaxKind[SyntaxKind["EnumElement"] = 209] = "EnumElement";
SyntaxKind[SyntaxKind["TypeAnnotation"] = 210] = "TypeAnnotation";
SyntaxKind[SyntaxKind["ComputedPropertyName"] = 211] = "ComputedPropertyName";
SyntaxKind[SyntaxKind["ExternalModuleReference"] = 212] = "ExternalModuleReference";
SyntaxKind[SyntaxKind["ModuleNameModuleReference"] = 213] = "ModuleNameModuleReference";
SyntaxKind[SyntaxKind["YieldExpression"] = 190] = "YieldExpression";
SyntaxKind[SyntaxKind["VariableDeclaration"] = 191] = "VariableDeclaration";
SyntaxKind[SyntaxKind["VariableDeclarator"] = 192] = "VariableDeclarator";
SyntaxKind[SyntaxKind["ArgumentList"] = 193] = "ArgumentList";
SyntaxKind[SyntaxKind["ParameterList"] = 194] = "ParameterList";
SyntaxKind[SyntaxKind["TypeArgumentList"] = 195] = "TypeArgumentList";
SyntaxKind[SyntaxKind["TypeParameterList"] = 196] = "TypeParameterList";
SyntaxKind[SyntaxKind["HeritageClause"] = 197] = "HeritageClause";
SyntaxKind[SyntaxKind["EqualsValueClause"] = 198] = "EqualsValueClause";
SyntaxKind[SyntaxKind["CaseSwitchClause"] = 199] = "CaseSwitchClause";
SyntaxKind[SyntaxKind["DefaultSwitchClause"] = 200] = "DefaultSwitchClause";
SyntaxKind[SyntaxKind["ElseClause"] = 201] = "ElseClause";
SyntaxKind[SyntaxKind["CatchClause"] = 202] = "CatchClause";
SyntaxKind[SyntaxKind["FinallyClause"] = 203] = "FinallyClause";
SyntaxKind[SyntaxKind["TemplateClause"] = 204] = "TemplateClause";
SyntaxKind[SyntaxKind["TypeParameter"] = 205] = "TypeParameter";
SyntaxKind[SyntaxKind["Constraint"] = 206] = "Constraint";
SyntaxKind[SyntaxKind["SimplePropertyAssignment"] = 207] = "SimplePropertyAssignment";
SyntaxKind[SyntaxKind["FunctionPropertyAssignment"] = 208] = "FunctionPropertyAssignment";
SyntaxKind[SyntaxKind["Parameter"] = 209] = "Parameter";
SyntaxKind[SyntaxKind["EnumElement"] = 210] = "EnumElement";
SyntaxKind[SyntaxKind["TypeAnnotation"] = 211] = "TypeAnnotation";
SyntaxKind[SyntaxKind["ComputedPropertyName"] = 212] = "ComputedPropertyName";
SyntaxKind[SyntaxKind["ExternalModuleReference"] = 213] = "ExternalModuleReference";
SyntaxKind[SyntaxKind["ModuleNameModuleReference"] = 214] = "ModuleNameModuleReference";
SyntaxKind[SyntaxKind["FirstStandardKeyword"] = SyntaxKind.BreakKeyword] = "FirstStandardKeyword";
SyntaxKind[SyntaxKind["LastStandardKeyword"] = SyntaxKind.WithKeyword] = "LastStandardKeyword";
SyntaxKind[SyntaxKind["FirstFutureReservedKeyword"] = SyntaxKind.ClassKeyword] = "FirstFutureReservedKeyword";
@ -1867,6 +1868,16 @@ var definitions = [
{ name: 'expression', type: 'IUnaryExpressionSyntax' }
]
},
{
name: 'YieldExpressionSyntax',
baseType: 'ISyntaxNode',
interfaces: ['IExpressionSyntax'],
children: [
{ name: 'yieldKeyword', isToken: true },
{ name: 'asterixToken', isToken: true, isOptional: true },
{ name: 'expression', type: 'IExpressionSyntax', isOptional: true }
]
},
{
name: 'DebuggerStatementSyntax',
baseType: 'ISyntaxNode',

File diff suppressed because one or more lines are too long

View File

@ -15,13 +15,14 @@ module TypeScript {
// only be used by the incremental parser if it is parsed in the same strict context as before.
// last masks off the part of the int
//
// The width of the node is stored in the remainder of the int. This allows us up to 256MB
// for a node by using all 28 bits. However, in the common case, we'll use less than 28 bits
// The width of the node is stored in the remainder of the int. This allows us up to 128MB
// for a node by using all 27 bits. However, in the common case, we'll use less than 27 bits
// for the width. Thus, the info will be stored in a single int in chakra.
NodeDataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
NodeIncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
NodeParsedInStrictModeMask = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
NodeParsedInDisallowInMask = 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000
NodeFullWidthShift = 4, // 1111 1111 1111 1111 1111 1111 1111 0000
NodeParsedInAllowYieldMask = 0x00000010, // 0000 0000 0000 0000 0000 0000 0001 0000
NodeFullWidthShift = 5, // 1111 1111 1111 1111 1111 1111 1110 0000
}
}

View File

@ -161,6 +161,9 @@ module TypeScript.Parser {
// for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for
// 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost
// all nodes would need extra state on them to store this info.
//
// Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6
// grammar specification.
var strictMode: boolean = false;
var disallowIn: boolean = false;
var allowYield: boolean = false;
@ -237,26 +240,28 @@ module TypeScript.Parser {
// TODO(cyrusn): This may be too conservative. Perhaps we could reuse hte node and
// attach the skipped tokens in front? For now though, being conservative is nice and
// safe, and likely won't ever affect perf.
if (_skippedTokens) {
return null;
if (!_skippedTokens) {
var node = source.currentNode();
// We can only reuse a node if it was parsed under the same strict mode that we're
// currently in. i.e. if we originally parsed a node in non-strict mode, but then
// the user added 'using strict' at the top of the file, then we can't use that node
// again as the presense of strict mode may cause us to parse the tokens in the file
// differetly.
//
// Note: we *can* reuse tokens when the strict mode changes. That's because tokens
// are unaffected by strict mode. It's just the parser will decide what to do with it
// differently depending on what mode it is in.
if (node &&
parsedInStrictMode(node) === strictMode &&
parsedInDisallowInMode(node) === disallowIn &&
parsedInAllowYieldMode(node) === allowYield) {
return node;
}
}
var node = source.currentNode();
// We can only reuse a node if it was parsed under the same strict mode that we're
// currently in. i.e. if we originally parsed a node in non-strict mode, but then
// the user added 'using strict' at the top of the file, then we can't use that node
// again as the presense of strict mode may cause us to parse the tokens in the file
// differetly.
//
// Note: we *can* reuse tokens when the strict mode changes. That's because tokens
// are unaffected by strict mode. It's just the parser will decide what to do with it
// differently depending on what mode it is in.
if (!node || parsedInStrictMode(node) !== strictMode || parsedInDisallowInMode(node) !== disallowIn) {
return undefined;
}
return node;
return undefined;
}
function currentToken(): ISyntaxToken {
@ -382,6 +387,12 @@ module TypeScript.Parser {
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 (tokenKind === SyntaxKind.YieldKeyword && allowYield) {
return false;
}
// Keywords are only identifiers if they're FutureReservedStrictWords and we're in
// strict mode. *Or* if it's a typescript 'keyword'.
if (tokenKind >= SyntaxKind.FirstFutureReservedStrictKeyword) {
@ -575,7 +586,8 @@ module TypeScript.Parser {
function updateParseNodeData() {
parseNodeData =
(strictMode ? SyntaxConstants.NodeParsedInStrictModeMask : 0) |
(disallowIn ? SyntaxConstants.NodeParsedInDisallowInMask : 0);
(disallowIn ? SyntaxConstants.NodeParsedInDisallowInMask : 0) |
(allowYield ? SyntaxConstants.NodeParsedInAllowYieldMask : 0);
}
function setStrictMode(val: boolean) {
@ -588,6 +600,11 @@ module TypeScript.Parser {
updateParseNodeData();
}
function setAllowYield(val: boolean) {
allowYield = val;
updateParseNodeData();
}
function parseSourceUnit(): SourceUnitSyntax {
// Note: saving and restoring the 'isInStrictMode' state is not really necessary here
// (as it will never be read afterwards). However, for symmetry with the rest of the
@ -921,6 +938,30 @@ module TypeScript.Parser {
setDisallowIn(false);
return result;
}
function allowYieldAnd<T>(func: () => T): T {
if (allowYield) {
// no need to do anything special if 'yield' is already allowed.
return func();
}
setAllowYield(true);
var result = func();
setAllowYield(false);
return result;
}
function disallowYieldAnd<T>(func: () => T): T {
if (allowYield) {
setAllowYield(false);
var result = func();
setAllowYield(true);
return result;
}
// no need to do anything special if 'yield' is already disallowed.
return func();
}
function tryParseEnumElementEqualsValueClause(): EqualsValueClauseSyntax {
return isEqualsValueClause(/*inParameter*/ false) ? allowInAnd(parseEqualsValueClause) : undefined;
@ -1047,7 +1088,7 @@ module TypeScript.Parser {
return parseGetAccessor(modifiers, _currenToken);
}
else if (tokenKind === SyntaxKind.SetKeyword) {
return parseSetccessor(modifiers, _currenToken);
return parseSetAccessor(modifiers, _currenToken);
}
else {
throw Errors.invalidOperation();
@ -1058,14 +1099,14 @@ module TypeScript.Parser {
return new GetAccessorSyntax(parseNodeData,
modifiers, consumeToken(getKeyword), parsePropertyName(),
parseCallSignature(/*requireCompleteTypeParameterList:*/ false),
parseFunctionBlock());
parseFunctionBlock(/*allowYield:*/ false));
}
function parseSetccessor(modifiers: ISyntaxToken[], setKeyword: ISyntaxToken): SetAccessorSyntax {
function parseSetAccessor(modifiers: ISyntaxToken[], setKeyword: ISyntaxToken): SetAccessorSyntax {
return new SetAccessorSyntax(parseNodeData,
modifiers, consumeToken(setKeyword), parsePropertyName(),
parseCallSignature(/*requireCompleteTypeParameterList:*/ false),
parseFunctionBlock());
parseFunctionBlock(/*allowYield:*/ false));
}
function isClassElement(inErrorRecovery: boolean): boolean {
@ -1194,7 +1235,7 @@ module TypeScript.Parser {
parseModifiers(),
eatToken(SyntaxKind.ConstructorKeyword),
parseCallSignature(/*requireCompleteTypeParameterList:*/ false),
isBlockOrArrow() ? parseFunctionBlock() : eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false));
isBlockOrArrow() ? parseFunctionBlock(/*allowYield:*/ false) : eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false));
}
function parseMemberFunctionDeclaration(modifiers: ISyntaxToken[], asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax): MemberFunctionDeclarationSyntax {
@ -1206,7 +1247,9 @@ module TypeScript.Parser {
asterixToken,
propertyName,
parseCallSignature(/*requireCompleteTypeParameterList:*/ false),
isBlockOrArrow() ? parseFunctionBlock() : eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false));
isBlockOrArrow()
? parseFunctionBlock(/*allowYield:*/ asterixToken !== undefined)
: eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false));
}
function parseMemberVariableDeclaration(modifiers: ISyntaxToken[], propertyName: IPropertyNameSyntax): MemberVariableDeclarationSyntax {
@ -1235,13 +1278,16 @@ module TypeScript.Parser {
// Note: if we see an arrow after the close paren, then try to parse out a function
// block anyways. It's likely the user just though '=> expr' was legal anywhere a
// block was legal.
var asterixToken: ISyntaxToken;
return new FunctionDeclarationSyntax(parseNodeData,
parseModifiers(),
eatToken(SyntaxKind.FunctionKeyword),
tryEatToken(SyntaxKind.AsteriskToken),
asterixToken = tryEatToken(SyntaxKind.AsteriskToken),
eatIdentifierToken(),
parseCallSignature(/*requireCompleteTypeParameterList:*/ false),
isBlockOrArrow() ? parseFunctionBlock() : eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false));
isBlockOrArrow()
? parseFunctionBlock(/*allowYield:*/ asterixToken !== undefined)
: eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false));
}
function parseModuleName(): INameSyntax {
@ -2038,6 +2084,12 @@ module TypeScript.Parser {
// For function expressions.
case SyntaxKind.FunctionKeyword:
return true;
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;
}
return isIdentifier(currentToken);
@ -2233,21 +2285,12 @@ module TypeScript.Parser {
function tryParseAssignmentExpressionOrHigherWorker(force: boolean): IExpressionSyntax {
// Augmented by TypeScript:
//
// AssignmentExpression[in]:
// 1) ConditionalExpression[in]
// 2) LeftHandSideExpression = AssignmentExpression[in]
// 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[in]
// 4) ArrowFunctionExpression <-- added by TypeScript
//
// Open spec question. Right now, there is no 'ArrowFunctionExpression[in]' variant.
// Thus, if the user has:
//
// for (var a = () => b in c) {}
//
// Then we will fail to parse (because the 'in' will be consumed as part of the body of
// the lambda, and not as part of the 'for' statement). This is likely not an issue
// whatsoever as there seems to be no good reason why anyone would ever write code like
// the above.
// 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).
@ -2257,6 +2300,10 @@ module TypeScript.Parser {
// LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done
// with AssignmentExpression if we see one.
var _currentToken = currentToken();
if (isYieldExpression(_currentToken)) {
return parseYieldExpression(_currentToken);
}
var arrowFunction = tryParseAnyArrowFunctionExpression(_currentToken);
if (arrowFunction) {
return arrowFunction;
@ -2294,6 +2341,64 @@ module TypeScript.Parser {
return parseConditionalExpressionRest(leftOperand);
}
function isYieldExpression(_currentToken: ISyntaxToken): boolean {
if (_currentToken.kind === 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 (allowYield) {
return true;
}
if (strictMode) {
// 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.
var token1 = peekToken(1);
if (!isOnDifferentLineThanPreviousToken(token1) && isIdentifier(token1)) {
return true;
}
}
return false;
}
function parseYieldExpression(yieldKeyword: ISyntaxToken): YieldExpressionSyntax {
// YieldExpression[In] :
// yield
// yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]
// yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]
yieldKeyword = consumeToken(yieldKeyword);
var _currentToken = currentToken();
if (!isOnDifferentLineThanPreviousToken(_currentToken) &&
(_currentToken.kind === SyntaxKind.AsteriskToken || isExpression(_currentToken))) {
return new YieldExpressionSyntax(parseNodeData, yieldKeyword, tryEatToken(SyntaxKind.AsteriskToken), parseAssignmentExpressionOrHigher());
}
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 new YieldExpressionSyntax(parseNodeData, yieldKeyword, /*asterixToken:*/ undefined, /*expression;*/ undefined);
}
}
function tryParseAnyArrowFunctionExpression(_currentToken: ISyntaxToken): IExpressionSyntax {
return isSimpleArrowFunctionExpression(_currentToken)
? parseSimpleArrowFunctionExpression()
@ -2824,12 +2929,13 @@ module TypeScript.Parser {
}
function parseFunctionExpression(functionKeyword: ISyntaxToken): FunctionExpressionSyntax {
var asterixToken: ISyntaxToken;
return new FunctionExpressionSyntax(parseNodeData,
consumeToken(functionKeyword),
tryEatToken(SyntaxKind.AsteriskToken),
asterixToken = tryEatToken(SyntaxKind.AsteriskToken),
eatOptionalIdentifierToken(),
parseCallSignature(/*requireCompleteTypeParameterList:*/ false),
parseFunctionBlock());
parseFunctionBlock(/*allowYield:*/ asterixToken !== undefined));
}
function parseObjectCreationExpression(newKeyword: ISyntaxToken): ObjectCreationExpressionSyntax {
@ -2963,7 +3069,7 @@ module TypeScript.Parser {
// { FunctionBody }
if (isBlock()) {
return parseFunctionBlock();
return parseFunctionBlock(/*allowYield:*/ false);
}
// We didn't have a block. However, we may be in an error situation. For example,
@ -3217,7 +3323,8 @@ module TypeScript.Parser {
}
}
// All the rest of the property assignments start with property names or an asterix token. They are:
// All the rest of the property assignments start with property names or an asterix.
// They are:
// id: e
// [e1]: e2
// id() { }
@ -3329,7 +3436,7 @@ module TypeScript.Parser {
asterixToken,
propertyName,
parseCallSignature(/*requireCompleteTypeParameterList:*/ false),
parseFunctionBlock());
parseFunctionBlock(/*allowYield:*/ asterixToken !== undefined));
}
function parseArrayLiteralExpression(openBracketToken: ISyntaxToken): ArrayLiteralExpressionSyntax {
@ -3377,7 +3484,7 @@ module TypeScript.Parser {
eatToken(SyntaxKind.CloseBraceToken));
}
function parseFunctionBlock(): BlockSyntax {
function parseFunctionBlock(_allowYield: boolean): BlockSyntax {
// If we got an errant => then we want to parse what's coming up without requiring an
// open brace. ItWe do this because it's not uncommon for people to get confused as to
// where/when they can use an => and we want to have good error recovery here.
@ -3393,11 +3500,13 @@ module TypeScript.Parser {
}
var openBraceToken = eatToken(SyntaxKind.OpenBraceToken);
var statements = hasEqualsGreaterThanToken || openBraceToken.fullWidth() > 0
? parseFunctionBlockStatements()
: [];
var statements: IStatementSyntax[];
return new BlockSyntax(parseNodeData, openBraceToken, statements, eatToken(SyntaxKind.CloseBraceToken));
if (hasEqualsGreaterThanToken || openBraceToken.fullWidth() > 0) {
statements = _allowYield ? allowYieldAnd(parseFunctionBlockStatements) : disallowYieldAnd(parseFunctionBlockStatements);
}
return new BlockSyntax(parseNodeData, openBraceToken, statements || [], eatToken(SyntaxKind.CloseBraceToken));
}
function parseFunctionBlockStatements() {

View File

@ -1018,6 +1018,12 @@ module TypeScript.PrettyPrinter {
visitNodeOrToken(this, node.expression);
}
public visitYieldExpression(node: YieldExpressionSyntax): void {
this.appendToken(node.yieldKeyword);
this.ensureSpace();
visitNodeOrToken(this, node.expression);
}
public visitDebuggerStatement(node: DebuggerStatementSyntax): void {
this.appendToken(node.debuggerKeyword);
this.appendToken(node.semicolonToken);

View File

@ -35,6 +35,15 @@ module TypeScript {
return (info & SyntaxConstants.NodeParsedInDisallowInMask) !== 0;
}
export function parsedInAllowYieldMode(node: ISyntaxNode): boolean {
var info = node.__data;
if (info === undefined) {
return false;
}
return (info & SyntaxConstants.NodeParsedInAllowYieldMask) !== 0;
}
export function previousToken(token: ISyntaxToken): ISyntaxToken {
var start = token.fullStart();
if (start === 0) {

View File

@ -1005,6 +1005,15 @@ var definitions:ITypeDefinition[] = [
<any>{ name: 'voidKeyword', isToken: true, excludeFromAST: true },
<any>{ name: 'expression', type: 'IUnaryExpressionSyntax' }]
},
<any>{
name: 'YieldExpressionSyntax',
baseType: 'ISyntaxNode',
interfaces: ['IExpressionSyntax'],
children: [
<any>{ name: 'yieldKeyword', isToken: true },
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
<any>{ name: 'expression', type: 'IExpressionSyntax', isOptional: true }]
},
<any>{
name: 'DebuggerStatementSyntax',
baseType: 'ISyntaxNode',

View File

@ -523,6 +523,13 @@ module TypeScript {
}
export interface TemplateAccessExpressionConstructor { new (data: number, expression: ILeftHandSideExpressionSyntax, templateExpression: IPrimaryExpressionSyntax): TemplateAccessExpressionSyntax }
export interface YieldExpressionSyntax extends ISyntaxNode, IExpressionSyntax {
yieldKeyword: ISyntaxToken;
asterixToken: ISyntaxToken;
expression: IExpressionSyntax;
}
export interface YieldExpressionConstructor { new (data: number, yieldKeyword: ISyntaxToken, asterixToken: ISyntaxToken, expression: IExpressionSyntax): YieldExpressionSyntax }
export interface VariableDeclarationSyntax extends ISyntaxNode {
varKeyword: ISyntaxToken;
variableDeclarators: ISeparatedSyntaxList<VariableDeclaratorSyntax>;

View File

@ -234,6 +234,7 @@ module TypeScript {
OmittedExpression,
TemplateExpression,
TemplateAccessExpression,
YieldExpression,
// Variable declarations
VariableDeclaration,

View File

@ -1427,6 +1427,25 @@ module TypeScript {
}
}
export var YieldExpressionSyntax: YieldExpressionConstructor = <any>function(data: number, yieldKeyword: ISyntaxToken, asterixToken: ISyntaxToken, expression: IExpressionSyntax) {
if (data) { this.__data = data; }
this.yieldKeyword = yieldKeyword,
this.asterixToken = asterixToken,
this.expression = expression,
yieldKeyword.parent = this,
asterixToken && (asterixToken.parent = this),
expression && (expression.parent = this);
};
YieldExpressionSyntax.prototype.kind = SyntaxKind.YieldExpression;
YieldExpressionSyntax.prototype.childCount = 3;
YieldExpressionSyntax.prototype.childAt = function(index: number): ISyntaxElement {
switch (index) {
case 0: return this.yieldKeyword;
case 1: return this.asterixToken;
case 2: return this.expression;
}
}
export var VariableDeclarationSyntax: VariableDeclarationConstructor = <any>function(data: number, varKeyword: ISyntaxToken, variableDeclarators: ISeparatedSyntaxList<VariableDeclaratorSyntax>) {
if (data) { this.__data = data; }
this.varKeyword = varKeyword,

View File

@ -1555,13 +1555,22 @@ module TypeScript {
public visitDeleteExpression(node: DeleteExpressionSyntax): void {
if (parsedInStrictMode(node) && node.expression.kind === SyntaxKind.IdentifierName) {
this.pushDiagnostic(firstToken(node), DiagnosticCode.delete_cannot_be_called_on_an_identifier_in_strict_mode);
this.pushDiagnostic(node.deleteKeyword, DiagnosticCode.delete_cannot_be_called_on_an_identifier_in_strict_mode);
return;
}
super.visitDeleteExpression(node);
}
public visitYieldExpression(node: YieldExpressionSyntax): void {
if (!parsedInAllowYieldMode(node)) {
this.pushDiagnostic(node.yieldKeyword, DiagnosticCode.yield_expression_must_be_contained_within_a_generator_declaration);
return;
}
super.visitYieldExpression(node);
}
private checkIllegalAssignment(node: BinaryExpressionSyntax): boolean {
if (parsedInStrictMode(node) && SyntaxFacts.isAssignmentOperatorToken(node.operatorToken.kind) && this.isEvalOrArguments(node.left)) {
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.left)]);

View File

@ -72,6 +72,7 @@ module TypeScript {
case SyntaxKind.OmittedExpression: return visitor.visitOmittedExpression(<OmittedExpressionSyntax>element);
case SyntaxKind.TemplateExpression: return visitor.visitTemplateExpression(<TemplateExpressionSyntax>element);
case SyntaxKind.TemplateAccessExpression: return visitor.visitTemplateAccessExpression(<TemplateAccessExpressionSyntax>element);
case SyntaxKind.YieldExpression: return visitor.visitYieldExpression(<YieldExpressionSyntax>element);
case SyntaxKind.VariableDeclaration: return visitor.visitVariableDeclaration(<VariableDeclarationSyntax>element);
case SyntaxKind.VariableDeclarator: return visitor.visitVariableDeclarator(<VariableDeclaratorSyntax>element);
case SyntaxKind.ArgumentList: return visitor.visitArgumentList(<ArgumentListSyntax>element);
@ -170,6 +171,7 @@ module TypeScript {
visitOmittedExpression(node: OmittedExpressionSyntax): any;
visitTemplateExpression(node: TemplateExpressionSyntax): any;
visitTemplateAccessExpression(node: TemplateAccessExpressionSyntax): any;
visitYieldExpression(node: YieldExpressionSyntax): any;
visitVariableDeclaration(node: VariableDeclarationSyntax): any;
visitVariableDeclarator(node: VariableDeclaratorSyntax): any;
visitArgumentList(node: ArgumentListSyntax): any;

View File

@ -472,6 +472,12 @@ module TypeScript {
visitNodeOrToken(this, node.templateExpression);
}
public visitYieldExpression(node: YieldExpressionSyntax): void {
this.visitToken(node.yieldKeyword);
this.visitOptionalToken(node.asterixToken);
visitNodeOrToken(this, node.expression);
}
public visitVariableDeclaration(node: VariableDeclarationSyntax): void {
this.visitToken(node.varKeyword);
this.visitList(node.variableDeclarators);