From bf5e9bb7b42a259bb587362bac0bb51fb764c03d Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 11 Jun 2025 20:39:44 +0100 Subject: [PATCH 01/20] use the node and grandparent getters instead of getNode() and getNode(2) --- src/slang-comments/printer.ts | 2 +- src/slang-nodes/ConditionalExpression.ts | 4 ++-- src/slang-printers/create-binary-operation-printer.ts | 2 +- src/slang-printers/print-binary-operation.ts | 4 ++-- src/slang-printers/print-comments.ts | 2 +- src/slang-printers/print-logical-operation.ts | 2 +- src/slang-printers/print-preserving-empty-lines.ts | 2 +- src/slangPrinter.ts | 6 +++--- tests/unit/comments/printer.test.js | 4 +--- 9 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/slang-comments/printer.ts b/src/slang-comments/printer.ts index cb2edf6bd..df3cc859c 100644 --- a/src/slang-comments/printer.ts +++ b/src/slang-comments/printer.ts @@ -4,7 +4,7 @@ import type { AstPath, Doc } from 'prettier'; import type { AstNode } from '../slang-nodes/types.d.ts'; export function printComment(commentPath: AstPath): Doc { - const comment = commentPath.getNode()!; + const comment = commentPath.node; if (isComment(comment)) { return comment.print(); diff --git a/src/slang-nodes/ConditionalExpression.ts b/src/slang-nodes/ConditionalExpression.ts index 24f7bfc22..5637b0145 100644 --- a/src/slang-nodes/ConditionalExpression.ts +++ b/src/slang-nodes/ConditionalExpression.ts @@ -24,7 +24,7 @@ function experimentalTernaries( print: PrintFunction, options: ParserOptions ): Doc { - const grandparent = path.getNode(2) as StrictAstNode; + const grandparent = path.grandparent as StrictAstNode; const isNested = grandparent.kind === NonterminalKind.ConditionalExpression; const isNestedAsTrueExpression = isNested && grandparent.trueExpression.variant === node; @@ -87,7 +87,7 @@ function traditionalTernaries( indent([ // Nested trueExpression and falseExpression are always printed in a new // line - (path.getNode(2) as StrictAstNode).kind === + (path.grandparent as StrictAstNode).kind === NonterminalKind.ConditionalExpression ? hardline : line, diff --git a/src/slang-printers/create-binary-operation-printer.ts b/src/slang-printers/create-binary-operation-printer.ts index 61a3dc1b0..c4862bd38 100644 --- a/src/slang-printers/create-binary-operation-printer.ts +++ b/src/slang-printers/create-binary-operation-printer.ts @@ -26,7 +26,7 @@ function rightOperandPrint( // If it's a single binary operation, avoid having a small right // operand like - 1 on its own line const leftOperand = node.leftOperand.variant; - const grandparentNode = path.getNode(2) as StrictAstNode; + const grandparentNode = path.grandparent as StrictAstNode; const shouldGroup = !( leftOperand.kind !== TerminalKind.Identifier && diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index cb0504c97..d00abe319 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -18,7 +18,7 @@ export const binaryGroupRulesBuilder = (shouldGroup: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - const grandparentNode = path.getNode(2) as StrictAstNode; + const grandparentNode = path.grandparent as StrictAstNode; if (!isBinaryOperation(grandparentNode)) return group(document); if (shouldGroup(grandparentNode)) return group(document); return document; @@ -44,7 +44,7 @@ export const binaryIndentRulesBuilder = (shouldIndent: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - let node = path.getNode() as StrictAstNode; + let node = path.node; for (let i = 2; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; diff --git a/src/slang-printers/print-comments.ts b/src/slang-printers/print-comments.ts index cabfb7b78..ee660df14 100644 --- a/src/slang-printers/print-comments.ts +++ b/src/slang-printers/print-comments.ts @@ -12,7 +12,7 @@ export function printComments(path: AstPath): Doc[] { const document = joinExisting( line, path.map((commentPath) => { - const comment = commentPath.getNode()!; + const comment = commentPath.node; if (comment.trailing || comment.leading || comment.printed) { return ''; } diff --git a/src/slang-printers/print-logical-operation.ts b/src/slang-printers/print-logical-operation.ts index 3934842ce..a033f5fe6 100644 --- a/src/slang-printers/print-logical-operation.ts +++ b/src/slang-printers/print-logical-operation.ts @@ -21,7 +21,7 @@ const logicalGroupRulesBuilder = binaryGroupRulesBuilder(() => false); const logicalIndentRulesBuilder = (path: AstPath, options: ParserOptions) => (document: Doc): Doc => { - let node = path.getNode() as StrictAstNode; + let node = path.node; for (let i = 2; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; diff --git a/src/slang-printers/print-preserving-empty-lines.ts b/src/slang-printers/print-preserving-empty-lines.ts index fa0f77d96..050b2aae5 100644 --- a/src/slang-printers/print-preserving-empty-lines.ts +++ b/src/slang-printers/print-preserving-empty-lines.ts @@ -18,7 +18,7 @@ export function printPreservingEmptyLines( options: ParserOptions ): Doc { return path.map((childPath) => { - const node = childPath.getNode() as StrictAstNode; + const node = childPath.node as StrictAstNode; return [ // Only attempt to prepend an empty line if `node` is not the first item diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index 77de7f400..7102660e3 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -20,7 +20,7 @@ function hasNodeIgnoreComment(node: StrictAstNode): boolean { } function ignoreComments(path: AstPath): void { - const node = path.getNode(); + const node = path.node; // We ignore anything that is not an object if (node === null || typeof node !== 'object') return; @@ -36,7 +36,7 @@ function ignoreComments(path: AstPath): void { // The key `comments` will contain every comment for this node case 'comments': path.each((commentPath) => { - const comment = commentPath.getNode()!; + const comment = commentPath.node; comment.printed = true; }, 'comments'); break; @@ -61,7 +61,7 @@ function genericPrint( options: ParserOptions, print: PrintFunction ): Doc { - const node = path.getNode(); + const node = path.node; if (node === null) { return ''; diff --git a/tests/unit/comments/printer.test.js b/tests/unit/comments/printer.test.js index c00c2dcde..bc01efd6c 100644 --- a/tests/unit/comments/printer.test.js +++ b/tests/unit/comments/printer.test.js @@ -1,9 +1,7 @@ import { printComment } from '../../../src/slang-comments/printer.ts'; test('given an unknown comment type then printComment function should throw', () => { - const mockCommentPath = { - getNode: () => ({ type: 'UnknownComment', range: [0, 1] }) - }; + const mockCommentPath = { node: { type: 'UnknownComment', range: [0, 1] } }; expect(() => { printComment(mockCommentPath); From 938025f907d3c459ffb55707b1e81ff4c7efa7f3 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 11 Jun 2025 20:53:56 +0100 Subject: [PATCH 02/20] small refactor --- src/slang-nodes/ConditionalExpression.ts | 10 +++++----- src/slang-printers/create-binary-operation-printer.ts | 10 ++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/slang-nodes/ConditionalExpression.ts b/src/slang-nodes/ConditionalExpression.ts index 5637b0145..429a0622d 100644 --- a/src/slang-nodes/ConditionalExpression.ts +++ b/src/slang-nodes/ConditionalExpression.ts @@ -50,9 +50,10 @@ function experimentalTernaries( path.call(print, 'trueExpression') ]); + const groupId = Symbol('Slang.ConditionalExpression.trueExpression'); const conditionAndTrueExpressionGroup = group( [operandDoc, trueExpressionDoc], - { id: Symbol('Slang.ConditionalExpression.trueExpression') } + { id: groupId } ); const falseExpression = path.call(print, 'falseExpression'); @@ -64,10 +65,9 @@ function experimentalTernaries( : ifBreak( [fillTab(options), indent(falseExpression)], [' ', falseExpression], - { - // We only add `fillTab` if we are sure the trueExpression is indented - groupId: conditionAndTrueExpressionGroup.id - } + // We only add `fillTab` if we are sure the trueExpression is + // indented. + { groupId } ) ]; diff --git a/src/slang-printers/create-binary-operation-printer.ts b/src/slang-printers/create-binary-operation-printer.ts index c4862bd38..b33f23c32 100644 --- a/src/slang-printers/create-binary-operation-printer.ts +++ b/src/slang-printers/create-binary-operation-printer.ts @@ -23,15 +23,13 @@ function rightOperandPrint( ? [` ${node.operator}`, line, path.call(print, 'rightOperand')] : [line, `${node.operator} `, path.call(print, 'rightOperand')]; - // If it's a single binary operation, avoid having a small right - // operand like - 1 on its own line + // 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 leftOperand = node.leftOperand.variant; const grandparentNode = path.grandparent as StrictAstNode; const shouldGroup = - !( - leftOperand.kind !== TerminalKind.Identifier && - isBinaryOperation(leftOperand) - ) && + (leftOperand.kind === TerminalKind.Identifier || + !isBinaryOperation(leftOperand)) && (!isBinaryOperation(grandparentNode) || grandparentNode.kind === NonterminalKind.AssignmentExpression); From 3b5433bcfa9457de59fe2f1a96e975e53f163f0a Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 11 Jun 2025 22:33:06 +0100 Subject: [PATCH 03/20] using destructuring when possible --- src/slang-comments/printer.ts | 2 +- src/slang-printers/print-binary-operation.ts | 2 +- src/slang-printers/print-comments.ts | 2 +- src/slang-printers/print-logical-operation.ts | 2 +- src/slangPrinter.ts | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slang-comments/printer.ts b/src/slang-comments/printer.ts index df3cc859c..49a8aed8c 100644 --- a/src/slang-comments/printer.ts +++ b/src/slang-comments/printer.ts @@ -4,7 +4,7 @@ import type { AstPath, Doc } from 'prettier'; import type { AstNode } from '../slang-nodes/types.d.ts'; export function printComment(commentPath: AstPath): Doc { - const comment = commentPath.node; + const { node: comment } = commentPath; if (isComment(comment)) { return comment.print(); diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index d00abe319..d6747d776 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -44,7 +44,7 @@ export const binaryIndentRulesBuilder = (shouldIndent: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - let node = path.node; + let { node } = path; for (let i = 2; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; diff --git a/src/slang-printers/print-comments.ts b/src/slang-printers/print-comments.ts index ee660df14..adbda0c97 100644 --- a/src/slang-printers/print-comments.ts +++ b/src/slang-printers/print-comments.ts @@ -12,7 +12,7 @@ export function printComments(path: AstPath): Doc[] { const document = joinExisting( line, path.map((commentPath) => { - const comment = commentPath.node; + const { node: comment } = commentPath; if (comment.trailing || comment.leading || comment.printed) { return ''; } diff --git a/src/slang-printers/print-logical-operation.ts b/src/slang-printers/print-logical-operation.ts index a033f5fe6..861876963 100644 --- a/src/slang-printers/print-logical-operation.ts +++ b/src/slang-printers/print-logical-operation.ts @@ -21,7 +21,7 @@ const logicalGroupRulesBuilder = binaryGroupRulesBuilder(() => false); const logicalIndentRulesBuilder = (path: AstPath, options: ParserOptions) => (document: Doc): Doc => { - let node = path.node; + let { node } = path; for (let i = 2; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index 7102660e3..cc9462947 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -20,7 +20,7 @@ function hasNodeIgnoreComment(node: StrictAstNode): boolean { } function ignoreComments(path: AstPath): void { - const node = path.node; + const { node } = path; // We ignore anything that is not an object if (node === null || typeof node !== 'object') return; @@ -36,7 +36,7 @@ function ignoreComments(path: AstPath): void { // The key `comments` will contain every comment for this node case 'comments': path.each((commentPath) => { - const comment = commentPath.node; + const { node: comment } = commentPath; comment.printed = true; }, 'comments'); break; @@ -61,7 +61,7 @@ function genericPrint( options: ParserOptions, print: PrintFunction ): Doc { - const node = path.node; + const { node } = path; if (node === null) { return ''; From 7964354bb80e219672426b49ea079344679926a9 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 18 Jun 2025 09:32:04 +0100 Subject: [PATCH 04/20] `i` should start at 2 instead of 0 because it's always used as `i + 2` --- src/slang-nodes/MemberAccessExpression.ts | 30 ++++++++++------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/slang-nodes/MemberAccessExpression.ts b/src/slang-nodes/MemberAccessExpression.ts index 705837e6c..734c8a0fa 100644 --- a/src/slang-nodes/MemberAccessExpression.ts +++ b/src/slang-nodes/MemberAccessExpression.ts @@ -24,30 +24,26 @@ function isEndOfChain( path: AstPath ): boolean { for ( - let i = 0, - currentNode: StrictAstNode = node, - grandparentNode = path.getNode(i + 2)!; - isChainableExpression(grandparentNode); - i += 2, - currentNode = grandparentNode, - grandparentNode = path.getNode(i + 2)! + let i = 2, current: StrictAstNode = node, grandparent = path.getNode(i)!; + isChainableExpression(grandparent); + i += 2, current = grandparent, grandparent = path.getNode(i)! ) { - switch (grandparentNode.kind) { + switch (grandparent.kind) { case NonterminalKind.MemberAccessExpression: - // If direct ParentNode is a MemberAccess we are not at the end of the - // chain. + // If `grandparent` is a MemberAccessExpression we are not at the end + // of the chain. return false; case NonterminalKind.IndexAccessExpression: - // If direct ParentNode is an IndexAccess and currentNode is not the - // operand then it must be the start or the end in which case it is the - // end of the chain. - if (currentNode !== grandparentNode.operand.variant) return true; + // If `grandparent` 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; break; case NonterminalKind.FunctionCallExpression: - // If direct ParentNode is a FunctionCall and currentNode is not the - // operand then it must be and argument in which case it is the end + // If `grandparent` 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 (currentNode !== grandparentNode.operand.variant) return true; + if (current !== grandparent.operand.variant) return true; break; } } From 0bf26d08f8277682da72eb5ce03480b42ac579fc Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 18 Jun 2025 20:32:41 +0100 Subject: [PATCH 05/20] small optimisations when we only need the destructured `node` --- src/slang-comments/printer.ts | 4 +--- src/slangPrinter.ts | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/slang-comments/printer.ts b/src/slang-comments/printer.ts index 49a8aed8c..302f6fe25 100644 --- a/src/slang-comments/printer.ts +++ b/src/slang-comments/printer.ts @@ -3,9 +3,7 @@ import { isComment } from '../slang-utils/is-comment.js'; import type { AstPath, Doc } from 'prettier'; import type { AstNode } from '../slang-nodes/types.d.ts'; -export function printComment(commentPath: AstPath): Doc { - const { node: comment } = commentPath; - +export function printComment({ node: comment }: AstPath): Doc { if (isComment(comment)) { return comment.print(); } diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index cc9462947..44ec531c3 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -35,10 +35,7 @@ function ignoreComments(path: AstPath): void { break; // The key `comments` will contain every comment for this node case 'comments': - path.each((commentPath) => { - const { node: comment } = commentPath; - comment.printed = true; - }, 'comments'); + path.each((commentPath) => (commentPath.node.printed = true), key); break; default: // If the value for that key is an Array or an Object we go deeper. From 7e3e7fd965a321f0d73e17e8af70ff0b9936b7f0 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 18 Jun 2025 20:56:14 +0100 Subject: [PATCH 06/20] variable is only used within the for loop --- src/slang-printers/print-binary-operation.ts | 3 +-- src/slang-printers/print-logical-operation.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index d6747d776..e189c0d8e 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -44,8 +44,7 @@ export const binaryIndentRulesBuilder = (shouldIndent: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - let { node } = path; - for (let i = 2; ; i += 2) { + for (let i = 2, { node } = path; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; if (!isBinaryOperation(grandparentNode)) return indent(document); diff --git a/src/slang-printers/print-logical-operation.ts b/src/slang-printers/print-logical-operation.ts index 861876963..1ade5c546 100644 --- a/src/slang-printers/print-logical-operation.ts +++ b/src/slang-printers/print-logical-operation.ts @@ -21,8 +21,7 @@ const logicalGroupRulesBuilder = binaryGroupRulesBuilder(() => false); const logicalIndentRulesBuilder = (path: AstPath, options: ParserOptions) => (document: Doc): Doc => { - let { node } = path; - for (let i = 2; ; i += 2) { + for (let i = 2, { node } = path; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; if ( From 52bf6730d80591adcbd560105d2f3382bb05434e Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 18 Jun 2025 21:22:18 +0100 Subject: [PATCH 07/20] more accurate type to avoid type assertion and destructure --- ...irst-comment.ts => add-collection-first-comment.ts} | 6 +++--- ...-last-comment.ts => add-collection-last-comment.ts} | 6 +++--- src/slang-comments/handlers/handle-block-comments.ts | 8 ++++---- .../handlers/handle-contract-definition-comments.ts | 6 +++--- .../handlers/handle-contract-specifiers-comments.ts | 4 ++-- .../handlers/handle-else-branch-comments.ts | 4 ++-- .../handlers/handle-if-statement-comments.ts | 9 +++------ .../handlers/handle-interface-definition-comments.ts | 8 ++++---- .../handlers/handle-library-definition-comments.ts | 8 ++++---- .../handlers/handle-modifier-invocation-comments.ts | 4 ++-- .../handlers/handle-parameters-declaration-comments.ts | 8 ++++---- ...handle-positional-arguments-declaration-comments.ts | 8 ++++---- .../handlers/handle-while-statement-comments.ts | 4 ++-- src/slang-nodes/types.d.ts | 10 +++++++++- src/slang-printers/print-preserving-empty-lines.ts | 10 +++------- 15 files changed, 52 insertions(+), 51 deletions(-) rename src/slang-comments/handlers/{add-collection-node-first-comment.ts => add-collection-first-comment.ts} (62%) rename src/slang-comments/handlers/{add-collection-node-last-comment.ts => add-collection-last-comment.ts} (64%) diff --git a/src/slang-comments/handlers/add-collection-node-first-comment.ts b/src/slang-comments/handlers/add-collection-first-comment.ts similarity index 62% rename from src/slang-comments/handlers/add-collection-node-first-comment.ts rename to src/slang-comments/handlers/add-collection-first-comment.ts index fa604808f..c6bfcb605 100644 --- a/src/slang-comments/handlers/add-collection-node-first-comment.ts +++ b/src/slang-comments/handlers/add-collection-first-comment.ts @@ -1,11 +1,11 @@ import { util } from 'prettier'; -import type { Comment, CollectionNode } from '../../slang-nodes/types.d.ts'; +import type { Comment, Collection } from '../../slang-nodes/types.js'; const { addDanglingComment, addLeadingComment } = util; -export default function addCollectionNodeFirstComment( - node: CollectionNode, +export default function addCollectionFirstComment( + node: Collection, comment: Comment ): void { if (node.items.length === 0) { diff --git a/src/slang-comments/handlers/add-collection-node-last-comment.ts b/src/slang-comments/handlers/add-collection-last-comment.ts similarity index 64% rename from src/slang-comments/handlers/add-collection-node-last-comment.ts rename to src/slang-comments/handlers/add-collection-last-comment.ts index 3924f8c10..e5fd5daf3 100644 --- a/src/slang-comments/handlers/add-collection-node-last-comment.ts +++ b/src/slang-comments/handlers/add-collection-last-comment.ts @@ -1,11 +1,11 @@ import { util } from 'prettier'; -import type { Comment, CollectionNode } from '../../slang-nodes/types.d.ts'; +import type { Comment, Collection } from '../../slang-nodes/types.js'; const { addDanglingComment, addTrailingComment } = util; -export default function addCollectionNodeLastComment( - node: CollectionNode, +export default function addCollectionLastComment( + node: Collection, comment: Comment ): void { if (node.items.length === 0) { diff --git a/src/slang-comments/handlers/handle-block-comments.ts b/src/slang-comments/handlers/handle-block-comments.ts index 1f05e3925..5ad4085a5 100644 --- a/src/slang-comments/handlers/handle-block-comments.ts +++ b/src/slang-comments/handlers/handle-block-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -15,12 +15,12 @@ export default function handleBlockComments({ } if (precedingNode?.kind === NonterminalKind.Statements) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } if (followingNode?.kind === NonterminalKind.Statements) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-contract-definition-comments.ts b/src/slang-comments/handlers/handle-contract-definition-comments.ts index e6f76f4a1..a8dc0a21d 100644 --- a/src/slang-comments/handlers/handle-contract-definition-comments.ts +++ b/src/slang-comments/handlers/handle-contract-definition-comments.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -36,7 +36,7 @@ export default function handleContractDefinitionComments({ // The comment is at the end of the body of the ContractDefinition. if (precedingNode?.kind === NonterminalKind.ContractMembers) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } @@ -52,7 +52,7 @@ export default function handleContractDefinitionComments({ // If the last ContractSpecifier's an InheritanceSpecifier, the comment // is appended to the last InheritanceType. if (lastContractSpecifier.kind === NonterminalKind.InheritanceSpecifier) { - addCollectionNodeLastComment(lastContractSpecifier.types, comment); + addCollectionLastComment(lastContractSpecifier.types, comment); return true; } if ( diff --git a/src/slang-comments/handlers/handle-contract-specifiers-comments.ts b/src/slang-comments/handlers/handle-contract-specifiers-comments.ts index 03aa79817..0af5a6df3 100644 --- a/src/slang-comments/handlers/handle-contract-specifiers-comments.ts +++ b/src/slang-comments/handlers/handle-contract-specifiers-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -20,7 +20,7 @@ export default function handleContractSpecifiersComments({ precedingNode.kind === NonterminalKind.ContractSpecifier ) { if (precedingNode.variant.kind === NonterminalKind.InheritanceSpecifier) { - addCollectionNodeLastComment(precedingNode.variant.types, comment); + addCollectionLastComment(precedingNode.variant.types, comment); return true; } if (precedingNode.variant.kind === NonterminalKind.StorageLayoutSpecifier) { diff --git a/src/slang-comments/handlers/handle-else-branch-comments.ts b/src/slang-comments/handlers/handle-else-branch-comments.ts index 0e25060c7..a3ee7b865 100644 --- a/src/slang-comments/handlers/handle-else-branch-comments.ts +++ b/src/slang-comments/handlers/handle-else-branch-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -20,7 +20,7 @@ export default function handleElseBranchComments({ followingNode.variant.kind === NonterminalKind.IfStatement ) { if (followingNode.variant.body.variant.kind === NonterminalKind.Block) { - addCollectionNodeFirstComment( + addCollectionFirstComment( followingNode.variant.body.variant.statements, comment ); diff --git a/src/slang-comments/handlers/handle-if-statement-comments.ts b/src/slang-comments/handlers/handle-if-statement-comments.ts index e03560b57..4a702cc51 100644 --- a/src/slang-comments/handlers/handle-if-statement-comments.ts +++ b/src/slang-comments/handlers/handle-if-statement-comments.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -45,10 +45,7 @@ export default function handleIfStatementComments({ if (followingNode.kind === NonterminalKind.IfStatement) { if (followingNode.body.variant.kind === NonterminalKind.Block) { - addCollectionNodeFirstComment( - followingNode.body.variant.statements, - comment - ); + addCollectionFirstComment(followingNode.body.variant.statements, comment); } else { addLeadingComment(followingNode.body.variant, comment); } @@ -60,7 +57,7 @@ export default function handleIfStatementComments({ // if (a) /* comment */ true if (enclosingNode.body === followingNode) { if (followingNode.variant.kind === NonterminalKind.Block) { - addCollectionNodeFirstComment(followingNode.variant.statements, comment); + addCollectionFirstComment(followingNode.variant.statements, comment); } else { addLeadingComment(followingNode, comment); } diff --git a/src/slang-comments/handlers/handle-interface-definition-comments.ts b/src/slang-comments/handlers/handle-interface-definition-comments.ts index 43dcfde07..356cfc328 100644 --- a/src/slang-comments/handlers/handle-interface-definition-comments.ts +++ b/src/slang-comments/handlers/handle-interface-definition-comments.ts @@ -1,8 +1,8 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -24,7 +24,7 @@ export default function handleInterfaceDefinitionComments({ // The comment is at the end of the body of the InterfaceDefinition. if (precedingNode?.kind === NonterminalKind.InterfaceMembers) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } @@ -33,7 +33,7 @@ export default function handleInterfaceDefinitionComments({ nextCharacter === '{' && followingNode?.kind === NonterminalKind.InterfaceMembers ) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-library-definition-comments.ts b/src/slang-comments/handlers/handle-library-definition-comments.ts index 4421794dc..dfe5bafe1 100644 --- a/src/slang-comments/handlers/handle-library-definition-comments.ts +++ b/src/slang-comments/handlers/handle-library-definition-comments.ts @@ -1,8 +1,8 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -24,7 +24,7 @@ export default function handleLibraryDefinitionComments({ // The comment is at the end of the body of the ContractDefinition. if (precedingNode?.kind === NonterminalKind.LibraryMembers) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } @@ -33,7 +33,7 @@ export default function handleLibraryDefinitionComments({ nextCharacter === '{' && followingNode?.kind === NonterminalKind.LibraryMembers ) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-modifier-invocation-comments.ts b/src/slang-comments/handlers/handle-modifier-invocation-comments.ts index 76869222d..06e8d749a 100644 --- a/src/slang-comments/handlers/handle-modifier-invocation-comments.ts +++ b/src/slang-comments/handlers/handle-modifier-invocation-comments.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -34,7 +34,7 @@ export default function handleModifierInvocationComments({ if (followingNode.variant.arguments.items.length === 0) { addTrailingComment(enclosingNode, comment); } else { - addCollectionNodeFirstComment(followingNode.variant.arguments, comment); + addCollectionFirstComment(followingNode.variant.arguments, comment); } return true; } diff --git a/src/slang-comments/handlers/handle-parameters-declaration-comments.ts b/src/slang-comments/handlers/handle-parameters-declaration-comments.ts index b2cbcd1a9..0100e853e 100644 --- a/src/slang-comments/handlers/handle-parameters-declaration-comments.ts +++ b/src/slang-comments/handlers/handle-parameters-declaration-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -15,12 +15,12 @@ export default function handleBlockComments({ } if (precedingNode?.kind === NonterminalKind.Parameters) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } if (followingNode?.kind === NonterminalKind.Parameters) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-positional-arguments-declaration-comments.ts b/src/slang-comments/handlers/handle-positional-arguments-declaration-comments.ts index 5078a0c40..865b93fb9 100644 --- a/src/slang-comments/handlers/handle-positional-arguments-declaration-comments.ts +++ b/src/slang-comments/handlers/handle-positional-arguments-declaration-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -15,12 +15,12 @@ export default function handlePositionalArgumentsDeclarationComments({ } if (precedingNode?.kind === NonterminalKind.PositionalArguments) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } if (followingNode?.kind === NonterminalKind.PositionalArguments) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-while-statement-comments.ts b/src/slang-comments/handlers/handle-while-statement-comments.ts index 29898c65f..3f40dc12c 100644 --- a/src/slang-comments/handlers/handle-while-statement-comments.ts +++ b/src/slang-comments/handlers/handle-while-statement-comments.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -37,7 +37,7 @@ export default function handleWhileStatementComments({ if (enclosingNode.body === followingNode) { if (followingNode.variant.kind === NonterminalKind.Block) { - addCollectionNodeFirstComment(followingNode.variant.statements, comment); + addCollectionFirstComment(followingNode.variant.statements, comment); } else { addLeadingComment(followingNode, comment); } diff --git a/src/slang-nodes/types.d.ts b/src/slang-nodes/types.d.ts index 0c64815c9..3227e19e0 100644 --- a/src/slang-nodes/types.d.ts +++ b/src/slang-nodes/types.d.ts @@ -460,7 +460,15 @@ export type StrictAstNode = | YulPaths | YulPath; -export type CollectionNode = Extract; +export type NodeCollection = Extract< + StrictAstNode, + { items: StrictAstNode[] | Identifier[] | YulIdentifier[] } +>; + +export type Collection = Extract< + StrictAstNode, + { items: StrictAstNode[] | Identifier[] | YulIdentifier[] | string[] } +>; export type BinaryOperation = Extract< StrictAstNode, diff --git a/src/slang-printers/print-preserving-empty-lines.ts b/src/slang-printers/print-preserving-empty-lines.ts index 050b2aae5..a3f4e0533 100644 --- a/src/slang-printers/print-preserving-empty-lines.ts +++ b/src/slang-printers/print-preserving-empty-lines.ts @@ -3,22 +3,18 @@ import { doc, util } from 'prettier'; import { locEnd } from '../slang-utils/loc.js'; import type { AstPath, Doc, ParserOptions } from 'prettier'; -import type { - AstNode, - CollectionNode, - StrictAstNode -} from '../slang-nodes/types.d.ts'; +import type { AstNode, NodeCollection } from '../slang-nodes/types.d.ts'; import type { PrintFunction } from '../types.d.ts'; const { hardline } = doc.builders; export function printPreservingEmptyLines( - path: AstPath, + path: AstPath, print: PrintFunction, options: ParserOptions ): Doc { return path.map((childPath) => { - const node = childPath.node as StrictAstNode; + const { node } = childPath; return [ // Only attempt to prepend an empty line if `node` is not the first item From c9c0cee247250cc3d782ddf78597abefa83bf446 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 25 Jun 2025 00:17:47 +0100 Subject: [PATCH 08/20] access the variant directly in the for..of loops --- src/slang-nodes/ContractDefinition.ts | 8 ++++---- src/slang-nodes/FallbackFunctionDefinition.ts | 8 ++++---- src/slang-nodes/FunctionDefinition.ts | 8 ++++---- src/slang-nodes/ReceiveFunctionDefinition.ts | 8 ++++---- src/slang-nodes/UnnamedFunctionDefinition.ts | 6 +++--- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/slang-nodes/ContractDefinition.ts b/src/slang-nodes/ContractDefinition.ts index 031d9af55..cfea4cf2c 100644 --- a/src/slang-nodes/ContractDefinition.ts +++ b/src/slang-nodes/ContractDefinition.ts @@ -49,12 +49,12 @@ export class ContractDefinition implements SlangNode { // the same name as the contract. const compiler = coerce(options.compiler); if (compiler && !satisfies(compiler, '>=0.5.0')) { - for (const member of this.members.items) { + for (const { variant: member } of this.members.items) { if ( - member.variant.kind === NonterminalKind.FunctionDefinition && - member.variant.name.variant.value !== this.name.value + member.kind === NonterminalKind.FunctionDefinition && + member.name.variant.value !== this.name.value ) { - member.variant.cleanModifierInvocationArguments(); + member.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/FallbackFunctionDefinition.ts b/src/slang-nodes/FallbackFunctionDefinition.ts index cff114207..8ed12dfb6 100644 --- a/src/slang-nodes/FallbackFunctionDefinition.ts +++ b/src/slang-nodes/FallbackFunctionDefinition.ts @@ -53,12 +53,12 @@ export class FallbackFunctionDefinition implements SlangNode { } cleanModifierInvocationArguments(): void { - for (const attribute of this.attributes.items) { + for (const { variant: attribute } of this.attributes.items) { if ( - typeof attribute.variant !== 'string' && - attribute.variant.kind === NonterminalKind.ModifierInvocation + typeof attribute !== 'string' && + attribute.kind === NonterminalKind.ModifierInvocation ) { - attribute.variant.cleanModifierInvocationArguments(); + attribute.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/FunctionDefinition.ts b/src/slang-nodes/FunctionDefinition.ts index 437258857..572f995ba 100644 --- a/src/slang-nodes/FunctionDefinition.ts +++ b/src/slang-nodes/FunctionDefinition.ts @@ -61,12 +61,12 @@ export class FunctionDefinition implements SlangNode { } cleanModifierInvocationArguments(): void { - for (const attribute of this.attributes.items) { + for (const { variant: attribute } of this.attributes.items) { if ( - typeof attribute.variant !== 'string' && - attribute.variant.kind === NonterminalKind.ModifierInvocation + typeof attribute !== 'string' && + attribute.kind === NonterminalKind.ModifierInvocation ) { - attribute.variant.cleanModifierInvocationArguments(); + attribute.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/ReceiveFunctionDefinition.ts b/src/slang-nodes/ReceiveFunctionDefinition.ts index b14bb68b2..bcd158749 100644 --- a/src/slang-nodes/ReceiveFunctionDefinition.ts +++ b/src/slang-nodes/ReceiveFunctionDefinition.ts @@ -46,12 +46,12 @@ export class ReceiveFunctionDefinition implements SlangNode { } cleanModifierInvocationArguments(): void { - for (const attribute of this.attributes.items) { + for (const { variant: attribute } of this.attributes.items) { if ( - typeof attribute.variant !== 'string' && - attribute.variant.kind === NonterminalKind.ModifierInvocation + typeof attribute !== 'string' && + attribute.kind === NonterminalKind.ModifierInvocation ) { - attribute.variant.cleanModifierInvocationArguments(); + attribute.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/UnnamedFunctionDefinition.ts b/src/slang-nodes/UnnamedFunctionDefinition.ts index f4c9df659..89caaadfb 100644 --- a/src/slang-nodes/UnnamedFunctionDefinition.ts +++ b/src/slang-nodes/UnnamedFunctionDefinition.ts @@ -46,9 +46,9 @@ export class UnnamedFunctionDefinition implements SlangNode { } cleanModifierInvocationArguments(): void { - for (const attribute of this.attributes.items) { - if (typeof attribute.variant !== 'string') { - attribute.variant.cleanModifierInvocationArguments(); + for (const { variant: attribute } of this.attributes.items) { + if (typeof attribute !== 'string') { + attribute.cleanModifierInvocationArguments(); } } } From f54b69b230e67629fe6027a83cfef95af2dac825 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 25 Jun 2025 00:29:18 +0100 Subject: [PATCH 09/20] since using the constant `groupId` there is no need for the group to be stored in a variable and can go directly in the resulting document --- src/slang-nodes/FunctionCallExpression.ts | 11 ++++---- src/slang-nodes/IndexAccessExpression.ts | 12 ++++---- src/slang-nodes/StateVariableDefinition.ts | 6 +--- .../TupleDeconstructionStatement.ts | 10 +++---- .../VariableDeclarationStatement.ts | 28 +++++++++---------- 5 files changed, 30 insertions(+), 37 deletions(-) diff --git a/src/slang-nodes/FunctionCallExpression.ts b/src/slang-nodes/FunctionCallExpression.ts index 78a9d1d83..029c6561e 100644 --- a/src/slang-nodes/FunctionCallExpression.ts +++ b/src/slang-nodes/FunctionCallExpression.ts @@ -39,18 +39,19 @@ export class FunctionCallExpression implements SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - let operandDoc = path.call(print, 'operand'); - let argumentsDoc = path.call(print, 'arguments'); + const operandDoc = path.call(print, 'operand'); + const argumentsDoc = path.call(print, 'arguments'); // If we are at the end of a MemberAccessChain we should indent the // arguments accordingly. if (isLabel(operandDoc) && operandDoc.label === 'MemberAccessChain') { const groupId = Symbol('Slang.FunctionCallExpression.operand'); - operandDoc = group(operandDoc.contents, { id: groupId }); - argumentsDoc = indentIfBreak(argumentsDoc, { groupId }); // We wrap the expression in a label in case there is an IndexAccess or // a FunctionCall following this IndexAccess. - return label('MemberAccessChain', [operandDoc, argumentsDoc]); + return label('MemberAccessChain', [ + group(operandDoc.contents, { id: groupId }), + indentIfBreak(argumentsDoc, { groupId }) + ]); } return [operandDoc, argumentsDoc].flat(); diff --git a/src/slang-nodes/IndexAccessExpression.ts b/src/slang-nodes/IndexAccessExpression.ts index 722acd46c..72ea2b63e 100644 --- a/src/slang-nodes/IndexAccessExpression.ts +++ b/src/slang-nodes/IndexAccessExpression.ts @@ -43,8 +43,8 @@ export class IndexAccessExpression implements SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - let operandDoc: Doc = path.call(print, 'operand'); - let indexDoc: Doc = group([ + const operandDoc: Doc = path.call(print, 'operand'); + const indexDoc: Doc = group([ '[', indent([softline, path.call(print, 'start'), path.call(print, 'end')]), softline, @@ -55,12 +55,12 @@ export class IndexAccessExpression implements SlangNode { // arguments accordingly. if (isLabel(operandDoc) && operandDoc.label === 'MemberAccessChain') { const groupId = Symbol('Slang.IndexAccessExpression.operand'); - operandDoc = group(operandDoc.contents, { id: groupId }); - - indexDoc = indentIfBreak(indexDoc, { groupId }); // We wrap the expression in a label in case there is an IndexAccess or // a FunctionCall following this IndexAccess. - return label('MemberAccessChain', [operandDoc, indexDoc]); + return label('MemberAccessChain', [ + group(operandDoc.contents, { id: groupId }), + indentIfBreak(indexDoc, { groupId }) + ]); } return [operandDoc, indexDoc].flat(); diff --git a/src/slang-nodes/StateVariableDefinition.ts b/src/slang-nodes/StateVariableDefinition.ts index 0e5a746fc..7db4c2c3c 100644 --- a/src/slang-nodes/StateVariableDefinition.ts +++ b/src/slang-nodes/StateVariableDefinition.ts @@ -53,13 +53,9 @@ export class StateVariableDefinition implements SlangNode { print(path: AstPath, print: PrintFunction): Doc { const groupId = Symbol('Slang.StateVariableDefinition.attributes'); - const attributesDoc = group(indent(path.call(print, 'attributes')), { - id: groupId - }); - return [ path.call(print, 'typeName'), - attributesDoc, + group(indent(path.call(print, 'attributes')), { id: groupId }), ' ', path.call(print, 'name'), this.value ? indentIfBreak(path.call(print, 'value'), { groupId }) : '', diff --git a/src/slang-nodes/TupleDeconstructionStatement.ts b/src/slang-nodes/TupleDeconstructionStatement.ts index df472ca87..5c15ef3f4 100644 --- a/src/slang-nodes/TupleDeconstructionStatement.ts +++ b/src/slang-nodes/TupleDeconstructionStatement.ts @@ -45,13 +45,11 @@ export class TupleDeconstructionStatement implements SlangNode { print: PrintFunction ): Doc { const groupId = Symbol('Slang.VariableDeclarationStatement.variables'); - const declarationDoc = group( - [this.varKeyword ? 'var (' : '(', path.call(print, 'elements'), ')'], - { id: groupId } - ); - return [ - declarationDoc, + group( + [this.varKeyword ? 'var (' : '(', path.call(print, 'elements'), ')'], + { id: groupId } + ), indentIfBreak([' = ', path.call(print, 'expression'), ';'], { groupId }) ]; } diff --git a/src/slang-nodes/VariableDeclarationStatement.ts b/src/slang-nodes/VariableDeclarationStatement.ts index 66f738c4e..842932609 100644 --- a/src/slang-nodes/VariableDeclarationStatement.ts +++ b/src/slang-nodes/VariableDeclarationStatement.ts @@ -58,22 +58,20 @@ export class VariableDeclarationStatement implements SlangNode { print: PrintFunction ): Doc { const groupId = Symbol('Slang.VariableDeclarationStatement.variables'); - const declarationDoc = group( - [ - path.call(print, 'variableType'), - indent([ - this.storageLocation - ? [line, path.call(print, 'storageLocation')] - : '', - ' ', - path.call(print, 'name') - ]) - ], - { id: groupId } - ); - return [ - declarationDoc, + group( + [ + path.call(print, 'variableType'), + indent([ + this.storageLocation + ? [line, path.call(print, 'storageLocation')] + : '', + ' ', + path.call(print, 'name') + ]) + ], + { id: groupId } + ), indentIfBreak(path.call(print, 'value'), { groupId }), ';' ]; From e36919f3840782439259bbd4d27dae9d77f72b4b Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 26 Jun 2025 23:55:49 +0100 Subject: [PATCH 10/20] other destructuring and variable caching that where missing --- src/index.ts | 6 ++---- src/slang-nodes/ConditionalExpression.ts | 6 +++--- src/slang-nodes/IfStatement.ts | 9 +++++---- src/slang-nodes/ReturnStatement.ts | 7 ++++--- src/slang-utils/create-hug-function.ts | 8 ++++---- src/slang-utils/metadata.ts | 16 ++++++++-------- src/slang-utils/sort-contract-specifiers.ts | 15 ++++++--------- src/slang-utils/sort-function-attributes.ts | 7 ++----- src/slangPrinter.ts | 6 +++--- 9 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/index.ts b/src/index.ts index da93e5983..e42f9c9a8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -51,10 +51,8 @@ const parsers = { [antlrParserId]: antlrParser }; -const antlrCanAttachComment = (node: { type: string }): boolean => - typeof node.type === 'string' && - node.type !== 'BlockComment' && - node.type !== 'LineComment'; +const antlrCanAttachComment = ({ type }: { type: string }): boolean => + typeof type === 'string' && type !== 'BlockComment' && type !== 'LineComment'; const canAttachComment = (node: AstNode): boolean => typeof node !== 'string' && typeof node !== 'undefined' && diff --git a/src/slang-nodes/ConditionalExpression.ts b/src/slang-nodes/ConditionalExpression.ts index 429a0622d..3eb098044 100644 --- a/src/slang-nodes/ConditionalExpression.ts +++ b/src/slang-nodes/ConditionalExpression.ts @@ -11,11 +11,11 @@ import type { PrintFunction, SlangNode } from '../types.d.ts'; const { group, hardline, ifBreak, indent, line, softline } = doc.builders; -function fillTab(options: ParserOptions): Doc { - if (options.useTabs) return '\t'; +function fillTab({ useTabs, tabWidth }: ParserOptions): Doc { + if (useTabs) return '\t'; // For the odd case of `tabWidth` of 1 or 0 we initiate `fillTab` as a single // space. - return options.tabWidth > 2 ? ' '.repeat(options.tabWidth - 1) : ' '; + return tabWidth > 2 ? ' '.repeat(tabWidth - 1) : ' '; } function experimentalTernaries( diff --git a/src/slang-nodes/IfStatement.ts b/src/slang-nodes/IfStatement.ts index 608d45614..be3af109c 100644 --- a/src/slang-nodes/IfStatement.ts +++ b/src/slang-nodes/IfStatement.ts @@ -47,19 +47,20 @@ export class IfStatement implements SlangNode { } print(path: AstPath, print: PrintFunction): Doc { + const { kind: bodyKind, comments: bodyComments } = this.body.variant; return [ 'if (', printSeparatedItem(path.call(print, 'condition')), ')', - this.body.variant.kind === NonterminalKind.Block + bodyKind === NonterminalKind.Block ? [' ', path.call(print, 'body')] : group(indent([line, path.call(print, 'body')]), { - shouldBreak: this.body.variant.kind === NonterminalKind.IfStatement // `if` within `if` + shouldBreak: bodyKind === NonterminalKind.IfStatement // `if` within `if` }), this.elseBranch ? [ - this.body.variant.kind !== NonterminalKind.Block || // else on a new line if body is not a block - this.body.variant.comments.some( + bodyKind !== NonterminalKind.Block || // else on a new line if body is not a block + bodyComments.some( (comment) => !isBlockComment(comment) || comment.placement === 'ownLine' ) // or if body has trailing single line comments or a block comment on a new line diff --git a/src/slang-nodes/ReturnStatement.ts b/src/slang-nodes/ReturnStatement.ts index 2e0a78f54..4e9a0433a 100644 --- a/src/slang-nodes/ReturnStatement.ts +++ b/src/slang-nodes/ReturnStatement.ts @@ -16,10 +16,11 @@ function printExpression( print: PrintFunction, options: ParserOptions ): Doc { - if (node.expression) { - return node.expression.variant.kind === NonterminalKind.TupleExpression || + const expressionVariant = node.expression?.variant; + if (expressionVariant) { + return expressionVariant.kind === NonterminalKind.TupleExpression || (options.experimentalTernaries && - node.expression.variant.kind === NonterminalKind.ConditionalExpression) + expressionVariant.kind === NonterminalKind.ConditionalExpression) ? [' ', path.call(print, 'expression')] : group(indent([line, path.call(print, 'expression')])); } diff --git a/src/slang-utils/create-hug-function.ts b/src/slang-utils/create-hug-function.ts index 866b092d1..07d3d10cc 100644 --- a/src/slang-utils/create-hug-function.ts +++ b/src/slang-utils/create-hug-function.ts @@ -10,13 +10,13 @@ export function createHugFunction( ): (node: Expression) => Expression { const operators = new Set(huggableOperators); return (node: Expression): Expression => { + const { variant } = node; if ( - node.variant.kind !== TerminalKind.Identifier && - isBinaryOperation(node.variant) && - operators.has(node.variant.operator) + variant.kind !== TerminalKind.Identifier && + isBinaryOperation(variant) && + operators.has(variant.operator) ) { const { loc } = node; - return Object.assign(Object.create(Expression.prototype) as Expression, { kind: NonterminalKind.Expression, loc: { ...loc }, diff --git a/src/slang-utils/metadata.ts b/src/slang-utils/metadata.ts index f5f7fc248..b4ac47523 100644 --- a/src/slang-utils/metadata.ts +++ b/src/slang-utils/metadata.ts @@ -144,11 +144,11 @@ export function updateMetadata( for (const childNode of childNodes) { if (typeof childNode === 'undefined' || Array.isArray(childNode)) continue; - const childLoc = childNode.loc; + const { leadingOffset, start } = childNode.loc; - if (childLoc.start - childLoc.leadingOffset === loc.start) { - loc.leadingOffset = childLoc.leadingOffset; - loc.start += childLoc.leadingOffset; + if (start - leadingOffset === loc.start) { + loc.leadingOffset = leadingOffset; + loc.start += leadingOffset; break; } } @@ -158,11 +158,11 @@ export function updateMetadata( for (const childNode of childNodes.reverse()) { if (typeof childNode === 'undefined' || Array.isArray(childNode)) continue; - const childLoc = childNode.loc; + const { trailingOffset, end } = childNode.loc; - if (childLoc.end + childLoc.trailingOffset === loc.end) { - loc.trailingOffset = childLoc.trailingOffset; - loc.end -= childLoc.trailingOffset; + if (end + trailingOffset === loc.end) { + loc.trailingOffset = trailingOffset; + loc.end -= trailingOffset; break; } } diff --git a/src/slang-utils/sort-contract-specifiers.ts b/src/slang-utils/sort-contract-specifiers.ts index ca66d7fff..7f0614b65 100644 --- a/src/slang-utils/sort-contract-specifiers.ts +++ b/src/slang-utils/sort-contract-specifiers.ts @@ -3,21 +3,18 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import type { ContractSpecifier } from '../slang-nodes/ContractSpecifier.js'; export function sortContractSpecifiers( - a: ContractSpecifier, - b: ContractSpecifier + { variant: { kind: aKind } }: ContractSpecifier, + { variant: { kind: bKind } }: ContractSpecifier ): number { - const aVariant = a.variant; - const bVariant = b.variant; - // OverrideSpecifiers before ModifierInvocation if ( - aVariant.kind === NonterminalKind.InheritanceSpecifier && - bVariant.kind === NonterminalKind.StorageLayoutSpecifier + aKind === NonterminalKind.InheritanceSpecifier && + bKind === NonterminalKind.StorageLayoutSpecifier ) return -1; if ( - bVariant.kind === NonterminalKind.InheritanceSpecifier && - aVariant.kind === NonterminalKind.StorageLayoutSpecifier + bKind === NonterminalKind.InheritanceSpecifier && + aKind === NonterminalKind.StorageLayoutSpecifier ) return 1; diff --git a/src/slang-utils/sort-function-attributes.ts b/src/slang-utils/sort-function-attributes.ts index 48d1a1da7..3b39415d4 100644 --- a/src/slang-utils/sort-function-attributes.ts +++ b/src/slang-utils/sort-function-attributes.ts @@ -12,12 +12,9 @@ const visibilityKeyWords = new Set([ const mutabilityKeyWords = new Set(['pure', 'constant', 'payable', 'view']); export function sortFunctionAttributes( - a: SortableAttribute, - b: SortableAttribute + { variant: aVariant }: SortableAttribute, + { variant: bVariant }: SortableAttribute ): number { - const aVariant = a.variant; - const bVariant = b.variant; - const aIsString = typeof aVariant === 'string'; const bIsString = typeof bVariant === 'string'; diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index 44ec531c3..666dc1064 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -5,12 +5,12 @@ import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { AstNode, StrictAstNode } from './slang-nodes/types.d.ts'; import type { PrintFunction } from './types.d.ts'; -function hasNodeIgnoreComment(node: StrictAstNode): boolean { +function hasNodeIgnoreComment({ comments }: StrictAstNode): boolean { // Prettier sets SourceUnit's comments to undefined after assigning comments // to each node. return ( - node.comments && - node.comments.some( + comments && + comments.some( (comment) => comment.value .slice(2, isBlockComment(comment) ? -2 : undefined) From 5018791b1c49a55cbb9474ff777f366a2a9bfaa7 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 27 Jun 2025 00:03:59 +0100 Subject: [PATCH 11/20] using existing helper --- src/slang-nodes/IndexAccessExpression.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/slang-nodes/IndexAccessExpression.ts b/src/slang-nodes/IndexAccessExpression.ts index 72ea2b63e..73077fe39 100644 --- a/src/slang-nodes/IndexAccessExpression.ts +++ b/src/slang-nodes/IndexAccessExpression.ts @@ -1,5 +1,6 @@ import { doc } from 'prettier'; import { NonterminalKind } from '@nomicfoundation/slang/cst'; +import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; import { isLabel } from '../slang-utils/is-label.js'; import { getNodeMetadata, updateMetadata } from '../slang-utils/metadata.js'; import { Expression } from './Expression.js'; @@ -10,7 +11,7 @@ import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { AstNode } from './types.d.ts'; import type { PrintFunction, SlangNode } from '../types.d.ts'; -const { group, indent, indentIfBreak, label, softline } = doc.builders; +const { group, indentIfBreak, label } = doc.builders; export class IndexAccessExpression implements SlangNode { readonly kind = NonterminalKind.IndexAccessExpression; @@ -43,13 +44,12 @@ export class IndexAccessExpression implements SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - const operandDoc: Doc = path.call(print, 'operand'); - const indexDoc: Doc = group([ + const operandDoc = path.call(print, 'operand'); + const indexDoc = [ '[', - indent([softline, path.call(print, 'start'), path.call(print, 'end')]), - softline, + printSeparatedItem([path.call(print, 'start'), path.call(print, 'end')]), ']' - ]); + ]; // If we are at the end of a MemberAccessChain we should indent the // arguments accordingly. From c39e874e5fb4a6a449ec3adb68ae53da28d76c73 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 27 Jun 2025 16:30:22 +0100 Subject: [PATCH 12/20] reordering import --- src/slang-utils/metadata.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slang-utils/metadata.ts b/src/slang-utils/metadata.ts index b4ac47523..ed49d6e52 100644 --- a/src/slang-utils/metadata.ts +++ b/src/slang-utils/metadata.ts @@ -1,5 +1,6 @@ import { TerminalKind, TerminalNode } from '@nomicfoundation/slang/cst'; import { createKindCheckFunction } from './create-kind-check-function.js'; +import { isComment } from './is-comment.js'; import { MultiLineComment } from '../slang-nodes/MultiLineComment.js'; import { MultiLineNatSpecComment } from '../slang-nodes/MultiLineNatSpecComment.js'; import { SingleLineComment } from '../slang-nodes/SingleLineComment.js'; @@ -8,7 +9,6 @@ import { SingleLineNatSpecComment } from '../slang-nodes/SingleLineNatSpecCommen import type { Node } from '@nomicfoundation/slang/cst'; import type { Comment, StrictAstNode } from '../slang-nodes/types.d.ts'; import type { Metadata, SlangAstNode } from '../types.d.ts'; -import { isComment } from './is-comment.js'; const isCommentOrWhiteSpace = createKindCheckFunction([ TerminalKind.MultiLineComment, From f77f647ba35fe8bf6f8c921fb086342219a4ec04 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sat, 28 Jun 2025 09:49:23 +0100 Subject: [PATCH 13/20] cleaning up extra check for existence of variable --- src/slangPrinter.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index 666dc1064..4f98631fd 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -8,14 +8,11 @@ import type { PrintFunction } from './types.d.ts'; function hasNodeIgnoreComment({ comments }: StrictAstNode): boolean { // Prettier sets SourceUnit's comments to undefined after assigning comments // to each node. - return ( - comments && - comments.some( - (comment) => - comment.value - .slice(2, isBlockComment(comment) ? -2 : undefined) - .trim() === 'prettier-ignore' - ) + return comments?.some( + (comment) => + comment.value + .slice(2, isBlockComment(comment) ? -2 : undefined) + .trim() === 'prettier-ignore' ); } From e6e60ada9cea8ebf250e4b674aeeea1378b39974 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sun, 29 Jun 2025 11:35:29 +0100 Subject: [PATCH 14/20] missing types annotations --- src/slang-nodes/BitwiseOrExpression.ts | 6 +++--- src/slang-nodes/PositionalArguments.ts | 4 ++-- src/slang-nodes/StringLiteral.ts | 2 +- src/slang-utils/metadata.ts | 5 ++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/slang-nodes/BitwiseOrExpression.ts b/src/slang-nodes/BitwiseOrExpression.ts index 614e71b4b..3c51cfa64 100644 --- a/src/slang-nodes/BitwiseOrExpression.ts +++ b/src/slang-nodes/BitwiseOrExpression.ts @@ -38,11 +38,11 @@ export class BitwiseOrExpression implements SlangNode { loc; - leftOperand; + leftOperand: Expression; - operator; + operator: string; - rightOperand; + rightOperand: Expression; constructor(ast: ast.BitwiseOrExpression, options: ParserOptions) { let metadata = getNodeMetadata(ast); diff --git a/src/slang-nodes/PositionalArguments.ts b/src/slang-nodes/PositionalArguments.ts index 7b47b0222..414b51b85 100644 --- a/src/slang-nodes/PositionalArguments.ts +++ b/src/slang-nodes/PositionalArguments.ts @@ -17,9 +17,9 @@ export class PositionalArguments implements SlangNode { loc; - items; + items: Expression[]; - separators; + separators: string[]; constructor(ast: ast.PositionalArguments, options: ParserOptions) { let metadata = getNodeMetadata(ast, true); diff --git a/src/slang-nodes/StringLiteral.ts b/src/slang-nodes/StringLiteral.ts index 12fb7514c..c7bf84476 100644 --- a/src/slang-nodes/StringLiteral.ts +++ b/src/slang-nodes/StringLiteral.ts @@ -14,7 +14,7 @@ export class StringLiteral implements SlangNode { loc; - variant; + variant: string; constructor(ast: ast.StringLiteral, options: ParserOptions) { const metadata = getNodeMetadata(ast); diff --git a/src/slang-utils/metadata.ts b/src/slang-utils/metadata.ts index ed49d6e52..f8b24304f 100644 --- a/src/slang-utils/metadata.ts +++ b/src/slang-utils/metadata.ts @@ -132,14 +132,13 @@ function collectComments( } export function updateMetadata( - metadata: Metadata, + { comments, loc }: Metadata, childNodes: (StrictAstNode | StrictAstNode[] | undefined)[] ): Metadata { // Collect comments - const comments = childNodes.reduce(collectComments, metadata.comments); + comments = childNodes.reduce(collectComments, comments); // calculate correct loc object - const { loc } = metadata; if (loc.leadingOffset === 0) { for (const childNode of childNodes) { if (typeof childNode === 'undefined' || Array.isArray(childNode)) From 1100fdaefd6adbadd7ad6c0f204b8473e4dc0f09 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 4 Jul 2025 15:12:48 +0100 Subject: [PATCH 15/20] fixing some file extensions --- .../handlers/add-collection-first-comment.ts | 2 +- .../handlers/add-collection-last-comment.ts | 2 +- src/slang-nodes/ContractSpecifier.ts | 4 ++-- src/slang-nodes/ContractSpecifiers.ts | 4 ++-- src/slang-nodes/StorageLayoutSpecifier.ts | 4 ++-- src/slang-printers/print-binary-operation.ts | 2 +- src/slang-utils/create-parser.ts | 2 +- src/slang-utils/metadata.ts | 21 +++++++++---------- 8 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/slang-comments/handlers/add-collection-first-comment.ts b/src/slang-comments/handlers/add-collection-first-comment.ts index c6bfcb605..03e21449e 100644 --- a/src/slang-comments/handlers/add-collection-first-comment.ts +++ b/src/slang-comments/handlers/add-collection-first-comment.ts @@ -1,6 +1,6 @@ import { util } from 'prettier'; -import type { Comment, Collection } from '../../slang-nodes/types.js'; +import type { Comment, Collection } from '../../slang-nodes/types.d.ts'; const { addDanglingComment, addLeadingComment } = util; diff --git a/src/slang-comments/handlers/add-collection-last-comment.ts b/src/slang-comments/handlers/add-collection-last-comment.ts index e5fd5daf3..b52fc3e72 100644 --- a/src/slang-comments/handlers/add-collection-last-comment.ts +++ b/src/slang-comments/handlers/add-collection-last-comment.ts @@ -1,6 +1,6 @@ import { util } from 'prettier'; -import type { Comment, Collection } from '../../slang-nodes/types.js'; +import type { Comment, Collection } from '../../slang-nodes/types.d.ts'; const { addDanglingComment, addTrailingComment } = util; diff --git a/src/slang-nodes/ContractSpecifier.ts b/src/slang-nodes/ContractSpecifier.ts index 3df944fa8..bfa0970fd 100644 --- a/src/slang-nodes/ContractSpecifier.ts +++ b/src/slang-nodes/ContractSpecifier.ts @@ -5,8 +5,8 @@ import { StorageLayoutSpecifier } from './StorageLayoutSpecifier.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; -import type { AstNode } from './types.js'; -import type { PrintFunction, SlangNode } from '../types.js'; +import type { AstNode } from './types.d.ts'; +import type { PrintFunction, SlangNode } from '../types.d.ts'; export class ContractSpecifier implements SlangNode { readonly kind = NonterminalKind.ContractSpecifier; diff --git a/src/slang-nodes/ContractSpecifiers.ts b/src/slang-nodes/ContractSpecifiers.ts index 96b52098e..60065bd2d 100644 --- a/src/slang-nodes/ContractSpecifiers.ts +++ b/src/slang-nodes/ContractSpecifiers.ts @@ -7,8 +7,8 @@ import { ContractSpecifier } from './ContractSpecifier.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; -import type { AstNode } from './types.js'; -import type { PrintFunction, SlangNode } from '../types.js'; +import type { AstNode } from './types.d.ts'; +import type { PrintFunction, SlangNode } from '../types.d.ts'; const { group, ifBreak, line, softline } = doc.builders; diff --git a/src/slang-nodes/StorageLayoutSpecifier.ts b/src/slang-nodes/StorageLayoutSpecifier.ts index f2b5e5ec0..de287758f 100644 --- a/src/slang-nodes/StorageLayoutSpecifier.ts +++ b/src/slang-nodes/StorageLayoutSpecifier.ts @@ -6,8 +6,8 @@ import { Expression } from './Expression.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; -import type { AstNode } from './types.js'; -import type { PrintFunction, SlangNode } from '../types.js'; +import type { AstNode } from './types.d.ts'; +import type { PrintFunction, SlangNode } from '../types.d.ts'; const { line } = doc.builders; diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index e189c0d8e..079833e6a 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -10,7 +10,7 @@ import type { BinaryOperation, StrictAstNode } from '../slang-nodes/types.d.ts'; -import type { PrintFunction } from '../types.js'; +import type { PrintFunction } from '../types.d.ts'; const { group, indent } = doc.builders; diff --git a/src/slang-utils/create-parser.ts b/src/slang-utils/create-parser.ts index 8d90b680e..e8880d9ec 100644 --- a/src/slang-utils/create-parser.ts +++ b/src/slang-utils/create-parser.ts @@ -5,7 +5,7 @@ import { minSatisfying } from 'semver'; import type { ParseOutput } from '@nomicfoundation/slang/parser'; import type { ParserOptions } from 'prettier'; -import type { AstNode } from '../slang-nodes/types.js'; +import type { AstNode } from '../slang-nodes/types.d.ts'; const supportedVersions = LanguageFacts.allVersions(); const supportedLength = supportedVersions.length; diff --git a/src/slang-utils/metadata.ts b/src/slang-utils/metadata.ts index f8b24304f..74512935d 100644 --- a/src/slang-utils/metadata.ts +++ b/src/slang-utils/metadata.ts @@ -53,22 +53,21 @@ export function getNodeMetadata( } }; } + const { cst: parent } = ast; + const children = parent.children().map(({ node }) => node); - const children = ast.cst.children().map((child) => { - return child.node; - }); - - const initialOffset = offsets.get(ast.cst.id) || 0; + const initialOffset = offsets.get(parent.id) || 0; let offset = initialOffset; const comments = children.reduce((commentsArray: Comment[], child) => { + const { id, kind, textLength } = child; if (child.isNonterminalNode()) { - offsets.set(child.id, offset); + offsets.set(id, offset); } else { if (isComment(child)) { - offsets.set(child.id, offset); + offsets.set(id, offset); } - switch (child.kind) { + switch (kind) { // Since the fetching the comments and calculating offsets are both done // as we iterate over the children and the comment also depends on the // offset, it's hard to separate these responsibilities into different @@ -91,12 +90,12 @@ export function getNodeMetadata( // functions, etc... // Since a user can add comments to this section of the code as well, // we need to track the offsets. - offsets.set(child.id, offset); + offsets.set(id, offset); break; } } - offset += child.textLength.utf16; + offset += textLength.utf16; return commentsArray; }, []); @@ -108,7 +107,7 @@ export function getNodeMetadata( : getLeadingOffset(children.reverse()); const loc = { start: initialOffset + leadingOffset, - end: initialOffset + ast.cst.textLength.utf16 - trailingOffset, + end: initialOffset + parent.textLength.utf16 - trailingOffset, leadingOffset, trailingOffset }; From 9371c3e7dfb24103ae713cc9e046e2262d7d6ed2 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 7 Jul 2025 17:57:42 +0100 Subject: [PATCH 16/20] `offset` by definition equals to `initialOffset + parent.textLength.utf16` after having collected the `textLength.utf16` of all the `children` --- src/slang-utils/metadata.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/slang-utils/metadata.ts b/src/slang-utils/metadata.ts index 74512935d..8ebe3c887 100644 --- a/src/slang-utils/metadata.ts +++ b/src/slang-utils/metadata.ts @@ -58,8 +58,9 @@ export function getNodeMetadata( const initialOffset = offsets.get(parent.id) || 0; let offset = initialOffset; + const comments: Comment[] = []; - const comments = children.reduce((commentsArray: Comment[], child) => { + for (const child of children) { const { id, kind, textLength } = child; if (child.isNonterminalNode()) { offsets.set(id, offset); @@ -73,16 +74,16 @@ export function getNodeMetadata( // offset, it's hard to separate these responsibilities into different // functions without doing the iteration twice. case TerminalKind.MultiLineComment: - commentsArray.push(new MultiLineComment(child)); + comments.push(new MultiLineComment(child)); break; case TerminalKind.MultiLineNatSpecComment: - commentsArray.push(new MultiLineNatSpecComment(child)); + comments.push(new MultiLineNatSpecComment(child)); break; case TerminalKind.SingleLineComment: - commentsArray.push(new SingleLineComment(child)); + comments.push(new SingleLineComment(child)); break; case TerminalKind.SingleLineNatSpecComment: - commentsArray.push(new SingleLineNatSpecComment(child)); + comments.push(new SingleLineNatSpecComment(child)); break; case TerminalKind.Identifier: case TerminalKind.YulIdentifier: @@ -96,8 +97,7 @@ export function getNodeMetadata( } offset += textLength.utf16; - return commentsArray; - }, []); + } const leadingOffset = enclosePeripheralComments ? 0 @@ -107,7 +107,7 @@ export function getNodeMetadata( : getLeadingOffset(children.reverse()); const loc = { start: initialOffset + leadingOffset, - end: initialOffset + parent.textLength.utf16 - trailingOffset, + end: offset - trailingOffset, leadingOffset, trailingOffset }; From 291b5df3b7b719b59543c70ea84d8901c0145491 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 7 Jul 2025 18:07:37 +0100 Subject: [PATCH 17/20] only check once for the value of a boolean --- src/slang-utils/metadata.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/slang-utils/metadata.ts b/src/slang-utils/metadata.ts index 8ebe3c887..f99d64f89 100644 --- a/src/slang-utils/metadata.ts +++ b/src/slang-utils/metadata.ts @@ -99,12 +99,10 @@ export function getNodeMetadata( offset += textLength.utf16; } - const leadingOffset = enclosePeripheralComments - ? 0 - : getLeadingOffset(children); - const trailingOffset = enclosePeripheralComments - ? 0 - : getLeadingOffset(children.reverse()); + const [leadingOffset, trailingOffset] = enclosePeripheralComments + ? [0, 0] + : [getLeadingOffset(children), getLeadingOffset(children.reverse())]; + const loc = { start: initialOffset + leadingOffset, end: offset - trailingOffset, From da8595c908ee4fc315242a6b64b960b3e9b99b53 Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 7 Jul 2025 21:21:25 +0100 Subject: [PATCH 18/20] using an actual `for...in` loop instead of storing the keys in an array and then using a `for...of` loop --- src/slangPrinter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index 4f98631fd..a6e7b5fe6 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -21,8 +21,8 @@ function ignoreComments(path: AstPath): void { // We ignore anything that is not an object if (node === null || typeof node !== 'object') return; - const keys = Object.keys(node) as (keyof StrictAstNode)[]; - for (const key of keys) { + let key: keyof StrictAstNode; + for (key in node) { switch (key) { // We ignore `kind`, `loc`, and comments since these are added by the // parser From 7d3e81fb418f759f0055ba34e040c4de7342d8f1 Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 8 Jul 2025 10:00:47 +0100 Subject: [PATCH 19/20] null check is not needed --- src/slangPrinter.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index a6e7b5fe6..834195362 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -57,10 +57,6 @@ function genericPrint( ): Doc { const { node } = path; - if (node === null) { - return ''; - } - if (hasNodeIgnoreComment(node)) { ignoreComments(path); From 3c9719bf0059e56d14c2e6e0e8be56ac70e32895 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 9 Jul 2025 09:02:48 +0100 Subject: [PATCH 20/20] undo the destructuring of single variable that did not improve the filesize --- src/slang-printers/print-binary-operation.ts | 2 +- src/slang-printers/print-comments.ts | 2 +- src/slang-printers/print-logical-operation.ts | 2 +- src/slang-printers/print-preserving-empty-lines.ts | 2 +- src/slang-utils/create-hug-function.ts | 4 ++-- src/slang-utils/create-parser.ts | 4 ++-- src/slangPrinter.ts | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index 079833e6a..7cc419b7d 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -44,7 +44,7 @@ export const binaryIndentRulesBuilder = (shouldIndent: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - for (let i = 2, { node } = path; ; i += 2) { + 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); diff --git a/src/slang-printers/print-comments.ts b/src/slang-printers/print-comments.ts index adbda0c97..ee660df14 100644 --- a/src/slang-printers/print-comments.ts +++ b/src/slang-printers/print-comments.ts @@ -12,7 +12,7 @@ export function printComments(path: AstPath): Doc[] { const document = joinExisting( line, path.map((commentPath) => { - const { node: comment } = commentPath; + const comment = commentPath.node; if (comment.trailing || comment.leading || comment.printed) { return ''; } diff --git a/src/slang-printers/print-logical-operation.ts b/src/slang-printers/print-logical-operation.ts index 1ade5c546..efdeacd32 100644 --- a/src/slang-printers/print-logical-operation.ts +++ b/src/slang-printers/print-logical-operation.ts @@ -21,7 +21,7 @@ const logicalGroupRulesBuilder = binaryGroupRulesBuilder(() => false); const logicalIndentRulesBuilder = (path: AstPath, options: ParserOptions) => (document: Doc): Doc => { - for (let i = 2, { node } = path; ; i += 2) { + for (let i = 2, node = path.node; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; if ( diff --git a/src/slang-printers/print-preserving-empty-lines.ts b/src/slang-printers/print-preserving-empty-lines.ts index a3f4e0533..ae5d67be7 100644 --- a/src/slang-printers/print-preserving-empty-lines.ts +++ b/src/slang-printers/print-preserving-empty-lines.ts @@ -14,7 +14,7 @@ export function printPreservingEmptyLines( options: ParserOptions ): Doc { return path.map((childPath) => { - const { node } = childPath; + const node = childPath.node; return [ // Only attempt to prepend an empty line if `node` is not the first item diff --git a/src/slang-utils/create-hug-function.ts b/src/slang-utils/create-hug-function.ts index 07d3d10cc..45dfa556c 100644 --- a/src/slang-utils/create-hug-function.ts +++ b/src/slang-utils/create-hug-function.ts @@ -10,13 +10,13 @@ export function createHugFunction( ): (node: Expression) => Expression { const operators = new Set(huggableOperators); return (node: Expression): Expression => { - const { variant } = node; + const variant = node.variant; if ( variant.kind !== TerminalKind.Identifier && isBinaryOperation(variant) && operators.has(variant.operator) ) { - const { loc } = node; + const loc = node.loc; return Object.assign(Object.create(Expression.prototype) as Expression, { kind: NonterminalKind.Expression, loc: { ...loc }, diff --git a/src/slang-utils/create-parser.ts b/src/slang-utils/create-parser.ts index e8880d9ec..088676e00 100644 --- a/src/slang-utils/create-parser.ts +++ b/src/slang-utils/create-parser.ts @@ -22,11 +22,11 @@ function parserAndOutput( } function createError( - { parseOutput }: { parseOutput: ParseOutput }, + result: { parseOutput: ParseOutput }, reason: string ): Error { return new Error( - `We encountered the following syntax error:\n\n\t${parseOutput.errors()[0].message}\n\n${reason}` + `We encountered the following syntax error:\n\n\t${result.parseOutput.errors()[0].message}\n\n${reason}` ); } diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index 834195362..524f20c5e 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -17,7 +17,7 @@ function hasNodeIgnoreComment({ comments }: StrictAstNode): boolean { } function ignoreComments(path: AstPath): void { - const { node } = path; + const node = path.node; // We ignore anything that is not an object if (node === null || typeof node !== 'object') return; @@ -55,7 +55,7 @@ function genericPrint( options: ParserOptions, print: PrintFunction ): Doc { - const { node } = path; + const node = path.node; if (hasNodeIgnoreComment(node)) { ignoreComments(path);