Support modifiers on object literal methods and accessors, and question tokens on object literal methods.

This makes parsing of these constructs the same whether they are in an object literal or a class.

This is important for incrementla parsing for knowing if we can reuse these nodes if we run
into them.
This commit is contained in:
Cyrus Najmabadi
2014-12-10 22:30:40 -08:00
parent 4850dfbb8e
commit fe57f3d2e4
24 changed files with 146 additions and 144 deletions
+16 -16
View File
@@ -695,7 +695,7 @@ module ts {
var members = node.members;
for (var i = 0; i < members.length; i++) {
var member = members[i];
if (member.kind === SyntaxKind.Constructor && (<ConstructorDeclaration>member).body) {
if (member.kind === SyntaxKind.Constructor && !isMissingNode((<ConstructorDeclaration>member).body)) {
return <ConstructorDeclaration>member;
}
}
@@ -2654,7 +2654,7 @@ module ts {
returnType = getAnnotatedAccessorType(setter);
}
if (!returnType && !(<FunctionLikeDeclaration>declaration).body) {
if (!returnType && isMissingNode((<FunctionLikeDeclaration>declaration).body)) {
returnType = anyType;
}
}
@@ -6372,7 +6372,7 @@ module ts {
}
// If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check.
if (!func.body || func.body.kind !== SyntaxKind.Block) {
if (isMissingNode(func.body) || func.body.kind !== SyntaxKind.Block) {
return;
}
@@ -7030,7 +7030,7 @@ module ts {
var func = getContainingFunction(node);
if (node.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) {
func = getContainingFunction(node);
if (!(func.kind === SyntaxKind.Constructor && func.body)) {
if (!(func.kind === SyntaxKind.Constructor && !isMissingNode(func.body))) {
error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation);
}
}
@@ -7127,7 +7127,7 @@ module ts {
}
// exit early in the case of signature - super checks are not relevant to them
if (!node.body) {
if (isMissingNode(node.body)) {
return;
}
@@ -7201,7 +7201,7 @@ module ts {
function checkAccessorDeclaration(node: AccessorDeclaration) {
if (fullTypeCheck) {
if (node.kind === SyntaxKind.GetAccessor) {
if (!isInAmbientContext(node) && node.body && !(bodyContainsAReturnStatement(<Block>node.body) || bodyContainsSingleThrowStatement(<Block>node.body))) {
if (!isInAmbientContext(node) && !isMissingNode(node.body) && !(bodyContainsAReturnStatement(<Block>node.body) || bodyContainsSingleThrowStatement(<Block>node.body))) {
error(node.name, Diagnostics.A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement);
}
}
@@ -7290,7 +7290,7 @@ module ts {
// TypeScript 1.0 spec (April 2014): 3.7.2.2
// Specialized signatures are not permitted in conjunction with a function body
if ((<FunctionLikeDeclaration>signatureDeclarationNode).body) {
if (!isMissingNode((<FunctionLikeDeclaration>signatureDeclarationNode).body)) {
error(signatureDeclarationNode, Diagnostics.A_signature_with_an_implementation_cannot_use_a_string_literal_type);
return;
}
@@ -7423,7 +7423,7 @@ module ts {
error(errorNode, diagnostic);
return;
}
else if ((<FunctionLikeDeclaration>subsequentNode).body) {
else if (!isMissingNode((<FunctionLikeDeclaration>subsequentNode).body)) {
error(errorNode, Diagnostics.Function_implementation_name_must_be_0, declarationNameToString(node.name));
return;
}
@@ -7465,7 +7465,7 @@ module ts {
someHaveQuestionToken = someHaveQuestionToken || hasQuestionToken(node);
allHaveQuestionToken = allHaveQuestionToken && hasQuestionToken(node);
if (node.body && bodyDeclaration) {
if (!isMissingNode(node.body) && bodyDeclaration) {
if (isConstructor) {
multipleConstructorImplementation = true;
}
@@ -7477,7 +7477,7 @@ module ts {
reportImplementationExpectedError(previousDeclaration);
}
if (node.body) {
if (!isMissingNode(node.body)) {
if (!bodyDeclaration) {
bodyDeclaration = node;
}
@@ -7660,7 +7660,7 @@ module ts {
// Report an implicit any error if there is no body, no explicit return type, and node is not a private method
// in an ambient context
if (compilerOptions.noImplicitAny && !node.body && !node.type && !isPrivateWithinAmbient(node)) {
if (compilerOptions.noImplicitAny && isMissingNode(node.body) && !node.type && !isPrivateWithinAmbient(node)) {
reportImplicitAnyError(node, anyType);
}
}
@@ -7674,7 +7674,7 @@ module ts {
function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) {
// no rest parameters \ declaration context \ overload - no codegen impact
if (!hasRestParameters(node) || isInAmbientContext(node) || !(<FunctionLikeDeclaration>node).body) {
if (!hasRestParameters(node) || isInAmbientContext(node) || isMissingNode((<FunctionLikeDeclaration>node).body)) {
return;
}
@@ -7706,7 +7706,7 @@ module ts {
}
var root = getRootDeclaration(node);
if (root.kind === SyntaxKind.Parameter && !(<FunctionLikeDeclaration>root.parent).body) {
if (root.kind === SyntaxKind.Parameter && isMissingNode((<FunctionLikeDeclaration>root.parent).body)) {
// just an overload - no codegen impact
return false;
}
@@ -7866,7 +7866,7 @@ module ts {
forEach((<BindingPattern>node.name).elements, checkSourceElement);
}
// For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body
if (node.initializer && getRootDeclaration(node).kind === SyntaxKind.Parameter && !getContainingFunction(node).body) {
if (node.initializer && getRootDeclaration(node).kind === SyntaxKind.Parameter && isMissingNode(getContainingFunction(node).body)) {
error(node, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation);
return;
}
@@ -8612,7 +8612,7 @@ module ts {
var declarations = symbol.declarations;
for (var i = 0; i < declarations.length; i++) {
var declaration = declarations[i];
if ((declaration.kind === SyntaxKind.ClassDeclaration || (declaration.kind === SyntaxKind.FunctionDeclaration && (<FunctionLikeDeclaration>declaration).body)) && !isInAmbientContext(declaration)) {
if ((declaration.kind === SyntaxKind.ClassDeclaration || (declaration.kind === SyntaxKind.FunctionDeclaration && !isMissingNode((<FunctionLikeDeclaration>declaration).body))) && !isInAmbientContext(declaration)) {
return declaration;
}
}
@@ -9499,7 +9499,7 @@ module ts {
}
function isImplementationOfOverload(node: FunctionLikeDeclaration) {
if (node.body) {
if (!isMissingNode(node.body)) {
var symbol = getSymbolOfNode(node);
var signaturesOfSymbol = getSignaturesOfSymbol(symbol);
// If this function body corresponds to function with multiple signature, it is implementation of overload
+2 -2
View File
@@ -268,7 +268,7 @@ module ts {
function getFirstConstructorWithBody(node: ClassDeclaration): ConstructorDeclaration {
return forEach(node.members, member => {
if (member.kind === SyntaxKind.Constructor && (<ConstructorDeclaration>member).body) {
if (member.kind === SyntaxKind.Constructor && !isMissingNode((<ConstructorDeclaration>member).body)) {
return <ConstructorDeclaration>member;
}
});
@@ -3106,7 +3106,7 @@ module ts {
}
function emitFunctionDeclaration(node: FunctionLikeDeclaration) {
if (!node.body) {
if (isMissingNode(node.body)) {
return emitPinnedOrTripleSlashComments(node);
}
+56 -32
View File
@@ -61,6 +61,10 @@ module ts {
}
export function isMissingNode(node: Node) {
if (node === undefined) {
return true;
}
return node.pos === node.end && node.kind !== SyntaxKind.EndOfFileToken;
}
@@ -1377,7 +1381,7 @@ module ts {
return inStrictModeContext() ? token > SyntaxKind.LastFutureReservedWord : token > SyntaxKind.LastReservedWord;
}
function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): boolean {
function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage): boolean {
if (token === kind) {
nextToken();
return true;
@@ -1385,7 +1389,7 @@ module ts {
// Report specific message if provided with one. Otherwise, report generic fallback message.
if (diagnosticMessage) {
parseErrorAtCurrentToken(diagnosticMessage, arg0);
parseErrorAtCurrentToken(diagnosticMessage);
}
else {
parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));
@@ -1420,7 +1424,7 @@ module ts {
return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak();
}
function parseSemicolon(diagnosticMessage?: DiagnosticMessage): boolean {
function parseSemicolon(): boolean {
if (canParseSemicolon()) {
if (token === SyntaxKind.SemicolonToken) {
// consume the semicolon if it was explicitly provided.
@@ -1430,7 +1434,7 @@ module ts {
return true;
}
else {
return parseExpected(SyntaxKind.SemicolonToken, diagnosticMessage);
return parseExpected(SyntaxKind.SemicolonToken);
}
}
@@ -3438,21 +3442,22 @@ module ts {
var fullStart = scanner.getStartPos();
var initialToken = token;
var modifiers = parseModifiers();
if (parseContextualModifier(SyntaxKind.GetKeyword) || parseContextualModifier(SyntaxKind.SetKeyword)) {
var kind = initialToken === SyntaxKind.GetKeyword ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor;
return parseAccessorDeclaration(kind, fullStart, /*modifiers*/undefined);
return parseAccessorDeclaration(kind, fullStart, modifiers);
}
var asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
var tokenIsIdentifier = isIdentifier();
var nameToken = token;
var propertyName = parsePropertyName();
if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) {
return parseMethodDeclaration(fullStart, /*modifiers:*/ undefined, asteriskToken, propertyName, /*questionToken:*/ undefined, /*requireBlock:*/ true);
}
// Disallowing of optional property assignments happens in the grammar checker.
var questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) {
return parseMethodDeclaration(fullStart, modifiers, asteriskToken, propertyName, questionToken);
}
// Parse to check if it is short-hand property assignment or normal property assignment
if ((token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBraceToken) && tokenIsIdentifier) {
@@ -3514,9 +3519,9 @@ module ts {
}
// STATEMENTS
function parseBlock(kind: SyntaxKind, ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean): Block {
function parseBlock(kind: SyntaxKind, ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean, diagnosticMessage?: DiagnosticMessage): Block {
var node = <Block>createNode(kind);
if (parseExpected(SyntaxKind.OpenBraceToken) || ignoreMissingOpenBrace) {
if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) {
node.statements = parseList(ParsingContext.BlockStatements, checkForStrictMode, parseStatement);
parseExpected(SyntaxKind.CloseBraceToken);
}
@@ -3526,11 +3531,11 @@ module ts {
return finishNode(node);
}
function parseFunctionBlock(allowYield: boolean, ignoreMissingOpenBrace: boolean): Block {
function parseFunctionBlock(allowYield: boolean, ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
var savedYieldContext = inYieldContext();
setYieldContext(allowYield);
var block = parseBlock(SyntaxKind.Block, ignoreMissingOpenBrace, /*checkForStrictMode*/ true);
var block = parseBlock(SyntaxKind.Block, ignoreMissingOpenBrace, /*checkForStrictMode*/ true, diagnosticMessage);
setYieldContext(savedYieldContext);
@@ -3949,13 +3954,13 @@ module ts {
return undefined;
}
function parseFunctionBlockOrSemicolon(isGenerator: boolean): Block {
if (token === SyntaxKind.OpenBraceToken) {
return parseFunctionBlock(isGenerator, /*ignoreMissingOpenBrace:*/ false);
function parseFunctionBlockOrSemicolon(isGenerator: boolean, diagnosticMessage?: DiagnosticMessage): Block {
if (token !== SyntaxKind.OpenBraceToken && canParseSemicolon()) {
parseSemicolon();
return;
}
parseSemicolon(Diagnostics.or_expected);
return undefined;
return parseFunctionBlock(isGenerator, /*ignoreMissingOpenBrace:*/ false, diagnosticMessage);
}
// DECLARATIONS
@@ -4070,7 +4075,7 @@ module ts {
node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
node.name = parseIdentifier();
fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ !!node.asteriskToken, /*requireCompleteParameterList:*/ false, node);
node.body = parseFunctionBlockOrSemicolon(!!node.asteriskToken);
node.body = parseFunctionBlockOrSemicolon(!!node.asteriskToken, Diagnostics.or_expected);
return finishNode(node);
}
@@ -4079,18 +4084,18 @@ module ts {
setModifiers(node, modifiers);
parseExpected(SyntaxKind.ConstructorKeyword);
fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, node);
node.body = parseFunctionBlockOrSemicolon(/*isGenerator:*/ false);
node.body = parseFunctionBlockOrSemicolon(/*isGenerator:*/ false, Diagnostics.or_expected);
return finishNode(node);
}
function parseMethodDeclaration(fullStart: number, modifiers: ModifiersArray, asteriskToken: Node, name: DeclarationName, questionToken: Node, requireBlock: boolean): MethodDeclaration {
function parseMethodDeclaration(fullStart: number, modifiers: ModifiersArray, asteriskToken: Node, name: DeclarationName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration {
var method = <MethodDeclaration>createNode(SyntaxKind.MethodDeclaration, fullStart);
setModifiers(method, modifiers);
method.asteriskToken = asteriskToken;
method.name = name;
method.questionToken = questionToken;
fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ !!asteriskToken, /*requireCompleteParameterList:*/ false, method);
method.body = requireBlock ? parseFunctionBlock(!!asteriskToken, /*ignoreMissingOpenBrace:*/ false) : parseFunctionBlockOrSemicolon(!!asteriskToken);
method.body = parseFunctionBlockOrSemicolon(!!asteriskToken, diagnosticMessage);
return finishNode(method);
}
@@ -4102,7 +4107,7 @@ module ts {
// report an error in the grammar checker.
var questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) {
return parseMethodDeclaration(fullStart, modifiers, asteriskToken, name, questionToken, /*requireBlock:*/ false);
return parseMethodDeclaration(fullStart, modifiers, asteriskToken, name, questionToken, Diagnostics.or_expected);
}
else {
var property = <PropertyDeclaration>createNode(SyntaxKind.PropertyDeclaration, fullStart);
@@ -4681,6 +4686,7 @@ module ts {
// We're automatically in an ambient context if this is a .d.ts file.
var inAmbientContext = fileExtensionIs(file.filename, ".d.ts");
var inFunctionBlock = false;
var inObjectLiteralExpression = false;
var inBlock = false;
var parent: Node;
visitNode(file);
@@ -4700,7 +4706,10 @@ module ts {
if (node.kind === SyntaxKind.Block || node.kind === SyntaxKind.TryBlock || node.kind === SyntaxKind.FinallyBlock) {
inBlock = true;
}
var savedInObjectLiteralExpression = inObjectLiteralExpression;
if (node.kind === SyntaxKind.ObjectLiteralExpression) {
inObjectLiteralExpression = true;
}
var savedInAmbientContext = inAmbientContext
if (node.flags & NodeFlags.Ambient) {
inAmbientContext = true;
@@ -4711,6 +4720,7 @@ module ts {
inAmbientContext = savedInAmbientContext;
inFunctionBlock = savedInFunctionBlock;
inBlock = savedInBlock;
inObjectLiteralExpression = savedInObjectLiteralExpression;
}
parent = savedParent;
@@ -5172,7 +5182,7 @@ module ts {
}
function checkFunctionDeclaration(node: FunctionLikeDeclaration) {
return checkForDisallowedModifiersInBlock(node) ||
return checkForDisallowedModifiersInBlockOrObjectLiteral(node) ||
checkAnySignatureDeclaration(node) ||
checkFunctionName(node.name) ||
checkForBodyInAmbientContext(node.body, /*isConstructor:*/ false) ||
@@ -5200,7 +5210,8 @@ module ts {
}
function checkGetAccessor(node: MethodDeclaration) {
return checkAnySignatureDeclaration(node) ||
return checkForDisallowedModifiersInBlockOrObjectLiteral(node) ||
checkAnySignatureDeclaration(node) ||
checkAccessor(node);
}
@@ -5298,12 +5309,22 @@ module ts {
}
function checkMethod(node: MethodDeclaration) {
if (checkAnySignatureDeclaration(node) ||
if (checkForDisallowedModifiersInBlockOrObjectLiteral(node) ||
checkAnySignatureDeclaration(node) ||
checkForBodyInAmbientContext(node.body, /*isConstructor:*/ false) ||
checkForGenerator(node)) {
return true;
}
if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) {
if (checkForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) {
return true;
}
else if (node.body === undefined) {
return grammarErrorAtPos(node.end - 1, ";".length, Diagnostics._0_expected, "{");
}
}
if (node.parent.kind === SyntaxKind.ClassDeclaration) {
if (checkForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) {
return true;
@@ -5316,7 +5337,7 @@ module ts {
if (inAmbientContext) {
return checkForDisallowedComputedProperty(node.name, Diagnostics.Computed_property_names_are_not_allowed_in_an_ambient_context);
}
else if (!node.body) {
else if (isMissingNode(node.body)) {
return checkForDisallowedComputedProperty(node.name, Diagnostics.Computed_property_names_are_not_allowed_in_method_overloads);
}
}
@@ -5711,7 +5732,8 @@ module ts {
}
function checkSetAccessor(node: MethodDeclaration) {
return checkAnySignatureDeclaration(node) ||
return checkForDisallowedModifiersInBlockOrObjectLiteral(node) ||
checkAnySignatureDeclaration(node) ||
checkAccessor(node);
}
@@ -5908,14 +5930,16 @@ module ts {
}
function checkVariableStatement(node: VariableStatement) {
return checkForDisallowedModifiersInBlock(node) ||
return checkForDisallowedModifiersInBlockOrObjectLiteral(node) ||
checkVariableDeclarations(node.declarations) ||
checkForDisallowedLetOrConstStatement(node);
}
function checkForDisallowedModifiersInBlock(node: Node) {
if (inBlock && node.modifiers) {
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
function checkForDisallowedModifiersInBlockOrObjectLiteral(node: Node) {
if (node.modifiers) {
if (inBlock || inObjectLiteralExpression) {
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
}
}
}