From 81e868444d1dfcc5e2af81d823beaab8bb88070d Mon Sep 17 00:00:00 2001 From: Klaus Date: Mon, 2 Mar 2026 22:50:13 -0300 Subject: [PATCH 1/2] avoid calling `path.node` when we already have the reference --- src/slang-nodes/ContractMembers.ts | 7 ++++--- src/slang-nodes/InterfaceMembers.ts | 7 ++++--- src/slang-nodes/LibraryMembers.ts | 7 ++++--- src/slang-nodes/MemberAccessExpression.ts | 14 +++++++------- src/slang-nodes/Parameters.ts | 2 +- src/slang-nodes/PositionalArguments.ts | 2 +- src/slang-nodes/SourceUnitMembers.ts | 2 +- src/slang-nodes/Statements.ts | 7 ++++--- src/slang-nodes/YulStatements.ts | 7 ++++--- src/slang-nodes/types.d.ts | 5 +++++ .../create-binary-operation-printer.ts | 5 +++-- src/slang-printers/print-binary-operation.ts | 12 ++++++------ src/slang-printers/print-comments.ts | 3 ++- src/slang-printers/print-logical-operation.ts | 12 ++++++------ src/slang-printers/print-preserving-empty-lines.ts | 5 +++-- src/slang-utils/is-chainable-expression.ts | 3 ++- 16 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/slang-nodes/ContractMembers.ts b/src/slang-nodes/ContractMembers.ts index d993ae306..395455211 100644 --- a/src/slang-nodes/ContractMembers.ts +++ b/src/slang-nodes/ContractMembers.ts @@ -36,9 +36,10 @@ export class ContractMembers extends SlangNode { options: ParserOptions ): Doc { return this.items.length > 0 || (this.comments?.length || 0) > 0 - ? printSeparatedItem(printPreservingEmptyLines(path, print, options), { - firstSeparator: hardline - }) + ? printSeparatedItem( + printPreservingEmptyLines(this, path, print, options), + { firstSeparator: hardline } + ) : ''; } } diff --git a/src/slang-nodes/InterfaceMembers.ts b/src/slang-nodes/InterfaceMembers.ts index fa73a9d72..16db09842 100644 --- a/src/slang-nodes/InterfaceMembers.ts +++ b/src/slang-nodes/InterfaceMembers.ts @@ -36,9 +36,10 @@ export class InterfaceMembers extends SlangNode { options: ParserOptions ): Doc { return this.items.length > 0 || (this.comments?.length || 0) > 0 - ? printSeparatedItem(printPreservingEmptyLines(path, print, options), { - firstSeparator: hardline - }) + ? printSeparatedItem( + printPreservingEmptyLines(this, path, print, options), + { firstSeparator: hardline } + ) : ''; } } diff --git a/src/slang-nodes/LibraryMembers.ts b/src/slang-nodes/LibraryMembers.ts index 90300bc5c..bfbefc1ea 100644 --- a/src/slang-nodes/LibraryMembers.ts +++ b/src/slang-nodes/LibraryMembers.ts @@ -36,9 +36,10 @@ export class LibraryMembers extends SlangNode { options: ParserOptions ): Doc { return this.items.length > 0 || (this.comments?.length || 0) > 0 - ? printSeparatedItem(printPreservingEmptyLines(path, print, options), { - firstSeparator: hardline - }) + ? printSeparatedItem( + printPreservingEmptyLines(this, path, print, options), + { firstSeparator: hardline } + ) : ''; } } diff --git a/src/slang-nodes/MemberAccessExpression.ts b/src/slang-nodes/MemberAccessExpression.ts index 3ad919c28..8ab238dfc 100644 --- a/src/slang-nodes/MemberAccessExpression.ts +++ b/src/slang-nodes/MemberAccessExpression.ts @@ -10,19 +10,18 @@ import { TerminalNode } from './TerminalNode.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { CollectedMetadata, PrintFunction } from '../types.d.ts'; -import type { AstNode } from './types.d.ts'; +import type { AstNode, ChainableExpression } from './types.d.ts'; const { group, indent, label, softline } = doc.builders; function isEndOfChain( - node: MemberAccessExpression, + node: ChainableExpression, path: AstPath ): boolean { - for ( - let i = 1, current: Expression['variant'] = node, parent = path.getNode(i); - parent && isChainableExpression(parent); - i++, current = parent, parent = path.getNode(i) - ) { + for (let i = 1, current = node; ; i++) { + const parent = path.getNode(i)!; + if (!isChainableExpression(parent)) break; + switch (parent.kind) { case NonterminalKind.MemberAccessExpression: // If `parent` is a MemberAccessExpression we are not at the end @@ -41,6 +40,7 @@ function isEndOfChain( if (current !== parent.operand) return true; break; } + current = parent; } return true; } diff --git a/src/slang-nodes/Parameters.ts b/src/slang-nodes/Parameters.ts index 52aab3e4f..168c080ae 100644 --- a/src/slang-nodes/Parameters.ts +++ b/src/slang-nodes/Parameters.ts @@ -36,7 +36,7 @@ export class Parameters extends SlangNode { return printSeparatedList(path.map(print, 'items'), { grouped: false }); } - const parameterComments = printComments(path, options); + const parameterComments = printComments(this, path, options); return parameterComments.length > 0 ? printSeparatedItem(parameterComments) diff --git a/src/slang-nodes/PositionalArguments.ts b/src/slang-nodes/PositionalArguments.ts index fe94e257c..de3f71739 100644 --- a/src/slang-nodes/PositionalArguments.ts +++ b/src/slang-nodes/PositionalArguments.ts @@ -36,7 +36,7 @@ export class PositionalArguments extends SlangNode { if (this.items.length > 0) { return printSeparatedList(path.map(print, 'items')); } - const argumentComments = printComments(path, options); + const argumentComments = printComments(this, path, options); return argumentComments.length > 0 ? printSeparatedItem(argumentComments) diff --git a/src/slang-nodes/SourceUnitMembers.ts b/src/slang-nodes/SourceUnitMembers.ts index 4adcbeac2..57e71770f 100644 --- a/src/slang-nodes/SourceUnitMembers.ts +++ b/src/slang-nodes/SourceUnitMembers.ts @@ -31,6 +31,6 @@ export class SourceUnitMembers extends SlangNode { print: PrintFunction, options: ParserOptions ): Doc { - return printPreservingEmptyLines(path, print, options); + return printPreservingEmptyLines(this, path, print, options); } } diff --git a/src/slang-nodes/Statements.ts b/src/slang-nodes/Statements.ts index def732d5c..d6a37c511 100644 --- a/src/slang-nodes/Statements.ts +++ b/src/slang-nodes/Statements.ts @@ -36,9 +36,10 @@ export class Statements extends SlangNode { options: ParserOptions ): Doc { return this.items.length > 0 || (this.comments?.length || 0) > 0 - ? printSeparatedItem(printPreservingEmptyLines(path, print, options), { - firstSeparator: hardline - }) + ? printSeparatedItem( + printPreservingEmptyLines(this, path, print, options), + { firstSeparator: hardline } + ) : ''; } } diff --git a/src/slang-nodes/YulStatements.ts b/src/slang-nodes/YulStatements.ts index 260ad201a..0a6b0bb07 100644 --- a/src/slang-nodes/YulStatements.ts +++ b/src/slang-nodes/YulStatements.ts @@ -36,9 +36,10 @@ export class YulStatements extends SlangNode { options: ParserOptions ): Doc { return this.items.length > 0 || (this.comments?.length || 0) > 0 - ? printSeparatedItem(printPreservingEmptyLines(path, print, options), { - firstSeparator: hardline - }) + ? printSeparatedItem( + printPreservingEmptyLines(this, path, print, options), + { firstSeparator: hardline } + ) : ''; } } diff --git a/src/slang-nodes/types.d.ts b/src/slang-nodes/types.d.ts index 9f56a82a9..7dc916cfd 100644 --- a/src/slang-nodes/types.d.ts +++ b/src/slang-nodes/types.d.ts @@ -494,6 +494,11 @@ export type BinaryOperation = Extract< } >; +export type ChainableExpression = + | FunctionCallExpression + | IndexAccessExpression + | MemberAccessExpression; + export type AstNode = | StrictAstNode | Comment diff --git a/src/slang-printers/create-binary-operation-printer.ts b/src/slang-printers/create-binary-operation-printer.ts index 4cb535a5a..b2fe7e9da 100644 --- a/src/slang-printers/create-binary-operation-printer.ts +++ b/src/slang-printers/create-binary-operation-printer.ts @@ -42,7 +42,8 @@ export const createBinaryOperationPrinter = path: AstPath ) => (document: Doc) => Doc, indentRulesBuilder: ( - path: AstPath + node: BinaryOperation, + path: AstPath ) => (document: Doc) => Doc ) => ( @@ -52,7 +53,7 @@ export const createBinaryOperationPrinter = options: ParserOptions ): Doc => { const groupRules = groupRulesBuilder(path); - const indentRules = indentRulesBuilder(path); + const indentRules = indentRulesBuilder(node, path); return groupRules([ path.call(print, 'leftOperand'), diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index b0feabe9b..5ba12d5a3 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -32,7 +32,7 @@ const isStatementWithoutIndentedOperation = createKindCheckFunction([ export const shouldNotIndent = ( node: StrictAstNode, - path: AstPath, + path: AstPath, index: number ): boolean => isStatementWithoutIndentedOperation(node) || @@ -42,15 +42,15 @@ export const shouldNotIndent = ( export const binaryIndentRulesBuilder = (shouldIndent: (node: BinaryOperation) => boolean) => - (path: AstPath) => + (node: BinaryOperation, path: AstPath) => (document: Doc): Doc => { - for (let i = 1, node = path.node; ; i++) { - const parent = path.getNode(i) as StrictAstNode; + for (let i = 1, current = node; ; i++) { + const parent = path.getNode(i)!; 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; + if (current === parent.rightOperand) break; + current = parent; } return document; }; diff --git a/src/slang-printers/print-comments.ts b/src/slang-printers/print-comments.ts index bfa8cf317..5352c3127 100644 --- a/src/slang-printers/print-comments.ts +++ b/src/slang-printers/print-comments.ts @@ -17,10 +17,11 @@ function isPrintable(comment: Comment): boolean { } export function printComments( + node: StrictAstNode, path: AstPath, options: ParserOptions ): Doc[] { - if (path.node.comments === undefined) return []; + if (node.comments === undefined) return []; return joinExisting( line, path.map((commentPath, index, comments: Comment[]) => { diff --git a/src/slang-printers/print-logical-operation.ts b/src/slang-printers/print-logical-operation.ts index d0b7387c7..12ef932f5 100644 --- a/src/slang-printers/print-logical-operation.ts +++ b/src/slang-printers/print-logical-operation.ts @@ -15,19 +15,19 @@ const { indent } = doc.builders; const logicalGroupRulesBuilder = binaryGroupRulesBuilder(() => false); const logicalIndentRulesBuilder = - (path: AstPath) => + (node: BinaryOperation, path: AstPath) => (document: Doc): Doc => { - for (let i = 1, node = path.node; ; i++) { - const parent = path.getNode(i) as StrictAstNode; + for (let i = 1, current = node; ; i++) { + const parent = path.getNode(i)!; if (shouldNotIndent(parent, path, i)) break; if ( parent.kind === NonterminalKind.ConditionalExpression && - parent.operand === node + parent.operand === current ) break; if (!isBinaryOperation(parent)) return indent(document); - if (node === parent.rightOperand) break; - node = parent; + if (current === parent.rightOperand) break; + current = parent; } return document; }; diff --git a/src/slang-printers/print-preserving-empty-lines.ts b/src/slang-printers/print-preserving-empty-lines.ts index a7ff8a51b..7b54dce64 100644 --- a/src/slang-printers/print-preserving-empty-lines.ts +++ b/src/slang-printers/print-preserving-empty-lines.ts @@ -10,11 +10,12 @@ import type { PrintFunction } from '../types.d.ts'; const { hardline } = doc.builders; export function printPreservingEmptyLines( + node: LineCollection, path: AstPath, print: PrintFunction, options: ParserOptions ): Doc { - return path.node.items.length > 0 + return node.items.length > 0 ? path.map((childPath) => { const node = childPath.node; @@ -35,5 +36,5 @@ export function printPreservingEmptyLines( : '' ]; }, 'items') - : printComments(path, options); + : printComments(node, path, options); } diff --git a/src/slang-utils/is-chainable-expression.ts b/src/slang-utils/is-chainable-expression.ts index 3437478c8..fa400d3e9 100644 --- a/src/slang-utils/is-chainable-expression.ts +++ b/src/slang-utils/is-chainable-expression.ts @@ -1,10 +1,11 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { createKindCheckFunction } from './create-kind-check-function.js'; +import type { ChainableExpression } from '../slang-nodes/types.js'; import type { Expression } from '../slang-nodes/Expression.js'; export const isChainableExpression = createKindCheckFunction([ NonterminalKind.FunctionCallExpression, NonterminalKind.IndexAccessExpression, NonterminalKind.MemberAccessExpression -]) as (node: Expression['variant']) => boolean; +]) as (node: Expression['variant']) => node is ChainableExpression; From fac35c7c2be83a0d48d779d4893e31e46269edeb Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 4 Mar 2026 17:33:57 -0300 Subject: [PATCH 2/2] small refactor to keep code smaller --- src/slang-nodes/MemberAccessExpression.ts | 5 ++--- src/slang-printers/print-binary-operation.ts | 5 ++--- src/slang-printers/print-logical-operation.ts | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/slang-nodes/MemberAccessExpression.ts b/src/slang-nodes/MemberAccessExpression.ts index 8ab238dfc..2573a4c33 100644 --- a/src/slang-nodes/MemberAccessExpression.ts +++ b/src/slang-nodes/MemberAccessExpression.ts @@ -18,8 +18,8 @@ function isEndOfChain( node: ChainableExpression, path: AstPath ): boolean { - for (let i = 1, current = node; ; i++) { - const parent = path.getNode(i)!; + for (let i = 1, current = node, parent; ; i++, current = parent) { + parent = path.getNode(i)!; if (!isChainableExpression(parent)) break; switch (parent.kind) { @@ -40,7 +40,6 @@ function isEndOfChain( if (current !== parent.operand) return true; break; } - current = parent; } return true; } diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index 5ba12d5a3..a9d21891d 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -44,13 +44,12 @@ export const binaryIndentRulesBuilder = (shouldIndent: (node: BinaryOperation) => boolean) => (node: BinaryOperation, path: AstPath) => (document: Doc): Doc => { - for (let i = 1, current = node; ; i++) { - const parent = path.getNode(i)!; + for (let i = 1, current = node, parent; ; i++, current = parent) { + parent = path.getNode(i)!; if (shouldNotIndent(parent, path, i)) break; if (!isBinaryOperation(parent)) return indent(document); if (shouldIndent(parent)) return indent(document); if (current === parent.rightOperand) break; - current = parent; } return document; }; diff --git a/src/slang-printers/print-logical-operation.ts b/src/slang-printers/print-logical-operation.ts index 12ef932f5..7d83a467e 100644 --- a/src/slang-printers/print-logical-operation.ts +++ b/src/slang-printers/print-logical-operation.ts @@ -17,8 +17,8 @@ const logicalGroupRulesBuilder = binaryGroupRulesBuilder(() => false); const logicalIndentRulesBuilder = (node: BinaryOperation, path: AstPath) => (document: Doc): Doc => { - for (let i = 1, current = node; ; i++) { - const parent = path.getNode(i)!; + for (let i = 1, current = node, parent; ; i++, current = parent) { + parent = path.getNode(i)!; if (shouldNotIndent(parent, path, i)) break; if ( parent.kind === NonterminalKind.ConditionalExpression && @@ -27,7 +27,6 @@ const logicalIndentRulesBuilder = break; if (!isBinaryOperation(parent)) return indent(document); if (current === parent.rightOperand) break; - current = parent; } return document; };