Initial parser support for destructuring patterns

This commit is contained in:
Anders Hejlsberg 2014-11-05 06:21:58 -08:00
parent 23c9b01024
commit 86f290fbb9
6 changed files with 141 additions and 26 deletions

View file

@ -289,7 +289,6 @@ module ts {
}
declareSymbol(blockScopeContainer.locals, undefined, node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
}
bindChildren(node, SymbolFlags.BlockScopedVariable, /*isBlockScopeContainer*/ false);
}
@ -303,11 +302,17 @@ module ts {
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.VariableDeclaration:
if (node.flags & NodeFlags.BlockScoped) {
bindBlockScopedVariableDeclaration(<Declaration>node);
case SyntaxKind.PatternDeclaration:
if ((<Declaration>node).name) {
if (node.flags & NodeFlags.BlockScoped) {
bindBlockScopedVariableDeclaration(<Declaration>node);
}
else {
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes, /*isBlockScopeContainer*/ false);
}
}
else {
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes, /*isBlockScopeContainer*/ false);
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
}
break;
case SyntaxKind.Property:
@ -377,7 +382,6 @@ module ts {
bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((<SourceFile>node).filename) + '"', /*isBlockScopeContainer*/ true);
break;
}
case SyntaxKind.Block:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
@ -385,9 +389,8 @@ module ts {
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.SwitchStatement:
bindChildren(node, 0 , true);
bindChildren(node, 0, /*isBlockScopeContainer*/ true);
break;
default:
var saveParent = parent;
parent = node;

View file

@ -4255,7 +4255,10 @@ module ts {
case SyntaxKind.BinaryExpression:
return isAssignedInBinaryExpression(<BinaryExpression>node);
case SyntaxKind.VariableDeclaration:
case SyntaxKind.PatternDeclaration:
return isAssignedInVariableDeclaration(<VariableDeclaration>node);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
case SyntaxKind.ArrayLiteral:
case SyntaxKind.ObjectLiteral:
case SyntaxKind.PropertyAccess:
@ -8034,6 +8037,9 @@ module ts {
break;
case SyntaxKind.Parameter:
case SyntaxKind.Property:
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
case SyntaxKind.PatternDeclaration:
case SyntaxKind.ArrayLiteral:
case SyntaxKind.ObjectLiteral:
case SyntaxKind.PropertyAssignment:

View file

@ -122,6 +122,8 @@ module ts {
let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." },
Invalid_template_literal_expected: { code: 1158, category: DiagnosticCategory.Error, key: "Invalid template literal; expected '}'" },
Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1159, category: DiagnosticCategory.Error, key: "Tagged templates are only available when targeting ECMAScript 6 and higher." },
Property_destructuring_pattern_expected: { code: 1160, category: DiagnosticCategory.Error, key: "Property destructuring pattern expected." },
Array_element_destructuring_pattern_expected: { code: 1161, category: DiagnosticCategory.Error, key: "Array element destructuring pattern expected." },
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." },

View file

@ -479,6 +479,14 @@
"category": "Error",
"code": 1159
},
"Property destructuring pattern expected.": {
"category": "Error",
"code": 1160
},
"Array element destructuring pattern expected.": {
"category": "Error",
"code": 1161
},
"Duplicate identifier '{0}'.": {
"category": "Error",

View file

@ -229,6 +229,14 @@ module ts {
return children((<UnionTypeNode>node).types);
case SyntaxKind.ParenType:
return child((<ParenTypeNode>node).type);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
return children((<BindingPattern>node).declarations);
case SyntaxKind.PatternDeclaration:
return child((<PatternDeclaration>node).propertyName) ||
child((<PatternDeclaration>node).name) ||
child((<PatternDeclaration>node).pattern) ||
child((<PatternDeclaration>node).initializer);
case SyntaxKind.ArrayLiteral:
return children((<ArrayLiteral>node).elements);
case SyntaxKind.ObjectLiteral:
@ -506,6 +514,7 @@ module ts {
case SyntaxKind.Property:
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.PatternDeclaration:
return (<VariableDeclaration>parent).initializer === node;
case SyntaxKind.ExpressionStatement:
case SyntaxKind.IfStatement:
@ -663,24 +672,26 @@ module ts {
}
enum ParsingContext {
SourceElements, // Elements in source file
ModuleElements, // Elements in module declaration
BlockStatements, // Statements in block
SwitchClauses, // Clauses in switch statement
SwitchClauseStatements, // Statements in switch clause
TypeMembers, // Members in interface or type literal
ClassMembers, // Members in class declaration
EnumMembers, // Members in enum declaration
BaseTypeReferences, // Type references in extends or implements clause
VariableDeclarations, // Variable declarations in variable statement
ArgumentExpressions, // Expressions in argument list
ObjectLiteralMembers, // Members in object literal
ArrayLiteralMembers, // Members in array literal
Parameters, // Parameters in parameter list
TypeParameters, // Type parameters in type parameter list
TypeArguments, // Type arguments in type argument list
TupleElementTypes, // Element types in tuple element type list
Count // Number of parsing contexts
SourceElements, // Elements in source file
ModuleElements, // Elements in module declaration
BlockStatements, // Statements in block
SwitchClauses, // Clauses in switch statement
SwitchClauseStatements, // Statements in switch clause
TypeMembers, // Members in interface or type literal
ClassMembers, // Members in class declaration
EnumMembers, // Members in enum declaration
BaseTypeReferences, // Type references in extends or implements clause
VariableDeclarations, // Variable declarations in variable statement
ObjectBindingDeclarations, // Binding elements in object binding list
ArrayBindingDeclarations, // Binding elements in array binding list
ArgumentExpressions, // Expressions in argument list
ObjectLiteralMembers, // Members in object literal
ArrayLiteralMembers, // Members in array literal
Parameters, // Parameters in parameter list
TypeParameters, // Type parameters in type parameter list
TypeArguments, // Type arguments in type argument list
TupleElementTypes, // Element types in tuple element type list
Count // Number of parsing contexts
}
enum Tristate {
@ -701,6 +712,8 @@ module ts {
case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected;
case ParsingContext.BaseTypeReferences: return Diagnostics.Type_reference_expected;
case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected;
case ParsingContext.ObjectBindingDeclarations: return Diagnostics.Property_destructuring_pattern_expected;
case ParsingContext.ArrayBindingDeclarations: return Diagnostics.Array_element_destructuring_pattern_expected;
case ParsingContext.ArgumentExpressions: return Diagnostics.Argument_expression_expected;
case ParsingContext.ObjectLiteralMembers: return Diagnostics.Property_assignment_expected;
case ParsingContext.ArrayLiteralMembers: return Diagnostics.Expression_or_comma_expected;
@ -1174,6 +1187,9 @@ module ts {
case ParsingContext.BaseTypeReferences:
return isIdentifier() && ((token !== SyntaxKind.ExtendsKeyword && token !== SyntaxKind.ImplementsKeyword) || !lookAhead(() => (nextToken(), isIdentifier())));
case ParsingContext.VariableDeclarations:
case ParsingContext.ObjectBindingDeclarations:
case ParsingContext.ArrayBindingDeclarations:
return isIdentifierOrPattern();
case ParsingContext.TypeParameters:
return isIdentifier();
case ParsingContext.ArgumentExpressions:
@ -1205,6 +1221,7 @@ module ts {
case ParsingContext.ClassMembers:
case ParsingContext.EnumMembers:
case ParsingContext.ObjectLiteralMembers:
case ParsingContext.ObjectBindingDeclarations:
return token === SyntaxKind.CloseBraceToken;
case ParsingContext.SwitchClauseStatements:
return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.CaseKeyword || token === SyntaxKind.DefaultKeyword;
@ -1220,6 +1237,7 @@ module ts {
return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken;
case ParsingContext.ArrayLiteralMembers:
case ParsingContext.TupleElementTypes:
case ParsingContext.ArrayBindingDeclarations:
return token === SyntaxKind.CloseBracketToken;
case ParsingContext.Parameters:
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
@ -3356,11 +3374,68 @@ module ts {
// DECLARATIONS
function parseBindingDeclaration(flags: NodeFlags, context: ParsingContext): PatternDeclaration {
var node = <PatternDeclaration>createNode(SyntaxKind.PatternDeclaration);
node.flags = flags;
if (context === ParsingContext.ObjectBindingDeclarations) {
var id = parseIdentifier();
if (parseOptional(SyntaxKind.ColonToken)) {
node.propertyName = id;
parseIdentifierOrPatternOfNode(node, flags);
}
else {
node.name = id;
}
}
else {
parseIdentifierOrPatternOfNode(node, flags);
}
return finishNode(node);
}
function parseBindingList(flags: NodeFlags, context: ParsingContext): NodeArray<PatternDeclaration> {
return parseDelimitedList(context, () => parseBindingDeclaration(flags, context), /*allowTrailingComma*/ true);
}
function parseObjectBindingPattern(flags: NodeFlags): BindingPattern {
var node = <BindingPattern>createNode(SyntaxKind.ObjectBindingPattern);
node.flags = flags;
parseExpected(SyntaxKind.OpenBraceToken);
node.declarations = parseBindingList(flags, ParsingContext.ObjectBindingDeclarations);
parseExpected(SyntaxKind.CloseBraceToken);
return finishNode(node);
}
function parseArrayBindingPattern(flags: NodeFlags): BindingPattern {
var node = <BindingPattern>createNode(SyntaxKind.ArrayBindingPattern);
node.flags = flags;
parseExpected(SyntaxKind.OpenBracketToken);
node.declarations = parseBindingList(flags, ParsingContext.ArrayBindingDeclarations);
parseExpected(SyntaxKind.CloseBracketToken);
return finishNode(node);
}
function isIdentifierOrPattern() {
return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken || isIdentifier();
}
function parseIdentifierOrPatternOfNode(node: NameOrPatternNode, flags: NodeFlags) {
if (token === SyntaxKind.OpenBracketToken) {
node.pattern = parseArrayBindingPattern(flags);
}
else if (token === SyntaxKind.OpenBraceToken) {
node.pattern = parseObjectBindingPattern(flags);
}
else {
node.name = parseIdentifier();
}
}
function parseVariableDeclaration(flags: NodeFlags, noIn?: boolean): VariableDeclaration {
var node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration);
node.flags = flags;
var errorCountBeforeVariableDeclaration = file.syntacticErrors.length;
node.name = parseIdentifier();
parseIdentifierOrPatternOfNode(node, flags);
node.type = parseTypeAnnotation();
// Issue any initializer-related errors on the equals token

View file

@ -162,6 +162,10 @@ module ts {
TupleType,
UnionType,
ParenType,
// Binding patterns
ObjectBindingPattern,
ArrayBindingPattern,
PatternDeclaration,
// Expression
ArrayLiteral,
ObjectLiteral,
@ -313,10 +317,27 @@ module ts {
export interface SignatureDeclaration extends Declaration, ParsedSignature { }
export interface VariableDeclaration extends Declaration {
pattern?: BindingPattern;
type?: TypeNode;
initializer?: Expression;
}
export interface BindingPattern extends Node {
declarations: PatternDeclaration[];
}
export interface PatternDeclaration extends Declaration {
propertyName?: Identifier; // Binding property name
name?: Identifier; // Declared variable name (pattern = undefined)
pattern?: BindingPattern; // Nested binding pattern (name = undefined)
initializer?: Expression; // Optional initializer
}
export interface NameOrPatternNode extends Node {
name?: Identifier;
pattern?: BindingPattern;
}
export interface PropertyDeclaration extends VariableDeclaration { }
export interface ParameterDeclaration extends VariableDeclaration { }