Merge pull request #1346 from Microsoft/destructuring

Destructuring
This commit is contained in:
Anders Hejlsberg
2014-12-09 11:39:23 -08:00
45 changed files with 2586 additions and 1080 deletions
+24 -17
View File
@@ -332,10 +332,9 @@ module ts {
// symbol as its sole member. To the rest of the system, this symbol will be indistinguishable
// from an actual type literal symbol you would have gotten had you used the long form.
var symbolKind = node.kind === SyntaxKind.FunctionType ? SymbolFlags.CallSignature : SymbolFlags.ConstructSignature;
var symbol = createSymbol(symbolKind, getDeclarationName(node));
addDeclarationToSymbol(symbol, node, symbolKind);
bindChildren(node, symbolKind, /*isBlockScopeContainer:*/ false);
var symbol = createSymbol(SymbolFlags.Signature, getDeclarationName(node));
addDeclarationToSymbol(symbol, node, SymbolFlags.Signature);
bindChildren(node, SymbolFlags.Signature, /*isBlockScopeContainer:*/ false);
var typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
@@ -376,10 +375,13 @@ module ts {
}
declareSymbol(blockScopeContainer.locals, undefined, node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
}
bindChildren(node, SymbolFlags.BlockScopedVariable, /*isBlockScopeContainer*/ false);
}
function getDestructuringParameterName(node: Declaration) {
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
}
function bind(node: Node) {
node.parent = parent;
switch (node.kind) {
@@ -387,10 +389,19 @@ module ts {
bindDeclaration(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.Parameter:
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false);
if (isBindingPattern((<Declaration>node).name)) {
bindAnonymousDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, getDestructuringParameterName(<Declaration>node), /*isBlockScopeContainer*/ false);
}
else {
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false);
}
break;
case SyntaxKind.VariableDeclaration:
if (node.flags & NodeFlags.BlockScoped) {
case SyntaxKind.BindingElement:
if (isBindingPattern((<Declaration>node).name)) {
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
}
else if (node.flags & NodeFlags.BlockScoped) {
bindBlockScopedVariableDeclaration(<Declaration>node);
}
else {
@@ -399,6 +410,8 @@ module ts {
break;
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
bindDeclaration(<Declaration>node, SymbolFlags.Property | ((<PropertyDeclaration>node).questionToken ? SymbolFlags.Optional : 0), SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
bindDeclaration(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
@@ -407,10 +420,9 @@ module ts {
bindDeclaration(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.CallSignature:
bindDeclaration(<Declaration>node, SymbolFlags.CallSignature, 0, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.ConstructSignature:
bindDeclaration(<Declaration>node, SymbolFlags.ConstructSignature, 0, /*isBlockScopeContainer*/ true);
case SyntaxKind.IndexSignature:
bindDeclaration(<Declaration>node, SymbolFlags.Signature, 0, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
@@ -418,12 +430,9 @@ module ts {
// as other properties in the object literal. So we use SymbolFlags.PropertyExcludes
// so that it will conflict with any other object literal members with the same
// name.
bindDeclaration(<Declaration>node, SymbolFlags.Method,
bindDeclaration(<Declaration>node, SymbolFlags.Method | ((<MethodDeclaration>node).questionToken ? SymbolFlags.Optional : 0),
isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.IndexSignature:
bindDeclaration(<Declaration>node, SymbolFlags.IndexSignature, 0, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.FunctionDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes, /*isBlockScopeContainer*/ true);
break;
@@ -483,7 +492,6 @@ module ts {
bindAnonymousDeclaration(<SourceFile>node, SymbolFlags.ValueModule, '"' + removeFileExtension((<SourceFile>node).filename) + '"', /*isBlockScopeContainer*/ true);
break;
}
case SyntaxKind.Block:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchClause:
@@ -491,9 +499,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;
+613 -449
View File
File diff suppressed because it is too large Load Diff
@@ -140,6 +140,10 @@ module ts {
Binary_digit_expected: { code: 1177, category: DiagnosticCategory.Error, key: "Binary digit expected." },
Octal_digit_expected: { code: 1178, category: DiagnosticCategory.Error, key: "Octal digit expected." },
Unexpected_token_expected: { code: 1179, category: DiagnosticCategory.Error, key: "Unexpected token. '{' expected." },
Property_destructuring_pattern_expected: { code: 1180, category: DiagnosticCategory.Error, key: "Property destructuring pattern expected." },
Array_element_destructuring_pattern_expected: { code: 1181, category: DiagnosticCategory.Error, key: "Array element destructuring pattern expected." },
A_destructuring_declaration_must_have_an_initializer: { code: 1182, category: DiagnosticCategory.Error, key: "A destructuring declaration must have an initializer." },
Destructuring_declarations_are_not_allowed_in_ambient_contexts: { code: 1183, category: DiagnosticCategory.Error, key: "Destructuring declarations are not allowed in ambient contexts." },
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." },
@@ -232,8 +236,6 @@ module ts {
Overload_signature_is_not_compatible_with_function_implementation: { code: 2394, category: DiagnosticCategory.Error, key: "Overload signature is not compatible with function implementation." },
Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local: { code: 2395, category: DiagnosticCategory.Error, key: "Individual declarations in merged declaration {0} must be all exported or all local." },
Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters: { code: 2396, category: DiagnosticCategory.Error, key: "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters." },
Duplicate_identifier_i_Compiler_uses_i_to_initialize_rest_parameter: { code: 2397, category: DiagnosticCategory.Error, key: "Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter." },
Expression_resolves_to_variable_declaration_i_that_compiler_uses_to_initialize_rest_parameter: { code: 2398, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter." },
Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference: { code: 2399, category: DiagnosticCategory.Error, key: "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference." },
Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference: { code: 2400, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference." },
Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference: { code: 2401, category: DiagnosticCategory.Error, key: "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference." },
@@ -289,6 +291,9 @@ module ts {
Type_alias_0_circularly_references_itself: { code: 2456, category: DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." },
Type_alias_name_cannot_be_0: { code: 2457, category: DiagnosticCategory.Error, key: "Type alias name cannot be '{0}'" },
An_AMD_module_cannot_have_multiple_name_assignments: { code: 2458, category: DiagnosticCategory.Error, key: "An AMD module cannot have multiple name assignments." },
Type_0_has_no_property_1_and_no_string_index_signature: { code: 2459, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}' and no string index signature." },
Type_0_has_no_property_1: { code: 2460, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}'." },
Type_0_is_not_an_array_type: { code: 2461, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type." },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
+28 -8
View File
@@ -552,6 +552,22 @@
"category": "Error",
"code": 1179
},
"Property destructuring pattern expected.": {
"category": "Error",
"code": 1180
},
"Array element destructuring pattern expected.": {
"category": "Error",
"code": 1181
},
"A destructuring declaration must have an initializer.": {
"category": "Error",
"code": 1182
},
"Destructuring declarations are not allowed in ambient contexts.": {
"category": "Error",
"code": 1183
},
"Duplicate identifier '{0}'.": {
"category": "Error",
@@ -921,14 +937,6 @@
"category": "Error",
"code": 2396
},
"Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter.": {
"category": "Error",
"code": 2397
},
"Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter.": {
"category": "Error",
"code": 2398
},
"Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.": {
"category": "Error",
"code": 2399
@@ -1153,6 +1161,18 @@
"category": "Error",
"code": 2458
},
"Type '{0}' has no property '{1}' and no string index signature.": {
"category": "Error",
"code": 2459
},
"Type '{0}' has no property '{1}'.": {
"category": "Error",
"code": 2460
},
"Type '{0}' is not an array type.": {
"category": "Error",
"code": 2461
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
+403 -121
View File
@@ -441,7 +441,7 @@ module ts {
handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning));
}
function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableOrParameterDeclaration, type: TypeNode | StringLiteralExpression, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode | StringLiteralExpression, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
write(": ");
if (type) {
@@ -1003,7 +1003,7 @@ module ts {
}
}
function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableOrParameterDeclaration) {
function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableLikeDeclaration) {
// if this is property of type literal,
// or is parameter of method/call/construct/index signature of type literal
// emit only if type is specified
@@ -1263,7 +1263,12 @@ module ts {
if (node.dotDotDotToken) {
write("...");
}
writeTextOfNode(currentSourceFile, node.name);
if (isBindingPattern(node.name)) {
write("_" + indexOf((<FunctionLikeDeclaration>node.parent).parameters, node));
}
else {
writeTextOfNode(currentSourceFile, node.name);
}
if (node.initializer || hasQuestionToken(node)) {
write("?");
}
@@ -1490,6 +1495,9 @@ module ts {
var currentSourceFile: SourceFile;
var extendsEmitted = false;
var tempCount = 0;
var tempVariables: Identifier[];
var tempParameters: Identifier[];
/** write emitted output to disk*/
var writeEmittedFiles = writeJavaScriptFile;
@@ -1885,6 +1893,44 @@ module ts {
writeFile(compilerHost, diagnostics, jsFilePath, emitOutput, writeByteOrderMark);
}
// Create a temporary variable with a unique unused name. The forLoopVariable parameter signals that the
// name should be one that is appropriate for a for loop variable.
function createTempVariable(location: Node, forLoopVariable?: boolean): Identifier {
var name = forLoopVariable ? "_i" : undefined;
while (true) {
if (name && resolver.isUnknownIdentifier(location, name)) {
break;
}
// _a .. _h, _j ... _z, _0, _1, ...
name = "_" + (tempCount < 25 ? String.fromCharCode(tempCount + (tempCount < 8 ? 0: 1) + CharacterCodes.a) : tempCount - 25);
tempCount++;
}
var result = <Identifier>createNode(SyntaxKind.Identifier);
result.text = name;
return result;
}
function recordTempDeclaration(name: Identifier) {
if (!tempVariables) {
tempVariables = [];
}
tempVariables.push(name);
}
function emitTempDeclarations(newLine: boolean) {
if (tempVariables) {
if (newLine) {
writeLine();
}
else {
write(" ");
}
write("var ");
emitCommaList(tempVariables);
write(";");
}
}
function emitTokenText(tokenKind: SyntaxKind, startPos: number, emitFn?: () => void) {
var tokenString = tokenToString(tokenKind);
if (emitFn) {
@@ -1903,16 +1949,13 @@ module ts {
}
}
function emitTrailingCommaIfPresent(nodeList: NodeArray<Node>, isMultiline: boolean): void {
function emitTrailingCommaIfPresent(nodeList: NodeArray<Node>): void {
if (nodeList.hasTrailingComma) {
write(",");
if (isMultiline) {
writeLine();
}
}
}
function emitCommaList(nodes: NodeArray<Node>, includeTrailingComma: boolean, count?: number) {
function emitCommaList(nodes: Node[], count?: number) {
if (!(count >= 0)) {
count = nodes.length;
}
@@ -1923,14 +1966,10 @@ module ts {
}
emit(nodes[i]);
}
if (includeTrailingComma) {
emitTrailingCommaIfPresent(nodes, /*isMultiline*/ false);
}
}
}
function emitMultiLineList(nodes: NodeArray<Node>, includeTrailingComma: boolean) {
function emitMultiLineList(nodes: Node[]) {
if (nodes) {
for (var i = 0; i < nodes.length; i++) {
if (i) {
@@ -1939,10 +1978,6 @@ module ts {
writeLine();
emit(nodes[i]);
}
if (includeTrailingComma) {
emitTrailingCommaIfPresent(nodes, /*isMultiline*/ true);
}
}
}
@@ -1970,8 +2005,9 @@ module ts {
}
function emitLiteral(node: LiteralExpression) {
var text = getLiteralText();
var text = compilerOptions.target < ScriptTarget.ES6 && isTemplateLiteralKind(node.kind) ? getTemplateLiteralAsStringLiteral(node) :
node.parent ? getSourceTextOfNodeFromSourceFile(currentSourceFile, node) :
node.text;
if (compilerOptions.sourceMap && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
writer.writeLiteral(text);
}
@@ -1982,14 +2018,6 @@ module ts {
else {
write(text);
}
function getLiteralText() {
if (compilerOptions.target < ScriptTarget.ES6 && isTemplateLiteralKind(node.kind)) {
return getTemplateLiteralAsStringLiteral(node)
}
return getSourceTextOfNodeFromSourceFile(currentSourceFile, node);
}
}
function getTemplateLiteralAsStringLiteral(node: LiteralExpression): string {
@@ -2133,6 +2161,7 @@ module ts {
switch (parent.kind) {
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyAssignment:
@@ -2171,7 +2200,10 @@ module ts {
}
function emitIdentifier(node: Identifier) {
if (!isNotExpressionIdentifier(node)) {
if (!node.parent) {
write(node.text);
}
else if (!isNotExpressionIdentifier(node)) {
emitExpressionIdentifier(node);
}
else {
@@ -2201,18 +2233,34 @@ module ts {
}
}
function emitObjectBindingPattern(node: BindingPattern) {
write("{ ");
emitCommaList(node.elements);
emitTrailingCommaIfPresent(node.elements);
write(" }");
}
function emitArrayBindingPattern(node: BindingPattern) {
write("[");
emitCommaList(node.elements);
emitTrailingCommaIfPresent(node.elements);
write("]");
}
function emitArrayLiteral(node: ArrayLiteralExpression) {
if (node.flags & NodeFlags.MultiLine) {
write("[");
increaseIndent();
emitMultiLineList(node.elements, /*includeTrailingComma*/ true);
emitMultiLineList(node.elements);
emitTrailingCommaIfPresent(node.elements);
decreaseIndent();
writeLine();
write("]");
}
else {
write("[");
emitCommaList(node.elements, /*includeTrailingComma*/ true);
emitCommaList(node.elements);
emitTrailingCommaIfPresent(node.elements);
write("]");
}
}
@@ -2224,14 +2272,20 @@ module ts {
else if (node.flags & NodeFlags.MultiLine) {
write("{");
increaseIndent();
emitMultiLineList(node.properties, /*includeTrailingComma*/ compilerOptions.target >= ScriptTarget.ES5);
emitMultiLineList(node.properties);
if (compilerOptions.target >= ScriptTarget.ES5) {
emitTrailingCommaIfPresent(node.properties);
}
decreaseIndent();
writeLine();
write("}");
}
else {
write("{ ");
emitCommaList(node.properties, /*includeTrailingComma*/ compilerOptions.target >= ScriptTarget.ES5);
emitCommaList(node.properties);
if (compilerOptions.target >= ScriptTarget.ES5) {
emitTrailingCommaIfPresent(node.properties);
}
write(" }");
}
}
@@ -2242,30 +2296,19 @@ module ts {
write("]");
}
function emitDownlevelMethod(node: MethodDeclaration) {
if (!isObjectLiteralMethod(node)) {
return;
}
emitLeadingComments(node);
emit(node.name);
write(": ");
write("function ");
emitSignatureAndBody(node);
emitTrailingComments(node);
}
function emitMethod(node: MethodDeclaration) {
if (!isObjectLiteralMethod(node)) {
return;
}
emitLeadingComments(node);
emit(node.name);
if (compilerOptions.target < ScriptTarget.ES6) {
write(": function ");
}
emitSignatureAndBody(node);
emitTrailingComments(node);
}
function emitPropertyAssignment(node: PropertyDeclaration) {
emitLeadingComments(node);
emit(node.name);
@@ -2274,18 +2317,9 @@ module ts {
emitTrailingComments(node);
}
function emitDownlevelShorthandPropertyAssignment(node: ShorthandPropertyAssignment) {
emitLeadingComments(node);
// Emit identifier as an identifier
emit(node.name);
write(": ");
// Even though this is stored as identifier treat it as an expression
// Short-hand, { x }, is equivalent of normal form { x: x }
emitExpressionIdentifier(node.name);
emitTrailingComments(node);
}
function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) {
emitLeadingComments(node);
emit(node.name);
// If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example:
// module m {
// export var y;
@@ -2294,16 +2328,14 @@ module ts {
// export var obj = { y };
// }
// The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version
var prefix = resolver.getExpressionNamePrefix(node.name);
if (prefix) {
emitDownlevelShorthandPropertyAssignment(node);
}
// If short-hand property has no prefix, emit it as short-hand.
else {
emitLeadingComments(node);
emit(node.name);
emitTrailingComments(node);
if (compilerOptions.target < ScriptTarget.ES6 || resolver.getExpressionNamePrefix(node.name)) {
// Emit identifier as an identifier
write(": ");
// Even though this is stored as identifier treat it as an expression
// Short-hand, { x }, is equivalent of normal form { x: x }
emitExpressionIdentifier(node.name);
}
emitTrailingComments(node);
}
function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean {
@@ -2356,13 +2388,13 @@ module ts {
emitThis(node.expression);
if (node.arguments.length) {
write(", ");
emitCommaList(node.arguments, /*includeTrailingComma*/ false);
emitCommaList(node.arguments);
}
write(")");
}
else {
write("(");
emitCommaList(node.arguments, /*includeTrailingComma*/ false);
emitCommaList(node.arguments);
write(")");
}
}
@@ -2372,7 +2404,7 @@ module ts {
emit(node.expression);
if (node.arguments) {
write("(");
emitCommaList(node.arguments, /*includeTrailingComma*/ false);
emitCommaList(node.arguments);
write(")");
}
}
@@ -2470,11 +2502,16 @@ module ts {
function emitBinaryExpression(node: BinaryExpression) {
emit(node.left);
if (node.operator !== SyntaxKind.CommaToken) write(" ");
write(tokenToString(node.operator));
write(" ");
emit(node.right);
if (node.operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
emitDestructuring(node);
}
else {
emit(node.left);
if (node.operator !== SyntaxKind.CommaToken) write(" ");
write(tokenToString(node.operator));
write(" ");
emit(node.right);
}
}
function emitConditionalExpression(node: ConditionalExpression) {
@@ -2494,6 +2531,9 @@ module ts {
emitCaptureThisForNodeIfNecessary(node.parent);
}
emitLines(node.statements);
if (node.kind === SyntaxKind.ModuleBlock) {
emitTempDeclarations(/*newLine*/ true);
}
decreaseIndent();
writeLine();
emitToken(SyntaxKind.CloseBraceToken, node.statements.end);
@@ -2581,7 +2621,7 @@ module ts {
emitToken(SyntaxKind.VarKeyword, endPos);
}
write(" ");
emitCommaList(node.declarations, /*includeTrailingComma*/ false);
emitCommaList(node.declarations);
}
if (node.initializer) {
emit(node.initializer);
@@ -2738,10 +2778,214 @@ module ts {
emitEnd(node.name);
}
function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, value?: Expression) {
var emitCount = 0;
// An exported declaration is actually emitted as an assignment (to a property on the module object), so
// temporary variables in an exported declaration need to have real declarations elsewhere
var isDeclaration = (root.kind === SyntaxKind.VariableDeclaration && !(root.flags & NodeFlags.Export)) || root.kind === SyntaxKind.Parameter;
if (root.kind === SyntaxKind.BinaryExpression) {
emitAssignmentExpression(<BinaryExpression>root);
}
else {
emitBindingElement(<BindingElement>root, value);
}
function emitAssignment(name: Identifier, value: Expression) {
if (emitCount++) {
write(", ");
}
if (name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement)) {
emitModuleMemberName(<Declaration>name.parent);
}
else {
emit(name);
}
write(" = ");
emit(value);
}
function ensureIdentifier(expr: Expression): Expression {
if (expr.kind !== SyntaxKind.Identifier) {
var identifier = createTempVariable(root);
if (!isDeclaration) {
recordTempDeclaration(identifier);
}
emitAssignment(identifier, expr);
expr = identifier;
}
return expr;
}
function createVoidZero(): Expression {
var zero = <LiteralExpression>createNode(SyntaxKind.NumericLiteral);
zero.text = "0";
var result = <PrefixUnaryExpression>createNode(SyntaxKind.PrefixUnaryExpression);
result.operator = SyntaxKind.VoidKeyword;
result.operand = zero;
return result;
}
function createDefaultValueCheck(value: Expression, defaultValue: Expression): Expression {
// The value expression will be evaluated twice, so for anything but a simple identifier
// we need to generate a temporary variable
value = ensureIdentifier(value);
// Return the expression 'value === void 0 ? defaultValue : value'
var equals = <BinaryExpression>createNode(SyntaxKind.BinaryExpression);
equals.left = value;
equals.operator = SyntaxKind.EqualsEqualsEqualsToken;
equals.right = createVoidZero();
var cond = <ConditionalExpression>createNode(SyntaxKind.ConditionalExpression);
cond.condition = equals;
cond.whenTrue = defaultValue;
cond.whenFalse = value;
return cond;
}
function createNumericLiteral(value: number) {
var node = <LiteralExpression>createNode(SyntaxKind.NumericLiteral);
node.text = "" + value;
return node;
}
function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
if (expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
return <LeftHandSideExpression>expr;
}
var node = <ParenthesizedExpression>createNode(SyntaxKind.ParenthesizedExpression);
node.expression = expr;
return node;
}
function createPropertyAccess(object: Expression, propName: Identifier): Expression {
if (propName.kind !== SyntaxKind.Identifier) {
return createElementAccess(object, propName);
}
var node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression);
node.expression = parenthesizeForAccess(object);
node.name = propName;
return node;
}
function createElementAccess(object: Expression, index: Expression): Expression {
var node = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression);
node.expression = parenthesizeForAccess(object);
node.argumentExpression = index;
return node;
}
function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression) {
var properties = target.properties;
if (properties.length !== 1) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
value = ensureIdentifier(value);
}
for (var i = 0; i < properties.length; i++) {
var p = properties[i];
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
// TODO(andersh): Computed property support
var propName = <Identifier>((<PropertyAssignment>p).name);
emitDestructuringAssignment((<PropertyAssignment>p).initializer || propName, createPropertyAccess(value, propName));
}
}
}
function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression) {
var elements = target.elements;
if (elements.length !== 1) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
value = ensureIdentifier(value);
}
for (var i = 0; i < elements.length; i++) {
var e = elements[i];
if (e.kind !== SyntaxKind.OmittedExpression) {
emitDestructuringAssignment(e, createElementAccess(value, createNumericLiteral(i)));
}
}
}
function emitDestructuringAssignment(target: Expression, value: Expression) {
if (target.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>target).operator === SyntaxKind.EqualsToken) {
value = createDefaultValueCheck(value,(<BinaryExpression>target).right);
target = (<BinaryExpression>target).left;
}
if (target.kind === SyntaxKind.ObjectLiteralExpression) {
emitObjectLiteralAssignment(<ObjectLiteralExpression>target, value);
}
else if (target.kind === SyntaxKind.ArrayLiteralExpression) {
emitArrayLiteralAssignment(<ArrayLiteralExpression>target, value);
}
else {
emitAssignment(<Identifier>target, value);
}
}
function emitAssignmentExpression(root: BinaryExpression) {
var target = root.left;
var value = root.right;
if (root.parent.kind === SyntaxKind.ExpressionStatement) {
emitDestructuringAssignment(target, value);
}
else {
if (root.parent.kind !== SyntaxKind.ParenthesizedExpression) {
write("(");
}
value = ensureIdentifier(value);
emitDestructuringAssignment(target, value);
write(", ");
emit(value);
if (root.parent.kind !== SyntaxKind.ParenthesizedExpression) {
write(")");
}
}
}
function emitBindingElement(target: BindingElement, value: Expression) {
if (target.initializer) {
// Combine value and initializer
value = value ? createDefaultValueCheck(value, target.initializer) : target.initializer;
}
else if (!value) {
// Use 'void 0' in absence of value and initializer
value = createVoidZero();
}
if (isBindingPattern(target.name)) {
var pattern = <BindingPattern>target.name;
var elements = pattern.elements;
if (elements.length !== 1) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
value = ensureIdentifier(value);
}
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
// Rewrite element to a declaration with an initializer that fetches property
var propName = element.propertyName || <Identifier>element.name;
emitBindingElement(element, createPropertyAccess(value, propName));
}
else if (element.kind !== SyntaxKind.OmittedExpression) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, createNumericLiteral(i)));
}
}
}
else {
emitAssignment(<Identifier>target.name, value);
}
}
}
function emitVariableDeclaration(node: VariableDeclaration) {
emitLeadingComments(node);
emitModuleMemberName(node);
emitOptional(" = ", node.initializer);
if (isBindingPattern(node.name)) {
emitDestructuring(node);
}
else {
emitModuleMemberName(node);
emitOptional(" = ", node.initializer);
}
emitTrailingComments(node);
}
@@ -2758,32 +3002,57 @@ module ts {
write("var ");
}
}
emitCommaList(node.declarations, /*includeTrailingComma*/ false);
emitCommaList(node.declarations);
write(";");
emitTrailingComments(node);
}
function emitParameter(node: ParameterDeclaration) {
emitLeadingComments(node);
emit(node.name);
if (isBindingPattern(node.name)) {
var name = createTempVariable(node);
if (!tempParameters) {
tempParameters = [];
}
tempParameters.push(name);
emit(name);
}
else {
emit(node.name);
}
// TODO(andersh): Enable ES6 code generation below
//if (node.propertyName) {
// emit(node.propertyName);
// write(": ");
//}
//emit(node.name);
//emitOptional(" = ", node.initializer);
emitTrailingComments(node);
}
function emitDefaultValueAssignments(node: FunctionLikeDeclaration) {
forEach(node.parameters, param => {
if (param.initializer) {
var tempIndex = 0;
forEach(node.parameters, p => {
if (isBindingPattern(p.name)) {
writeLine();
emitStart(param);
write("var ");
emitDestructuring(p, tempParameters[tempIndex]);
write(";");
tempIndex++;
}
else if (p.initializer) {
writeLine();
emitStart(p);
write("if (");
emitNode(param.name);
emitNode(p.name);
write(" === void 0)");
emitEnd(param);
emitEnd(p);
write(" { ");
emitStart(param);
emitNode(param.name);
emitStart(p);
emitNode(p.name);
write(" = ");
emitNode(param.initializer);
emitEnd(param);
emitNode(p.initializer);
emitEnd(p);
write("; }");
}
});
@@ -2793,6 +3062,7 @@ module ts {
if (hasRestParameters(node)) {
var restIndex = node.parameters.length - 1;
var restParam = node.parameters[restIndex];
var tempName = createTempVariable(node, /*forLoopVariable*/ true).text;
writeLine();
emitLeadingComments(restParam);
emitStart(restParam);
@@ -2804,22 +3074,22 @@ module ts {
writeLine();
write("for (");
emitStart(restParam);
write("var _i = " + restIndex + ";");
write("var " + tempName + " = " + restIndex + ";");
emitEnd(restParam);
write(" ");
emitStart(restParam);
write("_i < arguments.length;");
write(tempName + " < arguments.length;");
emitEnd(restParam);
write(" ");
emitStart(restParam);
write("_i++");
write(tempName + "++");
emitEnd(restParam);
write(") {");
increaseIndent();
writeLine();
emitStart(restParam);
emitNode(restParam.name);
write("[_i - " + restIndex + "] = arguments[_i];");
write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];");
emitEnd(restParam);
decreaseIndent();
writeLine();
@@ -2867,13 +3137,19 @@ module ts {
increaseIndent();
write("(");
if (node) {
emitCommaList(node.parameters, /*includeTrailingComma*/ false, node.parameters.length - (hasRestParameters(node) ? 1 : 0));
emitCommaList(node.parameters, node.parameters.length - (hasRestParameters(node) ? 1 : 0));
}
write(")");
decreaseIndent();
}
function emitSignatureAndBody(node: FunctionLikeDeclaration) {
var saveTempCount = tempCount;
var saveTempVariables = tempVariables;
var saveTempParameters = tempParameters;
tempCount = 0;
tempVariables = undefined;
tempParameters = undefined;
emitSignatureParameters(node);
write(" {");
scopeEmitStart(node);
@@ -2896,7 +3172,9 @@ module ts {
write("return ");
emitNode(node.body);
emitEnd(node.body);
write("; ");
write(";");
emitTempDeclarations(/*newLine*/ false);
write(" ");
emitStart(node.body);
write("}");
emitEnd(node.body);
@@ -2913,11 +3191,12 @@ module ts {
write(";");
emitTrailingComments(node.body);
}
emitTempDeclarations(/*newLine*/ true);
writeLine();
if (node.body.kind === SyntaxKind.Block) {
emitLeadingCommentsOfPosition((<Block>node.body).statements.end);
decreaseIndent();
emitToken(SyntaxKind.CloseBraceToken, (<Block>node.body).statements.end);
emitToken(SyntaxKind.CloseBraceToken,(<Block>node.body).statements.end);
}
else {
decreaseIndent();
@@ -2936,6 +3215,9 @@ module ts {
emitEnd(node);
write(";");
}
tempCount = saveTempCount;
tempVariables = saveTempVariables;
tempParameters = saveTempParameters;
}
function findInitialSuperCall(ctor: ConstructorDeclaration): ExpressionStatement {
@@ -3139,6 +3421,12 @@ module ts {
emitTrailingComments(node);
function emitConstructorOfClass() {
var saveTempCount = tempCount;
var saveTempVariables = tempVariables;
var saveTempParameters = tempParameters;
tempCount = 0;
tempVariables = undefined;
tempParameters = undefined;
// Emit the constructor overload pinned comments
forEach(node.members, member => {
if (member.kind === SyntaxKind.Constructor && !(<ConstructorDeclaration>member).body) {
@@ -3187,6 +3475,7 @@ module ts {
if (superCall) statements = statements.slice(1);
emitLines(statements);
}
emitTempDeclarations(/*newLine*/ true);
writeLine();
if (ctor) {
emitLeadingCommentsOfPosition((<Block>ctor.body).statements.end);
@@ -3198,6 +3487,9 @@ module ts {
if (ctor) {
emitTrailingComments(ctor);
}
tempCount = saveTempCount;
tempVariables = saveTempVariables;
tempParameters = saveTempParameters;
}
}
@@ -3305,7 +3597,13 @@ module ts {
emitEnd(node.name);
write(") ");
if (node.body.kind === SyntaxKind.ModuleBlock) {
var saveTempCount = tempCount;
var saveTempVariables = tempVariables;
tempCount = 0;
tempVariables = undefined;
emit(node.body);
tempCount = saveTempCount;
tempVariables = saveTempVariables;
}
else {
write("{");
@@ -3521,17 +3819,18 @@ module ts {
if (!node) {
return;
}
if (node.flags & NodeFlags.Ambient) {
return emitPinnedOrTripleSlashComments(node);
}
// Check if the node can be emitted regardless of the ScriptTarget
switch (node.kind) {
case SyntaxKind.Identifier:
return emitIdentifier(<Identifier>node);
case SyntaxKind.Parameter:
return emitParameter(<ParameterDeclaration>node);
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
return emitMethod(<MethodDeclaration>node);
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return emitAccessor(<AccessorDeclaration>node);
@@ -3559,12 +3858,18 @@ module ts {
return emitTemplateSpan(<TemplateSpan>node);
case SyntaxKind.QualifiedName:
return emitQualifiedName(<QualifiedName>node);
case SyntaxKind.ObjectBindingPattern:
return emitObjectBindingPattern(<BindingPattern>node);
case SyntaxKind.ArrayBindingPattern:
return emitArrayBindingPattern(<BindingPattern>node);
case SyntaxKind.ArrayLiteralExpression:
return emitArrayLiteral(<ArrayLiteralExpression>node);
case SyntaxKind.ObjectLiteralExpression:
return emitObjectLiteral(<ObjectLiteralExpression>node);
case SyntaxKind.PropertyAssignment:
return emitPropertyAssignment(<PropertyDeclaration>node);
case SyntaxKind.ShorthandPropertyAssignment:
return emitShorthandPropertyAssignment(<ShorthandPropertyAssignment>node);
case SyntaxKind.ComputedPropertyName:
return emitComputedPropertyName(<ComputedPropertyName>node);
case SyntaxKind.PropertyAccessExpression:
@@ -3659,29 +3964,6 @@ module ts {
case SyntaxKind.SourceFile:
return emitSourceFile(<SourceFile>node);
}
// Emit node which needs to be emitted differently depended on ScriptTarget
if (compilerOptions.target < ScriptTarget.ES6) {
// Emit node down-level
switch (node.kind) {
case SyntaxKind.ShorthandPropertyAssignment:
return emitDownlevelShorthandPropertyAssignment(<ShorthandPropertyAssignment>node);
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
return emitDownlevelMethod(<MethodDeclaration>node);
}
}
else {
// Emit node natively
Debug.assert(compilerOptions.target >= ScriptTarget.ES6, "Invalid ScriptTarget. We should emit as ES6 or above");
switch (node.kind) {
case SyntaxKind.ShorthandPropertyAssignment:
return emitShorthandPropertyAssignment(<ShorthandPropertyAssignment>node);
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
return emitMethod(<MethodDeclaration>node);
}
}
}
function hasDetachedComments(pos: number) {
+153 -54
View File
@@ -40,12 +40,8 @@ module ts {
return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind));
}
function createRootNode(kind: SyntaxKind, pos: number, end: number, flags: NodeFlags): Node {
var node = new (getNodeConstructor(kind))();
node.pos = pos;
node.end = end;
node.flags = flags;
return node;
export function createNode(kind: SyntaxKind): Node {
return new (getNodeConstructor(kind))();
}
export function getSourceFileOfNode(node: Node): SourceFile {
@@ -140,6 +136,7 @@ module ts {
// This list is a work in progress. Add missing node kinds to improve their error
// spans.
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
@@ -260,21 +257,19 @@ module ts {
return child((<TypeParameterDeclaration>node).name) ||
child((<TypeParameterDeclaration>node).constraint);
case SyntaxKind.Parameter:
return children(node.modifiers) ||
child((<ParameterDeclaration>node).dotDotDotToken) ||
child((<ParameterDeclaration>node).name) ||
child((<ParameterDeclaration>node).questionToken) ||
child((<ParameterDeclaration>node).type) ||
child((<ParameterDeclaration>node).initializer);
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
return children(node.modifiers) ||
child((<PropertyDeclaration>node).name) ||
child((<PropertyDeclaration>node).questionToken) ||
child((<PropertyDeclaration>node).type) ||
child((<PropertyDeclaration>node).initializer);
child((<VariableLikeDeclaration>node).propertyName) ||
child((<VariableLikeDeclaration>node).dotDotDotToken) ||
child((<VariableLikeDeclaration>node).name) ||
child((<VariableLikeDeclaration>node).questionToken) ||
child((<VariableLikeDeclaration>node).type) ||
child((<VariableLikeDeclaration>node).initializer);
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.CallSignature:
@@ -315,6 +310,9 @@ module ts {
return children((<UnionTypeNode>node).types);
case SyntaxKind.ParenthesizedType:
return child((<ParenthesizedTypeNode>node).type);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
return children((<BindingPattern>node).elements);
case SyntaxKind.ArrayLiteralExpression:
return children((<ArrayLiteralExpression>node).elements);
case SyntaxKind.ObjectLiteralExpression:
@@ -421,11 +419,6 @@ module ts {
return child((<CatchClause>node).name) ||
child((<CatchClause>node).type) ||
child((<CatchClause>node).block);
case SyntaxKind.VariableDeclaration:
return children(node.modifiers) ||
child((<VariableDeclaration>node).name) ||
child((<VariableDeclaration>node).type) ||
child((<VariableDeclaration>node).initializer);
case SyntaxKind.ClassDeclaration:
return children(node.modifiers) ||
child((<ClassDeclaration>node).name) ||
@@ -506,6 +499,7 @@ module ts {
export function isAnyFunction(node: Node): boolean {
if (node) {
switch (node.kind) {
case SyntaxKind.Constructor:
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
@@ -513,7 +507,14 @@ module ts {
case SyntaxKind.MethodSignature:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.Constructor:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
return true;
}
}
@@ -522,11 +523,11 @@ module ts {
}
export function isFunctionBlock(node: Node) {
return node !== undefined && node.kind === SyntaxKind.Block && isAnyFunction(node.parent);
return node && node.kind === SyntaxKind.Block && isAnyFunction(node.parent);
}
export function isObjectLiteralMethod(node: Node) {
return node !== undefined && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
}
export function getContainingFunction(node: Node): FunctionLikeDeclaration {
@@ -646,7 +647,8 @@ module ts {
case SyntaxKind.PropertySignature:
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyAssignment:
return (<VariableDeclaration>parent).initializer === node;
case SyntaxKind.BindingElement:
return (<VariableLikeDeclaration>parent).initializer === node;
case SyntaxKind.ExpressionStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.DoStatement:
@@ -730,6 +732,10 @@ module ts {
return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
}
export function isBindingPattern(node: Node) {
return node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern;
}
export function isInAmbientContext(node: Node): boolean {
while (node) {
if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true;
@@ -743,6 +749,7 @@ module ts {
case SyntaxKind.TypeParameter:
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyAssignment:
@@ -889,6 +896,8 @@ module ts {
EnumMembers, // Members in enum declaration
TypeReferences, // Type references in extends or implements clause
VariableDeclarations, // Variable declarations in variable statement
ObjectBindingElements, // Binding elements in object binding list
ArrayBindingElements, // Binding elements in array binding list
ArgumentExpressions, // Expressions in argument list
ObjectLiteralMembers, // Members in object literal
ArrayLiteralMembers, // Members in array literal
@@ -918,6 +927,8 @@ module ts {
case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected;
case ParsingContext.TypeReferences: return Diagnostics.Type_reference_expected;
case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected;
case ParsingContext.ObjectBindingElements: return Diagnostics.Property_destructuring_pattern_expected;
case ParsingContext.ArrayBindingElements: 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;
@@ -1087,17 +1098,20 @@ module ts {
// Note: any errors at the end of the file that do not precede a regular node, should get
// attached to the EOF token.
var parseErrorBeforeNextFinishedNode = false;
var sourceFile = <SourceFile>createRootNode(SyntaxKind.SourceFile, 0, sourceText.length,
fileExtensionIs(filename, ".d.ts") ? NodeFlags.DeclarationFile : 0);
var sourceFile = <SourceFile>createNode(SyntaxKind.SourceFile, 0);
if (fileExtensionIs(filename, ".d.ts")) {
sourceFile.flags = NodeFlags.DeclarationFile;
}
sourceFile.end = sourceText.length;
sourceFile.filename = normalizePath(filename);
sourceFile.text = sourceText;
sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
sourceFile.getLineStarts = getLineStarts;
sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics;
sourceFile.filename = normalizePath(filename);
sourceFile.text = sourceText;
sourceFile.referenceDiagnostics = [];
sourceFile.parseDiagnostics = [];
sourceFile.grammarDiagnostics = [];
@@ -1559,11 +1573,16 @@ module ts {
return token === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
case ParsingContext.ObjectLiteralMembers:
return token === SyntaxKind.OpenBracketToken || token === SyntaxKind.AsteriskToken || isLiteralPropertyName();
case ParsingContext.ObjectBindingElements:
return isLiteralPropertyName();
case ParsingContext.TypeReferences:
// We want to make sure that the "extends" in "extends foo" or the "implements" in
// "implements foo" is not considered a type name.
return isIdentifier() && !isNotHeritageClauseTypeName();
case ParsingContext.VariableDeclarations:
return isIdentifierOrPattern();
case ParsingContext.ArrayBindingElements:
return token === SyntaxKind.CommaToken || isIdentifierOrPattern();
case ParsingContext.TypeParameters:
return isIdentifier();
case ParsingContext.ArgumentExpressions:
@@ -1612,6 +1631,7 @@ module ts {
case ParsingContext.ClassMembers:
case ParsingContext.EnumMembers:
case ParsingContext.ObjectLiteralMembers:
case ParsingContext.ObjectBindingElements:
return token === SyntaxKind.CloseBraceToken;
case ParsingContext.SwitchClauseStatements:
return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.CaseKeyword || token === SyntaxKind.DefaultKeyword;
@@ -1627,10 +1647,11 @@ module ts {
return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken;
case ParsingContext.ArrayLiteralMembers:
case ParsingContext.TupleElementTypes:
case ParsingContext.ArrayBindingElements:
return token === SyntaxKind.CloseBracketToken;
case ParsingContext.Parameters:
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
return token === SyntaxKind.CloseParenToken || token === SyntaxKind.CloseBracketToken || token === SyntaxKind.OpenBraceToken;
return token === SyntaxKind.CloseParenToken || token === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/;
case ParsingContext.TypeArguments:
// Tokens other than '>' are here for better error recovery
return token === SyntaxKind.GreaterThanToken || token === SyntaxKind.OpenParenToken;
@@ -1966,10 +1987,10 @@ module ts {
}
}
function parseParameterType(): TypeNode | StringLiteralExpression {
function parseParameterType(): TypeNode {
if (parseOptional(SyntaxKind.ColonToken)) {
return token === SyntaxKind.StringLiteral
? <StringLiteralExpression>parseLiteralNode(/*internName:*/ true)
? <StringLiteralTypeNode>parseLiteralNode(/*internName:*/ true)
: parseType();
}
@@ -1977,7 +1998,7 @@ module ts {
}
function isStartOfParameter(): boolean {
return token === SyntaxKind.DotDotDotToken || isIdentifier() || isModifier(token);
return token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifier(token);
}
function setModifiers(node: Node, modifiers: ModifiersArray) {
@@ -1996,9 +2017,7 @@ module ts {
// [+GeneratorParameter]BindingIdentifier[Yield]Initializer[In]opt
// [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt
node.name = inGeneratorParameterContext()
? doInYieldContext(parseIdentifier)
: parseIdentifier();
node.name = inGeneratorParameterContext() ? doInYieldContext(parseIdentifierOrPattern) : parseIdentifierOrPattern();
if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifier(token)) {
// in cases like
@@ -2014,9 +2033,7 @@ module ts {
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
node.type = parseParameterType();
node.initializer = inGeneratorParameterContext()
? doOutsideOfYieldContext(parseParameterInitializer)
: parseParameterInitializer();
node.initializer = inGeneratorParameterContext() ? doOutsideOfYieldContext(parseParameterInitializer) : parseParameterInitializer();
// Do not check for initializers in an ambient context for parameters. This is not
// a grammar error because the grammar allows arbitrary call signatures in
@@ -3841,20 +3858,81 @@ module ts {
// DECLARATIONS
function parseBindingElement(context: ParsingContext): BindingElement {
if (context === ParsingContext.ArrayBindingElements && token === SyntaxKind.CommaToken) {
return <BindingElement>createNode(SyntaxKind.OmittedExpression);
}
var node = <BindingElement>createNode(SyntaxKind.BindingElement);
if (context === ParsingContext.ObjectBindingElements) {
// TODO(andersh): Handle computed properties
var id = parsePropertyName();
if (id.kind === SyntaxKind.Identifier && token !== SyntaxKind.ColonToken) {
node.name = <Identifier>id;
}
else {
parseExpected(SyntaxKind.ColonToken);
node.propertyName = <Identifier>id;
node.name = parseIdentifierOrPattern();
}
}
else {
node.name = parseIdentifierOrPattern();
}
node.initializer = parseInitializer(/*inParameter*/ false);
return finishNode(node);
}
function parseBindingList(context: ParsingContext): NodeArray<BindingElement> {
return parseDelimitedList(context, () => parseBindingElement(context));
}
function parseObjectBindingPattern(): BindingPattern {
var node = <BindingPattern>createNode(SyntaxKind.ObjectBindingPattern);
parseExpected(SyntaxKind.OpenBraceToken);
node.elements = parseBindingList(ParsingContext.ObjectBindingElements);
parseExpected(SyntaxKind.CloseBraceToken);
return finishNode(node);
}
function parseArrayBindingPattern(): BindingPattern {
var node = <BindingPattern>createNode(SyntaxKind.ArrayBindingPattern);
parseExpected(SyntaxKind.OpenBracketToken);
node.elements = parseBindingList(ParsingContext.ArrayBindingElements);
parseExpected(SyntaxKind.CloseBracketToken);
return finishNode(node);
}
function isIdentifierOrPattern() {
return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken || isIdentifier();
}
function parseIdentifierOrPattern(): Identifier | BindingPattern {
if (token === SyntaxKind.OpenBracketToken) {
return parseArrayBindingPattern();
}
if (token === SyntaxKind.OpenBraceToken) {
return parseObjectBindingPattern();
}
return parseIdentifier();
}
function parseVariableDeclaration(): VariableDeclaration {
var node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration);
node.name = parseIdentifier();
node.name = parseIdentifierOrPattern();
node.type = parseTypeAnnotation();
node.initializer = parseInitializer(/*inParameter*/ false);
return finishNode(node);
}
function setFlag(array: NodeArray<VariableDeclaration>, flag: NodeFlags): NodeArray<VariableDeclaration> {
for (var i = 0, n = array.length; i < n; i++) {
array[i].flags |= flag;
function setFlag(nodes: NodeArray<VariableDeclaration>, flag: NodeFlags): NodeArray<VariableDeclaration> {
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
node.flags |= flag;
if (node.name && isBindingPattern(node.name)) {
setFlag((<BindingPattern>node.name).elements, flag);
}
}
return array;
return nodes;
}
function parseVariableDeclarationList(): NodeArray<VariableDeclaration> {
@@ -4562,6 +4640,7 @@ module ts {
case SyntaxKind.EnumDeclaration: return checkEnumDeclaration(<EnumDeclaration>node);
case SyntaxKind.BinaryExpression: return checkBinaryExpression(<BinaryExpression>node);
case SyntaxKind.BindingElement: return checkBindingElement(<BindingElement>node);
case SyntaxKind.CatchClause: return checkCatchClause(<CatchClause>node);
case SyntaxKind.ClassDeclaration: return checkClassDeclaration(<ClassDeclaration>node);
case SyntaxKind.ComputedPropertyName: return checkComputedPropertyName(<ComputedPropertyName>node);
@@ -5386,7 +5465,7 @@ module ts {
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a
// strict mode FunctionLikeDeclaration or FunctionExpression(13.1)
if (node.parserContextFlags & ParserContextFlags.StrictMode && isEvalOrArgumentsIdentifier(node.name)) {
return reportInvalidUseInStrictMode(node.name);
return reportInvalidUseInStrictMode(<Identifier>node.name);
}
}
@@ -5658,18 +5737,38 @@ module ts {
return checkTypeArguments(node.typeArguments);
}
function checkVariableDeclaration(node: VariableDeclaration) {
if (inAmbientContext && node.initializer) {
var equalsPos = node.type ? skipTrivia(sourceText, node.type.end) : skipTrivia(sourceText, node.name.end);
return grammarErrorAtPos(equalsPos, "=".length, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
function checkBindingElement(node: BindingElement) {
if (node.parserContextFlags & ParserContextFlags.StrictMode && isEvalOrArgumentsIdentifier(node.name)) {
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
// and its Identifier is eval or arguments
return reportInvalidUseInStrictMode(<Identifier>node.name);
}
if (!inAmbientContext && !node.initializer && isConst(node)) {
return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized);
}
function checkVariableDeclaration(node: VariableDeclaration) {
if (inAmbientContext) {
if (isBindingPattern(node.name)) {
return grammarErrorOnNode(node, Diagnostics.Destructuring_declarations_are_not_allowed_in_ambient_contexts);
}
if (node.initializer) {
// Error on equals token which immediate precedes the initializer
return grammarErrorAtPos(node.initializer.pos - 1, 1, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
}
}
else {
if (!node.initializer) {
if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) {
return grammarErrorOnNode(node, Diagnostics.A_destructuring_declaration_must_have_an_initializer);
}
if (isConst(node)) {
return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized);
}
}
}
if (node.parserContextFlags & ParserContextFlags.StrictMode && isEvalOrArgumentsIdentifier(node.name)) {
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
// and its Identifier is eval or arguments
return reportInvalidUseInStrictMode(node.name);
return reportInvalidUseInStrictMode(<Identifier>node.name);
}
}
+77 -40
View File
@@ -167,6 +167,10 @@ module ts {
TupleType,
UnionType,
ParenthesizedType,
// Binding patterns
ObjectBindingPattern,
ArrayBindingPattern,
BindingElement,
// Expression
ArrayLiteralExpression,
ObjectLiteralExpression,
@@ -353,7 +357,8 @@ module ts {
}
export type EntityName = Identifier | QualifiedName;
export type DeclarationName = Identifier | LiteralExpression | ComputedPropertyName;
export type DeclarationName = Identifier | LiteralExpression | ComputedPropertyName | BindingPattern;
export interface Declaration extends Node {
_declarationBrand: any;
@@ -378,39 +383,43 @@ module ts {
type?: TypeNode;
}
// SyntaxKind.VariableDeclaration
export interface VariableDeclaration extends Declaration {
name: Identifier;
type?: TypeNode;
initializer?: Expression;
name: Identifier | BindingPattern; // Declared variable name
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
}
// SyntaxKind.Parameter
export interface ParameterDeclaration extends Declaration {
dotDotDotToken?: Node;
name: Identifier;
questionToken?: Node;
type?: TypeNode | StringLiteralExpression;
initializer?: Expression;
dotDotDotToken?: Node; // Present on rest parameter
name: Identifier | BindingPattern; // Declared parameter name
questionToken?: Node; // Present on optional parameter
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
}
// SyntaxKind.BindingElement
export interface BindingElement extends Declaration {
propertyName?: Identifier; // Binding property name (in object binding pattern)
dotDotDotToken?: Node; // Present on rest binding element
name: Identifier | BindingPattern; // Declared binding element name
initializer?: Expression; // Optional initializer
}
// SyntaxKind.Property
export interface PropertyDeclaration extends Declaration, ClassElement {
_propertyDeclarationBrand: any;
questionToken?: Node;
type?: TypeNode;
initializer?: Expression;
name: DeclarationName; // Declared property name
questionToken?: Node; // Present on optional property
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
}
export type VariableOrParameterDeclaration = VariableDeclaration | ParameterDeclaration;
export type VariableOrParameterOrPropertyDeclaration = VariableOrParameterDeclaration | PropertyDeclaration;
export interface ObjectLiteralElement extends Declaration {
_objectLiteralBrandBrand: any;
}
export interface ShorthandPropertyAssignment extends ObjectLiteralElement {
name: Identifier;
questionToken?: Node;
}
// SyntaxKind.PropertyAssignment
export interface PropertyAssignment extends ObjectLiteralElement {
_propertyAssignmentBrand: any;
name: DeclarationName;
@@ -418,6 +427,32 @@ module ts {
initializer: Expression;
}
// SyntaxKind.ShorthandPropertyAssignment
export interface ShorthandPropertyAssignment extends ObjectLiteralElement {
name: Identifier;
questionToken?: Node;
}
// SyntaxKind.VariableDeclaration
// SyntaxKind.Parameter
// SyntaxKind.BindingElement
// SyntaxKind.Property
// SyntaxKind.PropertyAssignment
// SyntaxKind.ShorthandPropertyAssignment
// SyntaxKind.EnumMember
export interface VariableLikeDeclaration extends Declaration {
propertyName?: Identifier;
dotDotDotToken?: Node;
name: DeclarationName;
questionToken?: Node;
type?: TypeNode;
initializer?: Expression;
}
export interface BindingPattern extends Node {
elements: NodeArray<BindingElement>;
}
/**
* Several node kinds share function-like features such as a signature,
* a name, and a body. These nodes should extend FunctionLikeDeclaration.
@@ -505,6 +540,8 @@ module ts {
type: TypeNode;
}
export interface StringLiteralTypeNode extends LiteralExpression, TypeNode { }
// Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing.
// Consider 'Expression'. Without the brand, 'Expression' is actually no different
// (structurally) than 'Node'. Because of this you can pass any Node to a function that
@@ -1034,13 +1071,14 @@ module ts {
hasSemanticErrors(sourceFile?: SourceFile): boolean;
isDeclarationVisible(node: Declaration): boolean;
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableOrParameterDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult;
isEntityNameVisible(entityName: EntityName, enclosingDeclaration: Node): SymbolVisibilityResult;
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
getConstantValue(node: PropertyAccessExpression | ElementAccessExpression): number;
isEmitBlocked(sourceFile?: SourceFile): boolean;
isUnknownIdentifier(location: Node, name: string): boolean;
}
export const enum SymbolFlags {
@@ -1061,35 +1099,33 @@ module ts {
Constructor = 0x00004000, // Constructor
GetAccessor = 0x00008000, // Get accessor
SetAccessor = 0x00010000, // Set accessor
CallSignature = 0x00020000, // Call signature
ConstructSignature = 0x00040000, // Construct signature
IndexSignature = 0x00080000, // Index signature
TypeParameter = 0x00100000, // Type parameter
TypeAlias = 0x00200000, // Type alias
Signature = 0x00020000, // Call, construct, or index signature
TypeParameter = 0x00040000, // Type parameter
TypeAlias = 0x00080000, // Type alias
// Export markers (see comment in declareModuleMember in binder)
ExportValue = 0x00400000, // Exported value marker
ExportType = 0x00800000, // Exported type marker
ExportNamespace = 0x01000000, // Exported namespace marker
Import = 0x02000000, // Import
Instantiated = 0x04000000, // Instantiated symbol
Merged = 0x08000000, // Merged symbol (created during program binding)
Transient = 0x10000000, // Transient symbol (created during type check)
Prototype = 0x20000000, // Prototype property (no source representation)
UnionProperty = 0x40000000, // Property in union type
ExportValue = 0x00100000, // Exported value marker
ExportType = 0x00200000, // Exported type marker
ExportNamespace = 0x00400000, // Exported namespace marker
Import = 0x00800000, // Import
Instantiated = 0x01000000, // Instantiated symbol
Merged = 0x02000000, // Merged symbol (created during program binding)
Transient = 0x04000000, // Transient symbol (created during type check)
Prototype = 0x08000000, // Prototype property (no source representation)
UnionProperty = 0x10000000, // Property in union type
Optional = 0x20000000, // Optional property
Enum = RegularEnum | ConstEnum,
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
Namespace = ValueModule | NamespaceModule,
Module = ValueModule | NamespaceModule,
Accessor = GetAccessor | SetAccessor,
Signature = CallSignature | ConstructSignature | IndexSignature,
// Variables can be redeclared, but can not redeclare a block-scoped declaration with the
// Variables can be redeclared, but can not redeclare a block-scoped declaration with the
// same name, or any other value that is not a variable, e.g. ValueModule or Class
FunctionScopedVariableExcludes = Value & ~FunctionScopedVariable,
FunctionScopedVariableExcludes = Value & ~FunctionScopedVariable,
// Block-scoped declarations are not allowed to be re-declared
// they can not merge with anything in the value space
@@ -1198,6 +1234,7 @@ module ts {
Union = 0x00004000, // Union
Anonymous = 0x00008000, // Anonymous
FromSignature = 0x00010000, // Created for signature assignment check
Unwidened = 0x00020000, // Unwidened type (is or contains Undefined or Null type)
Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null,
StringLike = String | StringLiteral,
+45 -15
View File
@@ -37,26 +37,50 @@ module ts.NavigationBar {
return indent;
}
function getChildNodes(nodes: Node[]): Node[] {
var childNodes: Node[] = [];
var childNodes: Node[] = [];
for (var i = 0, n = nodes.length; i < n; i++) {
var node = nodes[i];
if (node.kind === SyntaxKind.ClassDeclaration ||
node.kind === SyntaxKind.EnumDeclaration ||
node.kind === SyntaxKind.InterfaceDeclaration ||
node.kind === SyntaxKind.ModuleDeclaration ||
node.kind === SyntaxKind.FunctionDeclaration) {
childNodes.push(node);
}
else if (node.kind === SyntaxKind.VariableStatement) {
childNodes.push.apply(childNodes, (<VariableStatement>node).declarations);
function visit(node: Node) {
switch (node.kind) {
case SyntaxKind.VariableStatement:
forEach((<VariableStatement>node).declarations, visit);
break;
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
forEach((<BindingPattern>node).elements, visit);
break;
case SyntaxKind.VariableDeclaration:
if (isBindingPattern(node)) {
visit((<VariableDeclaration>node).name);
break;
}
// Fall through
case SyntaxKind.ClassDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.FunctionDeclaration:
childNodes.push(node);
}
}
//for (var i = 0, n = nodes.length; i < n; i++) {
// var node = nodes[i];
// if (node.kind === SyntaxKind.ClassDeclaration ||
// node.kind === SyntaxKind.EnumDeclaration ||
// node.kind === SyntaxKind.InterfaceDeclaration ||
// node.kind === SyntaxKind.ModuleDeclaration ||
// node.kind === SyntaxKind.FunctionDeclaration) {
// childNodes.push(node);
// }
// else if (node.kind === SyntaxKind.VariableStatement) {
// childNodes.push.apply(childNodes, (<VariableStatement>node).declarations);
// }
//}
forEach(nodes, visit);
return sortNodes(childNodes);
}
@@ -200,6 +224,9 @@ module ts.NavigationBar {
function createChildItem(node: Node): ts.NavigationBarItem {
switch (node.kind) {
case SyntaxKind.Parameter:
if (isBindingPattern((<ParameterDeclaration>node).name)) {
break;
}
if ((node.flags & NodeFlags.Modifier) === 0) {
return undefined;
}
@@ -235,6 +262,9 @@ module ts.NavigationBar {
return createItem(node, getTextOfNode((<FunctionLikeDeclaration>node).name), ts.ScriptElementKind.functionElement);
case SyntaxKind.VariableDeclaration:
if (isBindingPattern((<VariableDeclaration>node).name)) {
break;
}
if (isConst(node)) {
return createItem(node, getTextOfNode((<VariableDeclaration>node).name), ts.ScriptElementKind.constElement);
}
+8
View File
@@ -806,6 +806,8 @@ module ts {
// fall through
case SyntaxKind.Constructor:
case SyntaxKind.VariableStatement:
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
case SyntaxKind.ModuleBlock:
forEachChild(node, visit);
break;
@@ -823,6 +825,11 @@ module ts {
}
// fall through
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
if (isBindingPattern((<VariableDeclaration>node).name)) {
forEachChild((<VariableDeclaration>node).name, visit);
break;
}
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
@@ -4746,6 +4753,7 @@ module ts {
switch (node.kind) {
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyAssignment: