diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 80a04129ee..837113fd37 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9842,7 +9842,9 @@ namespace ts { let rightType = checkExpression(node.right, contextualMapper); switch (operator) { case SyntaxKind.AsteriskToken: + case SyntaxKind.AsteriskAsteriskToken: case SyntaxKind.AsteriskEqualsToken: + case SyntaxKind.AsteriskAsteriskEqualsToken: case SyntaxKind.SlashToken: case SyntaxKind.SlashEqualsToken: case SyntaxKind.PercentToken: @@ -9861,7 +9863,7 @@ namespace ts { case SyntaxKind.CaretEqualsToken: case SyntaxKind.AmpersandToken: case SyntaxKind.AmpersandEqualsToken: - // TypeScript 1.0 spec (April 2014): 4.15.1 + // TypeScript 1.0 spec (April 2014): 4.19.1 // These operators require their operands to be of type Any, the Number primitive type, // or an enum type. Operands of an enum type are treated // as having the primitive type Number. If one operand is the null or undefined value, @@ -9890,7 +9892,7 @@ namespace ts { return numberType; case SyntaxKind.PlusToken: case SyntaxKind.PlusEqualsToken: - // TypeScript 1.0 spec (April 2014): 4.15.2 + // TypeScript 1.0 spec (April 2014): 4.19.2 // The binary + operator requires both operands to be of the Number primitive type or an enum type, // or at least one of the operands to be of type Any or the String primitive type. diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 44e5a45b05..6ddf868efe 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2522,12 +2522,23 @@ 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 (languageVersion < ScriptTarget.ES7 && node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken) { + write("Math.pow("); + emit(node.left); + write(", "); + emit(node.right); + write(")"); + } + else { + 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 (exportChanged) { write(")"); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 330ad05518..7673f147e8 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3015,7 +3015,11 @@ namespace ts { let newPrecedence = getBinaryOperatorPrecedence(); // Check the precedence to see if we should "take" this operator - if (newPrecedence <= precedence) { + if (token === SyntaxKind.AsteriskAsteriskToken && newPrecedence < precedence) { + // ** operator is right-assocative + break; + } + else if (token !== SyntaxKind.AsteriskAsteriskToken && newPrecedence <= precedence) { break; } @@ -3089,6 +3093,8 @@ namespace ts { case SyntaxKind.SlashToken: case SyntaxKind.PercentToken: return 10; + case SyntaxKind.AsteriskAsteriskToken: + return 11; } // -1 is lower than all other precedences. Returning it will cause binary expression diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 82fbc8c2a5..91a2783d5d 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -136,6 +136,7 @@ namespace ts { "=>": SyntaxKind.EqualsGreaterThanToken, "+": SyntaxKind.PlusToken, "-": SyntaxKind.MinusToken, + "**": SyntaxKind.AsteriskAsteriskToken, "*": SyntaxKind.AsteriskToken, "/": SyntaxKind.SlashToken, "%": SyntaxKind.PercentToken, @@ -158,6 +159,7 @@ namespace ts { "+=": SyntaxKind.PlusEqualsToken, "-=": SyntaxKind.MinusEqualsToken, "*=": SyntaxKind.AsteriskEqualsToken, + "**=": SyntaxKind.AsteriskAsteriskEqualsToken, "/=": SyntaxKind.SlashEqualsToken, "%=": SyntaxKind.PercentEqualsToken, "<<=": SyntaxKind.LessThanLessThanEqualsToken, @@ -1212,6 +1214,12 @@ namespace ts { if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { return pos += 2, token = SyntaxKind.AsteriskEqualsToken; } + if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { + if (text.charCodeAt(pos + 2) === CharacterCodes.equals) { + return pos += 3, token = SyntaxKind.AsteriskAsteriskEqualsToken; + } + return pos += 2, token = SyntaxKind.AsteriskAsteriskToken; + } return pos++, token = SyntaxKind.AsteriskToken; case CharacterCodes.plus: if (text.charCodeAt(pos + 1) === CharacterCodes.plus) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d2757bb793..657e1f507c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -64,6 +64,7 @@ namespace ts { PlusToken, MinusToken, AsteriskToken, + AsteriskAsteriskToken, SlashToken, PercentToken, PlusPlusToken, @@ -86,6 +87,7 @@ namespace ts { PlusEqualsToken, MinusEqualsToken, AsteriskEqualsToken, + AsteriskAsteriskEqualsToken, SlashEqualsToken, PercentEqualsToken, LessThanLessThanEqualsToken, @@ -702,13 +704,15 @@ namespace ts { contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution } + export type UnaryOrBinaryExpression = UnaryExpression | BinaryExpression; + export interface UnaryExpression extends Expression { _unaryExpressionBrand: any; } export interface PrefixUnaryExpression extends UnaryExpression { operator: SyntaxKind; - operand: UnaryExpression; + operand: UnaryOrBinaryExpression; } export interface PostfixUnaryExpression extends PostfixExpression { @@ -733,19 +737,19 @@ namespace ts { } export interface DeleteExpression extends UnaryExpression { - expression: UnaryExpression; + expression: UnaryOrBinaryExpression; } export interface TypeOfExpression extends UnaryExpression { - expression: UnaryExpression; + expression: UnaryOrBinaryExpression; } export interface VoidExpression extends UnaryExpression { - expression: UnaryExpression; + expression: UnaryOrBinaryExpression; } export interface AwaitExpression extends UnaryExpression { - expression: UnaryExpression; + expression: UnaryOrBinaryExpression; } export interface YieldExpression extends Expression { @@ -852,7 +856,7 @@ namespace ts { export interface TypeAssertion extends UnaryExpression { type: TypeNode; - expression: UnaryExpression; + expression: UnaryOrBinaryExpression; } export type AssertionExpression = TypeAssertion | AsExpression; @@ -2101,6 +2105,7 @@ namespace ts { ES3 = 0, ES5 = 1, ES6 = 2, + ES7 = 3, Latest = ES6, }