diff --git a/src/slang-nodes/ConditionalExpression.ts b/src/slang-nodes/ConditionalExpression.ts index 3eb098044..d8098c3fe 100644 --- a/src/slang-nodes/ConditionalExpression.ts +++ b/src/slang-nodes/ConditionalExpression.ts @@ -100,6 +100,14 @@ function traditionalTernaries( ]); } +function getOperandSingleExpression({ + variant +}: Expression): Expression | undefined { + return variant.kind === NonterminalKind.TupleExpression + ? variant.items.getSingleExpression() + : undefined; +} + export class ConditionalExpression implements SlangNode { readonly kind = NonterminalKind.ConditionalExpression; @@ -133,13 +141,14 @@ export class ConditionalExpression implements SlangNode { // We can remove parentheses only because we are sure that the // `condition` must be a single `bool` value. const operandLoc = this.operand.loc; - while ( - this.operand.variant.kind === NonterminalKind.TupleExpression && - this.operand.variant.items.items.length === 1 && - this.operand.variant.items.items[0].expression!.variant.kind !== - NonterminalKind.ConditionalExpression + for ( + let operandSingleExpression = getOperandSingleExpression(this.operand); + operandSingleExpression && + operandSingleExpression.variant.kind !== + NonterminalKind.ConditionalExpression; + operandSingleExpression = getOperandSingleExpression(this.operand) ) { - this.operand = this.operand.variant.items.items[0].expression!; + this.operand = operandSingleExpression; } this.operand.loc = operandLoc; } diff --git a/src/slang-nodes/MemberAccessExpression.ts b/src/slang-nodes/MemberAccessExpression.ts index 734c8a0fa..b55919b6c 100644 --- a/src/slang-nodes/MemberAccessExpression.ts +++ b/src/slang-nodes/MemberAccessExpression.ts @@ -24,9 +24,9 @@ function isEndOfChain( path: AstPath ): boolean { for ( - let i = 2, current: StrictAstNode = node, grandparent = path.getNode(i)!; - isChainableExpression(grandparent); - i += 2, current = grandparent, grandparent = path.getNode(i)! + let i = 2, current: StrictAstNode = node, grandparent = path.getNode(i); + grandparent && isChainableExpression(grandparent); + i += 2, current = grandparent, grandparent = path.getNode(i) ) { switch (grandparent.kind) { case NonterminalKind.MemberAccessExpression: diff --git a/src/slang-nodes/TupleValues.ts b/src/slang-nodes/TupleValues.ts index e2e37cdcf..37eafc62b 100644 --- a/src/slang-nodes/TupleValues.ts +++ b/src/slang-nodes/TupleValues.ts @@ -8,6 +8,7 @@ import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { AstNode } from './types.d.ts'; import type { PrintFunction, SlangNode } from '../types.d.ts'; +import type { Expression } from './Expression.js'; export class TupleValues implements SlangNode { readonly kind = NonterminalKind.TupleValues; @@ -32,11 +33,16 @@ export class TupleValues implements SlangNode { this.loc = metadata.loc; } + getSingleExpression(): Expression | undefined { + const items = this.items; + return items.length === 1 ? items[0].expression : undefined; + } + print(path: AstPath, print: PrintFunction): Doc { - return this.items.length === 1 && - this.items[0].expression && - this.items[0].expression.variant.kind !== TerminalKind.Identifier && - isBinaryOperation(this.items[0].expression.variant) + const singleExpressionVariant = this.getSingleExpression()?.variant; + return singleExpressionVariant && + singleExpressionVariant.kind !== TerminalKind.Identifier && + isBinaryOperation(singleExpressionVariant) ? path.map(print, 'items') : printSeparatedList(path.map(print, 'items')); }