Skip to content

Commit 77eaf04

Browse files
committed
Merge pull request #4914 from Microsoft/exponentiation
[ES7] Exponentiation
2 parents c8ba166 + 9025879 commit 77eaf04

File tree

173 files changed

+13173
-225
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

173 files changed

+13173
-225
lines changed

lib/lib.core.es6.d.ts

+1-28
Original file line numberDiff line numberDiff line change
@@ -3965,34 +3965,7 @@ interface ObjectConstructor {
39653965
* Copy the values of all of the enumerable own properties from one or more source objects to a
39663966
* target object. Returns the target object.
39673967
* @param target The target object to copy to.
3968-
* @param source The source object from which to copy properties.
3969-
*/
3970-
assign<T, U>(target: T, source: U): T & U;
3971-
3972-
/**
3973-
* Copy the values of all of the enumerable own properties from one or more source objects to a
3974-
* target object. Returns the target object.
3975-
* @param target The target object to copy to.
3976-
* @param source1 The first source object from which to copy properties.
3977-
* @param source2 The second source object from which to copy properties.
3978-
*/
3979-
assign<T, U, V>(target: T, source1: U, source2: V): T & U & V;
3980-
3981-
/**
3982-
* Copy the values of all of the enumerable own properties from one or more source objects to a
3983-
* target object. Returns the target object.
3984-
* @param target The target object to copy to.
3985-
* @param source1 The first source object from which to copy properties.
3986-
* @param source2 The second source object from which to copy properties.
3987-
* @param source3 The third source object from which to copy properties.
3988-
*/
3989-
assign<T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
3990-
3991-
/**
3992-
* Copy the values of all of the enumerable own properties from one or more source objects to a
3993-
* target object. Returns the target object.
3994-
* @param target The target object to copy to.
3995-
* @param sources One or more source objects from which to copy properties
3968+
* @param sources One or more source objects to copy properties from.
39963969
*/
39973970
assign(target: any, ...sources: any[]): any;
39983971

src/compiler/checker.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -10074,7 +10074,9 @@ namespace ts {
1007410074
let rightType = checkExpression(right, contextualMapper);
1007510075
switch (operator) {
1007610076
case SyntaxKind.AsteriskToken:
10077+
case SyntaxKind.AsteriskAsteriskToken:
1007710078
case SyntaxKind.AsteriskEqualsToken:
10079+
case SyntaxKind.AsteriskAsteriskEqualsToken:
1007810080
case SyntaxKind.SlashToken:
1007910081
case SyntaxKind.SlashEqualsToken:
1008010082
case SyntaxKind.PercentToken:
@@ -10093,7 +10095,7 @@ namespace ts {
1009310095
case SyntaxKind.CaretEqualsToken:
1009410096
case SyntaxKind.AmpersandToken:
1009510097
case SyntaxKind.AmpersandEqualsToken:
10096-
// TypeScript 1.0 spec (April 2014): 4.15.1
10098+
// TypeScript 1.0 spec (April 2014): 4.19.1
1009710099
// These operators require their operands to be of type Any, the Number primitive type,
1009810100
// or an enum type. Operands of an enum type are treated
1009910101
// as having the primitive type Number. If one operand is the null or undefined value,
@@ -10122,7 +10124,7 @@ namespace ts {
1012210124
return numberType;
1012310125
case SyntaxKind.PlusToken:
1012410126
case SyntaxKind.PlusEqualsToken:
10125-
// TypeScript 1.0 spec (April 2014): 4.15.2
10127+
// TypeScript 1.0 spec (April 2014): 4.19.2
1012610128
// The binary + operator requires both operands to be of the Number primitive type or an enum type,
1012710129
// or at least one of the operands to be of type Any or the String primitive type.
1012810130

src/compiler/diagnosticMessages.json

+8
Original file line numberDiff line numberDiff line change
@@ -2477,5 +2477,13 @@
24772477
"A constructor cannot contain a 'super' call when its class extends 'null'": {
24782478
"category": "Error",
24792479
"code": 17005
2480+
},
2481+
"An unary expression with the '{0}' operator is not allowed in the left-hand side of an exponentiation expression. Consider enclosing the expression in parentheses.": {
2482+
"category": "Error",
2483+
"code": 17006
2484+
},
2485+
"A type assertion expression is not allowed in the left-hand side of an exponentiation expression. Consider enclosing the expression in parentheses.": {
2486+
"category": "Error",
2487+
"code": 17007
24802488
}
24812489
}

src/compiler/emitter.ts

+141-43
Original file line numberDiff line numberDiff line change
@@ -2783,6 +2783,68 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
27832783
}
27842784
}
27852785

2786+
/**
2787+
* Emit ES7 exponentiation operator downlevel using Math.pow
2788+
* @param node a binary expression node containing exponentiationOperator (**, **=)
2789+
*/
2790+
function emitExponentiationOperator(node: BinaryExpression) {
2791+
let leftHandSideExpression = node.left;
2792+
if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
2793+
let synthesizedLHS: ElementAccessExpression | PropertyAccessExpression;
2794+
let shouldEmitParentheses = false;
2795+
if (isElementAccessExpression(leftHandSideExpression)) {
2796+
shouldEmitParentheses = true;
2797+
write("(");
2798+
2799+
synthesizedLHS = <ElementAccessExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression, /*startsOnNewLine*/ false);
2800+
2801+
let identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldEmitCommaBeforeAssignment*/ false);
2802+
synthesizedLHS.expression = identifier;
2803+
2804+
if (leftHandSideExpression.argumentExpression.kind !== SyntaxKind.NumericLiteral &&
2805+
leftHandSideExpression.argumentExpression.kind !== SyntaxKind.StringLiteral) {
2806+
let tempArgumentExpression = createAndRecordTempVariable(TempFlags._i);
2807+
(<ElementAccessExpression>synthesizedLHS).argumentExpression = tempArgumentExpression;
2808+
emitAssignment(tempArgumentExpression, leftHandSideExpression.argumentExpression, /*shouldEmitCommaBeforeAssignment*/ true);
2809+
}
2810+
else {
2811+
(<ElementAccessExpression>synthesizedLHS).argumentExpression = leftHandSideExpression.argumentExpression;
2812+
}
2813+
write(", ");
2814+
}
2815+
else if (isPropertyAccessExpression(leftHandSideExpression)) {
2816+
shouldEmitParentheses = true;
2817+
write("(");
2818+
synthesizedLHS = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression, /*startsOnNewLine*/ false);
2819+
2820+
let identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldemitCommaBeforeAssignment*/ false);
2821+
synthesizedLHS.expression = identifier;
2822+
2823+
(<PropertyAccessExpression>synthesizedLHS).dotToken = leftHandSideExpression.dotToken;
2824+
(<PropertyAccessExpression>synthesizedLHS).name = leftHandSideExpression.name;
2825+
write(", ");
2826+
}
2827+
2828+
emit(synthesizedLHS || leftHandSideExpression);
2829+
write(" = ");
2830+
write("Math.pow(");
2831+
emit(synthesizedLHS || leftHandSideExpression);
2832+
write(", ");
2833+
emit(node.right);
2834+
write(")");
2835+
if (shouldEmitParentheses) {
2836+
write(")");
2837+
}
2838+
}
2839+
else {
2840+
write("Math.pow(");
2841+
emit(leftHandSideExpression);
2842+
write(", ");
2843+
emit(node.right);
2844+
write(")");
2845+
}
2846+
}
2847+
27862848
function emitBinaryExpression(node: BinaryExpression) {
27872849
if (languageVersion < ScriptTarget.ES6 && node.operatorToken.kind === SyntaxKind.EqualsToken &&
27882850
(node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
@@ -2800,12 +2862,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
28002862
emitNodeWithoutSourceMap(node.left);
28012863
write(`", `);
28022864
}
2803-
emit(node.left);
2804-
let indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== SyntaxKind.CommaToken ? " " : undefined);
2805-
write(tokenToString(node.operatorToken.kind));
2806-
let indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " ");
2807-
emit(node.right);
2808-
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
2865+
2866+
if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken || node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
2867+
// Downleveled emit exponentiation operator using Math.pow
2868+
emitExponentiationOperator(node);
2869+
}
2870+
else {
2871+
emit(node.left);
2872+
// Add indentation before emit the operator if the operator is on different line
2873+
// For example:
2874+
// 3
2875+
// + 2;
2876+
// emitted as
2877+
// 3
2878+
// + 2;
2879+
let indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== SyntaxKind.CommaToken ? " " : undefined);
2880+
write(tokenToString(node.operatorToken.kind));
2881+
let indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " ");
2882+
emit(node.right);
2883+
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
2884+
}
2885+
28092886
if (exportChanged) {
28102887
write(")");
28112888
}
@@ -3442,6 +3519,58 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
34423519
write(";");
34433520
}
34443521

3522+
/**
3523+
* Emit an assignment to a given identifier, 'name', with a given expression, 'value'.
3524+
* @param name an identifier as a left-hand-side operand of the assignment
3525+
* @param value an expression as a right-hand-side operand of the assignment
3526+
* @param shouldEmitCommaBeforeAssignment a boolean indicating whether to prefix an assignment with comma
3527+
*/
3528+
function emitAssignment(name: Identifier, value: Expression, shouldEmitCommaBeforeAssignment: boolean) {
3529+
if (shouldEmitCommaBeforeAssignment) {
3530+
write(", ");
3531+
}
3532+
3533+
let exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name);
3534+
3535+
if (exportChanged) {
3536+
write(`${exportFunctionForFile}("`);
3537+
emitNodeWithCommentsAndWithoutSourcemap(name);
3538+
write(`", `);
3539+
}
3540+
3541+
const isVariableDeclarationOrBindingElement =
3542+
name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement);
3543+
3544+
if (isVariableDeclarationOrBindingElement) {
3545+
emitModuleMemberName(<Declaration>name.parent);
3546+
}
3547+
else {
3548+
emit(name);
3549+
}
3550+
3551+
write(" = ");
3552+
emit(value);
3553+
3554+
if (exportChanged) {
3555+
write(")");
3556+
}
3557+
}
3558+
3559+
/**
3560+
* Create temporary variable, emit an assignment of the variable the given expression
3561+
* @param expression an expression to assign to the newly created temporary variable
3562+
* @param canDefineTempVariablesInPlace a boolean indicating whether you can define the temporary variable at an assignment location
3563+
* @param shouldEmitCommaBeforeAssignment a boolean indicating whether an assignment should prefix with comma
3564+
*/
3565+
function emitTempVariableAssignment(expression: Expression, canDefineTempVariablesInPlace: boolean, shouldEmitCommaBeforeAssignment: boolean): Identifier {
3566+
let identifier = createTempVariable(TempFlags.Auto);
3567+
if (!canDefineTempVariablesInPlace) {
3568+
recordTempDeclaration(identifier);
3569+
}
3570+
emitAssignment(identifier, expression, shouldEmitCommaBeforeAssignment);
3571+
return identifier;
3572+
}
3573+
34453574
function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, isAssignmentExpressionStatement: boolean, value?: Expression) {
34463575
let emitCount = 0;
34473576

@@ -3467,36 +3596,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
34673596
emitBindingElement(<BindingElement>root, value);
34683597
}
34693598

3470-
function emitAssignment(name: Identifier, value: Expression) {
3471-
if (emitCount++) {
3472-
write(", ");
3473-
}
3474-
3475-
const isVariableDeclarationOrBindingElement =
3476-
name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement);
3477-
3478-
let exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name);
3479-
3480-
if (exportChanged) {
3481-
write(`${exportFunctionForFile}("`);
3482-
emitNodeWithCommentsAndWithoutSourcemap(name);
3483-
write(`", `);
3484-
}
3485-
3486-
if (isVariableDeclarationOrBindingElement) {
3487-
emitModuleMemberName(<Declaration>name.parent);
3488-
}
3489-
else {
3490-
emit(name);
3491-
}
3492-
3493-
write(" = ");
3494-
emit(value);
3495-
3496-
if (exportChanged) {
3497-
write(")");
3498-
}
3499-
}
35003599

35013600
/**
35023601
* Ensures that there exists a declared identifier whose value holds the given expression.
@@ -3512,11 +3611,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
35123611
return expr;
35133612
}
35143613

3515-
let identifier = createTempVariable(TempFlags.Auto);
3516-
if (!canDefineTempVariablesInPlace) {
3517-
recordTempDeclaration(identifier);
3518-
}
3519-
emitAssignment(identifier, expr);
3614+
let identifier = emitTempVariableAssignment(expr, canDefineTempVariablesInPlace, emitCount > 0);
3615+
emitCount++;
35203616
return identifier;
35213617
}
35223618

@@ -3623,7 +3719,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
36233719
emitArrayLiteralAssignment(<ArrayLiteralExpression>target, value);
36243720
}
36253721
else {
3626-
emitAssignment(<Identifier>target, value);
3722+
emitAssignment(<Identifier>target, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0);
3723+
emitCount++;
36273724
}
36283725
}
36293726

@@ -3692,7 +3789,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
36923789
}
36933790
}
36943791
else {
3695-
emitAssignment(<Identifier>target.name, value);
3792+
emitAssignment(<Identifier>target.name, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0);
3793+
emitCount++;
36963794
}
36973795
}
36983796
}

0 commit comments

Comments
 (0)