diff --git a/src/slang-comments/handlers/add-collection-first-comment.ts b/src/slang-comments/handlers/add-collection-first-comment.ts index 1900498c8..ee5de3ce7 100644 --- a/src/slang-comments/handlers/add-collection-first-comment.ts +++ b/src/slang-comments/handlers/add-collection-first-comment.ts @@ -1,11 +1,11 @@ import { util } from 'prettier'; -import type { Comment, NodeCollection } from '../../slang-nodes/types.d.ts'; +import type { Comment, StrictCollection } from '../../slang-nodes/types.d.ts'; const { addDanglingComment, addLeadingComment } = util; export default function addCollectionFirstComment( - node: NodeCollection, + node: StrictCollection, comment: Comment ): void { if (node.items.length === 0) { diff --git a/src/slang-comments/handlers/add-collection-last-comment.ts b/src/slang-comments/handlers/add-collection-last-comment.ts index 6b288b996..3cc6f43e4 100644 --- a/src/slang-comments/handlers/add-collection-last-comment.ts +++ b/src/slang-comments/handlers/add-collection-last-comment.ts @@ -1,11 +1,11 @@ import { util } from 'prettier'; -import type { Comment, NodeCollection } from '../../slang-nodes/types.d.ts'; +import type { Comment, StrictCollection } from '../../slang-nodes/types.d.ts'; const { addDanglingComment, addTrailingComment } = util; export default function addCollectionLastComment( - node: NodeCollection, + node: StrictCollection, comment: Comment ): void { if (node.items.length === 0) { diff --git a/src/slang-nodes/AdditiveExpression.ts b/src/slang-nodes/AdditiveExpression.ts index b25e77302..e11e235b9 100644 --- a/src/slang-nodes/AdditiveExpression.ts +++ b/src/slang-nodes/AdditiveExpression.ts @@ -2,6 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printBinaryOperation } from '../slang-printers/print-binary-operation.js'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -28,18 +29,20 @@ const printAdditiveExpression = printBinaryOperation( export class AdditiveExpression extends SlangNode { readonly kind = NonterminalKind.AdditiveExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.AdditiveExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/AndExpression.ts b/src/slang-nodes/AndExpression.ts index 31aad5e3a..20b9e79bc 100644 --- a/src/slang-nodes/AndExpression.ts +++ b/src/slang-nodes/AndExpression.ts @@ -1,5 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printLogicalOperation } from '../slang-printers/print-logical-operation.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -11,18 +12,20 @@ import type { AstNode } from './types.d.ts'; export class AndExpression extends SlangNode { readonly kind = NonterminalKind.AndExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.AndExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); } diff --git a/src/slang-nodes/ArrayTypeName.ts b/src/slang-nodes/ArrayTypeName.ts index a748cde6b..a7ce37c14 100644 --- a/src/slang-nodes/ArrayTypeName.ts +++ b/src/slang-nodes/ArrayTypeName.ts @@ -1,5 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { TypeName } from './TypeName.js'; import { Expression } from './Expression.js'; @@ -14,14 +15,14 @@ export class ArrayTypeName extends SlangNode { operand: TypeName; - index?: Expression; + index?: Expression['variant']; constructor(ast: ast.ArrayTypeName, options: ParserOptions) { super(ast); this.operand = new TypeName(ast.operand, options); if (ast.index) { - this.index = new Expression(ast.index, options); + this.index = extractVariant(new Expression(ast.index, options)); } this.updateMetadata(this.operand, this.index); @@ -31,7 +32,7 @@ export class ArrayTypeName extends SlangNode { return [ path.call(printVariant(print), 'operand'), '[', - path.call(printVariant(print), 'index'), + path.call(print, 'index'), ']' ]; } diff --git a/src/slang-nodes/ArrayValues.ts b/src/slang-nodes/ArrayValues.ts index 371b6fb34..4d896e3b6 100644 --- a/src/slang-nodes/ArrayValues.ts +++ b/src/slang-nodes/ArrayValues.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printSeparatedList } from '../slang-printers/print-separated-list.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -12,15 +12,17 @@ import type { AstNode } from './types.d.ts'; export class ArrayValues extends SlangNode { readonly kind = NonterminalKind.ArrayValues; - items: Expression[]; + items: Expression['variant'][]; constructor(ast: ast.ArrayValues, options: ParserOptions) { super(ast, true); - this.items = ast.items.map((item) => new Expression(item, options)); + this.items = ast.items.map((item) => + extractVariant(new Expression(item, options)) + ); } print(path: AstPath, print: PrintFunction): Doc { - return printSeparatedList(path.map(printVariant(print), 'items')); + return printSeparatedList(path.map(print, 'items')); } } diff --git a/src/slang-nodes/AssignmentExpression.ts b/src/slang-nodes/AssignmentExpression.ts index 4444787a0..f1963330b 100644 --- a/src/slang-nodes/AssignmentExpression.ts +++ b/src/slang-nodes/AssignmentExpression.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { isBinaryOperation } from '../slang-utils/is-binary-operation.js'; import { printIndentedGroupOrSpacedDocument } from '../slang-printers/print-indented-group-or-spaced-document.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; import { TerminalNode } from './TerminalNode.js'; @@ -14,31 +14,32 @@ import type { AstNode } from './types.d.ts'; export class AssignmentExpression extends SlangNode { readonly kind = NonterminalKind.AssignmentExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.AssignmentExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); } print(path: AstPath, print: PrintFunction): Doc { - const rightOperandVariant = this.rightOperand.variant; return [ - path.call(printVariant(print), 'leftOperand'), + path.call(print, 'leftOperand'), ` ${this.operator}`, printIndentedGroupOrSpacedDocument( - path.call(printVariant(print), 'rightOperand'), - !(rightOperandVariant instanceof TerminalNode) && - isBinaryOperation(rightOperandVariant) + path.call(print, 'rightOperand'), + !(this.rightOperand instanceof TerminalNode) && + isBinaryOperation(this.rightOperand) ) ]; } diff --git a/src/slang-nodes/BitwiseAndExpression.ts b/src/slang-nodes/BitwiseAndExpression.ts index 8ae705251..88547f1d4 100644 --- a/src/slang-nodes/BitwiseAndExpression.ts +++ b/src/slang-nodes/BitwiseAndExpression.ts @@ -2,6 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printBinaryOperation } from '../slang-printers/print-binary-operation.js'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -24,18 +25,20 @@ const printBitwiseAndExpression = printBinaryOperation( export class BitwiseAndExpression extends SlangNode { readonly kind = NonterminalKind.BitwiseAndExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.BitwiseAndExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/BitwiseOrExpression.ts b/src/slang-nodes/BitwiseOrExpression.ts index faa529c75..c2daaa349 100644 --- a/src/slang-nodes/BitwiseOrExpression.ts +++ b/src/slang-nodes/BitwiseOrExpression.ts @@ -2,6 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printBinaryOperation } from '../slang-printers/print-binary-operation.js'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -34,18 +35,20 @@ const printBitwiseOrExpression = printBinaryOperation( export class BitwiseOrExpression extends SlangNode { readonly kind = NonterminalKind.BitwiseOrExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.BitwiseOrExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/BitwiseXorExpression.ts b/src/slang-nodes/BitwiseXorExpression.ts index 31b8d3c4e..9c9adfe84 100644 --- a/src/slang-nodes/BitwiseXorExpression.ts +++ b/src/slang-nodes/BitwiseXorExpression.ts @@ -2,6 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printBinaryOperation } from '../slang-printers/print-binary-operation.js'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -24,18 +25,20 @@ const printBitwiseXorExpression = printBinaryOperation( export class BitwiseXorExpression extends SlangNode { readonly kind = NonterminalKind.BitwiseXorExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.BitwiseXorExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/CallOptionsExpression.ts b/src/slang-nodes/CallOptionsExpression.ts index 8087da8fb..77bcccb24 100644 --- a/src/slang-nodes/CallOptionsExpression.ts +++ b/src/slang-nodes/CallOptionsExpression.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; import { CallOptions } from './CallOptions.js'; @@ -12,25 +12,20 @@ import type { AstNode } from './types.d.ts'; export class CallOptionsExpression extends SlangNode { readonly kind = NonterminalKind.CallOptionsExpression; - operand: Expression; + operand: Expression['variant']; options: CallOptions; constructor(ast: ast.CallOptionsExpression, options: ParserOptions) { super(ast); - this.operand = new Expression(ast.operand, options); + this.operand = extractVariant(new Expression(ast.operand, options)); this.options = new CallOptions(ast.options, options); this.updateMetadata(this.operand, this.options); } print(path: AstPath, print: PrintFunction): Doc { - return [ - path.call(printVariant(print), 'operand'), - '{', - path.call(print, 'options'), - '}' - ]; + return [path.call(print, 'operand'), '{', path.call(print, 'options'), '}']; } } diff --git a/src/slang-nodes/ConditionalExpression.ts b/src/slang-nodes/ConditionalExpression.ts index a502847ea..5e06c8a78 100644 --- a/src/slang-nodes/ConditionalExpression.ts +++ b/src/slang-nodes/ConditionalExpression.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { doc } from 'prettier'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -18,20 +18,19 @@ function experimentalTernaries( print: PrintFunction, { useTabs, tabWidth }: ParserOptions ): Doc { - const grandparent = path.grandparent as StrictAstNode; - const isNested = grandparent.kind === NonterminalKind.ConditionalExpression; - const isNestedAsTrueExpression = - isNested && grandparent.trueExpression.variant === node; - const falseExpressionVariantKind = node.falseExpression.variant.kind; + const parent = path.parent as StrictAstNode; + const isNested = parent.kind === NonterminalKind.ConditionalExpression; + const isNestedAsTrueExpression = isNested && parent.trueExpression === node; + const falseExpressionVariantKind = node.falseExpression.kind; const falseExpressionInSameLine = falseExpressionVariantKind === NonterminalKind.TupleExpression || falseExpressionVariantKind === NonterminalKind.ConditionalExpression; // If the `condition` breaks into multiple lines, we add parentheses, // unless it already is a `TupleExpression`. - const operand = path.call(printVariant(print), 'operand'); + const operand = path.call(print, 'operand'); const operandDoc = group([ - node.operand.variant.kind === NonterminalKind.TupleExpression + node.operand.kind === NonterminalKind.TupleExpression ? operand : ifBreak(['(', printSeparatedItem(operand), ')'], operand), ' ?' @@ -42,7 +41,7 @@ function experimentalTernaries( // `trueExpression`. const trueExpressionDoc = indent([ isNestedAsTrueExpression ? hardline : line, - path.call(printVariant(print), 'trueExpression') + path.call(print, 'trueExpression') ]); const groupId = Symbol('Slang.ConditionalExpression.trueExpression'); @@ -59,7 +58,7 @@ function experimentalTernaries( ? ' '.repeat(tabWidth - 1) : ' '; - const falseExpression = path.call(printVariant(print), 'falseExpression'); + const falseExpression = path.call(print, 'falseExpression'); const falseExpressionDoc = [ isNested ? hardline : line, ':', @@ -76,7 +75,7 @@ function experimentalTernaries( const document = group([conditionAndTrueExpressionGroup, falseExpressionDoc]); - return grandparent.kind === NonterminalKind.VariableDeclarationValue + return parent.kind === NonterminalKind.VariableDeclarationValue ? group(indent([softline, document])) : document; } @@ -86,46 +85,50 @@ function traditionalTernaries( print: PrintFunction ): Doc { return group([ - path.call(printVariant(print), 'operand'), + path.call(print, 'operand'), indent([ // Nested trueExpression and falseExpression are always printed in a new // line - (path.grandparent as StrictAstNode).kind === + (path.parent as StrictAstNode).kind === NonterminalKind.ConditionalExpression ? hardline : line, '? ', - path.call(printVariant(print), 'trueExpression'), + path.call(print, 'trueExpression'), line, ': ', - path.call(printVariant(print), 'falseExpression') + path.call(print, 'falseExpression') ]) ]); } -function getOperandSingleExpression({ - variant -}: Expression): Expression | undefined { - return variant.kind === NonterminalKind.TupleExpression - ? variant.items.getSingleExpression() +function getOperandSingleExpression( + operand: Expression['variant'] +): Expression['variant'] | undefined { + return operand.kind === NonterminalKind.TupleExpression + ? operand.items.getSingleExpression() : undefined; } export class ConditionalExpression extends SlangNode { readonly kind = NonterminalKind.ConditionalExpression; - operand: Expression; + operand: Expression['variant']; - trueExpression: Expression; + trueExpression: Expression['variant']; - falseExpression: Expression; + falseExpression: Expression['variant']; constructor(ast: ast.ConditionalExpression, options: ParserOptions) { super(ast); - this.operand = new Expression(ast.operand, options); - this.trueExpression = new Expression(ast.trueExpression, options); - this.falseExpression = new Expression(ast.falseExpression, options); + this.operand = extractVariant(new Expression(ast.operand, options)); + this.trueExpression = extractVariant( + new Expression(ast.trueExpression, options) + ); + this.falseExpression = extractVariant( + new Expression(ast.falseExpression, options) + ); this.updateMetadata( this.operand, @@ -140,8 +143,7 @@ export class ConditionalExpression extends SlangNode { for ( let operandSingleExpression = getOperandSingleExpression(this.operand); operandSingleExpression && - operandSingleExpression.variant.kind !== - NonterminalKind.ConditionalExpression; + operandSingleExpression.kind !== NonterminalKind.ConditionalExpression; operandSingleExpression = getOperandSingleExpression(this.operand) ) { this.operand = operandSingleExpression; diff --git a/src/slang-nodes/ConstantDefinition.ts b/src/slang-nodes/ConstantDefinition.ts index 412dbf79d..0e2e95a28 100644 --- a/src/slang-nodes/ConstantDefinition.ts +++ b/src/slang-nodes/ConstantDefinition.ts @@ -1,5 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { TypeName } from './TypeName.js'; import { TerminalNode } from './TerminalNode.js'; @@ -17,14 +18,14 @@ export class ConstantDefinition extends SlangNode { name: TerminalNode; - value: Expression; + value: Expression['variant']; constructor(ast: ast.ConstantDefinition, options: ParserOptions) { super(ast); this.typeName = new TypeName(ast.typeName, options); this.name = new TerminalNode(ast.name); - this.value = new Expression(ast.value, options); + this.value = extractVariant(new Expression(ast.value, options)); this.updateMetadata(this.typeName, this.value); } @@ -35,7 +36,7 @@ export class ConstantDefinition extends SlangNode { ' constant ', path.call(print, 'name'), ' = ', - path.call(printVariant(print), 'value'), + path.call(print, 'value'), ';' ]; } diff --git a/src/slang-nodes/DoWhileStatement.ts b/src/slang-nodes/DoWhileStatement.ts index a78347814..00cea0967 100644 --- a/src/slang-nodes/DoWhileStatement.ts +++ b/src/slang-nodes/DoWhileStatement.ts @@ -1,7 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { doc } from 'prettier'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; -import { printVariant } from '../slang-printers/print-variant.js'; import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Statement } from './Statement.js'; @@ -19,13 +18,13 @@ export class DoWhileStatement extends SlangNode { body: Statement['variant']; - condition: Expression; + condition: Expression['variant']; constructor(ast: ast.DoWhileStatement, options: ParserOptions) { super(ast); this.body = extractVariant(new Statement(ast.body, options)); - this.condition = new Expression(ast.condition, options); + this.condition = extractVariant(new Expression(ast.condition, options)); this.updateMetadata(this.body, this.condition); } @@ -38,7 +37,7 @@ export class DoWhileStatement extends SlangNode { ? [' ', body, ' '] : printSeparatedItem(body, { firstSeparator: line }), 'while (', - printSeparatedItem(path.call(printVariant(print), 'condition')), + printSeparatedItem(path.call(print, 'condition')), ');' ]; } diff --git a/src/slang-nodes/EqualityExpression.ts b/src/slang-nodes/EqualityExpression.ts index 805a183d3..81727e9f1 100644 --- a/src/slang-nodes/EqualityExpression.ts +++ b/src/slang-nodes/EqualityExpression.ts @@ -2,6 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; import { printBinaryOperation } from '../slang-printers/print-binary-operation.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -22,18 +23,20 @@ const printEqualityExpression = printBinaryOperation( export class EqualityExpression extends SlangNode { readonly kind = NonterminalKind.EqualityExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.EqualityExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/ExponentiationExpression.ts b/src/slang-nodes/ExponentiationExpression.ts index 6856705d6..b0f862c77 100644 --- a/src/slang-nodes/ExponentiationExpression.ts +++ b/src/slang-nodes/ExponentiationExpression.ts @@ -4,6 +4,7 @@ import { createBinaryOperationPrinter } from '../slang-printers/create-binary-op import { binaryIndentRulesBuilder } from '../slang-printers/print-binary-operation.js'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -39,11 +40,11 @@ const printExponentiationExpression = createBinaryOperationPrinter( export class ExponentiationExpression extends SlangNode { readonly kind = NonterminalKind.ExponentiationExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor( ast: ast.ExponentiationExpression, @@ -51,9 +52,11 @@ export class ExponentiationExpression extends SlangNode { ) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/Expression.ts b/src/slang-nodes/Expression.ts index 84d0f8169..0427f7b0f 100644 --- a/src/slang-nodes/Expression.ts +++ b/src/slang-nodes/Expression.ts @@ -4,7 +4,7 @@ import { TerminalNode as SlangTerminalNode } from '@nomicfoundation/slang/cst'; import { extractVariant } from '../slang-utils/extract-variant.js'; -import { PolymorphicNode } from './PolymorphicNode.js'; +import { SlangNode } from './SlangNode.js'; import { AssignmentExpression } from './AssignmentExpression.js'; import { ConditionalExpression } from './ConditionalExpression.js'; import { OrExpression } from './OrExpression.js'; @@ -126,7 +126,7 @@ function createNonterminalVariant( return exhaustiveCheck; } -export class Expression extends PolymorphicNode { +export class Expression extends SlangNode { readonly kind = NonterminalKind.Expression; variant: diff --git a/src/slang-nodes/ExpressionStatement.ts b/src/slang-nodes/ExpressionStatement.ts index 0c45f3e72..021a399d8 100644 --- a/src/slang-nodes/ExpressionStatement.ts +++ b/src/slang-nodes/ExpressionStatement.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -11,17 +11,17 @@ import type { AstNode } from './types.d.ts'; export class ExpressionStatement extends SlangNode { readonly kind = NonterminalKind.ExpressionStatement; - expression: Expression; + expression: Expression['variant']; constructor(ast: ast.ExpressionStatement, options: ParserOptions) { super(ast); - this.expression = new Expression(ast.expression, options); + this.expression = extractVariant(new Expression(ast.expression, options)); this.updateMetadata(this.expression); } print(path: AstPath, print: PrintFunction): Doc { - return [path.call(printVariant(print), 'expression'), ';']; + return [path.call(print, 'expression'), ';']; } } diff --git a/src/slang-nodes/ForStatement.ts b/src/slang-nodes/ForStatement.ts index 3f2853384..e68565be8 100644 --- a/src/slang-nodes/ForStatement.ts +++ b/src/slang-nodes/ForStatement.ts @@ -24,7 +24,7 @@ export class ForStatement extends SlangNode { condition: ForStatementCondition; - iterator?: Expression; + iterator?: Expression['variant']; body: Statement['variant']; @@ -37,7 +37,7 @@ export class ForStatement extends SlangNode { ); this.condition = new ForStatementCondition(ast.condition, options); if (ast.iterator) { - this.iterator = new Expression(ast.iterator, options); + this.iterator = extractVariant(new Expression(ast.iterator, options)); } this.body = extractVariant(new Statement(ast.body, options)); @@ -52,7 +52,7 @@ export class ForStatement extends SlangNode { print(path: AstPath, print: PrintFunction): Doc { const initialization = path.call(printVariant(print), 'initialization'); const condition = path.call(printVariant(print), 'condition'); - const iterator = path.call(printVariant(print), 'iterator'); + const iterator = path.call(print, 'iterator'); return [ 'for (', diff --git a/src/slang-nodes/FunctionCallExpression.ts b/src/slang-nodes/FunctionCallExpression.ts index fdfa7c0b2..4152289b6 100644 --- a/src/slang-nodes/FunctionCallExpression.ts +++ b/src/slang-nodes/FunctionCallExpression.ts @@ -2,7 +2,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { doc } from 'prettier'; import { isLabel } from '../slang-utils/is-label.js'; import { printGroupAndIndentIfBreakPair } from '../slang-printers/print-group-and-indent-if-break-pair.js'; -import { printVariant } from '../slang-printers/print-variant.js'; import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -18,7 +17,7 @@ const { label } = doc.builders; export class FunctionCallExpression extends SlangNode { readonly kind = NonterminalKind.FunctionCallExpression; - operand: Expression; + operand: Expression['variant']; arguments: ArgumentsDeclaration['variant']; @@ -28,7 +27,7 @@ export class FunctionCallExpression extends SlangNode { ) { super(ast); - this.operand = new Expression(ast.operand, options); + this.operand = extractVariant(new Expression(ast.operand, options)); this.arguments = extractVariant( new ArgumentsDeclaration(ast.arguments, options) ); @@ -37,7 +36,7 @@ export class FunctionCallExpression extends SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - const operand = path.call(printVariant(print), 'operand'); + const operand = path.call(print, 'operand'); const argumentsDoc = path.call(print, 'arguments'); // If we are at the end of a MemberAccessChain we should indent the diff --git a/src/slang-nodes/IfStatement.ts b/src/slang-nodes/IfStatement.ts index 63a364c20..7c68d1175 100644 --- a/src/slang-nodes/IfStatement.ts +++ b/src/slang-nodes/IfStatement.ts @@ -3,7 +3,6 @@ import { doc } from 'prettier'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; import { printIndentedGroupOrSpacedDocument } from '../slang-printers/print-indented-group-or-spaced-document.js'; import { isBlockComment } from '../slang-utils/is-comment.js'; -import { printVariant } from '../slang-printers/print-variant.js'; import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -20,7 +19,7 @@ const { hardline } = doc.builders; export class IfStatement extends SlangNode { readonly kind = NonterminalKind.IfStatement; - condition: Expression; + condition: Expression['variant']; body: Statement['variant']; @@ -29,7 +28,7 @@ export class IfStatement extends SlangNode { constructor(ast: ast.IfStatement, options: ParserOptions) { super(ast); - this.condition = new Expression(ast.condition, options); + this.condition = extractVariant(new Expression(ast.condition, options)); this.body = extractVariant(new Statement(ast.body, options)); if (ast.elseBranch) { this.elseBranch = new ElseBranch(ast.elseBranch, options); @@ -42,7 +41,7 @@ export class IfStatement extends SlangNode { const { kind: bodyKind, comments: bodyComments } = this.body; return [ 'if (', - printSeparatedItem(path.call(printVariant(print), 'condition')), + printSeparatedItem(path.call(print, 'condition')), ')', printIndentedGroupOrSpacedDocument( path.call(print, 'body'), diff --git a/src/slang-nodes/IndexAccessEnd.ts b/src/slang-nodes/IndexAccessEnd.ts index 99d4b0784..59dcedf69 100644 --- a/src/slang-nodes/IndexAccessEnd.ts +++ b/src/slang-nodes/IndexAccessEnd.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -11,19 +11,19 @@ import type { AstNode } from './types.d.ts'; export class IndexAccessEnd extends SlangNode { readonly kind = NonterminalKind.IndexAccessEnd; - end?: Expression; + end?: Expression['variant']; constructor(ast: ast.IndexAccessEnd, options: ParserOptions) { super(ast); if (ast.end) { - this.end = new Expression(ast.end, options); + this.end = extractVariant(new Expression(ast.end, options)); } this.updateMetadata(this.end); } print(path: AstPath, print: PrintFunction): Doc { - return [':', path.call(printVariant(print), 'end')]; + return [':', path.call(print, 'end')]; } } diff --git a/src/slang-nodes/IndexAccessExpression.ts b/src/slang-nodes/IndexAccessExpression.ts index f145cffb5..aa8f04086 100644 --- a/src/slang-nodes/IndexAccessExpression.ts +++ b/src/slang-nodes/IndexAccessExpression.ts @@ -3,7 +3,7 @@ import { doc } from 'prettier'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; import { printGroupAndIndentIfBreakPair } from '../slang-printers/print-group-and-indent-if-break-pair.js'; import { isLabel } from '../slang-utils/is-label.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; import { IndexAccessEnd } from './IndexAccessEnd.js'; @@ -18,18 +18,18 @@ const { label } = doc.builders; export class IndexAccessExpression extends SlangNode { readonly kind = NonterminalKind.IndexAccessExpression; - operand: Expression; + operand: Expression['variant']; - start?: Expression; + start?: Expression['variant']; end?: IndexAccessEnd; constructor(ast: ast.IndexAccessExpression, options: ParserOptions) { super(ast); - this.operand = new Expression(ast.operand, options); + this.operand = extractVariant(new Expression(ast.operand, options)); if (ast.start) { - this.start = new Expression(ast.start, options); + this.start = extractVariant(new Expression(ast.start, options)); } if (ast.end) { this.end = new IndexAccessEnd(ast.end, options); @@ -39,13 +39,10 @@ export class IndexAccessExpression extends SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - const operand = path.call(printVariant(print), 'operand'); + const operand = path.call(print, 'operand'); const indexDoc = [ '[', - printSeparatedItem([ - path.call(printVariant(print), 'start'), - path.call(print, 'end') - ]), + printSeparatedItem([path.call(print, 'start'), path.call(print, 'end')]), ']' ]; diff --git a/src/slang-nodes/InequalityExpression.ts b/src/slang-nodes/InequalityExpression.ts index 008f908f8..a24b02886 100644 --- a/src/slang-nodes/InequalityExpression.ts +++ b/src/slang-nodes/InequalityExpression.ts @@ -1,6 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; import { printBinaryOperation } from '../slang-printers/print-binary-operation.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -20,18 +21,20 @@ const printComparisonExpression = printBinaryOperation( export class InequalityExpression extends SlangNode { readonly kind = NonterminalKind.InequalityExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.InequalityExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); } diff --git a/src/slang-nodes/MemberAccessExpression.ts b/src/slang-nodes/MemberAccessExpression.ts index 5c234e773..42bd7eb38 100644 --- a/src/slang-nodes/MemberAccessExpression.ts +++ b/src/slang-nodes/MemberAccessExpression.ts @@ -2,7 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { doc } from 'prettier'; import { isLabel } from '../slang-utils/is-label.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; import { TerminalNode } from './TerminalNode.js'; @@ -25,26 +25,26 @@ function isEndOfChain( path: AstPath ): boolean { for ( - let i = 2, current: StrictAstNode = node, grandparent = path.getNode(i); - grandparent && isChainableExpression(grandparent); - i += 2, current = grandparent, grandparent = path.getNode(i) + let i = 1, current: StrictAstNode = node, parent = path.getNode(i); + parent && isChainableExpression(parent); + i++, current = parent, parent = path.getNode(i) ) { - switch (grandparent.kind) { + switch (parent.kind) { case NonterminalKind.MemberAccessExpression: - // If `grandparent` is a MemberAccessExpression we are not at the end + // If `parent` is a MemberAccessExpression we are not at the end // of the chain. return false; case NonterminalKind.IndexAccessExpression: - // If `grandparent` is an IndexAccessExpression and `current` is not + // If `parent` is an IndexAccessExpression and `current` is not // the operand then it must be the start or the end in which case it is // the end of the chain. - if (current !== grandparent.operand.variant) return true; + if (current !== parent.operand) return true; break; case NonterminalKind.FunctionCallExpression: - // If `grandparent` is a FunctionCallExpression and `current` is not + // If `parent` is a FunctionCallExpression and `current` is not // the operand then it must be and argument in which case it is the end // of the chain. - if (current !== grandparent.operand.variant) return true; + if (current !== parent.operand) return true; break; } } @@ -115,7 +115,7 @@ function processChain(chain: Doc[]): Doc { export class MemberAccessExpression extends SlangNode { readonly kind = NonterminalKind.MemberAccessExpression; - operand: Expression; + operand: Expression['variant']; member: TerminalNode; @@ -125,7 +125,7 @@ export class MemberAccessExpression extends SlangNode { ) { super(ast); - this.operand = new Expression(ast.operand, options); + this.operand = extractVariant(new Expression(ast.operand, options)); this.member = new TerminalNode(ast.member); this.updateMetadata(this.operand); @@ -133,7 +133,7 @@ export class MemberAccessExpression extends SlangNode { print(path: AstPath, print: PrintFunction): Doc { const document = [ - path.call(printVariant(print), 'operand'), + path.call(print, 'operand'), label('separator', [softline, '.']), path.call(print, 'member') ].flat(); diff --git a/src/slang-nodes/MultiplicativeExpression.ts b/src/slang-nodes/MultiplicativeExpression.ts index 1c3b13a1f..551f4fcd4 100644 --- a/src/slang-nodes/MultiplicativeExpression.ts +++ b/src/slang-nodes/MultiplicativeExpression.ts @@ -2,6 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printBinaryOperation } from '../slang-printers/print-binary-operation.js'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -31,11 +32,11 @@ const printMultiplicativeExpression = printBinaryOperation( export class MultiplicativeExpression extends SlangNode { readonly kind = NonterminalKind.MultiplicativeExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor( ast: ast.MultiplicativeExpression, @@ -43,9 +44,11 @@ export class MultiplicativeExpression extends SlangNode { ) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/NamedArgument.ts b/src/slang-nodes/NamedArgument.ts index db9549919..70e030578 100644 --- a/src/slang-nodes/NamedArgument.ts +++ b/src/slang-nodes/NamedArgument.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { TerminalNode } from './TerminalNode.js'; import { Expression } from './Expression.js'; @@ -14,22 +14,18 @@ export class NamedArgument extends SlangNode { name: TerminalNode; - value: Expression; + value: Expression['variant']; constructor(ast: ast.NamedArgument, options: ParserOptions) { super(ast); this.name = new TerminalNode(ast.name); - this.value = new Expression(ast.value, options); + this.value = extractVariant(new Expression(ast.value, options)); this.updateMetadata(this.value); } print(path: AstPath, print: PrintFunction): Doc { - return [ - path.call(print, 'name'), - ': ', - path.call(printVariant(print), 'value') - ]; + return [path.call(print, 'name'), ': ', path.call(print, 'value')]; } } diff --git a/src/slang-nodes/OrExpression.ts b/src/slang-nodes/OrExpression.ts index 759e2f0ed..a47872e92 100644 --- a/src/slang-nodes/OrExpression.ts +++ b/src/slang-nodes/OrExpression.ts @@ -1,6 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printLogicalOperation } from '../slang-printers/print-logical-operation.js'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -14,18 +15,20 @@ const tryToHug = createHugFunction(['&&']); export class OrExpression extends SlangNode { readonly kind = NonterminalKind.OrExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.OrExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/PositionalArguments.ts b/src/slang-nodes/PositionalArguments.ts index 75f22396a..01e1b3374 100644 --- a/src/slang-nodes/PositionalArguments.ts +++ b/src/slang-nodes/PositionalArguments.ts @@ -2,7 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printComments } from '../slang-printers/print-comments.js'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; import { printSeparatedList } from '../slang-printers/print-separated-list.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -14,12 +14,14 @@ import type { AstNode } from './types.d.ts'; export class PositionalArguments extends SlangNode { readonly kind = NonterminalKind.PositionalArguments; - items: Expression[]; + items: Expression['variant'][]; constructor(ast: ast.PositionalArguments, options: ParserOptions) { super(ast, true); - this.items = ast.items.map((item) => new Expression(item, options)); + this.items = ast.items.map((item) => + extractVariant(new Expression(item, options)) + ); } print( @@ -28,7 +30,7 @@ export class PositionalArguments extends SlangNode { options: ParserOptions ): Doc { if (this.items.length > 0) { - return printSeparatedList(path.map(printVariant(print), 'items')); + return printSeparatedList(path.map(print, 'items')); } const argumentComments = printComments(path, options); diff --git a/src/slang-nodes/PostfixExpression.ts b/src/slang-nodes/PostfixExpression.ts index bcaa05c20..4a5060237 100644 --- a/src/slang-nodes/PostfixExpression.ts +++ b/src/slang-nodes/PostfixExpression.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -11,20 +11,20 @@ import type { AstNode } from './types.d.ts'; export class PostfixExpression extends SlangNode { readonly kind = NonterminalKind.PostfixExpression; - operand: Expression; + operand: Expression['variant']; operator: string; constructor(ast: ast.PostfixExpression, options: ParserOptions) { super(ast); - this.operand = new Expression(ast.operand, options); + this.operand = extractVariant(new Expression(ast.operand, options)); this.operator = ast.operator.unparse(); this.updateMetadata(this.operand); } print(path: AstPath, print: PrintFunction): Doc { - return [path.call(printVariant(print), 'operand'), this.operator]; + return [path.call(print, 'operand'), this.operator]; } } diff --git a/src/slang-nodes/PrefixExpression.ts b/src/slang-nodes/PrefixExpression.ts index 01ce4c050..ee398b57b 100644 --- a/src/slang-nodes/PrefixExpression.ts +++ b/src/slang-nodes/PrefixExpression.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -13,13 +13,13 @@ export class PrefixExpression extends SlangNode { operator: string; - operand: Expression; + operand: Expression['variant']; constructor(ast: ast.PrefixExpression, options: ParserOptions) { super(ast); this.operator = ast.operator.unparse(); - this.operand = new Expression(ast.operand, options); + this.operand = extractVariant(new Expression(ast.operand, options)); this.updateMetadata(this.operand); @@ -29,6 +29,6 @@ export class PrefixExpression extends SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - return [this.operator, path.call(printVariant(print), 'operand')]; + return [this.operator, path.call(print, 'operand')]; } } diff --git a/src/slang-nodes/ReturnStatement.ts b/src/slang-nodes/ReturnStatement.ts index 61aea5a04..655a6f8ac 100644 --- a/src/slang-nodes/ReturnStatement.ts +++ b/src/slang-nodes/ReturnStatement.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printIndentedGroupOrSpacedDocument } from '../slang-printers/print-indented-group-or-spaced-document.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -12,13 +12,13 @@ import type { AstNode } from './types.d.ts'; export class ReturnStatement extends SlangNode { readonly kind = NonterminalKind.ReturnStatement; - expression?: Expression; + expression?: Expression['variant']; constructor(ast: ast.ReturnStatement, options: ParserOptions) { super(ast); if (ast.expression) { - this.expression = new Expression(ast.expression, options); + this.expression = extractVariant(new Expression(ast.expression, options)); } this.updateMetadata(this.expression); @@ -29,12 +29,12 @@ export class ReturnStatement extends SlangNode { print: PrintFunction, options: ParserOptions ): Doc { - const expressionVariantKind = this.expression?.variant.kind; + const expressionVariantKind = this.expression?.kind; return [ 'return', expressionVariantKind ? printIndentedGroupOrSpacedDocument( - path.call(printVariant(print), 'expression'), + path.call(print, 'expression'), expressionVariantKind !== NonterminalKind.TupleExpression && (!options.experimentalTernaries || expressionVariantKind !== NonterminalKind.ConditionalExpression) diff --git a/src/slang-nodes/ShiftExpression.ts b/src/slang-nodes/ShiftExpression.ts index d684c6952..d1326f9b2 100644 --- a/src/slang-nodes/ShiftExpression.ts +++ b/src/slang-nodes/ShiftExpression.ts @@ -2,6 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printBinaryOperation } from '../slang-printers/print-binary-operation.js'; import { createHugFunction } from '../slang-utils/create-hug-function.js'; import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -36,18 +37,20 @@ const printShiftExpression = printBinaryOperation( export class ShiftExpression extends SlangNode { readonly kind = NonterminalKind.ShiftExpression; - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; constructor(ast: ast.ShiftExpression, options: ParserOptions) { super(ast); - this.leftOperand = new Expression(ast.leftOperand, options); + this.leftOperand = extractVariant(new Expression(ast.leftOperand, options)); this.operator = ast.operator.unparse(); - this.rightOperand = new Expression(ast.rightOperand, options); + this.rightOperand = extractVariant( + new Expression(ast.rightOperand, options) + ); this.updateMetadata(this.leftOperand, this.rightOperand); diff --git a/src/slang-nodes/StateVariableDefinitionValue.ts b/src/slang-nodes/StateVariableDefinitionValue.ts index fa6c5d1aa..c634956b8 100644 --- a/src/slang-nodes/StateVariableDefinitionValue.ts +++ b/src/slang-nodes/StateVariableDefinitionValue.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printIndentedGroupOrSpacedDocument } from '../slang-printers/print-indented-group-or-spaced-document.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -12,7 +12,7 @@ import type { AstNode } from './types.d.ts'; export class StateVariableDefinitionValue extends SlangNode { readonly kind = NonterminalKind.StateVariableDefinitionValue; - value: Expression; + value: Expression['variant']; constructor( ast: ast.StateVariableDefinitionValue, @@ -20,7 +20,7 @@ export class StateVariableDefinitionValue extends SlangNode { ) { super(ast); - this.value = new Expression(ast.value, options); + this.value = extractVariant(new Expression(ast.value, options)); this.updateMetadata(this.value); } @@ -32,8 +32,8 @@ export class StateVariableDefinitionValue extends SlangNode { return [ ' =', printIndentedGroupOrSpacedDocument( - path.call(printVariant(print), 'value'), - this.value.variant.kind !== NonterminalKind.ArrayExpression + path.call(print, 'value'), + this.value.kind !== NonterminalKind.ArrayExpression ) ]; } diff --git a/src/slang-nodes/StorageLayoutSpecifier.ts b/src/slang-nodes/StorageLayoutSpecifier.ts index 2629f5757..8fcce6a07 100644 --- a/src/slang-nodes/StorageLayoutSpecifier.ts +++ b/src/slang-nodes/StorageLayoutSpecifier.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { doc } from 'prettier'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -15,7 +15,7 @@ const { line } = doc.builders; export class StorageLayoutSpecifier extends SlangNode { readonly kind = NonterminalKind.StorageLayoutSpecifier; - expression: Expression; + expression: Expression['variant']; constructor( ast: ast.StorageLayoutSpecifier, @@ -23,7 +23,7 @@ export class StorageLayoutSpecifier extends SlangNode { ) { super(ast); - this.expression = new Expression(ast.expression, options); + this.expression = extractVariant(new Expression(ast.expression, options)); this.updateMetadata(this.expression); } @@ -31,7 +31,7 @@ export class StorageLayoutSpecifier extends SlangNode { print(path: AstPath, print: PrintFunction): Doc { return [ 'layout at', - printSeparatedItem(path.call(printVariant(print), 'expression'), { + printSeparatedItem(path.call(print, 'expression'), { firstSeparator: line, // If this is the second ContractSpecifier we have to delegate printing // the line to the ContractSpecifiers node. diff --git a/src/slang-nodes/TryStatement.ts b/src/slang-nodes/TryStatement.ts index 66255d44c..c9f048bc8 100644 --- a/src/slang-nodes/TryStatement.ts +++ b/src/slang-nodes/TryStatement.ts @@ -2,7 +2,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { doc } from 'prettier'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; import { joinExisting } from '../slang-utils/join-existing.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; import { ReturnsDeclaration } from './ReturnsDeclaration.js'; @@ -19,7 +19,7 @@ const { line } = doc.builders; export class TryStatement extends SlangNode { readonly kind = NonterminalKind.TryStatement; - expression: Expression; + expression: Expression['variant']; returns?: ReturnsDeclaration; @@ -30,7 +30,7 @@ export class TryStatement extends SlangNode { constructor(ast: ast.TryStatement, options: ParserOptions) { super(ast); - this.expression = new Expression(ast.expression, options); + this.expression = extractVariant(new Expression(ast.expression, options)); if (ast.returns) { this.returns = new ReturnsDeclaration(ast.returns, options); } @@ -48,7 +48,7 @@ export class TryStatement extends SlangNode { print(path: AstPath, print: PrintFunction): Doc { return [ 'try', - printSeparatedItem(path.call(printVariant(print), 'expression'), { + printSeparatedItem(path.call(print, 'expression'), { firstSeparator: line }), joinExisting(' ', [ diff --git a/src/slang-nodes/TupleDeconstructionStatement.ts b/src/slang-nodes/TupleDeconstructionStatement.ts index 4398ca87d..2d286a20f 100644 --- a/src/slang-nodes/TupleDeconstructionStatement.ts +++ b/src/slang-nodes/TupleDeconstructionStatement.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printGroupAndIndentIfBreakPair } from '../slang-printers/print-group-and-indent-if-break-pair.js'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { TupleDeconstructionElements } from './TupleDeconstructionElements.js'; import { Expression } from './Expression.js'; @@ -17,7 +17,7 @@ export class TupleDeconstructionStatement extends SlangNode { elements: TupleDeconstructionElements; - expression: Expression; + expression: Expression['variant']; constructor( ast: ast.TupleDeconstructionStatement, @@ -27,7 +27,7 @@ export class TupleDeconstructionStatement extends SlangNode { this.varKeyword = ast.varKeyword?.unparse(); this.elements = new TupleDeconstructionElements(ast.elements, options); - this.expression = new Expression(ast.expression, options); + this.expression = extractVariant(new Expression(ast.expression, options)); this.updateMetadata(this.elements, this.expression); } @@ -38,7 +38,7 @@ export class TupleDeconstructionStatement extends SlangNode { ): Doc { return printGroupAndIndentIfBreakPair( [this.varKeyword ? 'var (' : '(', path.call(print, 'elements'), ') = '], - [path.call(printVariant(print), 'expression'), ';'] + [path.call(print, 'expression'), ';'] ); } } diff --git a/src/slang-nodes/TupleValue.ts b/src/slang-nodes/TupleValue.ts index 7a75347e5..0411f5c66 100644 --- a/src/slang-nodes/TupleValue.ts +++ b/src/slang-nodes/TupleValue.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -11,19 +11,19 @@ import type { AstNode } from './types.d.ts'; export class TupleValue extends SlangNode { readonly kind = NonterminalKind.TupleValue; - expression?: Expression; + expression?: Expression['variant']; constructor(ast: ast.TupleValue, options: ParserOptions) { super(ast); if (ast.expression) { - this.expression = new Expression(ast.expression, options); + this.expression = extractVariant(new Expression(ast.expression, options)); } this.updateMetadata(this.expression); } print(path: AstPath, print: PrintFunction): Doc { - return path.call(printVariant(print), 'expression'); + return path.call(print, 'expression'); } } diff --git a/src/slang-nodes/TupleValues.ts b/src/slang-nodes/TupleValues.ts index ac1437c6b..916f267b9 100644 --- a/src/slang-nodes/TupleValues.ts +++ b/src/slang-nodes/TupleValues.ts @@ -22,17 +22,17 @@ export class TupleValues extends SlangNode { this.items = ast.items.map((item) => new TupleValue(item, options)); } - getSingleExpression(): Expression | undefined { + getSingleExpression(): Expression['variant'] | undefined { const items = this.items; return items.length === 1 ? items[0].expression : undefined; } print(path: AstPath, print: PrintFunction): Doc { - const singleExpressionVariant = this.getSingleExpression()?.variant; + const singleExpression = this.getSingleExpression(); const items = path.map(print, 'items'); - return singleExpressionVariant && - !(singleExpressionVariant instanceof TerminalNode) && - isBinaryOperation(singleExpressionVariant) + return singleExpression && + !(singleExpression instanceof TerminalNode) && + isBinaryOperation(singleExpression) ? items : printSeparatedList(items); } diff --git a/src/slang-nodes/VariableDeclarationValue.ts b/src/slang-nodes/VariableDeclarationValue.ts index fff3b9c71..1306002ca 100644 --- a/src/slang-nodes/VariableDeclarationValue.ts +++ b/src/slang-nodes/VariableDeclarationValue.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printVariant } from '../slang-printers/print-variant.js'; +import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -11,7 +11,7 @@ import type { AstNode } from './types.d.ts'; export class VariableDeclarationValue extends SlangNode { readonly kind = NonterminalKind.VariableDeclarationValue; - expression: Expression; + expression: Expression['variant']; constructor( ast: ast.VariableDeclarationValue, @@ -19,12 +19,12 @@ export class VariableDeclarationValue extends SlangNode { ) { super(ast); - this.expression = new Expression(ast.expression, options); + this.expression = extractVariant(new Expression(ast.expression, options)); this.updateMetadata(this.expression); } print(path: AstPath, print: PrintFunction): Doc { - return [' = ', path.call(printVariant(print), 'expression')]; + return [' = ', path.call(print, 'expression')]; } } diff --git a/src/slang-nodes/WhileStatement.ts b/src/slang-nodes/WhileStatement.ts index 3eb67a05f..ccbd35772 100644 --- a/src/slang-nodes/WhileStatement.ts +++ b/src/slang-nodes/WhileStatement.ts @@ -1,7 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; import { printIndentedGroupOrSpacedDocument } from '../slang-printers/print-indented-group-or-spaced-document.js'; -import { printVariant } from '../slang-printers/print-variant.js'; import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -15,14 +14,14 @@ import type { AstNode } from './types.d.ts'; export class WhileStatement extends SlangNode { readonly kind = NonterminalKind.WhileStatement; - condition: Expression; + condition: Expression['variant']; body: Statement['variant']; constructor(ast: ast.WhileStatement, options: ParserOptions) { super(ast); - this.condition = new Expression(ast.condition, options); + this.condition = extractVariant(new Expression(ast.condition, options)); this.body = extractVariant(new Statement(ast.body, options)); this.updateMetadata(this.condition, this.body); @@ -31,7 +30,7 @@ export class WhileStatement extends SlangNode { print(path: AstPath, print: PrintFunction): Doc { return [ 'while (', - printSeparatedItem(path.call(printVariant(print), 'condition')), + printSeparatedItem(path.call(print, 'condition')), ')', printIndentedGroupOrSpacedDocument( path.call(print, 'body'), diff --git a/src/slang-nodes/types.d.ts b/src/slang-nodes/types.d.ts index e5f57a96d..56e7e5007 100644 --- a/src/slang-nodes/types.d.ts +++ b/src/slang-nodes/types.d.ts @@ -468,22 +468,22 @@ export type StrictPolymorphicNode = Extract< export type Collection = Extract; -export type NodeCollection = Extract< +export type StrictCollection = Extract< Collection, - { items: StrictAstNode[] | TerminalNode[] } + { items: (StrictAstNode | TerminalNode)[] } >; export type LineCollection = Extract< - NodeCollection, + StrictCollection, { items: StrictPolymorphicNode['variant'][] } >; export type BinaryOperation = Extract< StrictAstNode, { - leftOperand: Expression; + leftOperand: Expression['variant']; operator: string; - rightOperand: Expression; + rightOperand: Expression['variant']; } >; diff --git a/src/slang-printers/create-binary-operation-printer.ts b/src/slang-printers/create-binary-operation-printer.ts index a6287ab5b..2e97c66c0 100644 --- a/src/slang-printers/create-binary-operation-printer.ts +++ b/src/slang-printers/create-binary-operation-printer.ts @@ -2,7 +2,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { doc } from 'prettier'; import { isBinaryOperation } from '../slang-utils/is-binary-operation.js'; import { TerminalNode } from '../slang-nodes/TerminalNode.js'; -import { printVariant } from './print-variant.js'; import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { @@ -20,7 +19,7 @@ function rightOperandPrint( print: PrintFunction, options: ParserOptions ): Doc { - const rightOperand = path.call(printVariant(print), 'rightOperand'); + const rightOperand = path.call(print, 'rightOperand'); const rightOperandDoc = options.experimentalOperatorPosition === 'end' ? [` ${operator}`, line, rightOperand] @@ -28,13 +27,11 @@ function rightOperandPrint( // If there's only a single binary expression, we want to create a group in // order to avoid having a small right part like -1 be on its own line. - const leftOperandVariant = leftOperand.variant; - const grandparentNode = path.grandparent as StrictAstNode; + const parent = path.parent as StrictAstNode; const shouldGroup = - (leftOperandVariant instanceof TerminalNode || - !isBinaryOperation(leftOperandVariant)) && - (!isBinaryOperation(grandparentNode) || - grandparentNode.kind === NonterminalKind.AssignmentExpression); + (leftOperand instanceof TerminalNode || !isBinaryOperation(leftOperand)) && + (!isBinaryOperation(parent) || + parent.kind === NonterminalKind.AssignmentExpression); return shouldGroup ? group(rightOperandDoc) : rightOperandDoc; } @@ -59,7 +56,7 @@ export const createBinaryOperationPrinter = const indentRules = indentRulesBuilder(path, options); return groupRules([ - path.call(printVariant(print), 'leftOperand'), + path.call(print, 'leftOperand'), indentRules(rightOperandPrint(node, path, print, options)) ]); }; diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index 9e7792cd5..21361ea4a 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -18,9 +18,9 @@ export const binaryGroupRulesBuilder = (shouldGroup: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - const grandparentNode = path.grandparent as StrictAstNode; - if (!isBinaryOperation(grandparentNode)) return group(document); - if (shouldGroup(grandparentNode)) return group(document); + const parent = path.parent as StrictAstNode; + if (!isBinaryOperation(parent)) return group(document); + if (shouldGroup(parent)) return group(document); return document; }; @@ -44,13 +44,13 @@ export const binaryIndentRulesBuilder = (shouldIndent: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - for (let i = 2, node = path.node; ; i += 2) { - const grandparentNode = path.getNode(i) as StrictAstNode; - if (shouldNotIndent(grandparentNode, path, i)) break; - if (!isBinaryOperation(grandparentNode)) return indent(document); - if (shouldIndent(grandparentNode)) return indent(document); - if (node === grandparentNode.rightOperand.variant) break; - node = grandparentNode; + for (let i = 1, node = path.node; ; i++) { + const parent = path.getNode(i) as StrictAstNode; + if (shouldNotIndent(parent, path, i)) break; + if (!isBinaryOperation(parent)) return indent(document); + if (shouldIndent(parent)) return indent(document); + if (node === parent.rightOperand) break; + node = parent; } return document; }; diff --git a/src/slang-printers/print-logical-operation.ts b/src/slang-printers/print-logical-operation.ts index efdeacd32..55c2b72c9 100644 --- a/src/slang-printers/print-logical-operation.ts +++ b/src/slang-printers/print-logical-operation.ts @@ -21,18 +21,18 @@ const logicalGroupRulesBuilder = binaryGroupRulesBuilder(() => false); const logicalIndentRulesBuilder = (path: AstPath, options: ParserOptions) => (document: Doc): Doc => { - for (let i = 2, node = path.node; ; i += 2) { - const grandparentNode = path.getNode(i) as StrictAstNode; - if (shouldNotIndent(grandparentNode, path, i)) break; + for (let i = 1, node = path.node; ; i++) { + const parent = path.getNode(i) as StrictAstNode; + if (shouldNotIndent(parent, path, i)) break; if ( options.experimentalTernaries && - grandparentNode.kind === NonterminalKind.ConditionalExpression && - grandparentNode.operand.variant === node + parent.kind === NonterminalKind.ConditionalExpression && + parent.operand === node ) break; - if (!isBinaryOperation(grandparentNode)) return indent(document); - if (node === grandparentNode.rightOperand.variant) break; - node = grandparentNode; + if (!isBinaryOperation(parent)) return indent(document); + if (node === parent.rightOperand) break; + node = parent; } return document; }; diff --git a/src/slang-utils/create-hug-function.ts b/src/slang-utils/create-hug-function.ts index c16584603..f6c0ee24f 100644 --- a/src/slang-utils/create-hug-function.ts +++ b/src/slang-utils/create-hug-function.ts @@ -1,55 +1,50 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { Expression } from '../slang-nodes/Expression.js'; import { TupleExpression } from '../slang-nodes/TupleExpression.js'; import { TupleValues } from '../slang-nodes/TupleValues.js'; import { TupleValue } from '../slang-nodes/TupleValue.js'; import { TerminalNode } from '../slang-nodes/TerminalNode.js'; import { isBinaryOperation } from './is-binary-operation.js'; +import type { Expression } from '../slang-nodes/Expression.js'; + export function createHugFunction( huggableOperators: string[] -): (node: Expression) => Expression { +): (node: Expression['variant']) => Expression['variant'] { const operators = new Set(huggableOperators); - return (node: Expression): Expression => { - const variant = node.variant; + return (node: Expression['variant']): Expression['variant'] => { if ( - !(variant instanceof TerminalNode) && - isBinaryOperation(variant) && - operators.has(variant.operator) + !(node instanceof TerminalNode) && + isBinaryOperation(node) && + operators.has(node.operator) ) { const loc = node.loc; - return Object.assign(Object.create(Expression.prototype) as Expression, { - kind: NonterminalKind.Expression, - loc: { ...loc }, - comments: [], - variant: Object.assign( - Object.create(TupleExpression.prototype) as TupleExpression, - { - kind: NonterminalKind.TupleExpression, - loc: { ...loc }, - comments: [], - items: Object.assign( - Object.create(TupleValues.prototype) as TupleValues, - { - kind: NonterminalKind.TupleValues, - loc: { ...loc }, - comments: [], - items: [ - Object.assign( - Object.create(TupleValue.prototype) as TupleValue, - { - kind: NonterminalKind.TupleValue, - loc: { ...loc }, - comments: [], - expression: node - } - ) - ] - } - ) - } - ) - }); + return Object.assign( + Object.create(TupleExpression.prototype) as TupleExpression, + { + kind: NonterminalKind.TupleExpression, + loc: { ...loc }, + comments: [], + items: Object.assign( + Object.create(TupleValues.prototype) as TupleValues, + { + kind: NonterminalKind.TupleValues, + loc: { ...loc }, + comments: [], + items: [ + Object.assign( + Object.create(TupleValue.prototype) as TupleValue, + { + kind: NonterminalKind.TupleValue, + loc: { ...loc }, + comments: [], + expression: node + } + ) + ] + } + ) + } + ); } return node; diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index e0f133cae..4e4ab9ff5 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -20,6 +20,7 @@ import type { YulStatement } from './slang-nodes/YulStatement.js'; import type { ContractSpecifier } from './slang-nodes/ContractSpecifier.js'; import type { ElementaryType } from './slang-nodes/ElementaryType.js'; import type { ExperimentalFeature } from './slang-nodes/ExperimentalFeature.js'; +import type { Expression } from './slang-nodes/Expression.js'; function hasNodeIgnoreComment({ comments }: StrictAstNode): boolean { // Prettier sets SourceUnit's comments to undefined after assigning comments @@ -88,6 +89,7 @@ function genericPrint( | ContractSpecifier | ElementaryType | ExperimentalFeature + | Expression > >, options: ParserOptions,