diff --git a/src/binary-operator-printers/assignment.js b/src/binary-operator-printers/assignment.js index ab72d82ca..dce0e51de 100644 --- a/src/binary-operator-printers/assignment.js +++ b/src/binary-operator-printers/assignment.js @@ -1,4 +1,5 @@ import { doc } from 'prettier'; +import { printAssignmentRightSide } from '../common/printer-helpers.js'; const { group, line, indent } = doc.builders; @@ -19,10 +20,7 @@ export const assignment = { ].includes(op), print: (node, path, print) => [ path.call(print, 'left'), - ' ', - node.operator, - node.right.type === 'BinaryOperation' - ? group(indent([line, path.call(print, 'right')])) - : [' ', path.call(print, 'right')] + ` ${node.operator}`, + printAssignmentRightSide(path.call(print, 'right'), node.right) ] }; diff --git a/src/common/printer-helpers.js b/src/common/printer-helpers.js index 74a6a180c..0b07e2468 100644 --- a/src/common/printer-helpers.js +++ b/src/common/printer-helpers.js @@ -98,3 +98,14 @@ export const printSeparatedList = ( lastSeparator, grouped }); + +export const printAssignmentRightSide = (document, value) => + [ + 'TupleExpression', + 'FunctionCall', + 'IndexAccess', + 'NameValueExpression', + 'MemberAccess' + ].includes(value.type) + ? [' ', document] + : group(indent([line, document])); diff --git a/src/nodes/Conditional.js b/src/nodes/Conditional.js index 2c1f408eb..7bab7023e 100644 --- a/src/nodes/Conditional.js +++ b/src/nodes/Conditional.js @@ -55,11 +55,7 @@ const experimentalTernaries = (node, path, print, options) => { }) ]; - const document = group([conditionAndTrueExpressionGroup, falseExpressionDoc]); - - return parent.type === 'VariableDeclarationStatement' - ? indent([softline, document]) - : document; + return group([conditionAndTrueExpressionGroup, falseExpressionDoc]); }; const traditionalTernaries = (path, print) => diff --git a/src/nodes/FileLevelConstant.js b/src/nodes/FileLevelConstant.js index 4d0e141d2..310a8b9d2 100644 --- a/src/nodes/FileLevelConstant.js +++ b/src/nodes/FileLevelConstant.js @@ -1,10 +1,15 @@ +import { printAssignmentRightSide } from '../common/printer-helpers.js'; + export const FileLevelConstant = { print: ({ node, path, print }) => [ path.call(print, 'typeName'), ' constant ', node.name, - ' = ', - path.call(print, 'initialValue'), + ' =', + printAssignmentRightSide( + path.call(print, 'initialValue'), + node.initialValue + ), ';' ] }; diff --git a/src/nodes/StateVariableDeclaration.js b/src/nodes/StateVariableDeclaration.js index e9c6fb07a..1c3d10ed9 100644 --- a/src/nodes/StateVariableDeclaration.js +++ b/src/nodes/StateVariableDeclaration.js @@ -1,17 +1,17 @@ -import { doc } from 'prettier'; - -const { group, indent, line } = doc.builders; +import { printAssignmentRightSide } from '../common/printer-helpers.js'; const initialValue = (node, path, print) => { if (!node.initialValue) { return ''; } - if (node.initialValue.type === 'TupleExpression') { - return [' = ', path.call(print, 'initialValue')]; - } - - return group([' =', indent([line, path.call(print, 'initialValue')])]); + return [ + ' =', + printAssignmentRightSide( + path.call(print, 'initialValue'), + node.initialValue + ) + ]; }; export const StateVariableDeclaration = { diff --git a/src/nodes/VariableDeclarationStatement.js b/src/nodes/VariableDeclarationStatement.js index ae08a94a6..09a2e766b 100644 --- a/src/nodes/VariableDeclarationStatement.js +++ b/src/nodes/VariableDeclarationStatement.js @@ -1,13 +1,27 @@ import { doc } from 'prettier'; -import { printSeparatedList } from '../common/printer-helpers.js'; +import { + printAssignmentRightSide, + printSeparatedList +} from '../common/printer-helpers.js'; -const { group, indentIfBreak } = doc.builders; +const { group, indentIfBreak, line } = doc.builders; const embraceVariables = (document, embrace) => embrace ? ['(', printSeparatedList(document), ')'] : document; -const initialValue = (node, path, print) => - node.initialValue ? [' = ', path.call(print, 'initialValue')] : ''; +const initialValue = (node, path, print) => { + if (!node.initialValue) { + return ''; + } + + return [ + ' =', + printAssignmentRightSide( + path.call(print, 'initialValue'), + node.initialValue + ) + ]; +}; export const VariableDeclarationStatement = { print: ({ node, path, print }) => { diff --git a/src/slang-nodes/AssignmentExpression.ts b/src/slang-nodes/AssignmentExpression.ts index 647ad73d6..dd3196ca2 100644 --- a/src/slang-nodes/AssignmentExpression.ts +++ b/src/slang-nodes/AssignmentExpression.ts @@ -1,11 +1,8 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { isBinaryOperation } from '../slang-utils/is-binary-operation.js'; -import { printIndentedGroupOrSpacedDocument } from '../slang-printers/print-indented-group-or-spaced-document.js'; import { extractVariant } from '../slang-utils/extract-variant.js'; -import { isMultilineString } from '../slang-utils/is-multiline-string.js'; +import { printAssignmentRightSide } from '../slang-printers/print-assignment-right-side.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; -import { TerminalNode } from './TerminalNode.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; @@ -43,11 +40,9 @@ export class AssignmentExpression extends SlangNode { return [ path.call(print, 'leftOperand'), ` ${this.operator}`, - printIndentedGroupOrSpacedDocument( + printAssignmentRightSide( path.call(print, 'rightOperand'), - !(this.rightOperand instanceof TerminalNode) && - (isBinaryOperation(this.rightOperand) || - isMultilineString(this.rightOperand)) + this.rightOperand ) ]; } diff --git a/src/slang-nodes/ConditionalExpression.ts b/src/slang-nodes/ConditionalExpression.ts index 4a23b97d3..27821b35c 100644 --- a/src/slang-nodes/ConditionalExpression.ts +++ b/src/slang-nodes/ConditionalExpression.ts @@ -10,7 +10,7 @@ import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { CollectedMetadata, PrintFunction } from '../types.d.ts'; import type { AstNode, StrictAstNode } from './types.d.ts'; -const { group, hardline, ifBreak, indent, line, softline } = doc.builders; +const { group, hardline, ifBreak, indent, line } = doc.builders; function experimentalTernaries( node: ConditionalExpression, @@ -73,11 +73,7 @@ function experimentalTernaries( ) ]; - const document = group([conditionAndTrueExpressionGroup, falseExpressionDoc]); - - return parent.kind === NonterminalKind.VariableDeclarationValue - ? group(indent([softline, document])) - : document; + return group([conditionAndTrueExpressionGroup, falseExpressionDoc]); } function traditionalTernaries( diff --git a/src/slang-nodes/ConstantDefinition.ts b/src/slang-nodes/ConstantDefinition.ts index e4a72bfe7..649e5c7a5 100644 --- a/src/slang-nodes/ConstantDefinition.ts +++ b/src/slang-nodes/ConstantDefinition.ts @@ -1,5 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { extractVariant } from '../slang-utils/extract-variant.js'; +import { printAssignmentRightSide } from '../slang-printers/print-assignment-right-side.js'; import { SlangNode } from './SlangNode.js'; import { TypeName } from './TypeName.js'; import { TerminalNode } from './TerminalNode.js'; @@ -40,8 +41,8 @@ export class ConstantDefinition extends SlangNode { path.call(print, 'typeName'), ' constant ', path.call(print, 'name'), - ' = ', - path.call(print, 'value'), + ' =', + printAssignmentRightSide(path.call(print, 'value'), this.value), ';' ]; } diff --git a/src/slang-nodes/MemberAccessExpression.ts b/src/slang-nodes/MemberAccessExpression.ts index ec49a37bd..3ad919c28 100644 --- a/src/slang-nodes/MemberAccessExpression.ts +++ b/src/slang-nodes/MemberAccessExpression.ts @@ -1,8 +1,8 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { doc } from 'prettier'; import { isLabel } from '../slang-utils/is-label.js'; -import { createKindCheckFunction } from '../slang-utils/create-kind-check-function.js'; import { extractVariant } from '../slang-utils/extract-variant.js'; +import { isChainableExpression } from '../slang-utils/is-chainable-expression.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; import { TerminalNode } from './TerminalNode.js'; @@ -10,22 +10,16 @@ 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, StrictAstNode } from './types.d.ts'; +import type { AstNode } from './types.d.ts'; const { group, indent, label, softline } = doc.builders; -const isChainableExpression = createKindCheckFunction([ - NonterminalKind.FunctionCallExpression, - NonterminalKind.IndexAccessExpression, - NonterminalKind.MemberAccessExpression -]); - function isEndOfChain( node: MemberAccessExpression, - path: AstPath + path: AstPath ): boolean { for ( - let i = 1, current: StrictAstNode = node, parent = path.getNode(i); + let i = 1, current: Expression['variant'] = node, parent = path.getNode(i); parent && isChainableExpression(parent); i++, current = parent, parent = path.getNode(i) ) { diff --git a/src/slang-nodes/StateVariableDefinitionValue.ts b/src/slang-nodes/StateVariableDefinitionValue.ts index 38ed2b9e2..4b8c2495f 100644 --- a/src/slang-nodes/StateVariableDefinitionValue.ts +++ b/src/slang-nodes/StateVariableDefinitionValue.ts @@ -1,5 +1,5 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { printIndentedGroupOrSpacedDocument } from '../slang-printers/print-indented-group-or-spaced-document.js'; +import { printAssignmentRightSide } from '../slang-printers/print-assignment-right-side.js'; import { extractVariant } from '../slang-utils/extract-variant.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; @@ -32,10 +32,7 @@ export class StateVariableDefinitionValue extends SlangNode { ): Doc { return [ ' =', - printIndentedGroupOrSpacedDocument( - path.call(print, 'value'), - this.value.kind !== NonterminalKind.ArrayExpression - ) + printAssignmentRightSide(path.call(print, 'value'), this.value) ]; } } diff --git a/src/slang-nodes/VariableDeclarationValue.ts b/src/slang-nodes/VariableDeclarationValue.ts index f3de4faf2..fe132577f 100644 --- a/src/slang-nodes/VariableDeclarationValue.ts +++ b/src/slang-nodes/VariableDeclarationValue.ts @@ -1,10 +1,8 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; +import { printAssignmentRightSide } from '../slang-printers/print-assignment-right-side.js'; import { extractVariant } from '../slang-utils/extract-variant.js'; -import { printIndentedGroupOrSpacedDocument } from '../slang-printers/print-indented-group-or-spaced-document.js'; -import { isMultilineString } from '../slang-utils/is-multiline-string.js'; import { SlangNode } from './SlangNode.js'; import { Expression } from './Expression.js'; -import { TerminalNode } from './TerminalNode.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; @@ -33,11 +31,7 @@ export class VariableDeclarationValue extends SlangNode { print(path: AstPath, print: PrintFunction): Doc { return [ ' =', - printIndentedGroupOrSpacedDocument( - path.call(print, 'expression'), - !(this.expression instanceof TerminalNode) && - isMultilineString(this.expression) - ) + printAssignmentRightSide(path.call(print, 'expression'), this.expression) ]; } } diff --git a/src/slang-printers/print-assignment-right-side.ts b/src/slang-printers/print-assignment-right-side.ts new file mode 100644 index 000000000..68e9431c5 --- /dev/null +++ b/src/slang-printers/print-assignment-right-side.ts @@ -0,0 +1,17 @@ +import { NonterminalKind } from '@nomicfoundation/slang/cst'; +import { isChainableExpression } from '../slang-utils/is-chainable-expression.js'; +import { printIndentedGroupOrSpacedDocument } from './print-indented-group-or-spaced-document.js'; + +import type { Doc, doc } from 'prettier'; +import type { Expression } from '../slang-nodes/Expression.js'; + +export function printAssignmentRightSide( + document: Doc, + value: Expression['variant'] +): doc.builders.Group | [' ', Doc] { + return printIndentedGroupOrSpacedDocument( + document, + value.kind !== NonterminalKind.ArrayExpression && + !isChainableExpression(value) + ); +} diff --git a/src/slang-utils/is-chainable-expression.ts b/src/slang-utils/is-chainable-expression.ts new file mode 100644 index 000000000..3437478c8 --- /dev/null +++ b/src/slang-utils/is-chainable-expression.ts @@ -0,0 +1,10 @@ +import { NonterminalKind } from '@nomicfoundation/slang/cst'; +import { createKindCheckFunction } from './create-kind-check-function.js'; + +import type { Expression } from '../slang-nodes/Expression.js'; + +export const isChainableExpression = createKindCheckFunction([ + NonterminalKind.FunctionCallExpression, + NonterminalKind.IndexAccessExpression, + NonterminalKind.MemberAccessExpression +]) as (node: Expression['variant']) => boolean; diff --git a/src/slang-utils/is-multiline-string.ts b/src/slang-utils/is-multiline-string.ts deleted file mode 100644 index 121704328..000000000 --- a/src/slang-utils/is-multiline-string.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import { createKindCheckFunction } from './create-kind-check-function.js'; - -import type { StrictAstNode } from '../slang-nodes/types.js'; -import type { StringLiterals } from '../slang-nodes/StringLiterals.js'; -import type { HexStringLiterals } from '../slang-nodes/HexStringLiterals.js'; -import type { UnicodeStringLiterals } from '../slang-nodes/UnicodeStringLiterals.js'; - -export const isMultilineString = createKindCheckFunction([ - NonterminalKind.StringLiterals, - NonterminalKind.HexStringLiterals, - NonterminalKind.UnicodeStringLiterals -]) as ( - node: StrictAstNode -) => node is StringLiterals | HexStringLiterals | UnicodeStringLiterals; diff --git a/tests/config/run-format-test.js b/tests/config/run-format-test.js index c4892cb84..4e0af1597 100644 --- a/tests/config/run-format-test.js +++ b/tests/config/run-format-test.js @@ -85,8 +85,6 @@ const antlrMismatchTests = new Map( // ANTLR doesn't support UntypedTupleMember with a storage location, which // is valid Slang, but not in Solidity. "AllSolidityFeaturesV0.4.26/AllSolidityFeatures.sol", - // TODO: Review why this test doesn't match. - "MultipartStrings/MultipartStrings.sol", ].map((fixture) => { const [file, compareBytecode = () => true] = Array.isArray(fixture) ? fixture diff --git a/tests/format/BinaryOperators/__snapshots__/format.test.js.snap b/tests/format/BinaryOperators/__snapshots__/format.test.js.snap index 463f78323..92eb3ccd8 100644 --- a/tests/format/BinaryOperators/__snapshots__/format.test.js.snap +++ b/tests/format/BinaryOperators/__snapshots__/format.test.js.snap @@ -482,10 +482,11 @@ contract ComparisonOperators { a = veryVeryVeryVeryVeryLongVariableCalledA; veryVeryVeryVeryVeryLongVariableCalledB >= veryVeryVeryVeryVeryLongVariableCalledA; - a += veryVeryVeryVeryVeryLongVariableCalledA - || veryVeryVeryVeryVeryLongVariableCalledB - ? 1 - : 2 + a += + veryVeryVeryVeryVeryLongVariableCalledA + || veryVeryVeryVeryVeryLongVariableCalledB + ? 1 + : 2 ) {} a( veryVeryVeryVeryVeryLongVariableCalledA @@ -635,10 +636,11 @@ contract LogicalOperators { for ( a = veryVeryVeryVeryVeryLongVariableCalledA; a <= veryVeryVeryVeryVeryLongVariableCalledA; - a += veryVeryVeryVeryVeryLongVariableCalledA - || veryVeryVeryVeryVeryLongVariableCalledB - ? 1 - : 2 + a += + veryVeryVeryVeryVeryLongVariableCalledA + || veryVeryVeryVeryVeryLongVariableCalledB + ? 1 + : 2 ) {} a( veryVeryVeryVeryVeryLongVariableCalledA @@ -1163,10 +1165,11 @@ contract ComparisonOperators { a = veryVeryVeryVeryVeryLongVariableCalledA; veryVeryVeryVeryVeryLongVariableCalledB >= veryVeryVeryVeryVeryLongVariableCalledA; - a += veryVeryVeryVeryVeryLongVariableCalledA || - veryVeryVeryVeryVeryLongVariableCalledB - ? 1 - : 2 + a += + veryVeryVeryVeryVeryLongVariableCalledA || + veryVeryVeryVeryVeryLongVariableCalledB + ? 1 + : 2 ) {} a( veryVeryVeryVeryVeryLongVariableCalledA == @@ -1316,10 +1319,11 @@ contract LogicalOperators { for ( a = veryVeryVeryVeryVeryLongVariableCalledA; a <= veryVeryVeryVeryVeryLongVariableCalledA; - a += veryVeryVeryVeryVeryLongVariableCalledA || - veryVeryVeryVeryVeryLongVariableCalledB - ? 1 - : 2 + a += + veryVeryVeryVeryVeryLongVariableCalledA || + veryVeryVeryVeryVeryLongVariableCalledB + ? 1 + : 2 ) {} a( veryVeryVeryVeryVeryLongVariableCalledA || diff --git a/tests/format/Conditional/__snapshots__/format.test.js.snap b/tests/format/Conditional/__snapshots__/format.test.js.snap index 73ff6d291..3d7e486c1 100644 --- a/tests/format/Conditional/__snapshots__/format.test.js.snap +++ b/tests/format/Conditional/__snapshots__/format.test.js.snap @@ -38,9 +38,8 @@ pragma solidity ^0.4.24; contract Conditional { function foo() { - address contextAddress = longAddress_ == address(0) - ? msg.sender - : currentContextAddress_; + address contextAddress = + longAddress_ == address(0) ? msg.sender : currentContextAddress_; asset == ETH ? require( address(uint160(msg.sender)).send(quantity), diff --git a/tests/format/ExperimentalTernaries/__snapshots__/format.test.js.snap b/tests/format/ExperimentalTernaries/__snapshots__/format.test.js.snap index b8a0b451a..27de54357 100644 --- a/tests/format/ExperimentalTernaries/__snapshots__/format.test.js.snap +++ b/tests/format/ExperimentalTernaries/__snapshots__/format.test.js.snap @@ -373,22 +373,23 @@ contract Conditional { .willCauseAnIndentButNotParens(); // Assignment also groups and indents as Variable Declaration: - assignment = ( - isAnAdorableKittyCat() && - (someReallyLongCondition || moreInThisLongCondition) - ) ? - someReallyLargeExpression + assignment = + ( + isAnAdorableKittyCat() && + (someReallyLongCondition || moreInThisLongCondition) + ) ? + someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : ( + isNotAnAdorableKittyCat() && + (someReallyLongCondition || moreInThisLongCondition) + ) ? + bark() + : shortCondition() ? shortConsequent() + : someReallyLargeExpression .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens() - : ( - isNotAnAdorableKittyCat() && - (someReallyLongCondition || moreInThisLongCondition) - ) ? - bark() - : shortCondition() ? shortConsequent() - : someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens(); + .willCauseAnIndentButNotParens(); // illustrating case of mostly short conditionals string storage mostlyShort = @@ -883,22 +884,23 @@ contract Conditional { .willCauseAnIndentButNotParens(); // Assignment also groups and indents as Variable Declaration: - assignment = ( - isAnAdorableKittyCat() && - (someReallyLongCondition || moreInThisLongCondition) - ) ? - someReallyLargeExpression + assignment = + ( + isAnAdorableKittyCat() && + (someReallyLongCondition || moreInThisLongCondition) + ) ? + someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : ( + isNotAnAdorableKittyCat() && + (someReallyLongCondition || moreInThisLongCondition) + ) ? + bark() + : shortCondition() ? shortConsequent() + : someReallyLargeExpression .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens() - : ( - isNotAnAdorableKittyCat() && - (someReallyLongCondition || moreInThisLongCondition) - ) ? - bark() - : shortCondition() ? shortConsequent() - : someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens(); + .willCauseAnIndentButNotParens(); // illustrating case of mostly short conditionals string storage mostlyShort = @@ -1396,22 +1398,23 @@ contract Conditional { .willCauseAnIndentButNotParens(); // Assignment also groups and indents as Variable Declaration: - assignment = ( - isAnAdorableKittyCat() && - (someReallyLongCondition || moreInThisLongCondition) - ) ? - someReallyLargeExpression + assignment = + ( + isAnAdorableKittyCat() && + (someReallyLongCondition || moreInThisLongCondition) + ) ? + someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : ( + isNotAnAdorableKittyCat() && + (someReallyLongCondition || moreInThisLongCondition) + ) ? + bark() + : shortCondition() ? shortConsequent() + : someReallyLargeExpression .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens() - : ( - isNotAnAdorableKittyCat() && - (someReallyLongCondition || moreInThisLongCondition) - ) ? - bark() - : shortCondition() ? shortConsequent() - : someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens(); + .willCauseAnIndentButNotParens(); // illustrating case of mostly short conditionals string storage mostlyShort = @@ -1799,35 +1802,38 @@ pragma solidity ^0.4.24; contract Conditional { function blogPostExample() { // "curious" ternaries - string storage animalName = pet.canBark() - ? pet.isScary() - ? "wolf" - : "dog" - : pet.canMeow() - ? "cat" - : "probably a bunny"; - - // "case-style" ternaries - string storage animalName = pet.isScary() - ? "wolf" - : pet.canBark() - ? "dog" - : pet.canMeow() - ? "cat" - : "probably a bunny"; - - // fluidity between "case-style" and "curious" ternaries - string storage animalName = pet.canSqueak() - ? "mouse" - : pet.canBark() + string storage animalName = + pet.canBark() ? pet.isScary() ? "wolf" : "dog" : pet.canMeow() ? "cat" - : pet.canSqueak() - ? "mouse" + : "probably a bunny"; + + // "case-style" ternaries + string storage animalName = + pet.isScary() + ? "wolf" + : pet.canBark() + ? "dog" + : pet.canMeow() + ? "cat" : "probably a bunny"; + + // fluidity between "case-style" and "curious" ternaries + string storage animalName = + pet.canSqueak() + ? "mouse" + : pet.canBark() + ? pet.isScary() + ? "wolf" + : "dog" + : pet.canMeow() + ? "cat" + : pet.canSqueak() + ? "mouse" + : "probably a bunny"; } function examples1() { @@ -1835,67 +1841,72 @@ contract Conditional { string storage short = isLoud() ? makeNoise() : silent(); // next, put everything after the = - string storage lessShort = isLoudReallyLoud() - ? makeNoiseReallyLoudly.omgSoLoud() - : silent(); + string storage lessShort = + isLoudReallyLoud() ? makeNoiseReallyLoudly.omgSoLoud() : silent(); // next, indent the consequent: - string storage andIndented = isLoudReallyReallyReallyReallyLoud() - ? makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud() - : silent(); + string storage andIndented = + isLoudReallyReallyReallyReallyLoud() + ? makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud() + : silent(); // if we need to add spaces to the falseExpression to fill a tab, we indent it as well: - string - storage indentationInFalseExpression = isLoudReallyReallyReallyReallyLoud() + string storage indentationInFalseExpression = + isLoudReallyReallyReallyReallyLoud() ? makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud() : someReallyLargeExpression .thatWouldCauseALineBreak() .willCauseAnIndentButNotParens(); // unless the consequent is short (less than ten characters long): - string storage shortSoCase = isLoudReallyReallyReallyReallyLoud() - ? silent() - : (makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud()); + string storage shortSoCase = + isLoudReallyReallyReallyReallyLoud() + ? silent() + : (makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud()); // if chained, always break and put after the = - string storage chainedShort = isCat() - ? meow() - : isDog() - ? bark() - : silent(); + string storage chainedShort = + isCat() + ? meow() + : isDog() + ? bark() + : silent(); // when a consequent breaks in a chain: - string storage chainedWithLongConsequent = isCat() - ? someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens() - : isDog() - ? bark() - : silent(); + string storage chainedWithLongConsequent = + isCat() + ? someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : isDog() + ? bark() + : silent(); // nested ternary in consequent always breaks: - string storage chainedWithTernaryConsequent = isCat() - ? aNestedCondition - ? theResult() - : theAlternate() - : isDog() - ? bark() - : silent(); + string storage chainedWithTernaryConsequent = + isCat() + ? aNestedCondition + ? theResult() + : theAlternate() + : isDog() + ? bark() + : silent(); // consequent and terminal alternate break: - string storage consequentAndTerminalAlternateBreak = isCat() - ? someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens() - : isDog() - ? bark() - : someReallyLargeExpression + string storage consequentAndTerminalAlternateBreak = + isCat() + ? someReallyLargeExpression .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens(); + .willCauseAnIndentButNotParens() + : isDog() + ? bark() + : someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens(); // multiline conditions and consequents/alternates: - string - storage multilineConditionsConsequentsAndAlternates = (isAnAdorableKittyCat() && + string storage multilineConditionsConsequentsAndAlternates = + (isAnAdorableKittyCat() && (someReallyLongCondition || moreInThisLongCondition)) ? someReallyLargeExpression .thatWouldCauseALineBreak() @@ -1910,50 +1921,53 @@ contract Conditional { .willCauseAnIndentButNotParens(); // Assignment also groups and indents as Variable Declaration: - assignment = (isAnAdorableKittyCat() && - (someReallyLongCondition || moreInThisLongCondition)) - ? someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens() - : (isNotAnAdorableKittyCat() && + assignment = + (isAnAdorableKittyCat() && (someReallyLongCondition || moreInThisLongCondition)) - ? bark() - : shortCondition() - ? shortConsequent() - : someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens(); + ? someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : (isNotAnAdorableKittyCat() && + (someReallyLongCondition || moreInThisLongCondition)) + ? bark() + : shortCondition() + ? shortConsequent() + : someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens(); // illustrating case of mostly short conditionals - string storage mostlyShort = x == 1 - ? "one" - : x == 2 - ? "two" - : x == 3 - ? "three" - : (x == 5 && - y == 7 && - someOtherThing - .thatIsSoLong - .thatItBreaksTheTestCondition()) - ? "four" - : x == 6 - ? "six" - : "idk"; + string storage mostlyShort = + x == 1 + ? "one" + : x == 2 + ? "two" + : x == 3 + ? "three" + : (x == 5 && + y == 7 && + someOtherThing + .thatIsSoLong + .thatItBreaksTheTestCondition()) + ? "four" + : x == 6 + ? "six" + : "idk"; // long conditional, short consequent/alternate, not chained - do indent after ? - string storage longConditional = (bifornCringerMoshedPerplexSawder == - 2 / askTrovenaBeenaDependsRowans && - glimseGlyphsHazardNoopsTieTie >= - averredBathersBoxroomBuggyNurl() - .anodyneCondosMalateOverateRetinol()) - ? "foo" - : "bar"; + string storage longConditional = + (bifornCringerMoshedPerplexSawder == + 2 / askTrovenaBeenaDependsRowans && + glimseGlyphsHazardNoopsTieTie >= + averredBathersBoxroomBuggyNurl() + .anodyneCondosMalateOverateRetinol()) + ? "foo" + : "bar"; // long conditional, short consequent/alternate, chained // (break on short consequents iff in chained ternary and its conditional broke) - string - storage longConditionalChained = (bifornCringerMoshedPerplexSawder == + string storage longConditionalChained = + (bifornCringerMoshedPerplexSawder == 2 / askTrovenaBeenaDependsRowans && glimseGlyphsHazardNoopsTieTie >= averredBathersBoxroomBuggyNurl() @@ -2000,62 +2014,67 @@ contract Conditional { } function examples2() { - string storage message = i % 3 == 0 && i % 5 == 0 - ? "fizzbuzz" - : i % 3 == 0 - ? "fizz" - : i % 5 == 0 - ? "buzz" - : String(i); - - string storage paymentMessageShort = state == "success" - ? "Payment completed successfully" - : state == "processing" - ? "Payment processing" - : state == "invalid_cvc" - ? "There was an issue with your CVC number" - : state == "invalid_expiry" - ? "Expiry must be sometime in the past." - : "There was an issue with the payment. Please contact support."; - - string storage paymentMessageWithABreak = state == "success" - ? "Payment completed successfully" - : state == "processing" - ? "Payment processing" - : state == "invalid_cvc" - ? "There was an issue with your CVC number, and you need to take a prompt action on it." - : state == "invalid_expiry" - ? "Expiry must be sometime in the past." - : "There was an issue with the payment. Please contact support."; - - string storage typeofExample = definition.encode - ? definition.encode( - row[field] != "undefined" + string storage message = + i % 3 == 0 && i % 5 == 0 + ? "fizzbuzz" + : i % 3 == 0 + ? "fizz" + : i % 5 == 0 + ? "buzz" + : String(i); + + string storage paymentMessageShort = + state == "success" + ? "Payment completed successfully" + : state == "processing" + ? "Payment processing" + : state == "invalid_cvc" + ? "There was an issue with your CVC number" + : state == "invalid_expiry" + ? "Expiry must be sometime in the past." + : "There was an issue with the payment. Please contact support."; + + string storage paymentMessageWithABreak = + state == "success" + ? "Payment completed successfully" + : state == "processing" + ? "Payment processing" + : state == "invalid_cvc" + ? "There was an issue with your CVC number, and you need to take a prompt action on it." + : state == "invalid_expiry" + ? "Expiry must be sometime in the past." + : "There was an issue with the payment. Please contact support."; + + string storage typeofExample = + definition.encode + ? definition.encode( + row[field] != "undefined" + ? row[field] + : definition.defaults != "undefined" + ? definition.defaults + : "null" + ) + : row[field] != "undefined" ? row[field] : definition.defaults != "undefined" ? definition.defaults - : "null" - ) - : row[field] != "undefined" - ? row[field] - : definition.defaults != "undefined" - ? definition.defaults - : "null"; + : "null"; // (the following is semantically equivalent to the above, but written in a more-confusing style – it'd be hard to grok no matter the formatting) - string storage typeofExampleFlipped = definition.encode - ? definition.encode( - row[field] == "undefined" + string storage typeofExampleFlipped = + definition.encode + ? definition.encode( + row[field] == "undefined" + ? definition.defaults == "undefined" + ? "null" + : definition.defaults + : row[field] + ) + : row[field] == "undefined" ? definition.defaults == "undefined" ? "null" : definition.defaults - : row[field] - ) - : row[field] == "undefined" - ? definition.defaults == "undefined" - ? "null" - : definition.defaults - : row[field]; + : row[field]; } } diff --git a/tests/format/StringLiteral/__snapshots__/format.test.js.snap b/tests/format/StringLiteral/__snapshots__/format.test.js.snap index 38758d319..2488218d9 100644 --- a/tests/format/StringLiteral/__snapshots__/format.test.js.snap +++ b/tests/format/StringLiteral/__snapshots__/format.test.js.snap @@ -20,16 +20,15 @@ contract StringLiteral { =====================================output===================================== contract StringLiteral { - bytes32 public constant PERMIT_TYPEHASH = - keccak256( - "Permit(" - "address owner," - "address spender," - "uint256 value," - "uint256 nonce," - "uint256 deadline" - ")" - ); + bytes32 public constant PERMIT_TYPEHASH = keccak256( + "Permit(" + "address owner," + "address spender," + "uint256 value," + "uint256 nonce," + "uint256 deadline" + ")" + ); } ================================================================================ diff --git a/tests/format/strings/__snapshots__/format.test.js.snap b/tests/format/strings/__snapshots__/format.test.js.snap index 2331bc22e..5d368a54f 100644 --- a/tests/format/strings/__snapshots__/format.test.js.snap +++ b/tests/format/strings/__snapshots__/format.test.js.snap @@ -1473,8 +1473,9 @@ library strings { slice memory self, slice memory needle ) internal pure returns (uint cnt) { - uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + - needle._len; + uint ptr = + findPtr(self._len, self._ptr, needle._len, needle._ptr) + + needle._len; while (ptr <= self._ptr + self._len) { cnt++; ptr =