mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-07 14:34:35 -06:00
Add support for parsing yield expressions.
Conflicts: src/services/syntax/SyntaxGenerator.js.map
This commit is contained in:
parent
6895efc7c5
commit
7ab80d260e
@ -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.",
|
||||
|
||||
@ -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 },
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
@ -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
|
||||
}
|
||||
}
|
||||
@ -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() {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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>;
|
||||
|
||||
@ -234,6 +234,7 @@ module TypeScript {
|
||||
OmittedExpression,
|
||||
TemplateExpression,
|
||||
TemplateAccessExpression,
|
||||
YieldExpression,
|
||||
|
||||
// Variable declarations
|
||||
VariableDeclaration,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)]);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user