Modified associativity rules due to addition of exponentiation operator.

This commit is contained in:
Ron Buckton
2015-10-16 17:57:41 -07:00
parent 738388050f
commit be1de23248
2 changed files with 89 additions and 30 deletions

View File

@@ -135,22 +135,7 @@ namespace ts {
return modifiers;
}
// export function createSourceFileNode(): SourceFile {
// let node = <SourceFile>createNode(SyntaxKind.SourceFile);
// return node;
// }
// export function updateSourceFileNode(node: SourceFile, statements: NodeArray<Statement>, endOfFileToken: Node): SourceFile {
// if (statements !== node.statements || endOfFileToken !== node.endOfFileToken) {
// let newNode = createNode<SourceFile>(SyntaxKind.SourceFile);
// newNode.statements = statements;
// newNode.endOfFileToken = endOfFileToken;
// return updateFrom(node, newNode);
// }
// return node;
// }
export function createNumericLiteral2(value: number, location?: TextRange, flags?: NodeFlags): LiteralExpression {
let node = createNumericLiteral(String(value), location, flags);
return node;
@@ -168,30 +153,54 @@ namespace ts {
return nodeIsSynthesized(node) ? node : cloneNode(node);
}
export function parenthesizeForBinary(expr: Expression, operator: SyntaxKind) {
const enum BinaryOperandSide {
Left,
Right
}
function parenthesizeForBinary(operand: Expression, operator: SyntaxKind, side: BinaryOperandSide) {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
expr = (<AssertionExpression>expr).expression;
while (operand.kind === SyntaxKind.TypeAssertionExpression || operand.kind === SyntaxKind.AsExpression) {
operand = (<AssertionExpression>operand).expression;
}
// If the resulting expression is already parenthesized, we do not need to do any further processing.
if (isParenthesizedExpression(expr)) {
return expr;
if (isParenthesizedExpression(operand)) {
return operand;
}
let exprPrecedence = getExpressionPrecedence(expr);
return needsParenthesesForBinary(operand, operator, side)
? createParenthesizedExpression(operand)
: operand;
}
function needsParenthesesForBinary(operand: Expression, operator: SyntaxKind, side: BinaryOperandSide) {
let operandPrecedence = getExpressionPrecedence(operand);
let operatorPrecedence = getBinaryOperatorPrecedence(operator);
if (exprPrecedence < operatorPrecedence) {
// lower precedence, the expression needs parenthesis
return createParenthesizedExpression(expr);
}
else {
// higher precedence.
return expr;
switch (compareValues(operandPrecedence, operatorPrecedence)) {
case Comparison.LessThan:
return true;
case Comparison.EqualTo:
return isRightAssociativeOperandOnLeftHandSide(operand, side)
|| isModuloOperandOnRightHandSide(operand, operator, side);
case Comparison.GreaterThan:
return false;
}
}
function isRightAssociativeOperandOnLeftHandSide(operand: Expression, side: BinaryOperandSide) {
return side === BinaryOperandSide.Left
&& getExpressionAssociativity(operand) === Associativity.Right;
}
function isModuloOperandOnRightHandSide(operand: Expression, operator: SyntaxKind, side: BinaryOperandSide) {
return side === BinaryOperandSide.Right
&& operator !== SyntaxKind.PercentToken
&& isBinaryExpression(operand)
&& operand.operatorToken.kind === SyntaxKind.PercentToken;
}
export function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
@@ -262,7 +271,7 @@ namespace ts {
}
export function createBinaryExpression2(left: Expression, operator: SyntaxKind, right: Expression, location?: TextRange) {
return createBinaryExpression(parenthesizeForBinary(left, operator), createNode(operator), parenthesizeForBinary(right, operator), location);
return createBinaryExpression(parenthesizeForBinary(left, operator, BinaryOperandSide.Left), createNode(operator), parenthesizeForBinary(right, operator, BinaryOperandSide.Right), location);
}
export function createConditionalExpression2(condition: Expression, whenTrue: Expression, whenFalse: Expression, location?: TextRange, flags?: NodeFlags) {

View File

@@ -1072,6 +1072,56 @@ namespace ts {
}
}
export const enum Associativity {
Left,
Right
}
export function getExpressionAssociativity(expr: Expression) {
return getOperatorAssociativity(expr.kind, getOperator(expr), isNewExpression(expr) && !expr.arguments);
}
export function getBinaryOperatorAssociativity(operator: SyntaxKind) {
return getOperatorAssociativity(SyntaxKind.BinaryExpression, operator);
}
export function getOperatorAssociativity(kind: SyntaxKind, operator: SyntaxKind, isNewExpressionWithoutArguments?: boolean) {
switch (kind) {
case SyntaxKind.NewExpression:
return isNewExpressionWithoutArguments ? Associativity.Right : Associativity.Left;
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.TypeOfExpression:
case SyntaxKind.VoidExpression:
case SyntaxKind.DeleteExpression:
case SyntaxKind.AwaitExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.YieldExpression:
return Associativity.Right;
case SyntaxKind.BinaryExpression:
switch (operator) {
case SyntaxKind.AsteriskAsteriskToken:
case SyntaxKind.EqualsToken:
case SyntaxKind.PlusEqualsToken:
case SyntaxKind.MinusEqualsToken:
case SyntaxKind.AsteriskAsteriskEqualsToken:
case SyntaxKind.AsteriskEqualsToken:
case SyntaxKind.SlashEqualsToken:
case SyntaxKind.PercentEqualsToken:
case SyntaxKind.LessThanLessThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
case SyntaxKind.AmpersandEqualsToken:
case SyntaxKind.CaretEqualsToken:
case SyntaxKind.BarEqualsToken:
return Associativity.Right;
}
}
return Associativity.Left;
}
export function getExpressionPrecedence(expr: Expression) {
return getOperatorPrecedence(expr.kind, getOperator(expr), isNewExpression(expr) && !expr.arguments)
}