Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions src/clean.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
// Prettier offers a clean way to define ignored properties.
const ignoredProperties = new Set([
'loc',
'range',
'comments',
// this function is defined at constructor time so it won't pass AST
// comparisons.
'isEmpty'
]);
const ignoredProperties = new Set(['loc', 'range', 'comments']);
// eslint-disable-next-line @typescript-eslint/no-empty-function
function clean(/* ast, newObj, parent */): void {}
clean.ignoredProperties = ignoredProperties;
Expand Down
10 changes: 6 additions & 4 deletions src/slang-nodes/AssignmentExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ export class AssignmentExpression extends SlangNode {
}

print(path: AstPath<AssignmentExpression>, print: PrintFunction): Doc {
const rightOperandVariant = this.rightOperand.variant;
const rightOperand = path.call(print, 'rightOperand');
return [
path.call(print, 'leftOperand'),
` ${this.operator}`,
this.rightOperand.variant.kind !== TerminalKind.Identifier &&
isBinaryOperation(this.rightOperand.variant)
? group(indent([line, path.call(print, 'rightOperand')]))
: [' ', path.call(print, 'rightOperand')]
rightOperandVariant.kind !== TerminalKind.Identifier &&
isBinaryOperation(rightOperandVariant)
? group(indent([line, rightOperand]))
: [' ', rightOperand]
];
}
}
24 changes: 13 additions & 11 deletions src/slang-nodes/ConditionalExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,20 @@ import type { PrintFunction } from '../types.d.ts';

const { group, hardline, ifBreak, indent, line, softline } = doc.builders;

function fillTab({ useTabs, tabWidth }: ParserOptions<AstNode>): Doc {
if (useTabs) return '\t';
// For the odd case of `tabWidth` of 1 or 0 we initiate `fillTab` as a single
// space.
return tabWidth > 2 ? ' '.repeat(tabWidth - 1) : ' ';
}

function experimentalTernaries(
node: ConditionalExpression,
path: AstPath<ConditionalExpression>,
print: PrintFunction,
options: ParserOptions<AstNode>
{ useTabs, tabWidth }: ParserOptions<AstNode>
): Doc {
const grandparent = path.grandparent as StrictAstNode;
const isNested = grandparent.kind === NonterminalKind.ConditionalExpression;
const isNestedAsTrueExpression =
isNested && grandparent.trueExpression.variant === node;
const falseExpressionVariantKind = node.falseExpression.variant.kind;
const falseExpressionInSameLine =
node.falseExpression.variant.kind === NonterminalKind.TupleExpression ||
node.falseExpression.variant.kind === NonterminalKind.ConditionalExpression;
falseExpressionVariantKind === NonterminalKind.TupleExpression ||
falseExpressionVariantKind === NonterminalKind.ConditionalExpression;

// If the `condition` breaks into multiple lines, we add parentheses,
// unless it already is a `TupleExpression`.
Expand All @@ -56,14 +50,22 @@ function experimentalTernaries(
{ id: groupId }
);

// For the odd case of `tabWidth` of 1 or 0 we initiate `fillTab` as a single
// space.
const fillTab = useTabs
? '\t'
: tabWidth > 2
? ' '.repeat(tabWidth - 1)
: ' ';

const falseExpression = path.call(print, 'falseExpression');
const falseExpressionDoc = [
isNested ? hardline : line,
':',
falseExpressionInSameLine
? [' ', falseExpression]
: ifBreak(
[fillTab(options), indent(falseExpression)],
[fillTab, indent(falseExpression)],
[' ', falseExpression],
// We only add `fillTab` if we are sure the trueExpression is
// indented.
Expand Down
10 changes: 4 additions & 6 deletions src/slang-nodes/ContractSpecifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,16 @@ export class ContractSpecifiers extends SlangNode {
}

print(path: AstPath<ContractSpecifiers>, print: PrintFunction): Doc {
if (this.items.length === 0) return '';

const [specifier1, specifier2] = path.map(print, 'items');

if (typeof specifier1 === 'undefined') return '';

if (typeof specifier2 === 'undefined') return [' ', specifier1];

const groupId = Symbol('Slang.ContractSpecifiers.inheritance');
return printSeparatedList(
[group(specifier1, { id: groupId }), specifier2],
{
firstSeparator: line,
separator: ifBreak('', softline, { groupId })
}
{ firstSeparator: line, separator: ifBreak('', softline, { groupId }) }
);
}
}
7 changes: 4 additions & 3 deletions src/slang-nodes/DoWhileStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { AstPath, Doc, ParserOptions } from 'prettier';
import type { AstNode } from './types.d.ts';
import type { PrintFunction } from '../types.d.ts';

const { group, indent, line } = doc.builders;
const { line } = doc.builders;

export class DoWhileStatement extends SlangNode {
readonly kind = NonterminalKind.DoWhileStatement;
Expand All @@ -29,11 +29,12 @@ export class DoWhileStatement extends SlangNode {
}

print(path: AstPath<DoWhileStatement>, print: PrintFunction): Doc {
const body = path.call(print, 'body');
return [
'do',
this.body.variant.kind === NonterminalKind.Block
? [' ', path.call(print, 'body'), ' ']
: group([indent([line, path.call(print, 'body')]), line]),
? [' ', body, ' ']
: printSeparatedItem(body, { firstSeparator: line }),
'while (',
printSeparatedItem(path.call(print, 'condition')),
');'
Expand Down
5 changes: 3 additions & 2 deletions src/slang-nodes/ElseBranch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ export class ElseBranch extends SlangNode {
}

print(path: AstPath<ElseBranch>, print: PrintFunction): Doc {
const body = path.call(print, 'body');
return [
'else',
isIfStatementOrBlock(this.body.variant)
? [' ', path.call(print, 'body')]
: group(indent([line, path.call(print, 'body')]))
? [' ', body]
: group(indent([line, body]))
];
}
}
5 changes: 3 additions & 2 deletions src/slang-nodes/ForStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export class ForStatement extends SlangNode {
const initialization = path.call(print, 'initialization');
const condition = path.call(print, 'condition');
const iterator = path.call(print, 'iterator');
const body = path.call(print, 'body');

return [
'for (',
Expand All @@ -61,8 +62,8 @@ export class ForStatement extends SlangNode {
}),
')',
this.body.variant.kind === NonterminalKind.Block
? [' ', path.call(print, 'body')]
: group(indent([line, path.call(print, 'body')]))
? [' ', body]
: group(indent([line, body]))
];
}
}
8 changes: 4 additions & 4 deletions src/slang-nodes/FunctionCallExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,21 @@ export class FunctionCallExpression extends SlangNode {
}

print(path: AstPath<FunctionCallExpression>, print: PrintFunction): Doc {
const operandDoc = path.call(print, 'operand');
const operand = path.call(print, 'operand');
const argumentsDoc = path.call(print, 'arguments');

// If we are at the end of a MemberAccessChain we should indent the
// arguments accordingly.
if (isLabel(operandDoc) && operandDoc.label === 'MemberAccessChain') {
if (isLabel(operand) && operand.label === 'MemberAccessChain') {
const groupId = Symbol('Slang.FunctionCallExpression.operand');
// We wrap the expression in a label in case there is an IndexAccess or
// a FunctionCall following this IndexAccess.
return label('MemberAccessChain', [
group(operandDoc.contents, { id: groupId }),
group(operand.contents, { id: groupId }),
indentIfBreak(argumentsDoc, { groupId })
]);
}

return [operandDoc, argumentsDoc].flat();
return [operand, argumentsDoc].flat();
}
}
5 changes: 3 additions & 2 deletions src/slang-nodes/IfStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ export class IfStatement extends SlangNode {

print(path: AstPath<IfStatement>, print: PrintFunction): Doc {
const { kind: bodyKind, comments: bodyComments } = this.body.variant;
const body = path.call(print, 'body');
return [
'if (',
printSeparatedItem(path.call(print, 'condition')),
')',
bodyKind === NonterminalKind.Block
? [' ', path.call(print, 'body')]
: group(indent([line, path.call(print, 'body')]), {
? [' ', body]
: group(indent([line, body]), {
shouldBreak: bodyKind === NonterminalKind.IfStatement // `if` within `if`
}),
this.elseBranch
Expand Down
8 changes: 4 additions & 4 deletions src/slang-nodes/IndexAccessExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class IndexAccessExpression extends SlangNode {
}

print(path: AstPath<IndexAccessExpression>, print: PrintFunction): Doc {
const operandDoc = path.call(print, 'operand');
const operand = path.call(print, 'operand');
const indexDoc = [
'[',
printSeparatedItem([path.call(print, 'start'), path.call(print, 'end')]),
Expand All @@ -46,16 +46,16 @@ export class IndexAccessExpression extends SlangNode {

// If we are at the end of a MemberAccessChain we should indent the
// arguments accordingly.
if (isLabel(operandDoc) && operandDoc.label === 'MemberAccessChain') {
if (isLabel(operand) && operand.label === 'MemberAccessChain') {
const groupId = Symbol('Slang.IndexAccessExpression.operand');
// We wrap the expression in a label in case there is an IndexAccess or
// a FunctionCall following this IndexAccess.
return label('MemberAccessChain', [
group(operandDoc.contents, { id: groupId }),
group(operand.contents, { id: groupId }),
indentIfBreak(indexDoc, { groupId })
]);
}

return [operandDoc, indexDoc].flat();
return [operand, indexDoc].flat();
}
}
7 changes: 1 addition & 6 deletions src/slang-nodes/MemberAccessExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,8 @@ export class MemberAccessExpression extends SlangNode {
}

print(path: AstPath<MemberAccessExpression>, print: PrintFunction): Doc {
let operandDoc = path.call(print, 'operand');
if (Array.isArray(operandDoc)) {
operandDoc = operandDoc.flat();
}

const document = [
operandDoc,
path.call(print, 'operand'),
label('separator', [softline, '.']),
path.call(print, 'member')
].flat();
Expand Down
3 changes: 2 additions & 1 deletion src/slang-nodes/ModifierDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ export class ModifierDefinition extends SlangNode {
this.updateMetadata(this.parameters, this.attributes, this.body);

if (!this.parameters) {
const attributesLoc = this.attributes.loc;
const parametersOffset =
this.attributes.loc.start - this.attributes.loc.leadingOffset;
attributesLoc.start - attributesLoc.leadingOffset;
const parametersLoc = {
start: parametersOffset,
end: parametersOffset,
Expand Down
7 changes: 4 additions & 3 deletions src/slang-nodes/ModifierInvocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ export class ModifierInvocation extends SlangNode {
}

cleanModifierInvocationArguments(): void {
const argumentsVariant = this.arguments?.variant;
if (
this.arguments &&
this.arguments.variant.kind ===
argumentsVariant &&
argumentsVariant.kind ===
NonterminalKind.PositionalArgumentsDeclaration &&
this.arguments.variant.isEmpty()
argumentsVariant.isEmpty
) {
delete this.arguments;
}
Expand Down
4 changes: 1 addition & 3 deletions src/slang-nodes/PositionalArgumentsDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ export class PositionalArgumentsDeclaration extends SlangNode {

// We need to check the comments at this point because they will be removed
// from this node into the root node.
const empty =
this.isEmpty =
this.arguments.items.length === 0 && // no arguments
!this.comments.some((comment) => isBlockComment(comment)); // no block comments

this.isEmpty = (): boolean => empty;
}

print(
Expand Down
13 changes: 7 additions & 6 deletions src/slang-nodes/ReturnStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ function printExpression(
print: PrintFunction,
options: ParserOptions<AstNode>
): Doc {
const expressionVariant = node.expression?.variant;
if (expressionVariant) {
return expressionVariant.kind === NonterminalKind.TupleExpression ||
const expressionVariantKind = node.expression?.variant.kind;
const expression = path.call(print, 'expression');
if (expressionVariantKind) {
return expressionVariantKind === NonterminalKind.TupleExpression ||
(options.experimentalTernaries &&
expressionVariant.kind === NonterminalKind.ConditionalExpression)
? [' ', path.call(print, 'expression')]
: group(indent([line, path.call(print, 'expression')]));
expressionVariantKind === NonterminalKind.ConditionalExpression)
? [' ', expression]
: group(indent([line, expression]));
}
return '';
}
Expand Down
5 changes: 3 additions & 2 deletions src/slang-nodes/StateVariableDefinitionValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ export class StateVariableDefinitionValue extends SlangNode {
path: AstPath<StateVariableDefinitionValue>,
print: PrintFunction
): Doc {
const value = path.call(print, 'value');
return this.value.variant.kind === NonterminalKind.ArrayExpression
? [' = ', path.call(print, 'value')]
: group([' =', indent([line, path.call(print, 'value')])]);
? [' = ', value]
: group([' =', indent([line, value])]);
}
}
5 changes: 3 additions & 2 deletions src/slang-nodes/TupleValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ export class TupleValues extends SlangNode {

print(path: AstPath<TupleValues>, print: PrintFunction): Doc {
const singleExpressionVariant = this.getSingleExpression()?.variant;
const items = path.map(print, 'items');
return singleExpressionVariant &&
singleExpressionVariant.kind !== TerminalKind.Identifier &&
isBinaryOperation(singleExpressionVariant)
? path.map(print, 'items')
: printSeparatedList(path.map(print, 'items'));
? items
: printSeparatedList(items);
}
}
5 changes: 3 additions & 2 deletions src/slang-nodes/WhileStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ export class WhileStatement extends SlangNode {
}

print(path: AstPath<WhileStatement>, print: PrintFunction): Doc {
const body = path.call(print, 'body');
return [
'while (',
printSeparatedItem(path.call(print, 'condition')),
')',
this.body.variant.kind === NonterminalKind.Block
? [' ', path.call(print, 'body')]
: group(indent([line, path.call(print, 'body')]))
? [' ', body]
: group(indent([line, body]))
];
}
}
17 changes: 9 additions & 8 deletions src/slang-printers/create-binary-operation-printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,28 @@ import type { PrintFunction } from '../types.d.ts';
const { group, line } = doc.builders;

function rightOperandPrint(
node: BinaryOperation,
{ operator, leftOperand }: BinaryOperation,
path: AstPath<BinaryOperation>,
print: PrintFunction,
options: ParserOptions<AstNode>
): Doc {
const rightOperand =
const rightOperand = path.call(print, 'rightOperand');
const rightOperandDoc =
options.experimentalOperatorPosition === 'end'
? [` ${node.operator}`, line, path.call(print, 'rightOperand')]
: [line, `${node.operator} `, path.call(print, 'rightOperand')];
? [` ${operator}`, line, rightOperand]
: [line, `${operator} `, rightOperand];

// 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 leftOperandVariant = leftOperand.variant;
const grandparentNode = path.grandparent as StrictAstNode;
const shouldGroup =
(leftOperand.kind === TerminalKind.Identifier ||
!isBinaryOperation(leftOperand)) &&
(leftOperandVariant.kind === TerminalKind.Identifier ||
!isBinaryOperation(leftOperandVariant)) &&
(!isBinaryOperation(grandparentNode) ||
grandparentNode.kind === NonterminalKind.AssignmentExpression);

return shouldGroup ? group(rightOperand) : rightOperand;
return shouldGroup ? group(rightOperandDoc) : rightOperandDoc;
}

export const createBinaryOperationPrinter =
Expand Down
Loading