✨ Added rust prettier plugin
This commit is contained in:
70
frontend/package-lock.json
generated
70
frontend/package-lock.json
generated
@@ -39,6 +39,7 @@
|
|||||||
"@codemirror/view": "^6.38.2",
|
"@codemirror/view": "^6.38.2",
|
||||||
"@lezer/highlight": "^1.2.1",
|
"@lezer/highlight": "^1.2.1",
|
||||||
"@lezer/lr": "^1.4.2",
|
"@lezer/lr": "^1.4.2",
|
||||||
|
"@prettier/plugin-xml": "^3.4.2",
|
||||||
"codemirror": "^6.0.2",
|
"codemirror": "^6.0.2",
|
||||||
"codemirror-lang-elixir": "^4.0.0",
|
"codemirror-lang-elixir": "^4.0.0",
|
||||||
"colors-named": "^1.0.2",
|
"colors-named": "^1.0.2",
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
"franc-min": "^6.2.0",
|
"franc-min": "^6.2.0",
|
||||||
"hsl-matcher": "^1.2.4",
|
"hsl-matcher": "^1.2.4",
|
||||||
"java-parser": "^3.0.1",
|
"java-parser": "^3.0.1",
|
||||||
|
"jinx-rust": "^0.1.6",
|
||||||
"jsox": "^1.2.123",
|
"jsox": "^1.2.123",
|
||||||
"lezer": "^0.13.5",
|
"lezer": "^0.13.5",
|
||||||
"linguist-languages": "^9.0.0",
|
"linguist-languages": "^9.0.0",
|
||||||
@@ -54,6 +56,7 @@
|
|||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"pinia-plugin-persistedstate": "^4.5.0",
|
"pinia-plugin-persistedstate": "^4.5.0",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
|
"prettier-plugin-rust": "^0.1.9",
|
||||||
"remarkable": "^2.0.1",
|
"remarkable": "^2.0.1",
|
||||||
"sass": "^1.92.1",
|
"sass": "^1.92.1",
|
||||||
"sql-formatter": "^15.6.9",
|
"sql-formatter": "^15.6.9",
|
||||||
@@ -1854,6 +1857,18 @@
|
|||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@prettier/plugin-xml": {
|
||||||
|
"version": "3.4.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@prettier/plugin-xml/-/plugin-xml-3.4.2.tgz",
|
||||||
|
"integrity": "sha512-/UyNlHfkuLXG6Ed85KB0WBF283xn2yavR+UtRibBRUcvEJId2DSLdGXwJ/cDa1X++SWDPzq3+GSFniHjkNy7yg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@xml-tools/parser": "^1.0.11"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prettier": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rolldown/pluginutils": {
|
"node_modules/@rolldown/pluginutils": {
|
||||||
"version": "1.0.0-beta.29",
|
"version": "1.0.0-beta.29",
|
||||||
"resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz",
|
"resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz",
|
||||||
@@ -2730,6 +2745,24 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@xml-tools/parser": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@xml-tools/parser/-/parser-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"chevrotain": "7.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@xml-tools/parser/node_modules/chevrotain": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/chevrotain/-/chevrotain-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"regexp-to-ast": "0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.15.0",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
||||||
@@ -4821,6 +4854,12 @@
|
|||||||
"lodash": "4.17.21"
|
"lodash": "4.17.21"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jinx-rust": {
|
||||||
|
"version": "0.1.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/jinx-rust/-/jinx-rust-0.1.6.tgz",
|
||||||
|
"integrity": "sha512-qP+wtQL1PrDDFwtPKhNGtjWOmijCrKdfUHWTV2G/ikxfjrh+cjdvkQTmny9RAsVF0jiui9m+F0INWu4cuRcZeQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.4.2.tgz",
|
"resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.4.2.tgz",
|
||||||
@@ -5785,6 +5824,31 @@
|
|||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier-plugin-rust": {
|
||||||
|
"version": "0.1.9",
|
||||||
|
"resolved": "https://registry.npmmirror.com/prettier-plugin-rust/-/prettier-plugin-rust-0.1.9.tgz",
|
||||||
|
"integrity": "sha512-n1DTTJQaHMdnoG/+nKUvBm3EKsMVWsYES2UPCiOPiZdBrmuAO/pX++m7L3+Hz3uuhtddpH0HRKHB2F3jbtJBOQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jinx-rust": "0.1.6",
|
||||||
|
"prettier": "^2.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-plugin-rust/node_modules/prettier": {
|
||||||
|
"version": "2.8.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz",
|
||||||
|
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin-prettier.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/process": {
|
"node_modules/process": {
|
||||||
"version": "0.11.10",
|
"version": "0.11.10",
|
||||||
"resolved": "https://registry.npmmirror.com/process/-/process-0.11.10.tgz",
|
"resolved": "https://registry.npmmirror.com/process/-/process-0.11.10.tgz",
|
||||||
@@ -5977,6 +6041,12 @@
|
|||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/regexp-to-ast": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/remarkable": {
|
"node_modules/remarkable": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/remarkable/-/remarkable-2.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/remarkable/-/remarkable-2.0.1.tgz",
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
"@codemirror/view": "^6.38.2",
|
"@codemirror/view": "^6.38.2",
|
||||||
"@lezer/highlight": "^1.2.1",
|
"@lezer/highlight": "^1.2.1",
|
||||||
"@lezer/lr": "^1.4.2",
|
"@lezer/lr": "^1.4.2",
|
||||||
|
"@prettier/plugin-xml": "^3.4.2",
|
||||||
"codemirror": "^6.0.2",
|
"codemirror": "^6.0.2",
|
||||||
"codemirror-lang-elixir": "^4.0.0",
|
"codemirror-lang-elixir": "^4.0.0",
|
||||||
"colors-named": "^1.0.2",
|
"colors-named": "^1.0.2",
|
||||||
@@ -50,6 +51,7 @@
|
|||||||
"franc-min": "^6.2.0",
|
"franc-min": "^6.2.0",
|
||||||
"hsl-matcher": "^1.2.4",
|
"hsl-matcher": "^1.2.4",
|
||||||
"java-parser": "^3.0.1",
|
"java-parser": "^3.0.1",
|
||||||
|
"jinx-rust": "^0.1.6",
|
||||||
"jsox": "^1.2.123",
|
"jsox": "^1.2.123",
|
||||||
"lezer": "^0.13.5",
|
"lezer": "^0.13.5",
|
||||||
"linguist-languages": "^9.0.0",
|
"linguist-languages": "^9.0.0",
|
||||||
@@ -58,6 +60,7 @@
|
|||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"pinia-plugin-persistedstate": "^4.5.0",
|
"pinia-plugin-persistedstate": "^4.5.0",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
|
"prettier-plugin-rust": "^0.1.9",
|
||||||
"remarkable": "^2.0.1",
|
"remarkable": "^2.0.1",
|
||||||
"sass": "^1.92.1",
|
"sass": "^1.92.1",
|
||||||
"sql-formatter": "^15.6.9",
|
"sql-formatter": "^15.6.9",
|
||||||
|
|||||||
824
frontend/src/utils/prettier/plugins/rust/format/comments.ts
Normal file
824
frontend/src/utils/prettier/plugins/rust/format/comments.ts
Normal file
@@ -0,0 +1,824 @@
|
|||||||
|
import { CommentOrDocComment, LocArray, Node, NodeType, NodeWithBodyOrCases } from "jinx-rust";
|
||||||
|
import {
|
||||||
|
end,
|
||||||
|
getBodyOrCases,
|
||||||
|
getLastParameter,
|
||||||
|
hasOuterAttributes,
|
||||||
|
isInner,
|
||||||
|
is_Attribute,
|
||||||
|
is_AttributeOrDocComment,
|
||||||
|
is_BlockCommentKind,
|
||||||
|
is_BlockCommentNode,
|
||||||
|
is_Comment,
|
||||||
|
is_CommentOrDocComment,
|
||||||
|
is_ExpressionWithBodyOrCases,
|
||||||
|
is_ExternSpecifier,
|
||||||
|
is_FlowControlExpression,
|
||||||
|
is_FunctionDeclaration,
|
||||||
|
is_FunctionNode,
|
||||||
|
is_IfBlockExpression,
|
||||||
|
is_LineCommentKind,
|
||||||
|
is_LineCommentNode,
|
||||||
|
is_LocArray,
|
||||||
|
is_MacroRule,
|
||||||
|
is_NodeWithBodyOrCases,
|
||||||
|
is_ReassignmentNode,
|
||||||
|
is_StatementNode,
|
||||||
|
is_StructLiteralProperty,
|
||||||
|
is_StructLiteralPropertySpread,
|
||||||
|
nisAnyOf,
|
||||||
|
ownStart,
|
||||||
|
start,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import { is_CallExpression_or_CallLikeMacroInvocation } from "../transform";
|
||||||
|
import { Narrow, assert, exit, iLast, last_of, maybe_last_of } from "../utils/common";
|
||||||
|
import { is_MemberAccessLike, is_xVariableEqualishLike } from "./core";
|
||||||
|
import {
|
||||||
|
AnyComment,
|
||||||
|
CustomOptions,
|
||||||
|
DCM,
|
||||||
|
Doc,
|
||||||
|
MutatedAttribute,
|
||||||
|
NodeWithComments,
|
||||||
|
PrettierCommentInfo,
|
||||||
|
breakParent,
|
||||||
|
cursor,
|
||||||
|
hardline,
|
||||||
|
indent,
|
||||||
|
join,
|
||||||
|
line,
|
||||||
|
lineSuffix,
|
||||||
|
literalline,
|
||||||
|
} from "./external";
|
||||||
|
import { assertPathAtNode, canAttachComment, getAllComments, getContext, getNode, getOptions, pathCallEach } from "./plugin";
|
||||||
|
import { shouldPrintOuterAttributesAbove } from "./styling";
|
||||||
|
|
||||||
|
function addCommentHelper(node: Node, comment: AnyComment, leading = false, trailing = false) {
|
||||||
|
__DEV__: assert(!handled(comment));
|
||||||
|
((node as NodeWithComments<Node>).comments ??= []).push(comment);
|
||||||
|
(comment.leading = leading), (comment.trailing = trailing), (comment.printed = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addLeadingComment(node: Node, comment: AnyComment) {
|
||||||
|
addCommentHelper(node, comment, true);
|
||||||
|
}
|
||||||
|
function addDanglingComment(node: Node, comment: AnyComment, marker: DCM) {
|
||||||
|
addCommentHelper(node, comment);
|
||||||
|
comment.marker = marker;
|
||||||
|
}
|
||||||
|
function addTrailingComment(node: Node, comment: AnyComment) {
|
||||||
|
addCommentHelper(node, comment, false, true);
|
||||||
|
}
|
||||||
|
export function setPrettierIgnoreTarget(node: Node, comment: AnyComment) {
|
||||||
|
__DEV__: Narrow<Node & { prettierIgnore?: true }>(node), assert(isPrettierIgnoreComment(comment) || isPrettierIgnoreAttribute(comment));
|
||||||
|
comment.unignore = true;
|
||||||
|
node.prettierIgnore = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasComments<T extends Node>(node: T): node is NodeWithComments<T> {
|
||||||
|
return "comments" in node && node.comments.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function printDanglingComments(enclosingNode: Node, sameIndent: boolean, marker?: DCM) {
|
||||||
|
if (hasComments(enclosingNode)) {
|
||||||
|
const printed: Doc[] = [];
|
||||||
|
pathCallEach(enclosingNode, "comments", (comment) => {
|
||||||
|
if (isDangling(comment) && (!marker || comment.marker === marker)) {
|
||||||
|
printed.push(printComment(comment));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (printed.length > 0) {
|
||||||
|
return sameIndent //
|
||||||
|
? join(hardline, printed)
|
||||||
|
: indent([hardline, join(hardline, printed)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function needsHardlineAfterDanglingComment(node: Node) {
|
||||||
|
if (!hasComment(node)) return false;
|
||||||
|
const lastDanglingComment = maybe_last_of(getComments(node, CF.Dangling));
|
||||||
|
return lastDanglingComment && is_LineCommentNode(lastDanglingComment);
|
||||||
|
}
|
||||||
|
export function setDidPrintComment(comment: AnyComment) {
|
||||||
|
comment.printed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printComment(comment: AnyComment) {
|
||||||
|
__DEV__: assertPathAtNode("printComment", comment);
|
||||||
|
__DEV__: assert(handled(comment), `Assertion failed: Comment was not printed at ${comment.loc.url()}`, comment);
|
||||||
|
setDidPrintComment(comment);
|
||||||
|
return getContext().options.printer.printComment!(getContext().path as any, getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPreviousLineEmpty(node: Node) {
|
||||||
|
let index = start(node) - 1;
|
||||||
|
index = skipSpaces(index, true) as number;
|
||||||
|
index = skipNewline(index, true) as number;
|
||||||
|
index = skipSpaces(index, true) as number;
|
||||||
|
return index !== skipNewline(index, true);
|
||||||
|
}
|
||||||
|
export function hasBreaklineBefore(node: Node) {
|
||||||
|
return hasNewline(start(node) - 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasBreaklineAfter(node: Node) {
|
||||||
|
return hasNewline(end(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function printCommentsSeparately(ignored?: Set<AnyComment>) {
|
||||||
|
const node = getNode();
|
||||||
|
__DEV__: Narrow<Node & { comments?: AnyComment[] }>(node);
|
||||||
|
|
||||||
|
const leading: Doc[] = [];
|
||||||
|
const trailing: Doc[] = [];
|
||||||
|
let hasTrailingLineComment = false;
|
||||||
|
let hadLeadingBlockComment = false;
|
||||||
|
|
||||||
|
if ("comments" in node) {
|
||||||
|
pathCallEach(node, "comments", (comment) => {
|
||||||
|
if (ignored?.has(comment)) {
|
||||||
|
return;
|
||||||
|
} else if (isLeading(comment)) {
|
||||||
|
leading.push(printLeadingComment(comment));
|
||||||
|
} else if (isTrailing(comment)) {
|
||||||
|
trailing.push(printTrailingComment(comment));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node === getOptions().cursorNode) {
|
||||||
|
leading.unshift(cursor);
|
||||||
|
trailing.push(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (leading.length | trailing.length) > 0 ? { leading, trailing } : ({ leading: "", trailing: "" } as const);
|
||||||
|
|
||||||
|
function printLeadingComment(comment: AnyComment) {
|
||||||
|
if (is_Attribute(comment) && !comment.inner) {
|
||||||
|
const printed = printComment(comment);
|
||||||
|
return [printed, " "];
|
||||||
|
}
|
||||||
|
hadLeadingBlockComment ||= is_BlockCommentKind(comment) && hasBreaklineBefore(comment);
|
||||||
|
return [
|
||||||
|
printComment(comment),
|
||||||
|
is_BlockCommentKind(comment)
|
||||||
|
? hasBreaklineAfter(comment) //
|
||||||
|
? hadLeadingBlockComment
|
||||||
|
? hardline
|
||||||
|
: line
|
||||||
|
: " "
|
||||||
|
: hardline,
|
||||||
|
hasNewline(skipNewline(skipSpaces(end(comment)))) ? hardline : "",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function printTrailingComment(comment: AnyComment) {
|
||||||
|
const printed = printComment(comment);
|
||||||
|
return hasBreaklineBefore(comment)
|
||||||
|
? lineSuffix([hardline, isPreviousLineEmpty(comment) ? hardline : "", printed])
|
||||||
|
: is_BlockCommentNode(comment)
|
||||||
|
? [" ", printed]
|
||||||
|
: lineSuffix([" ", printed, hasTrailingLineComment === (hasTrailingLineComment = true) ? hardline : breakParent]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPostLeadingComment(comment: AnyComment) {
|
||||||
|
// console.log(comment.loc.url());
|
||||||
|
// is_BlockCommentKind(comment)
|
||||||
|
// ? hasBreaklineAfter(comment) //
|
||||||
|
// ? hasBreaklineBefore(comment)
|
||||||
|
// ? hardline
|
||||||
|
// : line
|
||||||
|
// : " "
|
||||||
|
// : hardline,
|
||||||
|
return hasNewline(skipNewline(skipSpaces(end(comment)))) ? hardline : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withComments<D extends Doc>(node: Node, printed: D, ignored?: Set<AnyComment>): D | Doc[] {
|
||||||
|
__DEV__: assertPathAtNode("withComments", node);
|
||||||
|
const { leading, trailing } = printCommentsSeparately(ignored);
|
||||||
|
return leading || trailing ? [...leading!, printed, ...trailing!] : printed;
|
||||||
|
// return needsOuterParens(node) ? group(["(", indent([softline, parts]), softline, ")"]) : parts;
|
||||||
|
// return parts;
|
||||||
|
}
|
||||||
|
export function getComments(node: Node, ...args: Parameters<typeof getCommentTestFunction>): AnyComment[] {
|
||||||
|
__DEV__: Narrow<Node & { comments?: AnyComment[] }>(node);
|
||||||
|
// if (!node || !node.comments) return [];
|
||||||
|
// if (args.length === 0) return node.comments;
|
||||||
|
// return args.length > 0 ? node.comments.filter(getCommentTestFunction(...args)) : node.comments;
|
||||||
|
return node && node.comments //
|
||||||
|
? args.length > 0
|
||||||
|
? node.comments.filter(getCommentTestFunction(...args))
|
||||||
|
: node.comments
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFirstComment(node: Node, flags: CF, fn?: (comment: AnyComment) => boolean): AnyComment | undefined {
|
||||||
|
const r = getComments(node, flags | CF.First, fn);
|
||||||
|
return r.length === 0 ? undefined : r[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function escapeComments(flags: number, fn?: (comment: AnyComment) => boolean) {
|
||||||
|
const comments = getAllComments().filter(getCommentTestFunction(flags, fn)) as AnyComment[];
|
||||||
|
comments.forEach(setDidPrintComment);
|
||||||
|
return new Set(comments);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum CF {
|
||||||
|
Leading = 1 << 1,
|
||||||
|
Trailing = 1 << 2,
|
||||||
|
Dangling = 1 << 3,
|
||||||
|
Block = 1 << 4,
|
||||||
|
Line = 1 << 5,
|
||||||
|
PrettierIgnore = 1 << 6,
|
||||||
|
First = 1 << 7,
|
||||||
|
Last = 1 << 8,
|
||||||
|
}
|
||||||
|
export function isPrettierIgnoreComment(comment: AnyComment) {
|
||||||
|
return is_Comment(comment) && /^\s*prettier-ignore\s*/.test(comment.value) && !comment.unignore;
|
||||||
|
}
|
||||||
|
export function isPrettierIgnoreAttribute(node: Node): node is MutatedAttribute {
|
||||||
|
return is_Attribute(node) && /^\s*rustfmt::skip\s*$/.test(node.value);
|
||||||
|
}
|
||||||
|
function getCommentTestFunction(flags: CF, fn?: (comment: AnyComment) => boolean) {
|
||||||
|
return function (comment: AnyComment, index: number, comments: AnyComment[]) {
|
||||||
|
__DEV__: Narrow<number>(flags), assert(handled(comment));
|
||||||
|
return !(
|
||||||
|
(flags & CF.Leading && !isLeading(comment)) ||
|
||||||
|
(flags & CF.Trailing && !isTrailing(comment)) ||
|
||||||
|
(flags & CF.Dangling && !isDangling(comment)) ||
|
||||||
|
(flags & CF.Block && !is_BlockCommentKind(comment)) ||
|
||||||
|
(flags & CF.Line && !is_LineCommentKind(comment)) ||
|
||||||
|
(flags & CF.First && index !== 0) ||
|
||||||
|
(flags & CF.Last && !iLast(index, comments)) ||
|
||||||
|
(flags & CF.PrettierIgnore && !(isPrettierIgnoreComment(comment) || isPrettierIgnoreAttribute(comment))) ||
|
||||||
|
(fn && !fn(comment))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasComment(node: Node, flags: number = 0, fn?: (comment: AnyComment) => boolean) {
|
||||||
|
if ("comments" in node && node.comments!.length > 0) {
|
||||||
|
return flags || fn ? (node.comments as AnyComment[]).some(getCommentTestFunction(flags, fn)) : true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
export function hasNewlineInRange(leftIndex: number, rightIndex: number) {
|
||||||
|
__DEV__: assert(leftIndex <= rightIndex);
|
||||||
|
const text = getContext().options.originalText;
|
||||||
|
for (var i = leftIndex; i < rightIndex; ++i) if (text.charCodeAt(i) === 10) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
export function isNextLineEmpty(node: Node) {
|
||||||
|
return isNextLineEmptyAfterIndex(end(node));
|
||||||
|
}
|
||||||
|
export function isNextLineEmptyAfterIndex(index: number | false) {
|
||||||
|
let oldIdx: number | false = -1;
|
||||||
|
let idx: number | false = index;
|
||||||
|
while (idx !== oldIdx) {
|
||||||
|
oldIdx = idx;
|
||||||
|
idx = skipToLineEnd(idx);
|
||||||
|
idx = skipBlockComment(idx);
|
||||||
|
idx = skipSpaces(idx);
|
||||||
|
idx = skipParens(idx);
|
||||||
|
}
|
||||||
|
idx = skipLineComment(idx);
|
||||||
|
idx = skipParens(idx);
|
||||||
|
idx = skipNewline(idx);
|
||||||
|
idx = skipParens(idx);
|
||||||
|
return idx !== false && hasNewline(idx);
|
||||||
|
}
|
||||||
|
export function hasNewline(index: number | false, backwards = false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const i = skipSpaces(index, backwards);
|
||||||
|
return i !== false && i !== skipNewline(i, backwards);
|
||||||
|
}
|
||||||
|
function skipLineComment(index: number | false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const { commentSpans, originalText } = getContext().options;
|
||||||
|
if (commentSpans.has(index) && originalText.charCodeAt(index + 1) === 47 /** "/" */)
|
||||||
|
return skipEverythingButNewLine(commentSpans.get(index)!);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
function skipBlockComment(index: number | false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const { commentSpans, originalText } = getContext().options;
|
||||||
|
if (commentSpans.has(index) && originalText.charCodeAt(index + 1) === 42 /** "*" */) return commentSpans.get(index)!;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
const [skipSpaces, skipToLineEnd, skipEverythingButNewLine] = [/[ \t]/, /[,; \t]/, /[^\r\n]/].map(function (re) {
|
||||||
|
return function (index: number | false, backwards = false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const { originalText: text } = getContext().options;
|
||||||
|
let cursor = index;
|
||||||
|
while (cursor >= 0 && cursor < text.length) {
|
||||||
|
if (re.test(text.charAt(cursor))) backwards ? cursor-- : cursor++;
|
||||||
|
else return cursor;
|
||||||
|
}
|
||||||
|
return cursor === -1 || cursor === text.length ? cursor : false;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function skipNewline(index: number | false, backwards = false) {
|
||||||
|
if (index === false) return false;
|
||||||
|
const { originalText } = getContext().options;
|
||||||
|
const atIndex = originalText.charCodeAt(index);
|
||||||
|
if (backwards) {
|
||||||
|
if (originalText.charCodeAt(index - 1) === 13 && atIndex === 10) return index - 2;
|
||||||
|
if (atIndex === 10) return index - 1;
|
||||||
|
} else {
|
||||||
|
if (atIndex === 13 && originalText.charCodeAt(index + 1) === 10) return index + 2;
|
||||||
|
if (atIndex === 10) return index + 1;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function skipParens(index: number | false, backwards = false) {
|
||||||
|
return index;
|
||||||
|
// if (index === false) return false;
|
||||||
|
// const { parensPositions } = getContext().options;
|
||||||
|
// while (parensPositions.has(index)) backwards ? index-- : index++;
|
||||||
|
// return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNextNonSpaceNonCommentCharacterIndex(node: Node) {
|
||||||
|
return getNextNonSpaceNonCommentCharacterIndexWithStartIndex(end(node));
|
||||||
|
}
|
||||||
|
function getNextNonSpaceNonCommentCharacterIndexWithStartIndex(i: number) {
|
||||||
|
let oldIdx = -1;
|
||||||
|
let nextIdx = i;
|
||||||
|
while (nextIdx !== oldIdx) {
|
||||||
|
oldIdx = nextIdx;
|
||||||
|
nextIdx = skipSpaces(nextIdx) as number;
|
||||||
|
nextIdx = skipBlockComment(nextIdx) as number;
|
||||||
|
nextIdx = skipLineComment(nextIdx) as number;
|
||||||
|
nextIdx = skipNewline(nextIdx) as number;
|
||||||
|
nextIdx = skipParens(nextIdx) as number;
|
||||||
|
}
|
||||||
|
return nextIdx;
|
||||||
|
}
|
||||||
|
export function getNextNonSpaceNonCommentCharacter(node: Node) {
|
||||||
|
return getContext().options.originalText.charAt(getNextNonSpaceNonCommentCharacterIndex(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CommentContext {
|
||||||
|
comment: AnyComment;
|
||||||
|
precedingNode: Node | undefined;
|
||||||
|
enclosingNode: Node | undefined;
|
||||||
|
followingNode: Node | undefined;
|
||||||
|
text: string;
|
||||||
|
options: CustomOptions;
|
||||||
|
ast: Node;
|
||||||
|
isLastComment: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handled(comment: AnyComment) {
|
||||||
|
return "printed" in comment;
|
||||||
|
}
|
||||||
|
function handleCommon(ctx: CommentContext): boolean {
|
||||||
|
{
|
||||||
|
const { comment, precedingNode, enclosingNode, followingNode } = ctx;
|
||||||
|
if (!enclosingNode) {
|
||||||
|
ctx.enclosingNode = ctx.comment.loc.src.program;
|
||||||
|
} else if (enclosingNode && is_NodeWithBodyOrCases(enclosingNode)) {
|
||||||
|
const body = getBodyOrCases(enclosingNode);
|
||||||
|
if (body) {
|
||||||
|
if (is_ExpressionWithBodyOrCases(enclosingNode) && enclosingNode.label) {
|
||||||
|
if (ctx.precedingNode === enclosingNode.label) {
|
||||||
|
ctx.precedingNode = undefined;
|
||||||
|
}
|
||||||
|
if (followingNode === enclosingNode.label) {
|
||||||
|
ctx.followingNode = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (comment.loc.isBefore(body)) {
|
||||||
|
if (followingNode && body.loc.contains(followingNode)) {
|
||||||
|
ctx.followingNode = undefined;
|
||||||
|
}
|
||||||
|
if (!ctx.precedingNode && !ctx.followingNode) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (comment.loc.isAfter(body)) {
|
||||||
|
if (precedingNode && body.loc.contains(precedingNode)) {
|
||||||
|
ctx.precedingNode = undefined;
|
||||||
|
}
|
||||||
|
if (!ctx.precedingNode && !ctx.followingNode) {
|
||||||
|
addTrailingComment(enclosingNode, comment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (body.loc.contains(comment)) {
|
||||||
|
if (precedingNode && !body.loc.contains(precedingNode)) {
|
||||||
|
ctx.precedingNode = undefined;
|
||||||
|
}
|
||||||
|
if (followingNode && !body.loc.contains(followingNode)) {
|
||||||
|
ctx.followingNode = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const fn of [
|
||||||
|
handleMixedInOuterAttributeComments,
|
||||||
|
handleAttributeComments,
|
||||||
|
handleDanglingComments,
|
||||||
|
handleFunctionComments,
|
||||||
|
handleMacroRuleComments,
|
||||||
|
handleStructLiteralComments,
|
||||||
|
handleVariableDeclaratorComments,
|
||||||
|
handleIfBlockExpressionComments,
|
||||||
|
handleMemberExpressionComments,
|
||||||
|
handleStatementComments,
|
||||||
|
handleFlowControlComments,
|
||||||
|
handleBadComments,
|
||||||
|
]) {
|
||||||
|
fn(ctx);
|
||||||
|
if (handled(ctx.comment)) {
|
||||||
|
// console.log(ctx.comment.loc.url(), fn.name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { precedingNode, followingNode, comment } = ctx;
|
||||||
|
|
||||||
|
if (isStartOfLine(comment)) {
|
||||||
|
if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else {
|
||||||
|
exit.never(ctx);
|
||||||
|
}
|
||||||
|
} else if (isEndOfLine(comment)) {
|
||||||
|
if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else {
|
||||||
|
exit.never(ctx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (precedingNode && followingNode) {
|
||||||
|
return false;
|
||||||
|
} else if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else {
|
||||||
|
exit.never(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handled(ctx.comment);
|
||||||
|
}
|
||||||
|
export function handleOwnLineComment(ctx: CommentContext) {
|
||||||
|
return handleCommon(ctx);
|
||||||
|
}
|
||||||
|
export function handleEndOfLineComment(ctx: CommentContext) {
|
||||||
|
const { precedingNode, enclosingNode, comment } = ctx;
|
||||||
|
if (
|
||||||
|
// handleCallExpressionComments
|
||||||
|
precedingNode &&
|
||||||
|
enclosingNode &&
|
||||||
|
is_CallExpression_or_CallLikeMacroInvocation(enclosingNode) &&
|
||||||
|
enclosingNode.arguments.length > 0 &&
|
||||||
|
precedingNode === (enclosingNode.typeArguments ? last_of(enclosingNode.typeArguments) : enclosingNode.callee)
|
||||||
|
) {
|
||||||
|
addLeadingComment(enclosingNode.arguments[0], comment);
|
||||||
|
return true;
|
||||||
|
} else if (
|
||||||
|
// handlePropertyComments
|
||||||
|
enclosingNode &&
|
||||||
|
is_StructLiteralProperty(enclosingNode)
|
||||||
|
) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return handleCommon(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleRemainingComment(ctx: CommentContext) {
|
||||||
|
return handleCommon(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStructLiteralComments({ enclosingNode, followingNode, comment }: CommentContext) {
|
||||||
|
if (enclosingNode && is_StructLiteralPropertySpread(enclosingNode) && followingNode === enclosingNode.expression) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleVariableDeclaratorComments({ enclosingNode, followingNode, comment }: CommentContext) {
|
||||||
|
if (
|
||||||
|
enclosingNode &&
|
||||||
|
(is_xVariableEqualishLike(enclosingNode) || is_ReassignmentNode(enclosingNode)) &&
|
||||||
|
followingNode &&
|
||||||
|
(is_BlockCommentKind(comment) ||
|
||||||
|
nisAnyOf(followingNode, [
|
||||||
|
NodeType.StructLiteral,
|
||||||
|
NodeType.StructPattern,
|
||||||
|
NodeType.TupleLiteral,
|
||||||
|
NodeType.TypeTuple,
|
||||||
|
NodeType.TuplePattern,
|
||||||
|
NodeType.ArrayLiteral,
|
||||||
|
NodeType.ArrayPattern,
|
||||||
|
NodeType.SizedArrayLiteral,
|
||||||
|
NodeType.TypeSizedArray,
|
||||||
|
]))
|
||||||
|
) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMixedInOuterAttributeComments({ precedingNode, enclosingNode, followingNode, comment }: CommentContext) {
|
||||||
|
if (enclosingNode && hasOuterAttributes(enclosingNode) && end(comment) <= ownStart(enclosingNode)) {
|
||||||
|
if (isPrettierIgnoreComment(comment) || isPrettierIgnoreAttribute(comment)) {
|
||||||
|
setPrettierIgnoreTarget(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
if (isEndOfLine(comment)) {
|
||||||
|
__DEV__: assert(!!precedingNode && is_Attribute(precedingNode), "", precedingNode);
|
||||||
|
if (shouldPrintOuterAttributesAbove(enclosingNode)) {
|
||||||
|
// #[attr] // comment
|
||||||
|
// node
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else {
|
||||||
|
// #[attr] /* comment */ node
|
||||||
|
addLeadingComment(followingNode || enclosingNode, comment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// __DEV__: assert(isStartOfLine(comment));
|
||||||
|
if (followingNode && end(followingNode) <= ownStart(enclosingNode)) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else if (precedingNode && enclosingNode.loc.contains(precedingNode)) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleAttributeComments({ precedingNode, enclosingNode, followingNode, comment, ast }: CommentContext) {
|
||||||
|
if (is_AttributeOrDocComment(comment)) {
|
||||||
|
if (
|
||||||
|
comment.inner &&
|
||||||
|
enclosingNode &&
|
||||||
|
is_FunctionDeclaration(enclosingNode) &&
|
||||||
|
(!followingNode || !is_StatementNode(followingNode)) &&
|
||||||
|
(!precedingNode || !is_StatementNode(precedingNode))
|
||||||
|
) {
|
||||||
|
if (enclosingNode.body) {
|
||||||
|
if (canAttachCommentInLocArray(enclosingNode.body)) {
|
||||||
|
addDanglingComment(enclosingNode, comment, DCM["body"]);
|
||||||
|
} else {
|
||||||
|
addLeadingComment(enclosingNode.body[0], comment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if (comment.loc.url().startsWith("tests/samples/macro/attr.rs") && getContext().options.danglingAttributes.includes(comment)) {
|
||||||
|
// // debugger;
|
||||||
|
// console.log({
|
||||||
|
// comment: comment.loc.url(),
|
||||||
|
// precedingNode: precedingNode?.loc.url(),
|
||||||
|
// enclosingNode: enclosingNode?.loc.url(),
|
||||||
|
// followingNode: followingNode?.loc.url(),
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else if (enclosingNode) {
|
||||||
|
for (var key in DCM)
|
||||||
|
if (key in enclosingNode) {
|
||||||
|
addDanglingComment(enclosingNode, comment, key as DCM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addDanglingComment(ast, comment, DCM["body"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBadComments({ precedingNode, enclosingNode, followingNode, ast, comment }: CommentContext) {
|
||||||
|
if (!enclosingNode) {
|
||||||
|
// console.log(comment.loc.url());
|
||||||
|
if (followingNode) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
} else if (precedingNode) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
} else {
|
||||||
|
addDanglingComment(enclosingNode || ast, comment, DCM["body"]);
|
||||||
|
}
|
||||||
|
} else if (!precedingNode && !followingNode) {
|
||||||
|
if (enclosingNode && enclosingNode !== ast) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
} else {
|
||||||
|
addDanglingComment(ast, comment, DCM["body"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function is_ABI_Comment({ precedingNode, enclosingNode, comment }: CommentContext) {
|
||||||
|
return (
|
||||||
|
is_CommentOrDocComment(comment) &&
|
||||||
|
((precedingNode && is_ExternSpecifier(precedingNode)) || (enclosingNode && is_ExternSpecifier(enclosingNode)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function handleFlowControlComments({ precedingNode, enclosingNode, followingNode, comment }: CommentContext) {
|
||||||
|
if (enclosingNode && is_FlowControlExpression(enclosingNode)) {
|
||||||
|
if (!precedingNode && (isOwnLine(comment) || isEndOfLine(comment)) && !followingNode) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleFunctionComments(ctx: CommentContext) {
|
||||||
|
const { precedingNode, enclosingNode, followingNode, comment } = ctx;
|
||||||
|
if (enclosingNode && is_FunctionNode(enclosingNode)) {
|
||||||
|
if (
|
||||||
|
is_FunctionDeclaration(enclosingNode) &&
|
||||||
|
((!is_ABI_Comment(ctx) && comment.loc.isBefore(enclosingNode.generics || enclosingNode.id)) ||
|
||||||
|
(enclosingNode.generics && comment.loc.isBetween(enclosingNode.generics, enclosingNode.parameters)))
|
||||||
|
) {
|
||||||
|
addLeadingComment(enclosingNode, comment);
|
||||||
|
} else if (
|
||||||
|
!enclosingNode.returnType &&
|
||||||
|
comment.loc.isBetween(
|
||||||
|
enclosingNode.parameters,
|
||||||
|
is_FunctionDeclaration(enclosingNode) ? enclosingNode.body! : enclosingNode.expression
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (is_FunctionDeclaration(enclosingNode)) {
|
||||||
|
addCommentToBlock(enclosingNode, comment);
|
||||||
|
} else {
|
||||||
|
addLeadingComment(enclosingNode.expression, comment);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
precedingNode && //
|
||||||
|
enclosingNode.parameters.loc.contains(comment)
|
||||||
|
) {
|
||||||
|
if (precedingNode === getLastParameter(enclosingNode)) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
followingNode &&
|
||||||
|
isStartOfLine(comment) &&
|
||||||
|
comment.loc.isAfter(enclosingNode.parameters) &&
|
||||||
|
(!is_FunctionDeclaration(enclosingNode) || !enclosingNode.whereBounds || comment.loc.isAfter(enclosingNode.whereBounds!)) &&
|
||||||
|
(!enclosingNode.returnType || comment.loc.isAfter(enclosingNode.returnType)) &&
|
||||||
|
followingNode === (is_FunctionDeclaration(enclosingNode) ? enclosingNode.body?.[0] : enclosingNode.expression)
|
||||||
|
) {
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleMacroRuleComments(ctx: CommentContext) {
|
||||||
|
const { precedingNode, enclosingNode, followingNode, comment } = ctx;
|
||||||
|
if (enclosingNode && is_MacroRule(enclosingNode)) {
|
||||||
|
if (enclosingNode.transform.loc.contains(comment)) {
|
||||||
|
__DEV__: assert(enclosingNode.transform.length > 0);
|
||||||
|
if (!precedingNode || !enclosingNode.transform.loc.contains(precedingNode)) {
|
||||||
|
__DEV__: assert(!!followingNode && enclosingNode.transform.loc.contains(followingNode));
|
||||||
|
addLeadingComment(followingNode, comment);
|
||||||
|
}
|
||||||
|
} else if (enclosingNode.match.loc.contains(comment)) {
|
||||||
|
__DEV__: assert(enclosingNode.match.length > 0);
|
||||||
|
if (!followingNode || !enclosingNode.match.loc.contains(followingNode)) {
|
||||||
|
__DEV__: assert(!!precedingNode && enclosingNode.match.loc.contains(precedingNode));
|
||||||
|
addTrailingComment(precedingNode!, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStatementComments(ctx: CommentContext) {
|
||||||
|
const { precedingNode, comment } = ctx;
|
||||||
|
if (isEndOfLine(comment) && precedingNode && (is_StatementNode(precedingNode) || precedingNode.loc.sliceText().endsWith(";"))) {
|
||||||
|
addTrailingComment(precedingNode, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCommentToBlock(block: NodeWithBodyOrCases, comment: AnyComment) {
|
||||||
|
const body = getBodyOrCases(block);
|
||||||
|
__DEV__: assert(!!body);
|
||||||
|
if (body.length > 0) {
|
||||||
|
addLeadingComment(body![0], comment);
|
||||||
|
} else {
|
||||||
|
addDanglingComment(block, comment, DCM["body"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleIfBlockExpressionComments(ctx: CommentContext) {
|
||||||
|
const { comment, enclosingNode } = ctx;
|
||||||
|
if (enclosingNode && is_IfBlockExpression(enclosingNode)) {
|
||||||
|
const { condition, body, else: else_ } = enclosingNode;
|
||||||
|
if (comment.loc.isBefore(condition)) {
|
||||||
|
addLeadingComment(condition, comment);
|
||||||
|
} else if (comment.loc.isBetween(condition, body)) {
|
||||||
|
addTrailingComment(condition, comment);
|
||||||
|
} else if (else_ && comment.loc.isBetween(body, else_)) {
|
||||||
|
if (is_IfBlockExpression(else_)) {
|
||||||
|
addLeadingComment(else_.condition, comment);
|
||||||
|
} else {
|
||||||
|
addCommentToBlock(else_, comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMemberExpressionComments({ comment, precedingNode, enclosingNode }: CommentContext) {
|
||||||
|
if (enclosingNode && is_MemberAccessLike(enclosingNode)) {
|
||||||
|
if (isStartOfLine(comment) || !precedingNode) addLeadingComment(enclosingNode, comment);
|
||||||
|
else addTrailingComment(precedingNode, comment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDanglingComments({ comment, enclosingNode }: CommentContext) {
|
||||||
|
if (enclosingNode) {
|
||||||
|
for (var key in DCM) {
|
||||||
|
if (key in enclosingNode) {
|
||||||
|
var arr: LocArray = enclosingNode[key];
|
||||||
|
if (is_LocArray(arr) && canAttachCommentInLocArray(arr) && arr.loc.contains(comment)) {
|
||||||
|
addDanglingComment(enclosingNode, comment, key as DCM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function canAttachCommentInLocArray(arr: LocArray) {
|
||||||
|
return arr.length === 0 || arr.every((node) => !canAttachComment(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOwnLine(comment: AnyComment) {
|
||||||
|
return isStartOfLine(comment) && hasBreaklineAfter(comment);
|
||||||
|
}
|
||||||
|
function isStartOfLine(comment: AnyComment) {
|
||||||
|
return comment.placement === "ownLine";
|
||||||
|
}
|
||||||
|
function isEndOfLine(comment: AnyComment) {
|
||||||
|
return comment.placement === "endOfLine";
|
||||||
|
}
|
||||||
|
export function isDangling(comment: AnyComment) {
|
||||||
|
__DEV__: assert(handled(comment));
|
||||||
|
return !comment.leading && !comment.trailing;
|
||||||
|
}
|
||||||
|
export function isLeading(comment: AnyComment) {
|
||||||
|
__DEV__: assert(handled(comment));
|
||||||
|
return comment.leading && !comment.trailing;
|
||||||
|
}
|
||||||
|
export function isTrailing(comment: AnyComment) {
|
||||||
|
__DEV__: assert(handled(comment));
|
||||||
|
return !comment.leading && comment.trailing;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function print_comment(comment: CommentOrDocComment) {
|
||||||
|
__DEV__: Narrow<PrettierCommentInfo>(comment);
|
||||||
|
|
||||||
|
const doc = is_BlockCommentNode(comment)
|
||||||
|
? isIndentableBlockComment(comment.value)
|
||||||
|
? [
|
||||||
|
(!handled(comment) || isTrailing(comment)) && !hasBreaklineBefore(comment) ? hardline : "",
|
||||||
|
getCommentStart(comment),
|
||||||
|
...comment.value.split(/\n/g).map((line, i, a) =>
|
||||||
|
i === 0 //
|
||||||
|
? [line.trimEnd(), hardline]
|
||||||
|
: !iLast(i, a)
|
||||||
|
? [" " + line.trim(), hardline]
|
||||||
|
: " " + line.trimStart()
|
||||||
|
),
|
||||||
|
"*/",
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
getCommentStart(comment), //
|
||||||
|
join(literalline, comment.value.split(/\n/g)),
|
||||||
|
"*/",
|
||||||
|
]
|
||||||
|
: [getCommentStart(comment), comment.value.trimEnd()];
|
||||||
|
|
||||||
|
return handled(comment) && isDangling(comment) //
|
||||||
|
? [doc, getPostLeadingComment(comment)]
|
||||||
|
: doc;
|
||||||
|
|
||||||
|
function getCommentStart(comment: CommentOrDocComment) {
|
||||||
|
return is_Comment(comment)
|
||||||
|
? is_BlockCommentKind(comment)
|
||||||
|
? "/*"
|
||||||
|
: "//"
|
||||||
|
: is_BlockCommentKind(comment)
|
||||||
|
? isInner(comment)
|
||||||
|
? "/*!"
|
||||||
|
: "/**"
|
||||||
|
: isInner(comment)
|
||||||
|
? "//!"
|
||||||
|
: "///";
|
||||||
|
}
|
||||||
|
function isIndentableBlockComment(value: string) {
|
||||||
|
const lines = `*${value}*`.split(/\n/g);
|
||||||
|
return lines.length > 1 && lines.every((line) => /^\s*\*/.test(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
282
frontend/src/utils/prettier/plugins/rust/format/complexity.ts
Normal file
282
frontend/src/utils/prettier/plugins/rust/format/complexity.ts
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
import {
|
||||||
|
ForLtParametersBody,
|
||||||
|
FunctionSpread,
|
||||||
|
GenericParameterDeclaration,
|
||||||
|
MaybeGenericArgsTarget,
|
||||||
|
MissingNode,
|
||||||
|
Node,
|
||||||
|
NodeType,
|
||||||
|
TypeBound,
|
||||||
|
TypeBoundsConstaint,
|
||||||
|
TypeCallArgument,
|
||||||
|
TypeNamespaceTargetNoSelector,
|
||||||
|
TypeNode,
|
||||||
|
} from "jinx-rust";
|
||||||
|
import {
|
||||||
|
getAstPath,
|
||||||
|
getOwnChildAstPath,
|
||||||
|
is_BareTypeTraitBound,
|
||||||
|
is_FunctionSpread,
|
||||||
|
is_LetScrutinee,
|
||||||
|
is_Literal,
|
||||||
|
is_MissingNode,
|
||||||
|
is_TypeBoundsStandaloneNode,
|
||||||
|
is_TypeFunctionNode,
|
||||||
|
is_TypeNode,
|
||||||
|
is_VariableDeclarationNode,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import { exit, has_key_defined, last_of, spliceAll } from "../utils/common";
|
||||||
|
import { canBreak } from "./external";
|
||||||
|
import { getContext, getNode, getOptions, getPrintFn } from "./plugin";
|
||||||
|
|
||||||
|
let DEPTH = 0;
|
||||||
|
const ANCESTRY: Node[] = [];
|
||||||
|
const LONE_SHORT_ARGUMENT_THRESHOLD_RATE = 0.25;
|
||||||
|
|
||||||
|
export function withCheckContext<R>(fn: () => R): R {
|
||||||
|
if (0 === DEPTH) {
|
||||||
|
return fn();
|
||||||
|
} else {
|
||||||
|
DEPTH = 0;
|
||||||
|
const prev = spliceAll(ANCESTRY);
|
||||||
|
try {
|
||||||
|
return fn();
|
||||||
|
} finally {
|
||||||
|
DEPTH = ANCESTRY.push(...prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function is_short(str: string) {
|
||||||
|
return str.length <= LONE_SHORT_ARGUMENT_THRESHOLD_RATE * getOptions().printWidth;
|
||||||
|
}
|
||||||
|
function print(target: Node) {
|
||||||
|
const current = getNode();
|
||||||
|
const keys: (string | number)[] = [...getAstPath(ANCESTRY[0], getNode())];
|
||||||
|
for (let i = 1; i < ANCESTRY.length; i++) keys.push(...getOwnChildAstPath(ANCESTRY[i - 1], ANCESTRY[i]));
|
||||||
|
keys.push(...getOwnChildAstPath(last_of(ANCESTRY), target));
|
||||||
|
try {
|
||||||
|
return getContext().path.call(() => getPrintFn(target)(), ...keys);
|
||||||
|
} catch (e) {
|
||||||
|
console.log({ current, target, keys, ANCESTRY });
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function IsSimpleFunction<T extends Node>(fn: (node: T) => boolean): (node: T) => boolean {
|
||||||
|
return function (node: T) {
|
||||||
|
if (0 !== DEPTH && node === ANCESTRY[DEPTH - 1]) {
|
||||||
|
return fn(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEPTH >= 2) {
|
||||||
|
return isShortBasic(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return fn((ANCESTRY[DEPTH++] = node) as any);
|
||||||
|
} finally {
|
||||||
|
ANCESTRY.length = --DEPTH;
|
||||||
|
}
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HasComplexFunction<T extends Node>(fn: (node: T) => boolean): (node: T) => boolean {
|
||||||
|
return function (node: T) {
|
||||||
|
if (0 !== DEPTH && node === ANCESTRY[DEPTH - 1]) {
|
||||||
|
return fn(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEPTH >= 2) {
|
||||||
|
return !isShortBasic(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return fn((ANCESTRY[DEPTH++] = node) as any);
|
||||||
|
} finally {
|
||||||
|
ANCESTRY.length = --DEPTH;
|
||||||
|
}
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isShortBasic = (node: Node) => {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.MissingNode:
|
||||||
|
return true;
|
||||||
|
case NodeType.Identifier:
|
||||||
|
case NodeType.Index:
|
||||||
|
case NodeType.LtIdentifier:
|
||||||
|
case NodeType.LbIdentifier:
|
||||||
|
case NodeType.McIdentifier:
|
||||||
|
return is_short(node.name);
|
||||||
|
case NodeType.Literal:
|
||||||
|
return is_short(node.value) && !/\n/.test(node.value);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isSimpleType = IsSimpleFunction<FunctionSpread | TypeNode | MissingNode>((node): boolean => {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.MissingNode:
|
||||||
|
case NodeType.FunctionSpread:
|
||||||
|
return true;
|
||||||
|
case NodeType.MacroInvocation:
|
||||||
|
return false;
|
||||||
|
case NodeType.Identifier:
|
||||||
|
case NodeType.TypeNever:
|
||||||
|
case NodeType.TypeInferred:
|
||||||
|
return true;
|
||||||
|
case NodeType.TypePath:
|
||||||
|
return isShortBasic(node.segment) && (!node.namespace || isSimpleType(node.namespace));
|
||||||
|
case NodeType.TypeCall:
|
||||||
|
return isSimpleType(node.typeCallee) && !hasComplexTypeArguments(node);
|
||||||
|
case NodeType.ExpressionTypeSelector:
|
||||||
|
return isSimpleType(node.typeTarget) && (!node.typeExpression || isSimpleType(node.typeExpression));
|
||||||
|
case NodeType.TypeDynBounds:
|
||||||
|
return !hasComplexTypeBounds(node);
|
||||||
|
case NodeType.TypeImplBounds:
|
||||||
|
return !hasComplexTypeBounds(node);
|
||||||
|
case NodeType.TypeFnPointer: {
|
||||||
|
const param = node.parameters[0];
|
||||||
|
return (
|
||||||
|
(!node.extern || !node.extern.abi || isShortBasic(node.extern.abi)) &&
|
||||||
|
!hasComplexLtParameters(node) &&
|
||||||
|
(node.parameters.length === 0 ||
|
||||||
|
(node.parameters.length === 1 &&
|
||||||
|
(is_FunctionSpread(param) ||
|
||||||
|
(!is_TypeFunctionNode(param.typeAnnotation) && isSimpleType(param.typeAnnotation))))) &&
|
||||||
|
(!node.returnType || isSimpleType(node.returnType))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case NodeType.TypeFunction:
|
||||||
|
return isSimpleType(node.callee) && node.parameters.every(isSimpleType) && (!node.returnType || isSimpleType(node.returnType));
|
||||||
|
case NodeType.TypeSizedArray:
|
||||||
|
return isSimpleType(node.typeExpression) && isShortBasic(node.sizeExpression);
|
||||||
|
case NodeType.TypeSlice:
|
||||||
|
return isSimpleType(node.typeExpression);
|
||||||
|
case NodeType.TypeTuple:
|
||||||
|
return node.items.length === 0 || (node.items.length === 1 && isSimpleType(node.items[0]));
|
||||||
|
case NodeType.TypeReference:
|
||||||
|
case NodeType.TypeDereferenceMut:
|
||||||
|
case NodeType.TypeDereferenceConst:
|
||||||
|
case NodeType.TypeParenthesized:
|
||||||
|
return isSimpleType(node.typeExpression);
|
||||||
|
default:
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hasComplexTypeBounds = HasComplexFunction<Extract<Node, TypeBoundsConstaint>>((node) => {
|
||||||
|
return !!node.typeBounds && node.typeBounds.length > 1 && !node.typeBounds.every(isSimpleTypeBound);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const isSimpleTypeBound = (node: TypeBound): boolean => {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.TypeParenthesized:
|
||||||
|
return isSimpleTypeBound(node.typeExpression);
|
||||||
|
// #Lifetime
|
||||||
|
case NodeType.LtIdentifier:
|
||||||
|
case NodeType.LtElided:
|
||||||
|
case NodeType.LtStatic:
|
||||||
|
return true;
|
||||||
|
case NodeType.TypeTraitBound:
|
||||||
|
return is_BareTypeTraitBound(node) && isSimpleTypeNamespaceTargetNoSelector(node.typeExpression);
|
||||||
|
default:
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function isSimpleTypeNamespaceTargetNoSelector(node: TypeNamespaceTargetNoSelector): boolean {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.Identifier:
|
||||||
|
return true;
|
||||||
|
case NodeType.TypePath:
|
||||||
|
return undefined === node.namespace || isSimpleTypeNamespaceTargetNoSelector(node.namespace);
|
||||||
|
case NodeType.TypeCall:
|
||||||
|
return false;
|
||||||
|
case NodeType.TypeFunction:
|
||||||
|
return isSimpleTypeNamespaceTargetNoSelector(node.callee) && node.parameters.length === 0 && !node.returnType;
|
||||||
|
default:
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSimpleTypeArgument = IsSimpleFunction<TypeCallArgument>((node) => {
|
||||||
|
if (is_TypeNode(node)) {
|
||||||
|
return isSimpleType(node);
|
||||||
|
}
|
||||||
|
switch (node.nodeType) {
|
||||||
|
// #Lifetime
|
||||||
|
case NodeType.LtIdentifier:
|
||||||
|
case NodeType.LtElided:
|
||||||
|
case NodeType.LtStatic:
|
||||||
|
case NodeType.Literal:
|
||||||
|
return true;
|
||||||
|
case NodeType.MinusExpression:
|
||||||
|
return is_Literal(node.expression);
|
||||||
|
case NodeType.BlockExpression:
|
||||||
|
return false; //willBreak(getPrintFn(node)("body"));
|
||||||
|
case NodeType.TypeCallNamedArgument:
|
||||||
|
return isSimpleType(node.typeExpression);
|
||||||
|
case NodeType.TypeCallNamedBound:
|
||||||
|
return isSimpleType(node.typeTarget) && !hasComplexTypeBounds(node);
|
||||||
|
default:
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hasComplexTypeArguments = HasComplexFunction<Extract<Node, MaybeGenericArgsTarget>>((node) =>
|
||||||
|
!node.typeArguments || node.typeArguments.length === 0
|
||||||
|
? false
|
||||||
|
: node.typeArguments.length === 1
|
||||||
|
? (() => {
|
||||||
|
const arg = node.typeArguments[0];
|
||||||
|
return is_TypeBoundsStandaloneNode(arg) || canBreak(print(arg));
|
||||||
|
})()
|
||||||
|
: true
|
||||||
|
);
|
||||||
|
|
||||||
|
export const hasComplexLtParameters = HasComplexFunction<Extract<Node, ForLtParametersBody>>((node) => {
|
||||||
|
const ltParameters = node.ltParameters;
|
||||||
|
if (!ltParameters || ltParameters.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ltParameters.length === 1) {
|
||||||
|
const arg = ltParameters[0];
|
||||||
|
if (arg.ltBounds && arg.ltBounds.length > 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const isShortGenericParameterDeclaration = IsSimpleFunction<GenericParameterDeclaration>((node) => {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.GenericTypeParameterDeclaration:
|
||||||
|
return !node.typeBounds && !node.typeDefault;
|
||||||
|
case NodeType.ConstTypeParameterDeclaration:
|
||||||
|
return (!node.typeAnnotation || is_MissingNode(node)) && !node.typeDefault;
|
||||||
|
case NodeType.GenericLtParameterDeclaration:
|
||||||
|
return !node.ltBounds;
|
||||||
|
default:
|
||||||
|
exit.never();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hasComplexGenerics = HasComplexFunction<Node>((node) => {
|
||||||
|
return has_key_defined(node, "generics") && node.generics.length > 0 && !node.generics.every(isShortGenericParameterDeclaration);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hasComplexTypeAnnotation = HasComplexFunction<Node>((node) => {
|
||||||
|
if (is_VariableDeclarationNode(node) && !is_LetScrutinee(node)) {
|
||||||
|
const { typeAnnotation } = node;
|
||||||
|
return !!typeAnnotation && !is_MissingNode(typeAnnotation) && !isSimpleType(typeAnnotation);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
2349
frontend/src/utils/prettier/plugins/rust/format/core.ts
Normal file
2349
frontend/src/utils/prettier/plugins/rust/format/core.ts
Normal file
File diff suppressed because it is too large
Load Diff
126
frontend/src/utils/prettier/plugins/rust/format/external.ts
Normal file
126
frontend/src/utils/prettier/plugins/rust/format/external.ts
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
import { Attribute, AttributeOrDocComment, Comment, DocCommentAttribute, LocArray, MemberExpression, Node, SourceFile } from "jinx-rust";
|
||||||
|
import { PickProps } from "jinx-rust/utils";
|
||||||
|
import type { Doc, ParserOptions, Printer } from "prettier";
|
||||||
|
import { doc } from "prettier";
|
||||||
|
import { AssertTypesEq } from "../utils/common";
|
||||||
|
|
||||||
|
export type { Doc, ParserOptions, Plugin, Printer } from "prettier";
|
||||||
|
|
||||||
|
|
||||||
|
export const {
|
||||||
|
join,
|
||||||
|
line,
|
||||||
|
softline,
|
||||||
|
hardline,
|
||||||
|
literalline,
|
||||||
|
group,
|
||||||
|
conditionalGroup,
|
||||||
|
fill,
|
||||||
|
lineSuffix,
|
||||||
|
lineSuffixBoundary,
|
||||||
|
cursor,
|
||||||
|
breakParent,
|
||||||
|
ifBreak,
|
||||||
|
trim,
|
||||||
|
indent,
|
||||||
|
indentIfBreak,
|
||||||
|
align,
|
||||||
|
addAlignmentToDoc,
|
||||||
|
markAsRoot,
|
||||||
|
dedentToRoot,
|
||||||
|
dedent,
|
||||||
|
hardlineWithoutBreakParent,
|
||||||
|
literallineWithoutBreakParent,
|
||||||
|
label,
|
||||||
|
} = doc.builders;
|
||||||
|
|
||||||
|
export const {
|
||||||
|
willBreak,
|
||||||
|
traverseDoc,
|
||||||
|
findInDoc,
|
||||||
|
mapDoc,
|
||||||
|
removeLines,
|
||||||
|
stripTrailingHardline,
|
||||||
|
} = doc.utils;
|
||||||
|
|
||||||
|
// Fallback implementations for removed utils in prettier 3
|
||||||
|
export const isConcat = (doc: any): boolean => Array.isArray(doc);
|
||||||
|
export const getDocParts = (doc: any): any[] => Array.isArray(doc) ? doc : [doc];
|
||||||
|
export const propagateBreaks = (doc: any): any => doc;
|
||||||
|
export const normalizeParts = (parts: any[]): any[] => parts.flat();
|
||||||
|
export const normalizeDoc = (doc: any): any => doc;
|
||||||
|
export const cleanDoc = (doc: any): any => doc;
|
||||||
|
export const canBreak = (doc: any): boolean => {
|
||||||
|
if (!doc) return false;
|
||||||
|
if (typeof doc === 'string') return false;
|
||||||
|
if (Array.isArray(doc)) return doc.some(canBreak);
|
||||||
|
if (doc.type === 'group' || doc.type === 'fill') return true;
|
||||||
|
return willBreak(doc);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Symbol_comments = Symbol.for("comments");
|
||||||
|
|
||||||
|
export interface CustomOptions extends ParserOptions<Node> {
|
||||||
|
[Symbol_comments]: AnyComment[];
|
||||||
|
rsParsedFile: SourceFile;
|
||||||
|
commentSpans: Map<number, number>;
|
||||||
|
printer: Printer<Node>;
|
||||||
|
cursorNode: any;
|
||||||
|
|
||||||
|
comments: Comment[];
|
||||||
|
danglingAttributes: AttributeOrDocComment[];
|
||||||
|
actuallyMethodNodes: WeakSet<MemberExpression>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeWithComments<T extends Node> = T & { comments: AnyComment[] };
|
||||||
|
export interface MutatedComment extends Comment, PrettierCommentInfo {}
|
||||||
|
export interface MutatedAttribute extends Attribute, PrettierCommentInfo {}
|
||||||
|
export interface MutatedDocComment extends DocCommentAttribute, PrettierCommentInfo {}
|
||||||
|
export type AnyComment = MutatedComment | MutatedAttribute | MutatedDocComment;
|
||||||
|
|
||||||
|
type keyofDelimitedArrayProps<T> = T extends never ? never : keyof PickProps<T, LocArray<any, "()" | "[]" | "{}" | "<>">>;
|
||||||
|
|
||||||
|
__DEV__: AssertTypesEq<keyof typeof DCM, keyofDelimitedArrayProps<Node>>();
|
||||||
|
|
||||||
|
export enum DCM {
|
||||||
|
"arguments" = "arguments",
|
||||||
|
"parameters" = "parameters",
|
||||||
|
"items" = "items",
|
||||||
|
"properties" = "properties",
|
||||||
|
"members" = "members",
|
||||||
|
"body" = "body",
|
||||||
|
"cases" = "cases",
|
||||||
|
"typeArguments" = "typeArguments",
|
||||||
|
"ltParameters" = "ltParameters",
|
||||||
|
"generics" = "generics",
|
||||||
|
"specifiers" = "specifiers",
|
||||||
|
"rules" = "rules",
|
||||||
|
"match" = "match",
|
||||||
|
"transform" = "transform",
|
||||||
|
"segments" = "segments",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PrettierCommentInfo {
|
||||||
|
trailing: boolean;
|
||||||
|
leading: boolean;
|
||||||
|
unignore: boolean;
|
||||||
|
printed: boolean;
|
||||||
|
placement: "ownLine" | "endOfLine" | "remaining";
|
||||||
|
// nodeDescription?: any;
|
||||||
|
marker?: DCM;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AstPath<T = Node> {
|
||||||
|
stack: (Node | string | number)[];
|
||||||
|
callParent<R>(callback: (path: this) => R, count?: number): R;
|
||||||
|
getName(): PropertyKey | null;
|
||||||
|
getValue(): T;
|
||||||
|
getNode(count?: number): T | null;
|
||||||
|
getParentNode(count?: number): T | null;
|
||||||
|
|
||||||
|
match(...predicates: ((node: Node, name: string | null, number: number | null) => boolean)[]): boolean;
|
||||||
|
|
||||||
|
call<R>(callback: (path: AstPath, index: number, value: any) => R, ...props: (string | number)[]): R;
|
||||||
|
each(callback: (path: AstPath, index: number, value: any) => void, ...props: (string | number)[]): void;
|
||||||
|
map<R>(callback: (path: AstPath, index: number, value: any) => R, ...props: (string | number)[]): R[];
|
||||||
|
}
|
||||||
367
frontend/src/utils/prettier/plugins/rust/format/plugin.ts
Normal file
367
frontend/src/utils/prettier/plugins/rust/format/plugin.ts
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
import { AttributeOrComment, IfBlockExpression, Node, Program, rs } from "jinx-rust";
|
||||||
|
import {
|
||||||
|
ArrayProps,
|
||||||
|
BoolProps,
|
||||||
|
NodeProps,
|
||||||
|
end,
|
||||||
|
hasAttributes,
|
||||||
|
insertNodes,
|
||||||
|
is_Attribute,
|
||||||
|
is_AttributeOrComment,
|
||||||
|
is_BlockCommentKind,
|
||||||
|
is_BlockCommentNode,
|
||||||
|
is_Comment,
|
||||||
|
is_DocCommentAttribute,
|
||||||
|
is_ElseBlock,
|
||||||
|
is_LineCommentNode,
|
||||||
|
is_MacroInvocation,
|
||||||
|
is_MacroRule,
|
||||||
|
is_MissingNode,
|
||||||
|
is_Node,
|
||||||
|
is_PunctuationToken,
|
||||||
|
is_UnionPattern,
|
||||||
|
start,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import { getCommentChildNodes, isTransformed, transform_ast } from "../transform";
|
||||||
|
import { Narrow, assert, color, each, exit, iLast, is_array, map_tagged_template, print_string } from "../utils/common";
|
||||||
|
import {
|
||||||
|
CF,
|
||||||
|
escapeComments,
|
||||||
|
getComments,
|
||||||
|
handleEndOfLineComment,
|
||||||
|
handleOwnLineComment,
|
||||||
|
handleRemainingComment,
|
||||||
|
hasBreaklineAfter,
|
||||||
|
hasComment,
|
||||||
|
isDangling,
|
||||||
|
isPrettierIgnoreAttribute,
|
||||||
|
setDidPrintComment,
|
||||||
|
withComments,
|
||||||
|
} from "./comments";
|
||||||
|
import { withCheckContext } from "./complexity";
|
||||||
|
import { isNoopExpressionStatement, maybeEmptyLine } from "./core";
|
||||||
|
import { AstPath, CustomOptions, Doc, Plugin, Symbol_comments, group, hardline, indent, line, softline, ParserOptions } from "./external";
|
||||||
|
import { printer } from "./printer";
|
||||||
|
import { needsInnerParens, needsOuterSoftbreakParens, shouldPrintOuterAttributesAbove } from "./styling";
|
||||||
|
|
||||||
|
export function is_printing_macro() {
|
||||||
|
return getContext().path.stack.some((node) => is_Node(node) && (is_MacroInvocation(node) || is_Attribute(node)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertPathAtNode(name: string, node: Node, ...ctx: any[]) {
|
||||||
|
__DEV__: if (getNode() !== node)
|
||||||
|
exit(`Attempted to call ${name}() in wrong prettier path context`, { asserted: node, actual: getNode() }, ...ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function f(...args: [strings: TemplateStringsArray, ...values: Doc[]]) {
|
||||||
|
let cancel = false;
|
||||||
|
const res = map_tagged_template(args, (doc) => {
|
||||||
|
cancel ||= !doc || (is_array(doc) && doc.length === 0);
|
||||||
|
return doc;
|
||||||
|
});
|
||||||
|
return cancel ? "" : res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sg_single(s: TemplateStringsArray, v_0: Doc) {
|
||||||
|
return group([s[0], indent([softline, v_0]), softline, s[1]]);
|
||||||
|
}
|
||||||
|
export function sg_duo(s: TemplateStringsArray, v_0: Doc, v_1: Doc) {
|
||||||
|
return group([s[0], indent([softline, v_0, s[1], line, v_1]), softline, s[2]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctx: {
|
||||||
|
path: AstPath;
|
||||||
|
options: CustomOptions;
|
||||||
|
print: (path?: AstPath | string | [] | undefined, args?: any) => Doc;
|
||||||
|
args: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNode = () => ctx.path.stack[ctx.path.stack.length - 1] as Node;
|
||||||
|
export const stackIncludes = (x: Node | string | number) => ctx.path.stack.includes(x);
|
||||||
|
export const getContext = () => ctx;
|
||||||
|
export const getOptions = () => ctx.options;
|
||||||
|
export const getProgram = () => ctx.options.rsParsedFile.program;
|
||||||
|
export const getAllComments = () => ctx.options[Symbol_comments];
|
||||||
|
export const getParentNode = (child?: Node) => {
|
||||||
|
__DEV__: if (child) assertPathAtNode("getParentNode", child);
|
||||||
|
return ctx.path.getParentNode();
|
||||||
|
};
|
||||||
|
export const getGrandParentNode = () => ctx.path.getParentNode(1) as Node;
|
||||||
|
export const getPrintFn = <T extends Node>(forNode?: T | undefined): print<T> => {
|
||||||
|
__DEV__: if (forNode) assertPathAtNode("getPrintFn", forNode);
|
||||||
|
return print as print<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const get = (property: keyof any) => getNode()[property];
|
||||||
|
const has = (property: keyof any) => !!get(property);
|
||||||
|
|
||||||
|
export function pathCall<T extends Node, K extends keyof NodeProps<T> & keyof T, R>(node: T, key: K, fn: (child: T[K]) => R): R {
|
||||||
|
return ctx.path.call(() => fn(getNode() as any), key as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pathCallEach<T extends Node, K extends AK<T>>(
|
||||||
|
node: T,
|
||||||
|
key: K, // @ts-expect-error
|
||||||
|
fn: (child: NonNullable<T[K]>[number], index: number) => void
|
||||||
|
) {
|
||||||
|
__DEV__: assertPathAtNode("", node); // @ts-expect-error
|
||||||
|
ctx.path.each((_, i) => fn(getNode() as any, i), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pathCallAtParent<T extends Node, R>(parent: T, fn: (parent: T) => R): R {
|
||||||
|
return ctx.path.callParent(() => {
|
||||||
|
__DEV__: assertPathAtNode("pathCallParent", parent);
|
||||||
|
return fn(parent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function pathCallParentOf<T extends Node, R>(child: Node, fn: (parent: T) => R): R {
|
||||||
|
__DEV__: assertPathAtNode("pathCallParentOf", child);
|
||||||
|
return ctx.path.callParent((p) => fn(getNode() as any));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pathCallTopMostIfBlockExpression<R>(node: IfBlockExpression, fn: (node: IfBlockExpression) => R): R {
|
||||||
|
const parent = getParentNode(node)!;
|
||||||
|
return is_ElseBlock(node, parent) ? pathCallAtParent(parent, (parent) => pathCallTopMostIfBlockExpression(parent, fn)) : fn(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
function print(property?: any, args?: any): Doc | Doc[] {
|
||||||
|
if (!property) return ctx.print(undefined!, args);
|
||||||
|
if (Array.isArray(property)) return ctx.print(property as any, args);
|
||||||
|
const value = get(property);
|
||||||
|
return !!value ? (Array.isArray(value) ? ctx.path.map(ctx.print, property) : ctx.print(property, args)) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace print {
|
||||||
|
export function b(property: string, res = `${property} `): Doc {
|
||||||
|
return has(property) ? res : "";
|
||||||
|
}
|
||||||
|
export function map(property: string, mapItem?: MapFn<any, any>): Doc[] {
|
||||||
|
return !has(property) ? [] : ctx.path.map(mapItem ? (p, i, a) => mapItem(a[i], i, a) : () => ctx.print(), property);
|
||||||
|
}
|
||||||
|
export function join(property: string, sep: SepFn<any, any> | Doc, trailingSep: TrailingSepFn<any, any> | Doc = ""): Doc[] {
|
||||||
|
return map_join(property, () => ctx.print(), sep, trailingSep);
|
||||||
|
}
|
||||||
|
export function map_join(
|
||||||
|
property: string,
|
||||||
|
mapFn: MapFn<any, any>,
|
||||||
|
sep: SepFn<any, any> | Doc,
|
||||||
|
sepTrailing: TrailingSepFn<any, any> | Doc = ""
|
||||||
|
) {
|
||||||
|
const sepFn = typeof sep === "function" ? sep : () => sep;
|
||||||
|
return map(property, (v, i, a) => [
|
||||||
|
mapFn(v, i, a),
|
||||||
|
iLast(i, a as any)
|
||||||
|
? typeof sepTrailing === "function"
|
||||||
|
? sepTrailing(v)
|
||||||
|
: sepTrailing
|
||||||
|
: sepFn(v, a[i + 1], i === 0 ? undefined : a[i - 1]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
type SepFn<T extends Node = Node, K extends AK<T> = AK<T>> = <A extends AV<T, K>>(item: A[number], next_item: A[number], prev_item: A[number] | undefined) => Doc;
|
||||||
|
type MapFn<T extends Node = Node, K extends AK<T> = AK<T>> = <A extends AV<T, K>>(item: A[number], index: number, arr: A) => Doc;
|
||||||
|
type TrailingSepFn<T extends Node = Node, K extends AK<T> = AK<T>> = <A extends AV<T, K>>(item: A[number]) => Doc;
|
||||||
|
type AV<T extends Node, K extends keyof T> = Extract<NonNullable<T[K]>, ReadonlyArray<unknown>>;
|
||||||
|
type AK<T extends Node> = keyof ArrayProps<T> & keyof T;
|
||||||
|
// type AK<T extends Node> = keyof PickProps<T, {nodeType:number}|{nodeType:number}[]> & keyof T;
|
||||||
|
|
||||||
|
export interface print<T extends Node> {
|
||||||
|
(property?: [], args?: any): Doc;
|
||||||
|
(property?: [AK<T>, number], args?: any): Doc;
|
||||||
|
(property?: AK<T>, args?: any): Doc[];
|
||||||
|
// (property?: T extends {rules:{nodeType:number}|{nodeType:number}[]} ? "rules" : never, args?: any): Doc[];
|
||||||
|
(property?: keyof NodeProps<T> & keyof T, args?: any): Doc;
|
||||||
|
b(property: keyof BoolProps<T>, res?: string): Doc;
|
||||||
|
map<K extends AK<T>>(property: K & keyof ArrayProps<T>, mapFn?: MapFn<T, K>): Doc[];
|
||||||
|
join<K extends AK<T>>(property: K, sep: SepFn<T, K> | Doc, trailingSep?: TrailingSepFn<T, K> | Doc): Doc[];
|
||||||
|
map_join<K extends AK<T>>(property: K, mapFn: MapFn<T, K>, sep: SepFn<T, K> | Doc, trailingSep?: TrailingSepFn<T, K> | Doc): Doc[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function genericPrint() {
|
||||||
|
return withCheckContext(() => {
|
||||||
|
const node = getNode();
|
||||||
|
__DEV__: assert(node.nodeType in printer);
|
||||||
|
|
||||||
|
let printed: Doc = hasPrettierIgnore(node) //
|
||||||
|
? node.loc.getOwnText()
|
||||||
|
: printer[node.nodeType]!(print as any, node as never);
|
||||||
|
|
||||||
|
const inner_parens = needsInnerParens(node);
|
||||||
|
|
||||||
|
if (inner_parens) {
|
||||||
|
printed = group(["(", printed, ")"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasAttributes(node)) {
|
||||||
|
const print_above = shouldPrintOuterAttributesAbove(node); /* || node.attributes.length > 1 */
|
||||||
|
printed = [
|
||||||
|
...print.join(
|
||||||
|
"attributes",
|
||||||
|
(attr) =>
|
||||||
|
print_above
|
||||||
|
? maybeEmptyLine(attr)
|
||||||
|
: is_LineCommentNode(attr) || (is_BlockCommentNode(attr) && hasBreaklineAfter(attr))
|
||||||
|
? hardline
|
||||||
|
: " ",
|
||||||
|
(attr) =>
|
||||||
|
print_above && is_DocCommentAttribute(attr)
|
||||||
|
? maybeEmptyLine(attr)
|
||||||
|
: print_above || is_LineCommentNode(attr) || (is_BlockCommentNode(attr) && hasBreaklineAfter(attr))
|
||||||
|
? hardline
|
||||||
|
: " "
|
||||||
|
),
|
||||||
|
printed,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
printed = withComments(
|
||||||
|
node,
|
||||||
|
printed,
|
||||||
|
hasPrettierIgnore(node) || ((is_Attribute(node) || is_MacroInvocation(node)) && !isTransformed(node))
|
||||||
|
? escapeComments(0, (comment) => node.loc.ownContains(comment))
|
||||||
|
: is_MacroRule(node)
|
||||||
|
? escapeComments(0, (comment) => node.transform.loc.contains(comment))
|
||||||
|
: is_UnionPattern(getParentNode() ?? ({ nodeType: 0 } as any))
|
||||||
|
? new Set(getComments(node, CF.Leading | CF.Trailing, (comment) => !isDangling(comment)))
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!inner_parens && needsOuterSoftbreakParens(node)) {
|
||||||
|
printed = [group(["(", indent([softline, printed]), softline, ")"])];
|
||||||
|
}
|
||||||
|
|
||||||
|
return printed;
|
||||||
|
});
|
||||||
|
|
||||||
|
function hasPrettierIgnore(node: Node) {
|
||||||
|
return (
|
||||||
|
(node as any).prettierIgnore ||
|
||||||
|
hasComment(node, CF.PrettierIgnore) ||
|
||||||
|
(hasAttributes(node) && node.attributes.some(isPrettierIgnoreAttribute))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canAttachComment(n: Node) {
|
||||||
|
return !is_Comment(n) && !isNoopExpressionStatement(n) && !is_MissingNode(n) && !is_PunctuationToken(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const plugin: Plugin<Node> = {
|
||||||
|
languages: [
|
||||||
|
{
|
||||||
|
name: "Rust",
|
||||||
|
aliases: ["rs"],
|
||||||
|
parsers: ["jinx-rust"],
|
||||||
|
extensions: [".rs", ".rs.in"],
|
||||||
|
linguistLanguageId: 327,
|
||||||
|
vscodeLanguageIds: ["rust"],
|
||||||
|
tmScope: "source.rust",
|
||||||
|
aceMode: "rust",
|
||||||
|
codemirrorMode: "rust",
|
||||||
|
codemirrorMimeType: "text/x-rustsrc",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
parsers: {
|
||||||
|
"jinx-rust": {
|
||||||
|
astFormat: "jinx-rust",
|
||||||
|
locStart: start,
|
||||||
|
locEnd: end,
|
||||||
|
parse(code: string, options: ParserOptions<Node> & Partial<CustomOptions>) {
|
||||||
|
const customOptions = options as CustomOptions;
|
||||||
|
ctx = { options: customOptions } as any;
|
||||||
|
|
||||||
|
customOptions.rsParsedFile = rs.parseFile((customOptions.originalText = code), { filepath: customOptions.filepath });
|
||||||
|
|
||||||
|
customOptions.actuallyMethodNodes = new WeakSet();
|
||||||
|
customOptions.danglingAttributes = [];
|
||||||
|
customOptions.comments = [];
|
||||||
|
|
||||||
|
transform_ast(customOptions);
|
||||||
|
|
||||||
|
const comments: AttributeOrComment[] = [];
|
||||||
|
insertNodes(comments, customOptions.comments);
|
||||||
|
insertNodes(comments, customOptions.danglingAttributes);
|
||||||
|
|
||||||
|
// @ts-expect-error
|
||||||
|
customOptions.rsParsedFile.program.comments = comments;
|
||||||
|
|
||||||
|
customOptions.commentSpans = new Map(comments.map((n) => [start(n), end(n)]));
|
||||||
|
|
||||||
|
return customOptions.rsParsedFile.program;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
printers: {
|
||||||
|
"jinx-rust": {
|
||||||
|
preprocess: (node: Node) => (node as Program).loc?.src || node,
|
||||||
|
print(path, options, print, args) {
|
||||||
|
if (path.stack.length === 1) {
|
||||||
|
__DEV__: Narrow<CustomOptions>(options);
|
||||||
|
ctx = { path, options, print: print as any, args };
|
||||||
|
try {
|
||||||
|
const printed = genericPrint();
|
||||||
|
__DEV__: devEndCheck(printed);
|
||||||
|
return printed;
|
||||||
|
} finally {
|
||||||
|
ctx = undefined!;
|
||||||
|
}
|
||||||
|
} else if (args || ctx.args) {
|
||||||
|
const prev_args = ctx.args;
|
||||||
|
try {
|
||||||
|
ctx.args = args;
|
||||||
|
return genericPrint();
|
||||||
|
} finally {
|
||||||
|
ctx.args = prev_args;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return genericPrint();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hasPrettierIgnore: () => false,
|
||||||
|
willPrintOwnComments: () => true,
|
||||||
|
isBlockComment: (node: Node): boolean => {
|
||||||
|
return is_AttributeOrComment(node) && is_BlockCommentKind(node as any);
|
||||||
|
},
|
||||||
|
canAttachComment: canAttachComment,
|
||||||
|
getCommentChildNodes: getCommentChildNodes,
|
||||||
|
printComment: genericPrint,
|
||||||
|
handleComments: {
|
||||||
|
// @ts-expect-error
|
||||||
|
avoidAstMutation: true,
|
||||||
|
ownLine: handleOwnLineComment,
|
||||||
|
endOfLine: handleEndOfLineComment,
|
||||||
|
remaining: handleRemainingComment,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: {},
|
||||||
|
defaultOptions: {
|
||||||
|
// default prettier (2) -> rustfmt (4)
|
||||||
|
tabWidth: 4,
|
||||||
|
// default prettier (80) -> rustfmt (100)
|
||||||
|
printWidth: 100,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function devEndCheck(printed: Doc) {
|
||||||
|
let first = false;
|
||||||
|
const comments = getAllComments();
|
||||||
|
each(comments, (comment, index) => {
|
||||||
|
if (!comment.printed) {
|
||||||
|
if (!first) (first = true), console.log(color.red(`Unprinted comments:`));
|
||||||
|
const len = 40;
|
||||||
|
const msg =
|
||||||
|
color.magenta(
|
||||||
|
(comment.marker ? `Dangling "${comment.marker}" ` : "") +
|
||||||
|
(is_Attribute(comment) ? "Attribute " : is_DocCommentAttribute(comment) ? "DocCommentAttribute" : "Comment") +
|
||||||
|
` ${index}/${comments.length}` +
|
||||||
|
color.yellow(` ${print_string(comment.loc.sliceText(0, len))}${comment.loc.len() > len ? " ..." : ""}`)
|
||||||
|
) + color.grey(`\n at ${comment.loc.url()}`);
|
||||||
|
if (globalThis.TESTS_FORMAT_DEV) exit(msg);
|
||||||
|
else console.log(msg);
|
||||||
|
setDidPrintComment(comment);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
719
frontend/src/utils/prettier/plugins/rust/format/printer.ts
Normal file
719
frontend/src/utils/prettier/plugins/rust/format/printer.ts
Normal file
@@ -0,0 +1,719 @@
|
|||||||
|
import { DelimKind, Node, NodeType, NTMap } from "jinx-rust";
|
||||||
|
import {
|
||||||
|
getDelimChars,
|
||||||
|
hasSuffix,
|
||||||
|
is_ArrayOrTupleLiteral,
|
||||||
|
is_BlockExpression,
|
||||||
|
is_ClosureFunctionExpression,
|
||||||
|
is_Identifier,
|
||||||
|
is_IfBlockExpression,
|
||||||
|
is_LiteralNumberLike,
|
||||||
|
is_StructLiteral,
|
||||||
|
start,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import {
|
||||||
|
BlockLikeMacroInvocation,
|
||||||
|
CallLikeMacroInvocation,
|
||||||
|
is_BlockLikeMacroInvocation,
|
||||||
|
is_CallLikeMacroInvocation,
|
||||||
|
isTransformed,
|
||||||
|
} from "../transform";
|
||||||
|
import { exit } from "../utils/common";
|
||||||
|
import { hasComment, print_comment } from "./comments";
|
||||||
|
import { isSimpleType } from "./complexity";
|
||||||
|
import {
|
||||||
|
adjustClause,
|
||||||
|
parenthesize_if_break,
|
||||||
|
printAnnotatedPattern,
|
||||||
|
printArrayLike,
|
||||||
|
printArrowFunction,
|
||||||
|
printAssignment,
|
||||||
|
printBinaryishExpression,
|
||||||
|
printBlockBody,
|
||||||
|
printBodyOrCases,
|
||||||
|
printCallArguments,
|
||||||
|
printCallExpression,
|
||||||
|
printCondition,
|
||||||
|
printDanglingCommentsForInline,
|
||||||
|
printDeclarationTypeBounds,
|
||||||
|
printEnumBody,
|
||||||
|
printFlowControlExpression,
|
||||||
|
printGenerics_x_whereBounds,
|
||||||
|
printIfBlock,
|
||||||
|
printIfBlockCondition,
|
||||||
|
printImplTraitForType,
|
||||||
|
printLtBounds,
|
||||||
|
printLtParameters,
|
||||||
|
printMacroRules,
|
||||||
|
printMaybeBlockBody,
|
||||||
|
printMemberExpression,
|
||||||
|
printNumber,
|
||||||
|
printObject,
|
||||||
|
printParametersAndReturnType,
|
||||||
|
printRuleMatch,
|
||||||
|
printRuleTransform,
|
||||||
|
printTypeAnnotation,
|
||||||
|
printTypeArguments,
|
||||||
|
printTypeBounds,
|
||||||
|
printUnaryExpression,
|
||||||
|
printUnionPattern,
|
||||||
|
} from "./core";
|
||||||
|
import { DCM, Doc, group, hardline, ifBreak, indent, join, line, softline, willBreak } from "./external";
|
||||||
|
import { f, getOptions, getParentNode, pathCall, sg_duo, sg_single, type print } from "./plugin";
|
||||||
|
import { needsParens, stmtNeedsSemi } from "./styling";
|
||||||
|
|
||||||
|
type nPrint<T extends Node> = (print: print<T>, node: T) => Doc | never;
|
||||||
|
|
||||||
|
export const printer: { [K in NodeType]: nPrint<Extract<NTMap[K], Node>> } = {
|
||||||
|
[NodeType.MissingNode](print, node) {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
[NodeType.SourceFile](print, node) {
|
||||||
|
return [
|
||||||
|
print.b("UTF8BOM", "\uFEFF"), //
|
||||||
|
print("shebang"),
|
||||||
|
print("program"),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.Shebang](print, node) {
|
||||||
|
return [`#!${node.value}`, hardline];
|
||||||
|
},
|
||||||
|
[NodeType.Program](print, node) {
|
||||||
|
return printBodyOrCases(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.Snippet](print, node) {
|
||||||
|
exit.never();
|
||||||
|
},
|
||||||
|
[NodeType.Identifier](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.Index](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.LbIdentifier](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.McIdentifier](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.LtIdentifier](print, node) {
|
||||||
|
return node.name;
|
||||||
|
},
|
||||||
|
[NodeType.PunctuationToken](print, node) {
|
||||||
|
return node.token;
|
||||||
|
},
|
||||||
|
[NodeType.DelimGroup](print, node) {
|
||||||
|
return node.loc.getOwnText();
|
||||||
|
},
|
||||||
|
[NodeType.Literal](print, node) {
|
||||||
|
let { value } = node;
|
||||||
|
if (is_LiteralNumberLike(node)) value = printNumber(value);
|
||||||
|
return hasSuffix(node) ? [value, print("suffix")] : value;
|
||||||
|
},
|
||||||
|
[NodeType.ItemPath](print, node) {
|
||||||
|
return [print("namespace"), "::", print("segment")];
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionPath](print, node) {
|
||||||
|
return [print("namespace"), "::", print("segment")];
|
||||||
|
},
|
||||||
|
[NodeType.TypePath](print, node) {
|
||||||
|
return [print("namespace"), "::", print("segment")];
|
||||||
|
},
|
||||||
|
[NodeType.Comment](print, node) {
|
||||||
|
return print_comment(node);
|
||||||
|
},
|
||||||
|
[NodeType.DocCommentAttribute](print, node) {
|
||||||
|
return print_comment(node);
|
||||||
|
},
|
||||||
|
[NodeType.Attribute](print, node) {
|
||||||
|
return [
|
||||||
|
node.inner ? "#![" : "#[",
|
||||||
|
isTransformed(node)
|
||||||
|
? [print("segments"), printDanglingCommentsForInline(node)] //
|
||||||
|
: node.segments.loc.sliceText(1, -1).trim(),
|
||||||
|
"]",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.MacroInvocation](print, node) {
|
||||||
|
const hasCurlyBrackets = node.segments.dk === DelimKind["{}"];
|
||||||
|
const delim = getDelimChars(node.segments);
|
||||||
|
if (node.segments.length === 0) {
|
||||||
|
return [print("callee"), "!", hasCurlyBrackets ? " " : "", delim.left, printDanglingCommentsForInline(node), delim.right];
|
||||||
|
}
|
||||||
|
if (isTransformed(node)) {
|
||||||
|
if (is_CallLikeMacroInvocation(node)) {
|
||||||
|
return [print("callee"), "!", printCallArguments(print as print<CallLikeMacroInvocation>, node)];
|
||||||
|
}
|
||||||
|
if (is_BlockLikeMacroInvocation(node)) {
|
||||||
|
return [print("callee"), "!", " ", printBlockBody(print as print<BlockLikeMacroInvocation>, node)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let content = node.segments.loc.sliceText(1, -1);
|
||||||
|
if (content.trim().length === 0) {
|
||||||
|
content = "";
|
||||||
|
} else if (!content.includes("\n")) {
|
||||||
|
content = content.trim();
|
||||||
|
if (hasCurlyBrackets) content = " " + content + " ";
|
||||||
|
}
|
||||||
|
return [print("callee"), "!", hasCurlyBrackets ? " " : "", delim.left, content, delim.right];
|
||||||
|
},
|
||||||
|
[NodeType.MacroRulesDeclaration](print, node) {
|
||||||
|
return ["macro_rules! ", print("id"), printMacroRules(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.MacroRuleDeclaration](print, node) {
|
||||||
|
return [printRuleMatch(print, node), " => ", printRuleTransform(print, node), ";"];
|
||||||
|
},
|
||||||
|
[NodeType.MacroDeclaration](print, node) {
|
||||||
|
return [print("pub"), "macro ", print("id"), printMacroRules(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.MacroInlineRuleDeclaration](print, node) {
|
||||||
|
return [printRuleMatch(print, node), " ", printRuleTransform(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.MacroGroup](print, node) {
|
||||||
|
return node.loc.getOwnText();
|
||||||
|
},
|
||||||
|
[NodeType.MacroParameterDeclaration](print, node) {
|
||||||
|
return [print("id"), ":", print("ty")];
|
||||||
|
},
|
||||||
|
[NodeType.PubSpecifier](print, node) {
|
||||||
|
if (!node.location) return "pub ";
|
||||||
|
if (is_Identifier(node.location)) {
|
||||||
|
switch (node.location.name) {
|
||||||
|
case "crate":
|
||||||
|
if (start(node) === start(node.location)) {
|
||||||
|
return "crate ";
|
||||||
|
} else {
|
||||||
|
return ["pub(", print("location"), ") "];
|
||||||
|
}
|
||||||
|
case "self":
|
||||||
|
case "super":
|
||||||
|
return ["pub(", print("location"), ") "];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ["pub(in ", print("location"), ") "];
|
||||||
|
},
|
||||||
|
[NodeType.ExternSpecifier](print, node) {
|
||||||
|
return ["extern ", f`${print("abi")} `];
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionStatement](print, node) {
|
||||||
|
return [print("expression"), stmtNeedsSemi(node) ? ";" : ""];
|
||||||
|
},
|
||||||
|
[NodeType.UseStatement](print, node) {
|
||||||
|
return [print("pub"), "use ", print("import"), ";"];
|
||||||
|
},
|
||||||
|
[NodeType.DestructuredImport](print, node) {
|
||||||
|
if (node.specifiers.length === 0) return [print("source"), "::{", printDanglingCommentsForInline(node, DCM["specifiers"]), "}"];
|
||||||
|
let space = true;
|
||||||
|
__DEV__: if (globalThis.TESTS_FORMAT_DEV) space = false;
|
||||||
|
return [
|
||||||
|
print("source"),
|
||||||
|
group([
|
||||||
|
"::{",
|
||||||
|
indent([space ? line : softline, join([",", line], print("specifiers")), ifBreak(",")]),
|
||||||
|
space ? line : softline,
|
||||||
|
"}",
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.AmbientImport](print, node) {
|
||||||
|
return f`${print("source")}::*` || "*";
|
||||||
|
},
|
||||||
|
[NodeType.AnonymousImport](print, node) {
|
||||||
|
return [print("source"), " as ", "_"];
|
||||||
|
},
|
||||||
|
[NodeType.NamedImport](print, node) {
|
||||||
|
return [print("source"), f` as ${print("local")}`];
|
||||||
|
},
|
||||||
|
[NodeType.ExternCrateStatement](print, node) {
|
||||||
|
return [print("pub"), "extern crate ", print("import"), ";"];
|
||||||
|
},
|
||||||
|
[NodeType.TypeAliasDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
"type",
|
||||||
|
printAssignment(
|
||||||
|
printGenerics_x_whereBounds(print, node, printDeclarationTypeBounds(print, node, ":")), //
|
||||||
|
" =",
|
||||||
|
"typeExpression"
|
||||||
|
),
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.LetVariableDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
"let ",
|
||||||
|
printAssignment(
|
||||||
|
printAnnotatedPattern(print, node), //
|
||||||
|
" =",
|
||||||
|
"expression"
|
||||||
|
),
|
||||||
|
f` else ${print("else")}`,
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ConstVariableDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
"const ",
|
||||||
|
printAssignment(
|
||||||
|
printAnnotatedPattern(print, node), //
|
||||||
|
" =",
|
||||||
|
"expression"
|
||||||
|
),
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.StaticVariableDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
"static ",
|
||||||
|
printAssignment(
|
||||||
|
printAnnotatedPattern(print, node), //
|
||||||
|
" =",
|
||||||
|
"expression"
|
||||||
|
),
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ModuleDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"), //
|
||||||
|
print.b("unsafe"),
|
||||||
|
"mod ",
|
||||||
|
print("id"),
|
||||||
|
printMaybeBlockBody(print, node),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ExternBlockDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"), //
|
||||||
|
print.b("unsafe"),
|
||||||
|
"extern ",
|
||||||
|
f`${print("abi")} `,
|
||||||
|
printBlockBody(print, node),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.FunctionDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("const"),
|
||||||
|
print.b("async"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
print("extern"),
|
||||||
|
"fn",
|
||||||
|
printGenerics_x_whereBounds(print, node, printParametersAndReturnType(node)),
|
||||||
|
printMaybeBlockBody(print, node),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.FunctionSelfParameterDeclaration](print, node) {
|
||||||
|
return group([print.b("ref", "&"), f`${print("lt")} `, print.b("mut"), "self", printTypeAnnotation(print, node)]);
|
||||||
|
},
|
||||||
|
[NodeType.FunctionParameterDeclaration](print, node) {
|
||||||
|
return group(printAnnotatedPattern(print, node));
|
||||||
|
},
|
||||||
|
[NodeType.FunctionSpread](print, node) {
|
||||||
|
return "...";
|
||||||
|
},
|
||||||
|
[NodeType.StructDeclaration](print, node) {
|
||||||
|
return [print("pub"), "struct", printGenerics_x_whereBounds(print, node, ""), printObject(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.StructPropertyDeclaration](print, node) {
|
||||||
|
return [print("pub"), print("id"), printTypeAnnotation(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.TupleStructDeclaration](print, node) {
|
||||||
|
return [print("pub"), "struct", printGenerics_x_whereBounds(print, node, printArrayLike(print, node)), ";"];
|
||||||
|
},
|
||||||
|
[NodeType.TupleStructItemDeclaration](print, node) {
|
||||||
|
return [print("pub"), print("typeAnnotation")];
|
||||||
|
},
|
||||||
|
[NodeType.UnionDeclaration](print, node) {
|
||||||
|
return [print("pub"), "union", printGenerics_x_whereBounds(print, node, ""), printObject(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.EnumDeclaration](print, node) {
|
||||||
|
return [print("pub"), "enum", printGenerics_x_whereBounds(print, node, ""), printEnumBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.EnumMemberDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
printAssignment(
|
||||||
|
print("id"), //
|
||||||
|
" =",
|
||||||
|
"value"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.EnumMemberTupleDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
printAssignment(
|
||||||
|
[print("id"), printArrayLike(print, node)], //
|
||||||
|
" =",
|
||||||
|
"value"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.EnumMemberStructDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
printAssignment(
|
||||||
|
[print("id"), printObject(print, node)], //
|
||||||
|
" =",
|
||||||
|
"value"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.TraitDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
"trait",
|
||||||
|
printGenerics_x_whereBounds(print, node, printDeclarationTypeBounds(print, node, ":")),
|
||||||
|
adjustClause(node, printBlockBody(print, node)),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.AutoTraitDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
"auto trait ",
|
||||||
|
print("id"),
|
||||||
|
" ",
|
||||||
|
printBlockBody(print, node as any), // see "transform.ts"
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.TraitAliasDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
"trait",
|
||||||
|
printGenerics_x_whereBounds(print, node, printDeclarationTypeBounds(print, node, " =")),
|
||||||
|
";",
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ImplDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
"impl",
|
||||||
|
printGenerics_x_whereBounds(print, node, [print.b("const"), printImplTraitForType(print, node)]),
|
||||||
|
adjustClause(node, printBlockBody(print, node)),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.NegativeImplDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
print("pub"),
|
||||||
|
"impl",
|
||||||
|
printGenerics_x_whereBounds(print, node, ["!", printImplTraitForType(print, node)]),
|
||||||
|
" ",
|
||||||
|
printBlockBody(print, node as any), // see "transform.ts"
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionTypeSelector](print, node) {
|
||||||
|
return group(["<", print("typeTarget"), f` as ${print("typeExpression")}`, ">"]);
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionTypeCast](print, node) {
|
||||||
|
return [print("typeCallee"), f`::${printTypeArguments(print, node)}`];
|
||||||
|
},
|
||||||
|
[NodeType.ExpressionAsTypeCast](print, node) {
|
||||||
|
return [print("expression"), " as ", print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.ReturnExpression](print, node) {
|
||||||
|
return ["return", printFlowControlExpression(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.BreakExpression](print, node) {
|
||||||
|
return ["break", f` ${print("label")}`, printFlowControlExpression(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.ContinueExpression](print, node) {
|
||||||
|
return ["continue", f` ${print("label")}`];
|
||||||
|
},
|
||||||
|
[NodeType.YieldExpression](print, node) {
|
||||||
|
return ["yield", printFlowControlExpression(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.RangeLiteral](print, node) {
|
||||||
|
return [print("lower"), "..", print.b("last", "="), print("upper")];
|
||||||
|
},
|
||||||
|
[NodeType.CallExpression](print, node) {
|
||||||
|
return printCallExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.MemberExpression](print, node) {
|
||||||
|
return printMemberExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.AwaitExpression](print, node) {
|
||||||
|
return [print("expression"), ".await"];
|
||||||
|
},
|
||||||
|
[NodeType.UnwrapExpression](print, node) {
|
||||||
|
return [print("expression"), "?"];
|
||||||
|
},
|
||||||
|
[NodeType.ParenthesizedExpression](print, node) {
|
||||||
|
exit.never();
|
||||||
|
const shouldHug = !hasComment(node.expression) && (is_ArrayOrTupleLiteral(node.expression) || is_StructLiteral(node.expression));
|
||||||
|
if (shouldHug) return ["(", print("expression"), ")"];
|
||||||
|
return group(["(", indent([softline, print("expression")]), softline, ")"]);
|
||||||
|
},
|
||||||
|
[NodeType.MinusExpression](print, node) {
|
||||||
|
return printUnaryExpression("-", node);
|
||||||
|
},
|
||||||
|
[NodeType.NotExpression](print, node) {
|
||||||
|
return printUnaryExpression("!", node);
|
||||||
|
},
|
||||||
|
[NodeType.OrExpression](print, node) {
|
||||||
|
return printBinaryishExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.AndExpression](print, node) {
|
||||||
|
return printBinaryishExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ReassignmentExpression](print, node) {
|
||||||
|
return printAssignment(print("left"), " =", "right");
|
||||||
|
},
|
||||||
|
[NodeType.UnassignedExpression](print, node) {
|
||||||
|
return "_";
|
||||||
|
},
|
||||||
|
[NodeType.OperationExpression](print, node) {
|
||||||
|
return printBinaryishExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ReassignmentOperationExpression](print, node) {
|
||||||
|
return printAssignment(print("left"), " " + node.kind, "right");
|
||||||
|
},
|
||||||
|
[NodeType.ComparisonExpression](print, node) {
|
||||||
|
return printBinaryishExpression(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.LetScrutinee](print, node) {
|
||||||
|
return ["let ", printAssignment(print("pattern"), " =", "expression")];
|
||||||
|
},
|
||||||
|
[NodeType.ClosureFunctionExpression](print, node) {
|
||||||
|
return printArrowFunction(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ClosureFunctionParameterDeclaration](print, node) {
|
||||||
|
return group(printAnnotatedPattern(print, node));
|
||||||
|
},
|
||||||
|
[NodeType.BlockExpression](print, node) {
|
||||||
|
return [
|
||||||
|
f`${print("label")}: `,
|
||||||
|
print.b("const"),
|
||||||
|
print.b("async"),
|
||||||
|
print.b("move"),
|
||||||
|
print.b("unsafe"),
|
||||||
|
printBlockBody(print, node),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.LoopBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, "loop ", printBlockBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.WhileBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, "while ", printCondition(print, node), printBlockBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.ForInBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, "for ", print("pattern"), " in ", print("expression"), " ", printBlockBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.IfBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, printIfBlock(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.TryBlockExpression](print, node) {
|
||||||
|
return [f`${print("label")}: `, "try ", printBlockBody(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.MatchExpression](print, node) {
|
||||||
|
const id = Symbol("match");
|
||||||
|
const expr = print("expression");
|
||||||
|
const needs_parens = pathCall(node, "expression", needsParens);
|
||||||
|
|
||||||
|
let printed: Doc = [
|
||||||
|
f`${print("label")}: `,
|
||||||
|
"match ",
|
||||||
|
needs_parens ? expr : group([indent([softline, expr]), softline], { id }),
|
||||||
|
needs_parens ? " " : !willBreak(expr) ? ifBreak("", " ", { groupId: id }) : "" /* ifBreak("", " ", { groupId: id }) */,
|
||||||
|
printBlockBody(print, node),
|
||||||
|
];
|
||||||
|
|
||||||
|
const parent = getParentNode()!;
|
||||||
|
if (is_ClosureFunctionExpression(parent) && parent.expression === node) {
|
||||||
|
printed = parenthesize_if_break([indent([softline, printed]), softline]);
|
||||||
|
}
|
||||||
|
return printed;
|
||||||
|
},
|
||||||
|
[NodeType.MatchExpressionCase](print, node) {
|
||||||
|
return group([
|
||||||
|
group(print("pattern")),
|
||||||
|
" ",
|
||||||
|
printIfBlockCondition(print, node),
|
||||||
|
"=>", //
|
||||||
|
(is_BlockExpression(node.expression) || is_IfBlockExpression(node.expression)) &&
|
||||||
|
!hasComment(node.expression, 0, (comment) => getOptions().danglingAttributes.includes(comment as any))
|
||||||
|
? [" ", print("expression")]
|
||||||
|
: group(indent([line, print("expression")])),
|
||||||
|
]);
|
||||||
|
return printAssignment(
|
||||||
|
[print("pattern"), " ", printIfBlockCondition(print, node)], //
|
||||||
|
"=>",
|
||||||
|
"expression"
|
||||||
|
);
|
||||||
|
return [print("pattern"), " ", printIfBlockCondition(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteral](print, node) {
|
||||||
|
return [print("struct"), printObject(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteralPropertyShorthand](print, node) {
|
||||||
|
return print("value");
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteralProperty](print, node) {
|
||||||
|
return [print("key"), ": ", print("value")];
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteralPropertySpread](print, node) {
|
||||||
|
return ["..", print("expression")];
|
||||||
|
},
|
||||||
|
[NodeType.StructLiteralRestUnassigned](print, node) {
|
||||||
|
return "..";
|
||||||
|
},
|
||||||
|
[NodeType.ArrayLiteral](print, node) {
|
||||||
|
return printArrayLike(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.SizedArrayLiteral](print, node) {
|
||||||
|
return sg_duo`[${print("initExpression")};${print("sizeExpression")}]`;
|
||||||
|
},
|
||||||
|
[NodeType.TupleLiteral](print, node) {
|
||||||
|
return printArrayLike(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ReferenceExpression](print, node) {
|
||||||
|
return printUnaryExpression(["&", print.b("mut")], node);
|
||||||
|
},
|
||||||
|
[NodeType.RawReferenceExpression](print, node) {
|
||||||
|
return printUnaryExpression(`&raw ${node.kind} `, node);
|
||||||
|
},
|
||||||
|
[NodeType.DereferenceExpression](print, node) {
|
||||||
|
return printUnaryExpression("*", node);
|
||||||
|
},
|
||||||
|
[NodeType.BoxExpression](print, node) {
|
||||||
|
return printUnaryExpression("box ", node);
|
||||||
|
},
|
||||||
|
[NodeType.UnionPattern](print, node) {
|
||||||
|
return printUnionPattern(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ParenthesizedPattern](print, node) {
|
||||||
|
exit.never();
|
||||||
|
return sg_single`(${print("pattern")})`;
|
||||||
|
},
|
||||||
|
[NodeType.RestPattern](print, node) {
|
||||||
|
return "..";
|
||||||
|
},
|
||||||
|
[NodeType.WildcardPattern](print, node) {
|
||||||
|
return "_";
|
||||||
|
},
|
||||||
|
[NodeType.PatternVariableDeclaration](print, node) {
|
||||||
|
return [print.b("ref"), print.b("mut"), printAssignment(print("id"), " @", "pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.StructPattern](print, node) {
|
||||||
|
return [print("struct"), printObject(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.StructPatternPropertyDestructured](print, node) {
|
||||||
|
return [print("key"), ": ", print("pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.StructPatternPropertyShorthand](print, node) {
|
||||||
|
return [print.b("box"), print.b("ref"), print.b("mut"), print("id")];
|
||||||
|
},
|
||||||
|
[NodeType.TuplePattern](print, node) {
|
||||||
|
return [print("struct"), printArrayLike(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.ArrayPattern](print, node) {
|
||||||
|
return printArrayLike(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.ReferencePattern](print, node) {
|
||||||
|
return ["&", print.b("mut"), print("pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.BoxPattern](print, node) {
|
||||||
|
return ["box ", print("pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.MinusPattern](print, node) {
|
||||||
|
return ["-", print("pattern")];
|
||||||
|
},
|
||||||
|
[NodeType.RangePattern](print, node) {
|
||||||
|
return [print("lower"), "..", print.b("last", "="), print("upper")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeCall](print, node) {
|
||||||
|
return [print("typeCallee"), printTypeArguments(print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.TypeCallNamedArgument](print, node) {
|
||||||
|
return printAssignment(print("target"), " =", "typeExpression");
|
||||||
|
},
|
||||||
|
[NodeType.TypeCallNamedBound](print, node) {
|
||||||
|
return [print("typeTarget"), printTypeBounds(":", print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.LtElided](print, node) {
|
||||||
|
return "'_";
|
||||||
|
},
|
||||||
|
[NodeType.LtStatic](print, node) {
|
||||||
|
return "'static";
|
||||||
|
},
|
||||||
|
[NodeType.TypeNever](print, node) {
|
||||||
|
return "!";
|
||||||
|
},
|
||||||
|
[NodeType.TypeInferred](print, node) {
|
||||||
|
return "_";
|
||||||
|
},
|
||||||
|
[NodeType.GenericTypeParameterDeclaration](print, node) {
|
||||||
|
return printAssignment(
|
||||||
|
[print("id"), printTypeBounds(":", print, node)], //
|
||||||
|
" =",
|
||||||
|
"typeDefault"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[NodeType.ConstTypeParameterDeclaration](print, node) {
|
||||||
|
return [
|
||||||
|
"const ",
|
||||||
|
printAssignment(
|
||||||
|
[print("id"), printTypeAnnotation(print, node)], //
|
||||||
|
" =",
|
||||||
|
"typeDefault"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[NodeType.GenericLtParameterDeclaration](print, node) {
|
||||||
|
return [print("id"), printLtBounds(":", print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.WhereTypeBoundDeclaration](print, node) {
|
||||||
|
return [printLtParameters(print, node), print("typeTarget"), printTypeBounds(":", print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.WhereLtBoundDeclaration](print, node) {
|
||||||
|
return [print("ltTarget"), printLtBounds(":", print, node)];
|
||||||
|
},
|
||||||
|
[NodeType.TypeTraitBound](print, node) {
|
||||||
|
return [print.b("maybeConst", "~const "), print.b("optional", "?"), printLtParameters(print, node), print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeDynBounds](print, node) {
|
||||||
|
return printTypeBounds("dyn", print, node);
|
||||||
|
},
|
||||||
|
[NodeType.TypeImplBounds](print, node) {
|
||||||
|
return printTypeBounds("impl", print, node);
|
||||||
|
},
|
||||||
|
[NodeType.TypeFnPointer](print, node) {
|
||||||
|
return [printLtParameters(print, node), print.b("unsafe"), print("extern"), "fn", printParametersAndReturnType(node)];
|
||||||
|
},
|
||||||
|
[NodeType.TypeFnPointerParameter](print, node) {
|
||||||
|
return [f`${print("id")}: `, print("typeAnnotation")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeFunction](print, node) {
|
||||||
|
return [print("callee"), printParametersAndReturnType(node)];
|
||||||
|
},
|
||||||
|
[NodeType.TypeTuple](print, node) {
|
||||||
|
return printArrayLike(print, node);
|
||||||
|
},
|
||||||
|
[NodeType.TypeSizedArray](print, node) {
|
||||||
|
return sg_duo`[${print("typeExpression")};${print("sizeExpression")}]`;
|
||||||
|
if (isSimpleType(node)) return ["[", print("typeExpression"), "; ", print("sizeExpression"), "]"];
|
||||||
|
},
|
||||||
|
[NodeType.TypeSlice](print, node) {
|
||||||
|
if (isSimpleType(node)) return ["[", print("typeExpression"), "]"];
|
||||||
|
return sg_single`[${print("typeExpression")}]`;
|
||||||
|
},
|
||||||
|
[NodeType.TypeReference](print, node) {
|
||||||
|
return ["&", f`${print("lt")} `, print.b("mut"), print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeDereferenceConst](print, node) {
|
||||||
|
return ["*const ", print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeDereferenceMut](print, node) {
|
||||||
|
return ["*mut ", print("typeExpression")];
|
||||||
|
},
|
||||||
|
[NodeType.TypeParenthesized](print, node) {
|
||||||
|
exit.never();
|
||||||
|
return sg_single`(${print("typeExpression")})`;
|
||||||
|
},
|
||||||
|
};
|
||||||
645
frontend/src/utils/prettier/plugins/rust/format/styling.ts
Normal file
645
frontend/src/utils/prettier/plugins/rust/format/styling.ts
Normal file
@@ -0,0 +1,645 @@
|
|||||||
|
import {
|
||||||
|
ClosureFunctionExpression,
|
||||||
|
ComparisonExpression,
|
||||||
|
ConditionExpression,
|
||||||
|
EnumDeclaration,
|
||||||
|
EnumMemberStructDeclaration,
|
||||||
|
ExpressionAsTypeCast,
|
||||||
|
ExpressionNode,
|
||||||
|
ExpressionStatement,
|
||||||
|
ExpressionWithBody,
|
||||||
|
LeftRightExpression,
|
||||||
|
LogicalExpression,
|
||||||
|
MacroDeclaration,
|
||||||
|
MacroRulesDeclaration,
|
||||||
|
MissingNode,
|
||||||
|
Node,
|
||||||
|
NodeType,
|
||||||
|
NodeWithBody,
|
||||||
|
NodeWithBodyOrCases,
|
||||||
|
OperationExpression,
|
||||||
|
PRCD,
|
||||||
|
StructDeclaration,
|
||||||
|
StructLiteral,
|
||||||
|
StructPattern,
|
||||||
|
TK,
|
||||||
|
UnionDeclaration,
|
||||||
|
} from "jinx-rust";
|
||||||
|
import {
|
||||||
|
can_have_OuterAttributes,
|
||||||
|
getAstPath,
|
||||||
|
getPrecedence,
|
||||||
|
hasAttributes,
|
||||||
|
hasBody,
|
||||||
|
hasCondition,
|
||||||
|
hasItems,
|
||||||
|
hasLetScrutineeCondition,
|
||||||
|
hasOuterAttributes,
|
||||||
|
hasProperties,
|
||||||
|
is_Attribute,
|
||||||
|
is_AttributeOrDocComment,
|
||||||
|
is_AwaitExpression,
|
||||||
|
is_BitwiseOperator,
|
||||||
|
is_CallExpression,
|
||||||
|
is_ClosureFunctionExpression,
|
||||||
|
is_ComparisonExpression,
|
||||||
|
is_DocCommentAttribute,
|
||||||
|
is_ElseBlock,
|
||||||
|
is_EnumMemberDeclaration,
|
||||||
|
is_EqualityOperator,
|
||||||
|
is_ExpressionAsTypeCast,
|
||||||
|
is_ExpressionStatement,
|
||||||
|
is_ExpressionWithBody,
|
||||||
|
is_ExpressionWithBodyOrCases,
|
||||||
|
is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation,
|
||||||
|
is_FlowControlExpression,
|
||||||
|
is_FlowControlMaybeValueExpression,
|
||||||
|
is_ForInBlockExpression,
|
||||||
|
is_Identifier,
|
||||||
|
is_IfBlockExpression,
|
||||||
|
is_ImplicitReturnAbleNode,
|
||||||
|
is_LeftRightExpression,
|
||||||
|
is_LetScrutinee,
|
||||||
|
is_Literal,
|
||||||
|
is_LiteralNumberLike,
|
||||||
|
is_LogicalExpression,
|
||||||
|
is_LoopBlockExpression,
|
||||||
|
is_MatchExpression,
|
||||||
|
is_MatchExpressionCase,
|
||||||
|
is_MemberExpression,
|
||||||
|
is_NodeWithBodyNoBody,
|
||||||
|
is_NodeWithMaybePatternNoUnionBody,
|
||||||
|
is_OperationExpression,
|
||||||
|
is_ParenthesizedNode,
|
||||||
|
is_PatternVariableDeclaration,
|
||||||
|
is_PostfixExpression,
|
||||||
|
is_RangeLiteral,
|
||||||
|
is_ReassignmentNode,
|
||||||
|
is_ReturnExpression,
|
||||||
|
is_StatementNode,
|
||||||
|
is_StructLiteral,
|
||||||
|
is_StructLiteralProperty,
|
||||||
|
is_StructPatternProperty,
|
||||||
|
is_StructPropertyDeclaration,
|
||||||
|
is_TypeBoundsStandaloneNode,
|
||||||
|
is_TypeFunctionNode,
|
||||||
|
is_TypeTraitBound,
|
||||||
|
is_UnaryExpression,
|
||||||
|
is_UnaryType,
|
||||||
|
is_UnionPattern,
|
||||||
|
is_WhileBlockExpression,
|
||||||
|
is_YieldExpression,
|
||||||
|
is_bitshiftOperator,
|
||||||
|
is_multiplicativeOperator,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import { BlockLikeMacroInvocation, is_BlockLikeMacroInvocation, is_CallExpression_or_CallLikeMacroInvocation } from "../transform";
|
||||||
|
import { exit, last_of } from "../utils/common";
|
||||||
|
import { CF, hasBreaklineAfter, hasComment } from "./comments";
|
||||||
|
import { flowControlExpressionNeedsOuterParens } from "./core";
|
||||||
|
import { Doc, hardline, softline, willBreak } from "./external";
|
||||||
|
import {
|
||||||
|
assertPathAtNode,
|
||||||
|
getContext,
|
||||||
|
getGrandParentNode,
|
||||||
|
getNode,
|
||||||
|
getOptions,
|
||||||
|
getParentNode,
|
||||||
|
getPrintFn,
|
||||||
|
is_printing_macro,
|
||||||
|
pathCallAtParent,
|
||||||
|
pathCallParentOf,
|
||||||
|
stackIncludes,
|
||||||
|
} from "./plugin";
|
||||||
|
|
||||||
|
export function needsOuterSoftbreakParens(node: Node) {
|
||||||
|
const parent = getParentNode(node);
|
||||||
|
|
||||||
|
if (!parent) return false;
|
||||||
|
|
||||||
|
if (is_ExpressionAsTypeCast(node)) {
|
||||||
|
return precedenceNeedsParens(node, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
is_FlowControlMaybeValueExpression(parent) && //
|
||||||
|
parent.expression === node &&
|
||||||
|
flowControlExpressionNeedsOuterParens(parent)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node) &&
|
||||||
|
(false ||
|
||||||
|
(is_MemberExpression(parent) && parent.expression === node) ||
|
||||||
|
(is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(parent) && !is_ElseBlock(node, parent)))
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_UnionPattern(node) && is_NodeWithMaybePatternNoUnionBody(parent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasComment(node)) {
|
||||||
|
if (is_UnaryExpression(parent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasComment(node, CF.Line)) {
|
||||||
|
if (is_ReturnExpression(parent) || (is_YieldExpression(parent) && parent.expression === node)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
hasComment(node, CF.Leading, (comment) => is_Attribute(comment) && !comment.inner) &&
|
||||||
|
!can_have_OuterAttributes(node, parent, true)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function needsInnerParens(node: Node) {
|
||||||
|
if (needsOuterSoftbreakParens(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = getParentNode(node);
|
||||||
|
|
||||||
|
if (!parent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_Identifier(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_Literal(node)) {
|
||||||
|
return is_LiteralNumberLike(node) && is_MemberExpression(parent) && node === parent.expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_CallExpression(parent) && parent.callee === node && is_MemberExpression(node)) {
|
||||||
|
return !getOptions().actuallyMethodNodes.has(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ReassignmentNode(node)) {
|
||||||
|
if (is_printing_macro()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ClosureFunctionExpression(parent) && node === parent.expression) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ExpressionStatement(parent)) {
|
||||||
|
return is_StructLiteral(node.left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ReassignmentNode(parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ParenthesizedNode(parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ExpressionStatement(parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_RangeLiteral(node)) {
|
||||||
|
return (
|
||||||
|
is_ExpressionAsTypeCast(parent) ||
|
||||||
|
is_LogicalExpression(parent) ||
|
||||||
|
is_UnaryExpression(parent) ||
|
||||||
|
is_PostfixExpression(parent) ||
|
||||||
|
(is_MemberExpression(parent) && node === parent.expression) ||
|
||||||
|
(is_CallExpression(parent) && node === parent.callee) ||
|
||||||
|
is_OperationExpression(parent) ||
|
||||||
|
is_ComparisonExpression(parent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_LetScrutinee(parent) && is_LogicalExpression(node) && parent.expression === (node as any)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_UnaryExpression(node)) {
|
||||||
|
switch (parent.nodeType) {
|
||||||
|
case NodeType.MemberExpression:
|
||||||
|
case NodeType.AwaitExpression:
|
||||||
|
return node === parent.expression;
|
||||||
|
case NodeType.CallExpression:
|
||||||
|
return node === parent.callee;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node)) {
|
||||||
|
if (is_ExpressionWithBodyOrCases(parent)) {
|
||||||
|
return !is_ElseBlock(node, parent);
|
||||||
|
}
|
||||||
|
if (is_LetScrutinee(parent) && parent.expression === node && is_ExpressionWithBodyOrCases(getGrandParentNode())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
is_ExpressionAsTypeCast(parent) ||
|
||||||
|
is_LogicalExpression(parent) ||
|
||||||
|
is_UnaryExpression(parent) ||
|
||||||
|
is_PostfixExpression(parent) ||
|
||||||
|
(is_MemberExpression(parent) && node === parent.expression) ||
|
||||||
|
(is_CallExpression(parent) && node === parent.callee) ||
|
||||||
|
is_OperationExpression(parent) ||
|
||||||
|
is_ComparisonExpression(parent) ||
|
||||||
|
is_RangeLiteral(parent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_StructLiteral(node)) {
|
||||||
|
if (is_ExpressionWithBodyOrCases(parent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_LetScrutinee(parent) && parent.expression === node && is_ExpressionWithBodyOrCases(getGrandParentNode())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (is_UnaryExpression(parent) || is_PostfixExpression(parent) || is_MemberExpression(parent)) {
|
||||||
|
return parent.expression === node;
|
||||||
|
}
|
||||||
|
if (is_CallExpression(parent)) {
|
||||||
|
return parent.callee === node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_LogicalExpression(node) || is_OperationExpression(node) || is_ComparisonExpression(node) || is_ClosureFunctionExpression(node)) {
|
||||||
|
return precedenceNeedsParens(node, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_TypeFunctionNode(node)) {
|
||||||
|
const gp = getGrandParentNode();
|
||||||
|
if (node.returnType && is_TypeTraitBound(parent) && is_TypeBoundsStandaloneNode(gp) && last_of(gp.typeBounds) !== parent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_TypeBoundsStandaloneNode(node)) {
|
||||||
|
return (
|
||||||
|
(is_UnaryType(parent) && node.typeBounds.length > 1) ||
|
||||||
|
is_TypeBoundsStandaloneNode(parent) ||
|
||||||
|
is_TypeTraitBound(parent) ||
|
||||||
|
(is_TypeFunctionNode(parent) && parent.returnType === node)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_PatternVariableDeclaration(parent)) {
|
||||||
|
return is_UnionPattern(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function precedenceNeedsParens(node: LeftRightExpression | ClosureFunctionExpression | ExpressionAsTypeCast, parent: Node) {
|
||||||
|
if (is_UnaryExpression(parent) || is_PostfixExpression(parent)) return true;
|
||||||
|
if (is_ReassignmentNode(parent)) return parent.left === node;
|
||||||
|
if (is_MemberExpression(parent)) return parent.expression === node;
|
||||||
|
if (is_CallExpression(parent)) return parent.callee === node;
|
||||||
|
if (is_ExpressionAsTypeCast(parent)) return !is_ExpressionAsTypeCast(node);
|
||||||
|
if (is_LogicalExpression(parent)) return is_LogicalExpression(node) ? parent.nodeType !== node.nodeType : evalPrecedence(node, parent);
|
||||||
|
if (is_OperationExpression(parent) || is_ComparisonExpression(parent)) return evalPrecedence(node, parent);
|
||||||
|
return false;
|
||||||
|
function evalPrecedence(
|
||||||
|
child: LeftRightExpression | ClosureFunctionExpression | ExpressionAsTypeCast,
|
||||||
|
parent: ComparisonExpression | OperationExpression | LogicalExpression
|
||||||
|
) {
|
||||||
|
if (is_ExpressionAsTypeCast(child) || is_ClosureFunctionExpression(child)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function getPrec(node, bool) {
|
||||||
|
// if (is_EqualityOperator(node.tk)) {
|
||||||
|
// return 11.3;
|
||||||
|
// }
|
||||||
|
// if (is_LargerLesserOperator(node.tk)) {
|
||||||
|
// return 11.6;
|
||||||
|
// }
|
||||||
|
return getPrecedence(node, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
const childPRCD = getPrec(child, is_insideScrutinee(child));
|
||||||
|
const parentPRCD = getPrec(parent, is_insideScrutinee(parent));
|
||||||
|
|
||||||
|
if (parentPRCD > childPRCD) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentPRCD === childPRCD && parent.right === child) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentPRCD === childPRCD && !shouldFlatten(parent, child)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentPRCD < childPRCD && child.tk === TK["%"]) {
|
||||||
|
return parentPRCD === PRCD["+-"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_BitwiseOperator(parent.tk) || (is_BitwiseOperator(child.tk) && is_EqualityOperator(parent.tk))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldFlatten(parent: ExpressionNode | ConditionExpression, node: ExpressionNode | ConditionExpression) {
|
||||||
|
if (getPrecedence(node, is_insideScrutinee(node)) !== getPrecedence(parent, is_insideScrutinee(parent))) return false;
|
||||||
|
if (is_ComparisonExpression(parent) && is_ComparisonExpression(node)) return false;
|
||||||
|
if (is_OperationExpression(parent) && is_OperationExpression(node)) {
|
||||||
|
if (
|
||||||
|
(node.tk === TK["%"] && is_multiplicativeOperator(parent.tk)) ||
|
||||||
|
(parent.tk === TK["%"] && is_multiplicativeOperator(node.tk)) ||
|
||||||
|
(node.tk !== parent.tk && is_multiplicativeOperator(node.tk) && is_multiplicativeOperator(parent.tk)) ||
|
||||||
|
(is_bitshiftOperator(node.tk) && is_bitshiftOperator(parent.tk))
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function needsParens(node: Node) {
|
||||||
|
return needsOuterSoftbreakParens(node) || needsInnerParens(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stmtNeedsSemi(stmt: ExpressionStatement, disregardExprType = false) {
|
||||||
|
return pathCallParentOf(stmt, (parent) => needsSemi(parent as any, stmt, disregardExprType));
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoNode = { nodeType: 0 } as MissingNode;
|
||||||
|
|
||||||
|
export function needsSemi(parent: NodeWithBody, stmt: ExpressionStatement, disregardExprType = false) {
|
||||||
|
const expr = disregardExprType ? NoNode : stmt.expression!;
|
||||||
|
const hadSemi = !disregardExprType && stmt.semi;
|
||||||
|
|
||||||
|
return (
|
||||||
|
!!expr &&
|
||||||
|
(forcePreserveSemi()
|
||||||
|
? true
|
||||||
|
: shouldNeverSemi()
|
||||||
|
? false
|
||||||
|
: shouldPreserveSemi()
|
||||||
|
? hadSemi || shouldAlwaysSemi() || canAutoCompleteSemi()
|
||||||
|
: true)
|
||||||
|
);
|
||||||
|
|
||||||
|
function forcePreserveSemi() {
|
||||||
|
/** Rust Compiler bug (preserve optional semicolon) */
|
||||||
|
// rust-lang/rust#70844 https://github.com/rust-lang/rust/issues/70844
|
||||||
|
// issue#22 https://github.com/jinxdash/prettier-plugin-rust/issues/22
|
||||||
|
return (
|
||||||
|
hadSemi &&
|
||||||
|
stmt === last_of(parent.body!) &&
|
||||||
|
((is_IfBlockExpression(expr) &&
|
||||||
|
hasLetScrutineeCondition(expr) &&
|
||||||
|
!(is_LetScrutinee(expr.condition) && is_Identifier(expr.condition.expression))) ||
|
||||||
|
(is_MatchExpression(expr) && !is_Identifier(expr.expression)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function shouldNeverSemi() {
|
||||||
|
return is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(expr);
|
||||||
|
}
|
||||||
|
function shouldPreserveSemi() {
|
||||||
|
return stmt === last_of(parent.body!) && (is_ImplicitReturnAbleNode(parent) || is_BlockLikeMacroInvocation(parent));
|
||||||
|
}
|
||||||
|
function shouldAlwaysSemi() {
|
||||||
|
return is_FlowControlExpression(expr) || is_ReassignmentNode(expr);
|
||||||
|
}
|
||||||
|
function canAutoCompleteSemi() {
|
||||||
|
return withPathAt(parent, function checkParent(child: NodeWithBodyOrCases): boolean {
|
||||||
|
return pathCallParentOf(child, (parent) => {
|
||||||
|
if (is_IfBlockExpression(parent) && parent.else === child) {
|
||||||
|
// if ... { ... } else if { ... } ...
|
||||||
|
// ^ ------------------------------- parent
|
||||||
|
// ^ ----------- child
|
||||||
|
return checkParent(parent);
|
||||||
|
}
|
||||||
|
if (is_ExpressionStatement(parent)) {
|
||||||
|
// { .... { ... } ... }
|
||||||
|
// ^ -----------------^ grandparent
|
||||||
|
// ^ --- ^ ExpressionStatement<child>
|
||||||
|
if (hasOuterAttributes(parent)) return false;
|
||||||
|
return stmtNeedsSemi(parent, true);
|
||||||
|
}
|
||||||
|
if (is_MatchExpressionCase(parent) && parent.expression === child) {
|
||||||
|
return pathCallParentOf(parent, checkParent);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canInlineBlockBody(node: NodeWithBodyOrCases | BlockLikeMacroInvocation): boolean {
|
||||||
|
if (!is_ExpressionWithBody(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const body = node.body;
|
||||||
|
|
||||||
|
if (body.length === 0) {
|
||||||
|
return canInlineInlineable(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.length === 1) {
|
||||||
|
const stmt = body[0];
|
||||||
|
if (is_AttributeOrDocComment(stmt)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (is_ExpressionStatement(stmt) && !needsSemi(node, stmt)) {
|
||||||
|
/**
|
||||||
|
* parent ( ExpressionStatement | StructLiteralProperty | LetVariableDeclaration | ... )
|
||||||
|
* ...
|
||||||
|
* node {
|
||||||
|
* expr
|
||||||
|
* }
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Q: Can you inline "node { expr }" ?
|
||||||
|
*/
|
||||||
|
const expr = stmt.expression!;
|
||||||
|
|
||||||
|
if (
|
||||||
|
is_FlowControlExpression(expr) || //
|
||||||
|
is_ClosureFunctionExpression(expr) ||
|
||||||
|
is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(expr)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return canInlineInlineable(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// function q(node: ExpressionWithBody) {
|
||||||
|
// pathCallTopMostIfBlockExpression(node, (node) => {});
|
||||||
|
// }
|
||||||
|
|
||||||
|
function canInlineInlineable(node: ExpressionWithBody) {
|
||||||
|
if (is_ForInBlockExpression(node) || is_LoopBlockExpression(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (is_WhileBlockExpression(node)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = getParentNode(node)!;
|
||||||
|
|
||||||
|
if (
|
||||||
|
is_ExpressionStatement(parent) &&
|
||||||
|
(!is_ImplicitReturnAbleNode(node) || pathCallAtParent(parent, (parent) => stmtNeedsSemi(parent, true)))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ElseBlock(node, parent)) {
|
||||||
|
return pathCallAtParent(parent, canInlineBlockBody);
|
||||||
|
}
|
||||||
|
// if (is_CaseBlock(node, parent)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
if (is_IfBlockExpression(node)) {
|
||||||
|
if (
|
||||||
|
!node.else ||
|
||||||
|
// hasLetScrutineeCondition(node) ||
|
||||||
|
is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node.condition) ||
|
||||||
|
willBreak(getPrintFn(node)("condition"))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const grandparent = getGrandParentNode();
|
||||||
|
if (is_ExpressionStatement(parent) && hasBody(grandparent) && grandparent.body.length > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
return (
|
||||||
|
is_CallExpression_or_CallLikeMacroInvocation(parent) ||
|
||||||
|
hasItems(parent) ||
|
||||||
|
hasProperties(parent) ||
|
||||||
|
is_ClosureFunctionExpression(parent) ||
|
||||||
|
is_MemberExpression(parent) ||
|
||||||
|
is_AwaitExpression(parent) ||
|
||||||
|
is_LeftRightExpression(parent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeWithBracketContent =
|
||||||
|
| NodeWithBodyOrCases
|
||||||
|
| BlockLikeMacroInvocation
|
||||||
|
| EnumDeclaration
|
||||||
|
| StructDeclaration
|
||||||
|
| StructLiteral
|
||||||
|
| StructPattern
|
||||||
|
| EnumMemberStructDeclaration
|
||||||
|
| UnionDeclaration
|
||||||
|
| MacroRulesDeclaration
|
||||||
|
| MacroDeclaration;
|
||||||
|
|
||||||
|
export function emptyContent(node: NodeWithBracketContent): Doc {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case NodeType.Program:
|
||||||
|
case NodeType.MacroRulesDeclaration:
|
||||||
|
case NodeType.MacroDeclaration:
|
||||||
|
case NodeType.ExternBlockDeclaration:
|
||||||
|
case NodeType.ModuleDeclaration:
|
||||||
|
case NodeType.TraitDeclaration:
|
||||||
|
case NodeType.StructDeclaration:
|
||||||
|
case NodeType.MacroInvocation:
|
||||||
|
case NodeType.FunctionDeclaration:
|
||||||
|
case NodeType.ImplDeclaration:
|
||||||
|
case NodeType.UnionDeclaration:
|
||||||
|
case NodeType.EnumDeclaration:
|
||||||
|
case NodeType.EnumMemberStructDeclaration:
|
||||||
|
case NodeType.StructLiteral:
|
||||||
|
case NodeType.StructPattern:
|
||||||
|
// case NodeType.MatchExpression:
|
||||||
|
return "";
|
||||||
|
case NodeType.BlockExpression:
|
||||||
|
case NodeType.WhileBlockExpression:
|
||||||
|
case NodeType.ForInBlockExpression:
|
||||||
|
case NodeType.TryBlockExpression:
|
||||||
|
case NodeType.IfBlockExpression:
|
||||||
|
return canInlineInlineable(node)
|
||||||
|
? is_IfBlockExpression(node) || is_ElseBlock(node, getParentNode()!)
|
||||||
|
? softline
|
||||||
|
: ""
|
||||||
|
: hardline;
|
||||||
|
case NodeType.LoopBlockExpression:
|
||||||
|
case NodeType.MatchExpression:
|
||||||
|
return hardline;
|
||||||
|
default:
|
||||||
|
if (is_NodeWithBodyNoBody(node)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
__DEV__: exit.never(node);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function is_insideScrutinee(target: Node) {
|
||||||
|
return withPathAt(target, (n) => stackIncludes("condition") && r(n));
|
||||||
|
function r(CHILD: Node) {
|
||||||
|
switch (CHILD.nodeType) {
|
||||||
|
case NodeType.OrExpression:
|
||||||
|
case NodeType.AndExpression:
|
||||||
|
return pathCallParentOf(CHILD, (PARENT) =>
|
||||||
|
hasCondition(PARENT) && PARENT.condition === CHILD //
|
||||||
|
? hasLetScrutineeCondition(PARENT)
|
||||||
|
: r(PARENT)
|
||||||
|
);
|
||||||
|
case NodeType.LetScrutinee:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function withPathAt<T extends Node, R>(target: T, callback: (target: T) => R): R {
|
||||||
|
if (target === getNode()) return callback(target);
|
||||||
|
if (target === getParentNode()) return pathCallAtParent(target, () => callback(target));
|
||||||
|
if (stackIncludes(target)) return pathCallAtParent(getParentNode()!, () => withPathAt(target, callback));
|
||||||
|
return getContext().path.call(() => {
|
||||||
|
__DEV__: assertPathAtNode("withPathAt", target);
|
||||||
|
return callback(target); // @ts-ignore
|
||||||
|
}, ...getAstPath(getNode(), target));
|
||||||
|
}
|
||||||
|
export function shouldPrintOuterAttributesAbove(node: Node) {
|
||||||
|
return (
|
||||||
|
is_StatementNode(node) ||
|
||||||
|
is_MatchExpressionCase(node) ||
|
||||||
|
(hasAttributes(node) &&
|
||||||
|
node.attributes.some(
|
||||||
|
canInlineOuterAttribute(node)
|
||||||
|
? (attr) => is_DocCommentAttribute(attr) || hasBreaklineAfter(attr) //
|
||||||
|
: is_DocCommentAttribute
|
||||||
|
))
|
||||||
|
);
|
||||||
|
function canInlineOuterAttribute(node: Node) {
|
||||||
|
return (
|
||||||
|
is_EnumMemberDeclaration(node) ||
|
||||||
|
is_StructPropertyDeclaration(node) ||
|
||||||
|
is_StructLiteralProperty(node) ||
|
||||||
|
is_StructPatternProperty(node)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
frontend/src/utils/prettier/plugins/rust/index.ts
Normal file
8
frontend/src/utils/prettier/plugins/rust/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { plugin } from "./format/plugin";
|
||||||
|
|
||||||
|
export default plugin;
|
||||||
|
export const languages = plugin.languages;
|
||||||
|
export const parsers = plugin.parsers;
|
||||||
|
export const printers = plugin.printers;
|
||||||
|
export const options = plugin.options;
|
||||||
|
export const defaultOptions = plugin.defaultOptions;
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import {
|
||||||
|
AttrSegment,
|
||||||
|
CallExpression,
|
||||||
|
DelimKind,
|
||||||
|
ExpressionPath,
|
||||||
|
Identifier,
|
||||||
|
Literal,
|
||||||
|
LocArray,
|
||||||
|
MacroInvocation,
|
||||||
|
NodeType,
|
||||||
|
PunctuationToken,
|
||||||
|
ReassignmentExpression,
|
||||||
|
TK,
|
||||||
|
rs,
|
||||||
|
} from "jinx-rust";
|
||||||
|
import { isTK, start } from "jinx-rust/utils";
|
||||||
|
import { assert, exit } from "../../utils/common";
|
||||||
|
import { isIdent } from "./utils";
|
||||||
|
|
||||||
|
type SimpleAttrItem =
|
||||||
|
| Identifier //
|
||||||
|
| Literal
|
||||||
|
| ExpressionPath
|
||||||
|
| CallExpression
|
||||||
|
| ReassignmentExpression
|
||||||
|
| MacroInvocation;
|
||||||
|
|
||||||
|
export function transform_simpleAttrSyntax(segments: MacroInvocation["segments"]) {
|
||||||
|
assert(segments.length !== 0, segments.loc.url());
|
||||||
|
return transform_segments(segments, false);
|
||||||
|
|
||||||
|
function transform_segments<N extends boolean>(
|
||||||
|
seq: LocArray<AttrSegment>,
|
||||||
|
nestedCall: N
|
||||||
|
): N extends true ? LocArray<SimpleAttrItem, "()"> : SimpleAttrItem {
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
if (nestedCall) {
|
||||||
|
const args = rs.createLocArray<SimpleAttrItem, any>(DelimKind["()"], seq.loc.clone());
|
||||||
|
while (i !== seq.length) {
|
||||||
|
args.push(read(true));
|
||||||
|
if (i === seq.length) break;
|
||||||
|
assert(isTK(seq[i++], TK[","]));
|
||||||
|
}
|
||||||
|
return args as any;
|
||||||
|
} else {
|
||||||
|
const res = read(true);
|
||||||
|
assert(i === seq.length, res.loc.url());
|
||||||
|
return res as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function read(allowEq: boolean): SimpleAttrItem {
|
||||||
|
let lhs: Identifier | ExpressionPath;
|
||||||
|
|
||||||
|
switch (seq[i].nodeType) {
|
||||||
|
case NodeType.Literal:
|
||||||
|
return seq[i++] as Literal;
|
||||||
|
case NodeType.Identifier:
|
||||||
|
lhs = seq[i++] as Identifier;
|
||||||
|
break;
|
||||||
|
case NodeType.PunctuationToken:
|
||||||
|
assert((seq[i] as PunctuationToken).tk === TK["::"], seq[i].loc.url());
|
||||||
|
lhs = eatPathSegment(undefined);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit.never();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (i === seq.length) return lhs;
|
||||||
|
const seg = seq[i];
|
||||||
|
switch (seg.nodeType) {
|
||||||
|
case NodeType.PunctuationToken:
|
||||||
|
switch (seg.tk) {
|
||||||
|
case TK[","]:
|
||||||
|
assert(nestedCall);
|
||||||
|
return lhs;
|
||||||
|
case TK["="]: {
|
||||||
|
assert(allowEq);
|
||||||
|
const right = (i++, read(false));
|
||||||
|
return rs.mockNode(NodeType.ReassignmentExpression, right.loc.cloneFrom(start(lhs)), {
|
||||||
|
tk: TK["="],
|
||||||
|
kind: DelimKind["="],
|
||||||
|
left: lhs,
|
||||||
|
right,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
case TK["::"]:
|
||||||
|
lhs = eatPathSegment(lhs);
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
exit.never();
|
||||||
|
}
|
||||||
|
case NodeType.DelimGroup:
|
||||||
|
assert(seg.segments.dk === DelimKind["()"]);
|
||||||
|
return rs.mockNode(NodeType.CallExpression, seq[i++].loc.cloneFrom(start(lhs)), {
|
||||||
|
callee: lhs,
|
||||||
|
typeArguments: undefined,
|
||||||
|
method: undefined,
|
||||||
|
arguments: transform_segments(seg.segments, true),
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
exit.never();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function eatPathSegment(left: undefined | Identifier | ExpressionPath) {
|
||||||
|
const segment = seq[i + 1];
|
||||||
|
assert(isIdent(segment));
|
||||||
|
const res = rs.mockNode(NodeType.ExpressionPath, segment.loc.cloneFrom(start(left ?? seq[i])), { namespace: left, segment });
|
||||||
|
i += 2;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import {
|
||||||
|
DelimGroup,
|
||||||
|
DelimKind,
|
||||||
|
IfBlockExpression,
|
||||||
|
LocArray,
|
||||||
|
MacroInvocation,
|
||||||
|
NodeType,
|
||||||
|
NodeWithBody,
|
||||||
|
rs,
|
||||||
|
Segment,
|
||||||
|
Snippet,
|
||||||
|
StatementNode,
|
||||||
|
TK,
|
||||||
|
} from "jinx-rust";
|
||||||
|
import { insertNodes, start, transferAttributes } from "jinx-rust/utils";
|
||||||
|
import { assert, iLast } from "../../utils/common";
|
||||||
|
import { isGroup, isIdent, isToken } from "./utils";
|
||||||
|
|
||||||
|
export function transform_macro_cfg_if(segments: MacroInvocation["segments"]) {
|
||||||
|
const danglingAttributes: Snippet["danglingAttributes"] = [];
|
||||||
|
const comments: Snippet["comments"] = [];
|
||||||
|
|
||||||
|
const block = (function create_if_block(i: number): IfBlockExpression | undefined {
|
||||||
|
if (i >= segments.length) return undefined;
|
||||||
|
|
||||||
|
const _if = segments[i];
|
||||||
|
const pound = segments[i + 1];
|
||||||
|
const grp = segments[i + 2];
|
||||||
|
const block = segments[i + 3];
|
||||||
|
const _else = segments[i + 4];
|
||||||
|
|
||||||
|
assert(
|
||||||
|
isIdent(_if, "if") &&
|
||||||
|
isToken(pound, TK["#"]) &&
|
||||||
|
isGroup(grp, DelimKind["[]"]) &&
|
||||||
|
isGroup(block, DelimKind["{}"]) &&
|
||||||
|
(!_else || isIdent(_else, "else"))
|
||||||
|
);
|
||||||
|
|
||||||
|
return create_block(block, (body) =>
|
||||||
|
rs.mockNode(NodeType.IfBlockExpression, block.loc.cloneFrom(start(_if)), {
|
||||||
|
label: undefined,
|
||||||
|
condition: rs.mockNode(NodeType.Attribute, grp.loc.cloneFrom(start(pound)), {
|
||||||
|
segments: grp.segments,
|
||||||
|
value: grp.segments.loc.sliceText(),
|
||||||
|
line: false,
|
||||||
|
inner: false,
|
||||||
|
}) as any,
|
||||||
|
body: body,
|
||||||
|
else: (_else && iLast(i + 5, segments)
|
||||||
|
? function create_else_block(i: number) {
|
||||||
|
const block = segments[i];
|
||||||
|
assert(isGroup(block, DelimKind["{}"]));
|
||||||
|
return create_block(block, (body) =>
|
||||||
|
rs.mockNode(NodeType.BlockExpression, body.loc.clone(), {
|
||||||
|
label: undefined,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: create_if_block)(i + 5),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})(0);
|
||||||
|
|
||||||
|
const ast = rs.createLocArray(
|
||||||
|
segments.dk,
|
||||||
|
segments.loc,
|
||||||
|
block && [
|
||||||
|
rs.mockNode(NodeType.ExpressionStatement, block.loc.clone(), {
|
||||||
|
expression: block,
|
||||||
|
semi: false,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return rs.mockNode(NodeType.Snippet, segments.loc.clone(), { ast, danglingAttributes, comments });
|
||||||
|
|
||||||
|
function create_block<R extends NodeWithBody>(
|
||||||
|
group: DelimGroup<Segment> & { segments: { dk: 3 } },
|
||||||
|
fn: (statements: LocArray<StatementNode, "{}">) => R
|
||||||
|
): R {
|
||||||
|
const snippet = rs.toBlockBody(group.segments);
|
||||||
|
|
||||||
|
insertNodes(danglingAttributes, snippet.danglingAttributes);
|
||||||
|
insertNodes(comments, snippet.comments);
|
||||||
|
|
||||||
|
const block = fn(snippet.ast);
|
||||||
|
transferAttributes(snippet, block);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { DelimGroup, DelimKind, Identifier, LocArray, PunctuationToken, Segment, TK } from "jinx-rust";
|
||||||
|
import { isTK, is_DelimGroup, is_Identifier, is_PunctuationToken } from "jinx-rust/utils";
|
||||||
|
|
||||||
|
export function isIdent(node: Segment | undefined, name?: string): node is Identifier {
|
||||||
|
return !!node && is_Identifier(node) && (null == name || node.name === name);
|
||||||
|
}
|
||||||
|
export function isToken(node: Segment | undefined, tk?: TK): node is PunctuationToken {
|
||||||
|
return !!node && (null == tk ? is_PunctuationToken(node) : isTK(node, tk));
|
||||||
|
}
|
||||||
|
export function isGroup<D extends DelimKind>(node: Segment | undefined, dk?: D): node is DelimGroup & { segments: LocArray<any, D> } {
|
||||||
|
return !!node && is_DelimGroup(node) && (null == dk || node.segments.dk === dk);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCallLike(tk_1: Segment | undefined, tk_2: Segment | undefined): boolean {
|
||||||
|
return !!tk_1 && !!tk_2 && is_Identifier(tk_1) && is_DelimGroup(tk_2) && tk_2.segments.dk === DelimKind["()"];
|
||||||
|
}
|
||||||
568
frontend/src/utils/prettier/plugins/rust/transform/index.ts
Normal file
568
frontend/src/utils/prettier/plugins/rust/transform/index.ts
Normal file
@@ -0,0 +1,568 @@
|
|||||||
|
import {
|
||||||
|
Attribute,
|
||||||
|
AttributeOrDocComment,
|
||||||
|
CallExpression,
|
||||||
|
DelimKind,
|
||||||
|
ExpressionNode,
|
||||||
|
LocArray,
|
||||||
|
MacroInvocation,
|
||||||
|
MemberExpression,
|
||||||
|
Node,
|
||||||
|
NodeType,
|
||||||
|
NodeWithBodyNoBody,
|
||||||
|
NodeWithTypeBounds,
|
||||||
|
NTMap,
|
||||||
|
ProgramLike,
|
||||||
|
rs,
|
||||||
|
Snippet,
|
||||||
|
StatementNode,
|
||||||
|
StructLiteral,
|
||||||
|
StructPattern,
|
||||||
|
TK,
|
||||||
|
TypeBound,
|
||||||
|
TypeBoundsStandaloneNode,
|
||||||
|
TypeDynBounds,
|
||||||
|
TypeTraitBound,
|
||||||
|
} from "jinx-rust";
|
||||||
|
import {
|
||||||
|
countActualNodeChildren,
|
||||||
|
deleteAttributes,
|
||||||
|
each_childNode,
|
||||||
|
end,
|
||||||
|
getActualNodeChildren,
|
||||||
|
getBodyOrCases,
|
||||||
|
getMacroName,
|
||||||
|
getNodeChildren,
|
||||||
|
hasAttributes,
|
||||||
|
hasMethod,
|
||||||
|
hasTypeBounds,
|
||||||
|
includesTK,
|
||||||
|
insertNode,
|
||||||
|
insertNodes,
|
||||||
|
is_AttributeOrDocComment,
|
||||||
|
is_BareTypeTraitBound,
|
||||||
|
is_BlockExpression,
|
||||||
|
is_CallExpression,
|
||||||
|
is_ClosureFunctionExpression,
|
||||||
|
is_DocCommentAttribute,
|
||||||
|
is_ExpressionStatement,
|
||||||
|
is_ExpressionWithBodyOrCases,
|
||||||
|
is_FlowControlExpression,
|
||||||
|
is_IfBlockExpression,
|
||||||
|
is_MacroInvocation,
|
||||||
|
is_Node,
|
||||||
|
is_NodeWithBodyNoBody,
|
||||||
|
is_NodeWithBodyOrCases,
|
||||||
|
is_Program,
|
||||||
|
is_PunctuationToken,
|
||||||
|
is_ReassignmentNode,
|
||||||
|
is_Snippet,
|
||||||
|
is_TypeBoundsStandaloneNode,
|
||||||
|
is_TypeDynBounds,
|
||||||
|
is_TypeImplBounds,
|
||||||
|
is_TypeTraitBound,
|
||||||
|
ownStart,
|
||||||
|
reassignNodeProperty,
|
||||||
|
start,
|
||||||
|
transferAttributes,
|
||||||
|
unsafe_set_nodeType,
|
||||||
|
} from "jinx-rust/utils";
|
||||||
|
import { isPrettierIgnoreAttribute, setPrettierIgnoreTarget } from "../format/comments";
|
||||||
|
import { is_StructSpread } from "../format/core";
|
||||||
|
import { CustomOptions } from "../format/external";
|
||||||
|
import { getOptions } from "../format/plugin";
|
||||||
|
import {
|
||||||
|
Array_replace,
|
||||||
|
Array_splice,
|
||||||
|
assert,
|
||||||
|
binarySearchIn,
|
||||||
|
each,
|
||||||
|
exit,
|
||||||
|
iLast,
|
||||||
|
last_of,
|
||||||
|
Map_get,
|
||||||
|
spliceAll,
|
||||||
|
try_eval,
|
||||||
|
} from "../utils/common";
|
||||||
|
import { transform_simpleAttrSyntax } from "./custom/attribute";
|
||||||
|
import { transform_macro_cfg_if } from "./custom/cfg_if";
|
||||||
|
|
||||||
|
export interface ExpressionLikeAttribute extends Attribute {
|
||||||
|
segments: LocArray<any, "[]">;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CallLikeMacroInvocation extends MacroInvocation {
|
||||||
|
segments: LocArray<any, any>;
|
||||||
|
callee: MacroInvocation["callee"];
|
||||||
|
method: undefined;
|
||||||
|
typeArguments: undefined;
|
||||||
|
arguments: LocArray<ExpressionNode, "()" | "[]" | "{}">;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BlockLikeMacroInvocation extends MacroInvocation {
|
||||||
|
segments: LocArray<any, any>;
|
||||||
|
body: LocArray<StatementNode, "()" | "[]" | "{}">;
|
||||||
|
attributes?: AttributeOrDocComment[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function is_CallLikeMacroInvocation(node: Node): node is CallLikeMacroInvocation {
|
||||||
|
return is_MacroInvocation(node) && "arguments" in node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function is_BlockLikeMacroInvocation(node: Node): node is BlockLikeMacroInvocation {
|
||||||
|
return is_MacroInvocation(node) && "body" in node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function is_CallExpression_or_CallLikeMacroInvocation(node: any): node is CallExpression | CallLikeMacroInvocation {
|
||||||
|
return is_CallExpression(node) || is_CallLikeMacroInvocation(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
const IGNORED_MACROS = new Set([
|
||||||
|
// std
|
||||||
|
// crates
|
||||||
|
"quote",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const HARDCODED_MACRO_DELIMS = new Map<string, MacroInvocation["segments"]["dk"]>();
|
||||||
|
each(
|
||||||
|
{
|
||||||
|
[DelimKind["{}"]]: [
|
||||||
|
// std
|
||||||
|
"thread_local",
|
||||||
|
// crates
|
||||||
|
"cfg_if",
|
||||||
|
],
|
||||||
|
[DelimKind["()"]]: [
|
||||||
|
// std
|
||||||
|
"assert_eq",
|
||||||
|
"assert_ne",
|
||||||
|
"assert",
|
||||||
|
"cfg",
|
||||||
|
"concat_bytes",
|
||||||
|
"concat_idents",
|
||||||
|
"concat",
|
||||||
|
"debug_assert_eq",
|
||||||
|
"debug_assert_ne",
|
||||||
|
"debug_assert",
|
||||||
|
"eprint",
|
||||||
|
"eprintln",
|
||||||
|
"format_args_nl",
|
||||||
|
"format_args",
|
||||||
|
"format",
|
||||||
|
"matches",
|
||||||
|
"panic",
|
||||||
|
"print",
|
||||||
|
"println",
|
||||||
|
"try",
|
||||||
|
"unimplemented",
|
||||||
|
"unreachable",
|
||||||
|
"write",
|
||||||
|
"writeln",
|
||||||
|
// crates
|
||||||
|
],
|
||||||
|
[DelimKind["[]"]]: [
|
||||||
|
// std
|
||||||
|
"vec",
|
||||||
|
// crates
|
||||||
|
],
|
||||||
|
},
|
||||||
|
(names, tk) =>
|
||||||
|
each(names, (name) => {
|
||||||
|
HARDCODED_MACRO_DELIMS.set(name, +tk as MacroInvocation["segments"]["dk"]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
let _COMMENTS: CustomOptions["comments"] = undefined!;
|
||||||
|
let _DANGLING_ATTRIBUTES: CustomOptions["danglingAttributes"] = undefined!;
|
||||||
|
|
||||||
|
export function transform_ast(options: CustomOptions) {
|
||||||
|
try {
|
||||||
|
_COMMENTS = options.comments;
|
||||||
|
_DANGLING_ATTRIBUTES = options.danglingAttributes;
|
||||||
|
transformNode(options.rsParsedFile);
|
||||||
|
} finally {
|
||||||
|
_depth = 0;
|
||||||
|
_COMMENTS = undefined!;
|
||||||
|
_DANGLING_ATTRIBUTES = undefined!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _depth = 0;
|
||||||
|
const isReadingSnippet = () => 0 !== _depth;
|
||||||
|
|
||||||
|
function maybe_transform_node<T extends Node, S extends Snippet>(
|
||||||
|
node: T,
|
||||||
|
read_snippet: () => S,
|
||||||
|
fn: (node: T, snippet: S) => void
|
||||||
|
): T | undefined {
|
||||||
|
const snippet = try_eval(read_snippet);
|
||||||
|
if (snippet) {
|
||||||
|
++_depth;
|
||||||
|
transformNode(snippet);
|
||||||
|
--_depth;
|
||||||
|
fn(node, snippet);
|
||||||
|
transformed.add(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const transformed = new WeakSet<Node>();
|
||||||
|
export function isTransformed(node: Node) {
|
||||||
|
return transformed.has(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transform: { [K in NodeType]?: (node: NTMap[K]) => void } = {
|
||||||
|
[NodeType.Attribute](node) {
|
||||||
|
try_eval(() => {
|
||||||
|
node.segments = rs.createLocArray(node.segments.dk, node.segments.loc.clone(), [
|
||||||
|
transform_simpleAttrSyntax(node.segments),
|
||||||
|
]) as any;
|
||||||
|
transformed.add(node);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[NodeType.MacroInlineRuleDeclaration](node) {
|
||||||
|
node.match.dk = DelimKind["()"];
|
||||||
|
node.transform.dk = DelimKind["{}"];
|
||||||
|
},
|
||||||
|
[NodeType.MacroInvocation](node) {
|
||||||
|
const name = getMacroName(node);
|
||||||
|
|
||||||
|
if (
|
||||||
|
IGNORED_MACROS.has(name) ||
|
||||||
|
node.segments.length === 0 ||
|
||||||
|
(node.segments.length === 1 && is_PunctuationToken(node.segments[0]))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tk = transformMacroDelim(name, node);
|
||||||
|
|
||||||
|
if (name === "matches") {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === "if_chain") {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === "cfg_if") {
|
||||||
|
transformBlockLike(() => transform_macro_cfg_if(node.segments) as any);
|
||||||
|
} else if (tk === DelimKind["{}"]) {
|
||||||
|
transformBlockLike(); /* || (includesTK(node, TK[","]) && transformCallLike()); */
|
||||||
|
} else {
|
||||||
|
transformCallLike(); /* || (includesTK(node, TK[";"]) && transformBlockLike()); */
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformBlockLike(transform = () => rs.toBlockBody(node.segments)) {
|
||||||
|
return maybe_transform_node(node as BlockLikeMacroInvocation, transform, (node, snippet) => {
|
||||||
|
const _body = snippet.ast;
|
||||||
|
_body.dk = tk;
|
||||||
|
|
||||||
|
node.body = _body;
|
||||||
|
node.segments = _body;
|
||||||
|
transferAttributes(snippet, node);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformCallLike() {
|
||||||
|
return maybe_transform_node(
|
||||||
|
node as CallLikeMacroInvocation,
|
||||||
|
() => rs.toCallExpressionArguments(node.segments),
|
||||||
|
(node, snippet) => {
|
||||||
|
const _arguments = snippet.ast;
|
||||||
|
_arguments.dk = tk;
|
||||||
|
|
||||||
|
node.method = undefined;
|
||||||
|
node.typeArguments = undefined;
|
||||||
|
node.arguments = _arguments;
|
||||||
|
node.segments = _arguments;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[NodeType.CallExpression](node) {
|
||||||
|
if (hasMethod(node)) {
|
||||||
|
node.callee = rs.mockNode(NodeType.MemberExpression, node.method.loc.cloneFrom(start(node.callee)), {
|
||||||
|
expression: node.callee,
|
||||||
|
property: node.method,
|
||||||
|
computed: false,
|
||||||
|
});
|
||||||
|
node.method = undefined!;
|
||||||
|
getOptions().actuallyMethodNodes.add(node.callee as MemberExpression);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
[NodeType.AutoTraitDeclaration](node) {
|
||||||
|
mockBodyNoBody(node);
|
||||||
|
},
|
||||||
|
[NodeType.NegativeImplDeclaration](node) {
|
||||||
|
mockBodyNoBody(node);
|
||||||
|
},
|
||||||
|
|
||||||
|
[NodeType.StructLiteral](node) {
|
||||||
|
moveSpreadsToEnd(node);
|
||||||
|
},
|
||||||
|
[NodeType.StructPattern](node) {
|
||||||
|
moveSpreadsToEnd(node);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function moveSpreadsToEnd(node: StructLiteral | StructPattern) {
|
||||||
|
const props = node.properties;
|
||||||
|
if (props.some((p, i, a) => is_StructSpread(p) && !iLast(i, a))) {
|
||||||
|
const spreads: any[] = [];
|
||||||
|
for (let i = 0; i < props.length; i++) {
|
||||||
|
const prop = props[i];
|
||||||
|
if (is_StructSpread(prop)) {
|
||||||
|
Array_splice(props, prop, i--);
|
||||||
|
spreads.push(prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props.push(...spreads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockBodyNoBody(node: NodeWithBodyNoBody) {
|
||||||
|
// @ts-expect-error
|
||||||
|
node.body = rs.createLocArray(last_of(rs.toTokens(node).ast).loc.clone(), DelimKind["{}"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformMacroDelim(name: string, node: MacroInvocation): 1 | 2 | 3 {
|
||||||
|
if (HARDCODED_MACRO_DELIMS.has(name)) {
|
||||||
|
return HARDCODED_MACRO_DELIMS.get(name)!;
|
||||||
|
}
|
||||||
|
if (node.segments.dk === DelimKind["{}"] && includesTK(node, TK[","])) {
|
||||||
|
return DelimKind["()"];
|
||||||
|
}
|
||||||
|
if (node.segments.dk === DelimKind["()"] && includesTK(node, TK[";"])) {
|
||||||
|
return DelimKind["{}"];
|
||||||
|
}
|
||||||
|
return node.segments.dk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function createTransformed<S extends Node>(create: () => S): S {
|
||||||
|
// return transformNode(create());
|
||||||
|
// }
|
||||||
|
|
||||||
|
const seen = new WeakSet<Node>();
|
||||||
|
function transformNode<T extends Node>(node: T, parent?: Node, key?: string, index?: any): T {
|
||||||
|
if (!seen.has(node)) {
|
||||||
|
seen.add(node);
|
||||||
|
if (is_Snippet(node) || is_Program(node)) {
|
||||||
|
registerPogramLike(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
each_childNode(node, transformNode);
|
||||||
|
|
||||||
|
insert_blocks(node, parent, key, index);
|
||||||
|
|
||||||
|
transform[node.nodeType]?.(node as any);
|
||||||
|
|
||||||
|
flatten_typeBounds(node);
|
||||||
|
|
||||||
|
transform_nodeAttributes(node);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function insert_blocks(node: Node, parent?: Node, key?: string, index?: any) {
|
||||||
|
if (parent && key) {
|
||||||
|
if (
|
||||||
|
!is_ExpressionStatement(parent) &&
|
||||||
|
(false ||
|
||||||
|
// "1 + break" -> "1 + { break; }"
|
||||||
|
is_FlowControlExpression(node) ||
|
||||||
|
// "1 + a = b" -> "1 + { a = b; }"
|
||||||
|
(!isReadingSnippet() && is_ReassignmentNode(node) && !(is_ReassignmentNode(parent) && parent.left === node)))
|
||||||
|
) {
|
||||||
|
reassignNodeProperty(blockify(node), parent, key, index);
|
||||||
|
} else if (
|
||||||
|
is_ClosureFunctionExpression(node) &&
|
||||||
|
(false ||
|
||||||
|
// "|| -> T x" -> "|| -> T { x }"
|
||||||
|
(!!node.returnType && !is_BlockExpression(node.expression)) ||
|
||||||
|
// "|| match x {}" -> "|| { match x {} }"
|
||||||
|
(is_ExpressionWithBodyOrCases(node.expression) &&
|
||||||
|
!is_BlockExpression(node.expression) &&
|
||||||
|
!is_IfBlockExpression(node.expression)))
|
||||||
|
) {
|
||||||
|
node.expression = blockify(node.expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function blockify(node: ExpressionNode) {
|
||||||
|
const block = rs.mockNode(NodeType.BlockExpression, node.loc.clone(), {
|
||||||
|
label: undefined,
|
||||||
|
body: rs.createLocArray(DelimKind["{}"], node.loc.clone(), [
|
||||||
|
rs.mockNode(NodeType.ExpressionStatement, node.loc.clone(), { semi: false, expression: node }),
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
transferAttributes(node, block);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatten_typeBounds(topNode: Node) {
|
||||||
|
if (hasTypeBounds(topNode)) {
|
||||||
|
const nestedBounds: TypeTraitBound[] = topNode.typeBounds.filter(isBoundWithNestedBounds);
|
||||||
|
const [first, ...subsequent] = nestedBounds;
|
||||||
|
|
||||||
|
const flatten = (bound: TypeTraitBound) =>
|
||||||
|
Array_replace(topNode.typeBounds, bound, ...(bound.typeExpression as unknown as TypeDynBounds).typeBounds);
|
||||||
|
|
||||||
|
if (nestedBounds.every(isBareBoundWithNestedBoundsNoPrefix)) {
|
||||||
|
// A + (B + C)
|
||||||
|
// -> A + B + C
|
||||||
|
each(nestedBounds, flatten);
|
||||||
|
} else if (
|
||||||
|
!hasDefinedPrefix(topNode) &&
|
||||||
|
first === topNode.typeBounds[0] &&
|
||||||
|
!isBareBoundWithNestedBoundsNoPrefix(first) &&
|
||||||
|
subsequent.every(isBareBoundWithNestedBoundsNoPrefix)
|
||||||
|
) {
|
||||||
|
if (is_TypeDynBounds(topNode)) {
|
||||||
|
if (is_TypeImplBounds(first.typeExpression)) {
|
||||||
|
// (impl A) + B
|
||||||
|
// -> impl A + B
|
||||||
|
unsafe_set_nodeType(topNode, NodeType.TypeImplBounds);
|
||||||
|
} else {
|
||||||
|
// (dyn A) + B
|
||||||
|
// -> dyn A + B
|
||||||
|
topNode.dyn = true;
|
||||||
|
}
|
||||||
|
each(nestedBounds, flatten);
|
||||||
|
} else {
|
||||||
|
each(subsequent, flatten);
|
||||||
|
(first.typeExpression as unknown as TypeDynBounds).typeBounds.push(...topNode.typeBounds.slice(1));
|
||||||
|
topNode.typeBounds.length = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBoundWithNestedBounds(bound: TypeBound): bound is TypeTraitBound & { typeExpression: TypeBoundsStandaloneNode } {
|
||||||
|
return is_TypeTraitBound(bound) && is_TypeBoundsStandaloneNode(bound.typeExpression);
|
||||||
|
}
|
||||||
|
function isBareBoundWithNestedBounds(bound: TypeBound): bound is TypeTraitBound & { typeExpression: TypeBoundsStandaloneNode } {
|
||||||
|
return isBoundWithNestedBounds(bound) && is_BareTypeTraitBound(bound);
|
||||||
|
}
|
||||||
|
function isBareBoundWithNestedBoundsNoPrefix(bound: TypeBound): bound is TypeTraitBound & { typeExpression: TypeDynBounds } {
|
||||||
|
return isBareBoundWithNestedBounds(bound) && !hasDefinedPrefix(bound.typeExpression);
|
||||||
|
}
|
||||||
|
function hasDefinedPrefix(node: NodeWithTypeBounds) {
|
||||||
|
return (is_TypeDynBounds(node) && node.dyn) || is_TypeImplBounds(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function transform_nodeAttributes(node: Node) {
|
||||||
|
/**
|
||||||
|
* # Inside Token trees:
|
||||||
|
*
|
||||||
|
* 1. DocCommentAttribute --is parsed as--> Comment
|
||||||
|
* 2. Attribute --is parsed as--> Token<'#'>, DelimGroup<'[]'>
|
||||||
|
*
|
||||||
|
* # Transforming tokens into a Snippet:
|
||||||
|
*
|
||||||
|
* 1. DocCommentAttribute <--replace from-- Comment
|
||||||
|
* a) Remove node with same loc from comments
|
||||||
|
* b) Merge Snippet.danglingAttributes with Program.danglingAttributes
|
||||||
|
*
|
||||||
|
* 2. Attribute (no action needed)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (hasAttributes(node)) {
|
||||||
|
const attrs = node.attributes;
|
||||||
|
for (let i = 0; i < attrs.length; i++) {
|
||||||
|
const attr = attrs[i];
|
||||||
|
if (isReadingSnippet() && is_DocCommentAttribute(attr)) {
|
||||||
|
const index = binarySearchIn(_COMMENTS, start(attr), start);
|
||||||
|
__DEV__: assert(index !== -1), assert(end(_COMMENTS[index]) === end(attr));
|
||||||
|
_COMMENTS.splice(index, 1);
|
||||||
|
}
|
||||||
|
if (attr.inner) {
|
||||||
|
if (isPrettierIgnoreAttribute(attr)) {
|
||||||
|
setPrettierIgnoreTarget(is_Program(node) ? node.loc.src : node, attr);
|
||||||
|
}
|
||||||
|
// @ts-expect-error Inserting Attribute into StatementNode[]
|
||||||
|
insertNode(is_Snippet(node) ? node.ast : getBodyOrCases(node)!, attr);
|
||||||
|
Array_splice(attrs, attr, i--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attrs.length === 0) {
|
||||||
|
deleteAttributes(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerPogramLike(program: Extract<Node, ProgramLike>) {
|
||||||
|
const comments = spliceAll(program.comments);
|
||||||
|
const danglingAttributes = spliceAll(program.danglingAttributes);
|
||||||
|
for (let i = 0; i < danglingAttributes.length; i++) {
|
||||||
|
const attr = danglingAttributes[i];
|
||||||
|
// if (isReadingSnippet() && is_DocCommentAttribute(attr)) {
|
||||||
|
// }
|
||||||
|
if (is_DocCommentAttribute(attr)) {
|
||||||
|
if (isReadingSnippet()) {
|
||||||
|
const index = binarySearchIn(_COMMENTS, start(attr), start);
|
||||||
|
__DEV__: assert(index !== -1), assert(end(_COMMENTS[index]) === end(attr));
|
||||||
|
_COMMENTS.splice(index, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transformNode(danglingAttributes[i], program, "danglingAttributes", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isReadingSnippet()) insertNodes(_COMMENTS, comments);
|
||||||
|
insertNodes(_DANGLING_ATTRIBUTES, danglingAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CommentChildNodes = new WeakMap<Node, Node[]>();
|
||||||
|
|
||||||
|
export function getCommentChildNodes(n: any): Node[] {
|
||||||
|
const children = Map_get(CommentChildNodes, n, getTransformedNodeChildren);
|
||||||
|
/**
|
||||||
|
* parent {
|
||||||
|
* #[attr]
|
||||||
|
* #![attr] <-------- list misplaced inner attrs as part of "#[attr] child {}"
|
||||||
|
* child {}
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
if (is_NodeWithBodyOrCases(n) || is_BlockLikeMacroInvocation(n)) {
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
const attr = children[i];
|
||||||
|
if (is_AttributeOrDocComment(attr)) {
|
||||||
|
const target = children.find((n) => start(n) <= start(attr) && ownStart(n) >= end(attr));
|
||||||
|
if (target) {
|
||||||
|
children.splice(i--, 1);
|
||||||
|
insertNode(Map_get(CommentChildNodes, target, getTransformedNodeChildren), attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
|
||||||
|
function getTransformedNodeChildren(node: Node) {
|
||||||
|
if (is_Program(node)) node.comments ??= []; // prettier core deletes this property
|
||||||
|
const children = getNodeChildren(node);
|
||||||
|
|
||||||
|
if (is_NodeWithBodyNoBody(node)) {
|
||||||
|
insertNodes(children, (node as any).body);
|
||||||
|
}
|
||||||
|
|
||||||
|
__DEV__: {
|
||||||
|
const actual_count = countActualNodeChildren(node);
|
||||||
|
if (
|
||||||
|
children.length !== actual_count &&
|
||||||
|
!(is_MacroInvocation(node) && actual_count - node.segments.length === children.length)
|
||||||
|
) {
|
||||||
|
const actual = getActualNodeChildren(node);
|
||||||
|
const missing = actual.filter((n) => !children.includes(n));
|
||||||
|
const unknown = children.filter((n) => !actual.includes(n));
|
||||||
|
const duplicates_in_object = actual.filter((n, i, a) => i !== 0 && n === a[i - 1]);
|
||||||
|
const duplicates_in_childNodes = children.filter((n, i, a) => i !== 0 && n === a[i - 1]);
|
||||||
|
const ctx = { missing, unknown, duplicates_in_object, duplicates_in_childNodes };
|
||||||
|
for (let key in ctx) if (ctx[key].length === 0) delete ctx[key];
|
||||||
|
exit(`${node.type} was transformed but did not patch its childNodes list`, ctx, node.loc.url(), node);
|
||||||
|
}
|
||||||
|
for (const child of children)
|
||||||
|
if (!is_Node(child)) exit(`${node.type}'s childNodes includes unexpected entries`, { node, child });
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
}
|
||||||
246
frontend/src/utils/prettier/plugins/rust/utils/common.ts
Normal file
246
frontend/src/utils/prettier/plugins/rust/utils/common.ts
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
import { createCustomError } from "./debug";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface ImportMeta {
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Narrow<T extends R, R = unknown>(value: R): asserts value is T {}
|
||||||
|
export function AssertTypesEq<A extends B, B>(...args: [B] extends [A] ? [] : [RIGHT_TYPES_NOT_ASSIGNABLE_TO_LEFT: Exclude<B, A>]) {}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
type indexof<A> = A extends readonly any[] ? A extends 0 ? any : keyof A & number : A extends Set<unknown> ? never : A extends Map<infer U, unknown> ? U
|
||||||
|
: A extends Iterable<unknown> ? never : A extends object ? keyof A & (number | string) : never;
|
||||||
|
// prettier-ignore
|
||||||
|
type valueof<A> = A extends ReadonlyArray<infer U> ? A extends 0 ? any : U : A extends Set<infer U> ? U : A extends Map<unknown, infer U> ? U
|
||||||
|
: A extends Iterable<infer U> ? U : A extends object ? A[keyof A & (number | string)] : never;
|
||||||
|
// prettier-ignore
|
||||||
|
type vObject<V extends unknown = unknown, K extends unknown = unknown> = | object | readonly V[] | { [key: string]: V } | anySet<V> | anyMap<K, V>;
|
||||||
|
export type itfn<A, R> = (value: valueof<A>, key: indexof<A>) => R;
|
||||||
|
type anySet<V extends unknown = unknown> = Set<V>;
|
||||||
|
type anyMap<K extends unknown = unknown, V extends unknown = unknown> = Map<K, V>;
|
||||||
|
type anyfunction<A extends any[] = unknown[], R = unknown> = (...args: A) => R;
|
||||||
|
type objlike = object | anyfunction;
|
||||||
|
type anymap<K extends unknown = unknown, V extends unknown = unknown> = K extends objlike ? Map<K, V> | WeakMap<K, V> : Map<K, V>;
|
||||||
|
|
||||||
|
export function exit(message: string, ...ctx: any[]): never {
|
||||||
|
if (ctx.length > 0) console.log("Error context:", { ...ctx });
|
||||||
|
throw createCustomError({ message });
|
||||||
|
}
|
||||||
|
exit.never = function never(...ctx: any[]): never {
|
||||||
|
exit("Reached unreachable code", ...ctx);
|
||||||
|
};
|
||||||
|
export function assert(predicate: boolean, err?: string, ...ctx: any[]): asserts predicate {
|
||||||
|
__DEV__: if (typeof predicate !== "boolean") exit("Expected boolean", predicate);
|
||||||
|
if (false === predicate) exit(err ?? "Assertion failed", ...ctx);
|
||||||
|
}
|
||||||
|
export function Identity<T>(v: T): T {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function last_of<T extends ArrayLike<any>>(arr: T): T extends readonly [...infer A, infer U] ? U : T[number] {
|
||||||
|
__DEV__: isArrayLike(arr) || exit("Expected Array"), arr.length > 0 || exit("Attempted to retrieve last item of an empty array", arr);
|
||||||
|
return arr[arr.length - 1];
|
||||||
|
}
|
||||||
|
export function maybe_last_of<T extends readonly any[] | undefined>(
|
||||||
|
arr: T
|
||||||
|
): T extends any[] ? (T extends readonly [...infer A, infer U] ? U : T[number]) : undefined {
|
||||||
|
return (undefined === arr || 0 === arr.length ? undefined : last_of(arr as any[])) as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normPath(filepath: string) {
|
||||||
|
return filepath.replace(/^file:\/\/\//, "").replace(/\\\\?/g, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function print_string(str: string) {
|
||||||
|
return /[\u0000-\u0020]/.test(str)
|
||||||
|
? str
|
||||||
|
.replace(/ /g, "•")
|
||||||
|
.replace(/\n/g, "↲")
|
||||||
|
.replace(/\t/g, "╚")
|
||||||
|
.replace(/[\u0000-\u0020]/g, "□")
|
||||||
|
: str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isArrayLike(value: any): value is ArrayLike<unknown> {
|
||||||
|
return is_object(value) && oisArrayLike(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function oisArrayLike(value: {}): value is ArrayLike<unknown> {
|
||||||
|
return "length" in value && (0 === (value as any).length || "0" in value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function binarySearchIn<T extends {}>(array: ArrayLike<T>, target: number, toValue: (item: T) => number) {
|
||||||
|
if (isEmpty(array)) return -1;
|
||||||
|
let i = 0;
|
||||||
|
let low = 0;
|
||||||
|
let high = array.length - 1;
|
||||||
|
let value = toValue(array[high]);
|
||||||
|
if (target >= value) return high;
|
||||||
|
else high--;
|
||||||
|
while (low <= high) {
|
||||||
|
i = low + ((high - low) >> 1);
|
||||||
|
value = toValue(array[i]);
|
||||||
|
if (target === value) return i;
|
||||||
|
if (target > value) low = i + 1;
|
||||||
|
else high = i - 1;
|
||||||
|
}
|
||||||
|
return low - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTerminalWidth(fallbackWidth = 200) {
|
||||||
|
return globalThis?.process?.stdout?.columns ?? fallbackWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
|
||||||
|
export const color = ((cfn, mfn) => ({
|
||||||
|
black: cfn(30),
|
||||||
|
red: cfn(31),
|
||||||
|
green: cfn(32),
|
||||||
|
yellow: cfn(33),
|
||||||
|
blue: cfn(34),
|
||||||
|
magenta: cfn(35),
|
||||||
|
cyan: cfn(36),
|
||||||
|
white: cfn(37),
|
||||||
|
grey: cfn(90),
|
||||||
|
bold: mfn(1, 22),
|
||||||
|
italic: mfn(3, 23),
|
||||||
|
underline: mfn(4, 24),
|
||||||
|
hidden: mfn(8, 28),
|
||||||
|
hiddenCursor: (str: string) => `\x1B[?25l${str}\x1B[?25h`,
|
||||||
|
unstyle: (str: string) => str.replace(/\x1B\[[0-9][0-9]?m/g, ""),
|
||||||
|
unstyledLength: (str: string) => str.replace(/\x1B\[[0-9][0-9]?m/g, "").length,
|
||||||
|
link: (str: string) => color.underline(color.blue(str)),
|
||||||
|
}))(
|
||||||
|
(c1: number) => (isBrowser ? Identity : (str: string) => `\x1B[${c1}m${str.replace(/\x1B\[39m/g, `\x1B[${c1}m`)}\x1B[39m`),
|
||||||
|
(c1: number, c2: number) => (isBrowser ? Identity : (str: string) => `\x1B[${c1}m${str}\x1B[${c2}m`)
|
||||||
|
);
|
||||||
|
export function Map_get<K extends object, V>(map: WeakMap<K, V>, key: K, init: (key: K) => V): V;
|
||||||
|
export function Map_get<K, V>(map: Map<K, V>, key: K, init: (key: K) => V): V;
|
||||||
|
export function Map_get<K, V>(map: anymap<K, V>, key: K, init: (key: K) => V): V {
|
||||||
|
if (!map.has(key)) map.set(key, init(key));
|
||||||
|
return map.get(key)!;
|
||||||
|
}
|
||||||
|
export function isEmpty(array: ArrayLike<any>): boolean {
|
||||||
|
__DEV__: assert(isArrayLike(array));
|
||||||
|
return 0 === array.length;
|
||||||
|
}
|
||||||
|
export function Array_splice<T extends any[]>(array: T, target: T[number], index: number = array.indexOf(target)) {
|
||||||
|
__DEV__: {
|
||||||
|
const i = arguments.length === 2 ? array.indexOf(target) : index;
|
||||||
|
assert(i === index && i !== -1 && i === array.lastIndexOf(target), "", { array, target, index, i });
|
||||||
|
}
|
||||||
|
array.splice(index, 1);
|
||||||
|
}
|
||||||
|
export function Array_replace<T extends any[]>(array: T, target: T[number], ...replacements: T[number][]) {
|
||||||
|
const i = array.indexOf(target);
|
||||||
|
__DEV__: if (i === -1 || i !== array.lastIndexOf(target))
|
||||||
|
exit("Array_replace", { index: i, lastIndex: array.lastIndexOf(target), array, target, replacements });
|
||||||
|
array.splice(array.indexOf(target), 1, ...replacements);
|
||||||
|
}
|
||||||
|
export function has_key_defined<T extends object, K extends T extends never ? never : keyof T>(
|
||||||
|
o: T,
|
||||||
|
k: K
|
||||||
|
): o is K extends never
|
||||||
|
? never
|
||||||
|
: T extends { [k in K]: any }
|
||||||
|
? T & { [k in K]: {} }
|
||||||
|
: T extends { [k in K]?: any }
|
||||||
|
? T & { [k in K]: {} }
|
||||||
|
: never {
|
||||||
|
return k in o && undefined !== o[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function is_object(data: unknown): data is object | ({ [key: string]: unknown } | unknown[]) {
|
||||||
|
return "object" === typeof data && null !== data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function is_array(data: unknown): data is any[] {
|
||||||
|
return Array.isArray(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ois_vobject(data: any) {
|
||||||
|
__DEV__: assert(is_object(data));
|
||||||
|
switch (data.constructor) {
|
||||||
|
case Array:
|
||||||
|
case Object:
|
||||||
|
case Set:
|
||||||
|
case Map:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function each<A extends vObject>(data: A, callback: itfn<A, void>): void;
|
||||||
|
export function each(data: any, callback: (value: any, index: any) => void): void {
|
||||||
|
__DEV__: assert(ois_vobject(data));
|
||||||
|
// prettier-ignore
|
||||||
|
switch (data.constructor) {
|
||||||
|
case Array: { let i = 0; for (; i < data.length; i++) callback(data[i], i); return; }
|
||||||
|
case Object: { let k; for (k in data) callback(data[k], k); return; }
|
||||||
|
case Set: { let d; for (d of data) callback(d, undefined!); return; }
|
||||||
|
case Map: { let e; for (e of data) callback(e[1], e[0]); return; }
|
||||||
|
default: { let x; for (x of data) callback(x, undefined!); return; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function iLast(index: number, array: any[]) {
|
||||||
|
return 1 + index === array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function find_last<T>(arr: T[], test: itfn<T[], boolean>): T | undefined {
|
||||||
|
for (var i = arr.length; --i !== -1; ) if (test(arr[i], i)) return arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function try_eval<T>(fn: () => T): T | undefined {
|
||||||
|
try {
|
||||||
|
return fn();
|
||||||
|
} catch (e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clamp(min: number, max: number, value: number) {
|
||||||
|
return value > min ? (value < max ? value : max) : min;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MaybeFlatten<T> = T extends ReadonlyArray<infer U> ? MaybeFlatten<Exclude<U, T>> : T;
|
||||||
|
export type FlatArray<T> = MaybeFlatten<T>[];
|
||||||
|
export function flat<T extends readonly any[]>(arr: T): FlatArray<T> {
|
||||||
|
return (arr as any as [any]).flat(Infinity);
|
||||||
|
}
|
||||||
|
export function flatMap<T extends readonly any[], R>(arr: T, mapFn: (item: T[number], index: number, array: T) => R): FlatArray<R> {
|
||||||
|
return flat(arr.map(mapFn as any));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function joinln(...arr: string[]): string {
|
||||||
|
return arr.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function join_lines(fn: () => Generator<string, void, void>): string {
|
||||||
|
return [...fn()].join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function reduce_tagged_template<T>(args: [strings: TemplateStringsArray, ...values: T[]], map: (value: T) => string) {
|
||||||
|
for (var str = "" + args[0][0], i = 1; i < args.length; i++) str += map(args[i] as T) + args[0][i];
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function map_tagged_template<T, R>(args: [strings: TemplateStringsArray, ...values: T[]], map: (value: T) => R) {
|
||||||
|
const arr: (R | string)[] = [args[0][0]];
|
||||||
|
for (var i = 1; i < args.length; i++) arr.push(map(args[i] as T), args[0][i]);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function spliceAll<T extends any[]>(array: T): [...T] {
|
||||||
|
const r: [...T] = [...array];
|
||||||
|
array.length = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function spread<R>(fn: () => Iterable<R>): R[] {
|
||||||
|
return [...fn()];
|
||||||
|
}
|
||||||
141
frontend/src/utils/prettier/plugins/rust/utils/debug.ts
Normal file
141
frontend/src/utils/prettier/plugins/rust/utils/debug.ts
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
import { clamp, color, getTerminalWidth, normPath } from "./common";
|
||||||
|
|
||||||
|
const cwd =
|
||||||
|
typeof process === "object" && typeof process?.cwd === "function" ? /* @__PURE__ */ normPath(/* @__PURE__ */ process.cwd() ?? "") : "";
|
||||||
|
function normPath_strip_cwd(filepath: string) {
|
||||||
|
let normFilePath = normPath(filepath);
|
||||||
|
return normFilePath.startsWith(cwd) ? normFilePath.slice(cwd.length + 1) : normFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
type StackStyleFn = (callee: string, item: StackItem) => (str: string) => string;
|
||||||
|
interface Stack extends Array<StackItem> {
|
||||||
|
message: string;
|
||||||
|
style?: { callee?: StackStyleFn; url?: StackStyleFn } | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StackLine {
|
||||||
|
declare readonly raw: string;
|
||||||
|
declare readonly callee: string;
|
||||||
|
declare readonly filepath: string;
|
||||||
|
declare readonly line: string;
|
||||||
|
declare readonly col: string;
|
||||||
|
declare readonly other: string;
|
||||||
|
declare readonly url: string;
|
||||||
|
constructor(raw: string) {
|
||||||
|
({
|
||||||
|
1: this.callee = "",
|
||||||
|
2: this.filepath = "",
|
||||||
|
3: this.line = "",
|
||||||
|
4: this.col = "",
|
||||||
|
5: this.other = "",
|
||||||
|
} = (this.raw = raw).match(/at (?:(.+?)\s+\()?(?:(.+?):([0-9]+)(?::([0-9]+))?|([^)]+))\)?/) ?? ["", "", "", "", "", ""]);
|
||||||
|
this.url = this.filepath //
|
||||||
|
? normPath_strip_cwd(this.filepath) + (this.line && this.col && `:${this.line}:${this.col}`)
|
||||||
|
: this.other === "native"
|
||||||
|
? "<native>"
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrintWidth() {
|
||||||
|
return clamp(0, getTerminalWidth(128), 200) - 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StackItem extends StackLine {
|
||||||
|
constructor(private readonly stack: Stack, readonly i: number, raw: string) {
|
||||||
|
super(raw);
|
||||||
|
}
|
||||||
|
hidden = false;
|
||||||
|
hide() {
|
||||||
|
this.hidden = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
hideNext(n: number) {
|
||||||
|
for (let i = 0; i < n; i++) this.at(i)?.hide();
|
||||||
|
}
|
||||||
|
hideWhileTrue(test: (line: StackItem) => boolean) {
|
||||||
|
let line: StackItem | undefined = this;
|
||||||
|
while (line && test(line)) line = line.hide().next();
|
||||||
|
}
|
||||||
|
at(relIndex: number) {
|
||||||
|
return this.i + relIndex >= this.stack.length || this.i + relIndex < 0 ? undefined : this.stack[this.i + relIndex];
|
||||||
|
}
|
||||||
|
next() {
|
||||||
|
return this.at(+1);
|
||||||
|
}
|
||||||
|
toString() {
|
||||||
|
const url = this.url;
|
||||||
|
const calleeColor = this.stack.style?.callee?.(this.callee, this) ?? color.cyan;
|
||||||
|
const urlColor = this.stack.style?.url?.(url, this) ?? color.grey;
|
||||||
|
return compose2Cols(" at " + calleeColor(this.callee), urlColor(url), getPrintWidth());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
function createStack(message: string, Error_stack: string, style: Stack["style"]): Stack {
|
||||||
|
for (var STACK: Stack = [] as any, i = 0, stack = Error_stack.split("\n").slice(2); i < stack.length; i++) STACK[i] = new StackItem(STACK, i, stack[i]);
|
||||||
|
return (STACK.message = message), (STACK.style = style), STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
function composeStack(stack: Stack) {
|
||||||
|
var hidden = 0;
|
||||||
|
var str = stack.message;
|
||||||
|
for (var item of stack) item.hidden ? ++hidden : (str += "\n" + item.toString());
|
||||||
|
return str + (hidden > 0 ? "\n" + color.grey(compose2Cols("", `...filtered ${hidden} lines`, getPrintWidth())) : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get_caller_cmd(offset = 0) {
|
||||||
|
const obj: { stack: string } = {} as any;
|
||||||
|
Error.captureStackTrace(obj, get_caller_cmd);
|
||||||
|
const lines = obj.stack.split("\n");
|
||||||
|
return new StackLine(lines[1 + clamp(0, lines.length - 2, offset)]).url;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Error_prepareStackTrace;
|
||||||
|
let replaced_default_prepareStackTrace = false;
|
||||||
|
function custom_prepareStackTrace(err, calls) {
|
||||||
|
return (Error_prepareStackTrace?.(err, calls) ?? calls.join("\n"))?.replace(/file:\/\/\//g, "").replace(/\\\\?/g, "/") ?? calls;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function overrideDefaultError(silent = false) {
|
||||||
|
if (replaced_default_prepareStackTrace === (replaced_default_prepareStackTrace = true)) return;
|
||||||
|
Error_prepareStackTrace = Error.prepareStackTrace ?? ((_, calls) => calls.join("\n"));
|
||||||
|
Error.prepareStackTrace = custom_prepareStackTrace;
|
||||||
|
if (!silent) console.log(color.grey(`[devtools] Replaced Error.prepareStackTrace at ${get_caller_cmd(1)}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createCustomError({
|
||||||
|
message = "Unknown Error",
|
||||||
|
editStack = (stack: StackItem[]) => {},
|
||||||
|
style = undefined as Stack["style"],
|
||||||
|
stackTraceLimit = 20,
|
||||||
|
}): Error {
|
||||||
|
const _stackTraceLimit = Error.stackTraceLimit;
|
||||||
|
const _prepareStackTrace = Error.prepareStackTrace;
|
||||||
|
if (replaced_default_prepareStackTrace && _prepareStackTrace === custom_prepareStackTrace)
|
||||||
|
Error.prepareStackTrace = Error_prepareStackTrace;
|
||||||
|
|
||||||
|
Error.stackTraceLimit = stackTraceLimit;
|
||||||
|
|
||||||
|
const _ctx: { stack: string } = {} as any;
|
||||||
|
|
||||||
|
Error.captureStackTrace(_ctx, createCustomError);
|
||||||
|
|
||||||
|
const stack = createStack(message, _ctx.stack, style);
|
||||||
|
Error.prepareStackTrace = function (err, calls) {
|
||||||
|
editStack(stack);
|
||||||
|
return composeStack(stack);
|
||||||
|
};
|
||||||
|
|
||||||
|
const err = new Error(message); // (get) to trigger prepareStackTrace, (set) to prevent treeshaking
|
||||||
|
err.stack = err.stack;
|
||||||
|
|
||||||
|
Error.stackTraceLimit = _stackTraceLimit;
|
||||||
|
Error.prepareStackTrace = _prepareStackTrace;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compose2Cols(left: string, right: string, len = 64, min = 1) {
|
||||||
|
return left + " ".repeat(clamp(min, len, len - (color.unstyledLength(left) + color.unstyledLength(right)))) + right;
|
||||||
|
}
|
||||||
@@ -40,6 +40,8 @@ import goPrettierPlugin from "@/utils/prettier/plugins/go/go"
|
|||||||
import sqlPrettierPlugin from "@/utils/prettier/plugins/sql/sql"
|
import sqlPrettierPlugin from "@/utils/prettier/plugins/sql/sql"
|
||||||
import phpPrettierPlugin from "@/utils/prettier/plugins/php"
|
import phpPrettierPlugin from "@/utils/prettier/plugins/php"
|
||||||
import javaPrettierPlugin from "@/utils/prettier/plugins/java"
|
import javaPrettierPlugin from "@/utils/prettier/plugins/java"
|
||||||
|
import xmlPrettierPlugin from "@prettier/plugin-xml"
|
||||||
|
import * as rustPrettierPlugin from "@/utils/prettier/plugins/rust";
|
||||||
import * as prettierPluginEstree from "prettier/plugins/estree";
|
import * as prettierPluginEstree from "prettier/plugins/estree";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,9 +93,15 @@ export const LANGUAGES: LanguageInfo[] = [
|
|||||||
parser: "css",
|
parser: "css",
|
||||||
plugins: [cssPrettierPlugin]
|
plugins: [cssPrettierPlugin]
|
||||||
}),
|
}),
|
||||||
new LanguageInfo("xml", "XML", xmlLanguage.parser),
|
new LanguageInfo("xml", "XML", xmlLanguage.parser,{
|
||||||
|
parser: "xml",
|
||||||
|
plugins: [xmlPrettierPlugin]
|
||||||
|
}),
|
||||||
new LanguageInfo("cpp", "C++", cppLanguage.parser),
|
new LanguageInfo("cpp", "C++", cppLanguage.parser),
|
||||||
new LanguageInfo("rs", "Rust", rustLanguage.parser),
|
new LanguageInfo("rs", "Rust", rustLanguage.parser,{
|
||||||
|
parser: "jinx-rust",
|
||||||
|
plugins: [rustPrettierPlugin]
|
||||||
|
}),
|
||||||
new LanguageInfo("cs", "C#", StreamLanguage.define(csharp).parser),
|
new LanguageInfo("cs", "C#", StreamLanguage.define(csharp).parser),
|
||||||
new LanguageInfo("rb", "Ruby", StreamLanguage.define(ruby).parser),
|
new LanguageInfo("rb", "Ruby", StreamLanguage.define(ruby).parser),
|
||||||
new LanguageInfo("sh", "Shell", StreamLanguage.define(shell).parser),
|
new LanguageInfo("sh", "Shell", StreamLanguage.define(shell).parser),
|
||||||
|
|||||||
Reference in New Issue
Block a user