-
Notifications
You must be signed in to change notification settings - Fork 12.9k
[ES7] Exponentiation #4914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ES7] Exponentiation #4914
Changes from all commits
04ed892
76ef7b4
21d0369
1140eb8
072089f
31b8736
4fc74b2
4037255
a3f5666
df18dfc
5f7914c
ca5da90
bf0903b
1326ba9
ce7a054
69dc707
7b3de84
80cdfd4
a00e90c
f8d6b34
bf970be
46d799e
d0aaf41
bd7cc1e
fbe559e
788f222
bfaa51b
d96a00e
8be77b4
37db03a
3b8cdb6
75de6d4
cd3f711
af5dc3e
5e921c1
1fc11aa
d57ee1d
d3e10b3
2918f9d
6a62c01
e405cce
9025879
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2778,6 +2778,68 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi | |
} | ||
} | ||
|
||
/** | ||
* Emit ES7 exponentiation operator downlevel using Math.pow | ||
* @param node a binary expression node containing exponentiationOperator (**, **=) | ||
*/ | ||
function emitExponentiationOperator(node: BinaryExpression) { | ||
let leftHandSideExpression = node.left; | ||
if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) { | ||
let synthesizedLHS: ElementAccessExpression | PropertyAccessExpression; | ||
let shouldEmitParentheses = false; | ||
if (isElementAccessExpression(leftHandSideExpression)) { | ||
shouldEmitParentheses = true; | ||
write("("); | ||
|
||
synthesizedLHS = <ElementAccessExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression, /*startsOnNewLine*/ false); | ||
|
||
let identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldEmitCommaBeforeAssignment*/ false); | ||
synthesizedLHS.expression = identifier; | ||
|
||
if (leftHandSideExpression.argumentExpression.kind !== SyntaxKind.NumericLiteral && | ||
leftHandSideExpression.argumentExpression.kind !== SyntaxKind.StringLiteral) { | ||
let tempArgumentExpression = createAndRecordTempVariable(TempFlags._i); | ||
(<ElementAccessExpression>synthesizedLHS).argumentExpression = tempArgumentExpression; | ||
emitAssignment(tempArgumentExpression, leftHandSideExpression.argumentExpression, /*shouldEmitCommaBeforeAssignment*/ true); | ||
} | ||
else { | ||
(<ElementAccessExpression>synthesizedLHS).argumentExpression = leftHandSideExpression.argumentExpression; | ||
} | ||
write(", "); | ||
} | ||
else if (isPropertyAccessExpression(leftHandSideExpression)) { | ||
shouldEmitParentheses = true; | ||
write("("); | ||
synthesizedLHS = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression, /*startsOnNewLine*/ false); | ||
|
||
let identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldemitCommaBeforeAssignment*/ false); | ||
synthesizedLHS.expression = identifier; | ||
|
||
(<PropertyAccessExpression>synthesizedLHS).dotToken = leftHandSideExpression.dotToken; | ||
(<PropertyAccessExpression>synthesizedLHS).name = leftHandSideExpression.name; | ||
write(", "); | ||
} | ||
|
||
emit(synthesizedLHS || leftHandSideExpression); | ||
write(" = "); | ||
write("Math.pow("); | ||
emit(synthesizedLHS || leftHandSideExpression); | ||
write(", "); | ||
emit(node.right); | ||
write(")"); | ||
if (shouldEmitParentheses) { | ||
write(")"); | ||
} | ||
} | ||
else { | ||
write("Math.pow("); | ||
emit(leftHandSideExpression); | ||
write(", "); | ||
emit(node.right); | ||
write(")"); | ||
} | ||
} | ||
|
||
function emitBinaryExpression(node: BinaryExpression) { | ||
if (languageVersion < ScriptTarget.ES6 && node.operatorToken.kind === SyntaxKind.EqualsToken && | ||
(node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { | ||
|
@@ -2795,12 +2857,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi | |
emitNodeWithoutSourceMap(node.left); | ||
write(`", `); | ||
} | ||
emit(node.left); | ||
let indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== SyntaxKind.CommaToken ? " " : undefined); | ||
write(tokenToString(node.operatorToken.kind)); | ||
let indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " "); | ||
emit(node.right); | ||
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator); | ||
|
||
if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken || node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) { | ||
// Downleveled emit exponentiation operator using Math.pow | ||
emitExponentiationOperator(node); | ||
} | ||
else { | ||
emit(node.left); | ||
// Add indentation before emit the operator if the operator is on different line | ||
// For example: | ||
// 3 | ||
// + 2; | ||
// emitted as | ||
// 3 | ||
// + 2; | ||
let indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== SyntaxKind.CommaToken ? " " : undefined); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this last parameter supposed to be? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an already existed code. I believe what it does is toe indent the operator if it is on different line 3
+2; will be 3
+ 2; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure; can you leave a comment specifying what the parameter name is, and potentially break the call into several lines? |
||
write(tokenToString(node.operatorToken.kind)); | ||
let indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " "); | ||
emit(node.right); | ||
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator); | ||
} | ||
|
||
if (exportChanged) { | ||
write(")"); | ||
} | ||
|
@@ -3437,6 +3514,58 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi | |
write(";"); | ||
} | ||
|
||
/** | ||
* Emit an assignment to a given identifier, 'name', with a given expression, 'value'. | ||
* @param name an identifier as a left-hand-side operand of the assignment | ||
* @param value an expression as a right-hand-side operand of the assignment | ||
* @param shouldEmitCommaBeforeAssignment a boolean indicating whether to prefix an assignment with comma | ||
*/ | ||
function emitAssignment(name: Identifier, value: Expression, shouldEmitCommaBeforeAssignment: boolean) { | ||
if (shouldEmitCommaBeforeAssignment) { | ||
write(", "); | ||
} | ||
|
||
let exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name); | ||
|
||
if (exportChanged) { | ||
write(`${exportFunctionForFile}("`); | ||
emitNodeWithCommentsAndWithoutSourcemap(name); | ||
write(`", `); | ||
} | ||
|
||
const isVariableDeclarationOrBindingElement = | ||
name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement); | ||
|
||
if (isVariableDeclarationOrBindingElement) { | ||
emitModuleMemberName(<Declaration>name.parent); | ||
} | ||
else { | ||
emit(name); | ||
} | ||
|
||
write(" = "); | ||
emit(value); | ||
|
||
if (exportChanged) { | ||
write(")"); | ||
} | ||
} | ||
|
||
/** | ||
* Create temporary variable, emit an assignment of the variable the given expression | ||
* @param expression an expression to assign to the newly created temporary variable | ||
* @param canDefineTempVariablesInPlace a boolean indicating whether you can define the temporary variable at an assignment location | ||
* @param shouldEmitCommaBeforeAssignment a boolean indicating whether an assignment should prefix with comma | ||
*/ | ||
function emitTempVariableAssignment(expression: Expression, canDefineTempVariablesInPlace: boolean, shouldEmitCommaBeforeAssignment: boolean): Identifier { | ||
let identifier = createTempVariable(TempFlags.Auto); | ||
if (!canDefineTempVariablesInPlace) { | ||
recordTempDeclaration(identifier); | ||
} | ||
emitAssignment(identifier, expression, shouldEmitCommaBeforeAssignment); | ||
return identifier; | ||
} | ||
|
||
function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, isAssignmentExpressionStatement: boolean, value?: Expression) { | ||
let emitCount = 0; | ||
|
||
|
@@ -3462,36 +3591,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi | |
emitBindingElement(<BindingElement>root, value); | ||
} | ||
|
||
function emitAssignment(name: Identifier, value: Expression) { | ||
if (emitCount++) { | ||
write(", "); | ||
} | ||
|
||
const isVariableDeclarationOrBindingElement = | ||
name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement); | ||
|
||
let exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name); | ||
|
||
if (exportChanged) { | ||
write(`${exportFunctionForFile}("`); | ||
emitNodeWithCommentsAndWithoutSourcemap(name); | ||
write(`", `); | ||
} | ||
|
||
if (isVariableDeclarationOrBindingElement) { | ||
emitModuleMemberName(<Declaration>name.parent); | ||
} | ||
else { | ||
emit(name); | ||
} | ||
|
||
write(" = "); | ||
emit(value); | ||
|
||
if (exportChanged) { | ||
write(")"); | ||
} | ||
} | ||
|
||
/** | ||
* Ensures that there exists a declared identifier whose value holds the given expression. | ||
|
@@ -3507,11 +3606,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi | |
return expr; | ||
} | ||
|
||
let identifier = createTempVariable(TempFlags.Auto); | ||
if (!canDefineTempVariablesInPlace) { | ||
recordTempDeclaration(identifier); | ||
} | ||
emitAssignment(identifier, expr); | ||
let identifier = emitTempVariableAssignment(expr, canDefineTempVariablesInPlace, emitCount > 0); | ||
emitCount++; | ||
return identifier; | ||
} | ||
|
||
|
@@ -3611,7 +3707,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi | |
emitArrayLiteralAssignment(<ArrayLiteralExpression>target, value); | ||
} | ||
else { | ||
emitAssignment(<Identifier>target, value); | ||
emitAssignment(<Identifier>target, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0); | ||
emitCount++; | ||
} | ||
} | ||
|
||
|
@@ -3680,7 +3777,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi | |
} | ||
} | ||
else { | ||
emitAssignment(<Identifier>target.name, value); | ||
emitAssignment(<Identifier>target.name, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0); | ||
emitCount++; | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of this looks duplicated, couldn't you consolidate it further?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand what you mean
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parts of the
if
and theelse if
look the same.