Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize emit to wrap overlength lines #74

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ce01152
Add line wrapping
rimuy Jun 3, 2022
2df78fd
Merge branch 'roblox-ts:master' into optimize-emit
rimuy Jun 3, 2022
788f109
Rename short parameters
rimuy Jun 3, 2022
ac640e1
Eliminate some duplicated values
rimuy Jun 3, 2022
07e924d
Fix variable declaration
rimuy Jun 4, 2022
ea9d1c1
Update renderFunctionExpression.ts
rimuy Jun 4, 2022
51e5527
Reduce render calls duplication
rimuy Jun 4, 2022
f8de141
Remove redundant variables
rimuy Jun 4, 2022
11df90d
Improve format handling for functions and arrays
rimuy Jun 4, 2022
c46e3cb
Add JSDoc parameters
rimuy Jun 4, 2022
1af441f
Fix doc typo in renderParameters.ts
rimuy Jun 4, 2022
07f7bf1
Rename formatFunction -> renderFunction
rimuy Jun 4, 2022
b98067f
Update renderArray.ts
rimuy Jun 5, 2022
da07037
Add renderRightHandSide.ts
rimuy Jun 5, 2022
9575278
Update renderFunction.ts
rimuy Jun 5, 2022
ea962ac
Simplify indexable expressions
rimuy Jun 5, 2022
19052c0
Add RenderState.list()
rimuy Jun 5, 2022
9bb9e53
Update renderFunction.ts JSDoc info
rimuy Jun 5, 2022
9ec84d5
Improve renderFunction.ts
rimuy Jun 5, 2022
ee97a72
Update renderComputedIndexExpression.ts
rimuy Jun 5, 2022
3e74739
Remove redundant generic in renderRightHandSide.ts
rimuy Jun 5, 2022
557599b
Increase printWidth to 100
rimuy Jun 5, 2022
555ed71
Remove redundant skipCheck paramater in RenderState.isFormattable
rimuy Jun 6, 2022
e7f3b7c
Remove package*.json updates
rimuy Jun 6, 2022
2faf92f
Move isFormattable out of RenderState
rimuy Jun 6, 2022
4fc5094
Revert string literals change
rimuy Jun 6, 2022
feb3e66
Update renderRightHandSide.ts
rimuy Jun 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/LuauRenderer/RenderState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class RenderState {
* Pops an indent from the current indent level.
*/
private popIndent() {
this.indent = this.indent.substr(INDENT_CHARACTER_LENGTH);
this.indent = this.indent.substring(INDENT_CHARACTER_LENGTH);
}

private tempIdFallback = 0;
Expand Down Expand Up @@ -104,4 +104,16 @@ export class RenderState {
this.popIndent();
return result;
}

/**
* Returns a rendered list of lines.
* @param callback The renderer callback.
*/
public list(callback: () => ReadonlyArray<string>) {
let result = "";
this.block(() => {
callback().forEach((v, i, list) => (result += this.line(`${v}${i < list.length - 1 ? "," : ""}`)));
});
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import { render, RenderState } from "LuauRenderer";
import { renderArguments } from "LuauRenderer/util/renderArguments";

export function renderCallExpression(state: RenderState, node: luau.CallExpression) {
return `${render(state, node.expression)}(${renderArguments(state, node.args)})`;
const nameStr = render(state, node.expression);
return `${nameStr}(${renderArguments(state, node.args, nameStr)})`;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import luau from "LuauAST";
import { render, RenderState } from "LuauRenderer";
import { isFormattable } from "LuauRenderer/util/isFormattable";

export function renderComputedIndexExpression(state: RenderState, node: luau.ComputedIndexExpression) {
const expStr = render(state, node.expression);
if (luau.isStringLiteral(node.index) && luau.isValidIdentifier(node.index.value)) {
return `${expStr}.${node.index.value}`;
const nameStr = node.index.value;
const formatStr = `${expStr}.${nameStr}`;
if (isFormattable(formatStr)) {
return `${state.newline(expStr)}${state.block(() => state.indented(`.${nameStr}`))}`;
}
return formatStr;
} else {
const indexStr = render(state, node.index);
return `${expStr}[${indexStr}]`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import { renderArguments } from "LuauRenderer/util/renderArguments";

export function renderMethodCallExpression(state: RenderState, node: luau.MethodCallExpression) {
assert(luau.isValidIdentifier(node.name));
return `${render(state, node.expression)}:${node.name}(${renderArguments(state, node.args)})`;
const nameStr = `${render(state, node.expression)}:${node.name}`;
return `${nameStr}(${renderArguments(state, node.args, nameStr)})`;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import luau from "LuauAST";
import { render, RenderState } from "LuauRenderer";
import { isFormattable } from "LuauRenderer/util/isFormattable";

export function renderPropertyAccessExpression(state: RenderState, node: luau.PropertyAccessExpression) {
const expStr = render(state, node.expression);
const nameStr = node.name;
if (luau.isValidIdentifier(nameStr)) {
return `${expStr}.${nameStr}`;
const formatStr = `${expStr}.${nameStr}`;
if (isFormattable(formatStr)) {
return `${state.newline(expStr)}${state.block(() => state.indented(`.${nameStr}`))}`;
}
return formatStr;
} else {
return `${expStr}["${nameStr}"]`;
}
Expand Down
16 changes: 14 additions & 2 deletions src/LuauRenderer/nodes/expressions/renderArray.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import luau from "LuauAST";
import { render, RenderState } from "LuauRenderer";
import { isFormattable } from "LuauRenderer/util/isFormattable";

export function renderArray(state: RenderState, node: luau.Array) {
if (luau.list.isEmpty(node.members)) {
return "{}";
}
const renderMembers = () => luau.list.mapToArray(node.members, member => render(state, member));
const members = renderMembers();
const arrayStr = `{ ${members.join(", ")} }`;
// should format if a member is a non-empty function expression
const skipFormatCheck = luau.list.some(
node.members,
member => luau.isFunctionExpression(member) && !luau.list.isEmpty(member.statements),
);

const membersStr = luau.list.mapToArray(node.members, member => render(state, member)).join(", ");
return `{ ${membersStr} }`;
if (skipFormatCheck || isFormattable(arrayStr)) {
return `${state.newline("{")}${state.list(renderMembers)}${state.indented("}")}`;
}

return arrayStr;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import { renderParameters } from "LuauRenderer/util/renderParameters";
import { renderStatements } from "LuauRenderer/util/renderStatements";

export function renderFunctionExpression(state: RenderState, node: luau.FunctionExpression) {
const nameStr = "function";
if (luau.list.isEmpty(node.statements)) {
return `function(${renderParameters(state, node)}) end`;
return `${nameStr}(${renderParameters(state, node, nameStr)}) end`;
}

let result = "";
result += state.newline(`function(${renderParameters(state, node)})`);
result += state.newline(`${nameStr}(${renderParameters(state, node, nameStr)})`);
result += state.block(() => renderStatements(state, node.statements));
result += state.indented(`end`);
return result;
Expand Down
4 changes: 2 additions & 2 deletions src/LuauRenderer/nodes/statements/renderAssignment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import luau from "LuauAST";
import { assert } from "LuauAST/util/assert";
import { render, RenderState } from "LuauRenderer";
import { renderRightHandSide } from "LuauRenderer/util/renderRightHandSide";

export function renderAssignment(state: RenderState, node: luau.Assignment) {
let leftStr: string;
Expand All @@ -10,6 +11,5 @@ export function renderAssignment(state: RenderState, node: luau.Assignment) {
} else {
leftStr = render(state, node.left);
}
const rightStr = render(state, node.right);
return state.line(`${leftStr} ${node.operator} ${rightStr}`, node);
return state.line(renderRightHandSide(state, `${leftStr} ${node.operator} `, node.right), node);
}
1 change: 0 additions & 1 deletion src/LuauRenderer/nodes/statements/renderForStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ export function renderForStatement(state: RenderState, node: luau.ForStatement)
result += state.line(`for ${idsStr} in ${expStr} do`);
result += state.block(() => renderStatements(state, node.statements));
result += state.line(`end`);

return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function renderFunctionDeclaration(state: RenderState, node: luau.Functio
assert(luau.isAnyIdentifier(node.name), "local function cannot be a property");
}
const nameStr = render(state, node.name);
const paramStr = renderParameters(state, node);
const paramStr = renderParameters(state, node, nameStr);

let result = "";
result += state.line(`${node.localize ? "local " : ""}function ${nameStr}(${paramStr})`);
Expand Down
3 changes: 2 additions & 1 deletion src/LuauRenderer/nodes/statements/renderMethodDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { renderParameters } from "LuauRenderer/util/renderParameters";
import { renderStatements } from "LuauRenderer/util/renderStatements";

export function renderMethodDeclaration(state: RenderState, node: luau.MethodDeclaration) {
const nameStr = render(state, node.expression);
let result = "";
result += state.line(`function ${render(state, node.expression)}:${node.name}(${renderParameters(state, node)})`);
result += state.line(`function ${nameStr}:${node.name}(${renderParameters(state, node, nameStr)})`);
result += state.block(() => renderStatements(state, node.statements));
result += state.line(`end`);
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,5 @@ export function renderNumericForStatement(state: RenderState, node: luau.Numeric
result += state.line(`for ${idStr} = ${predicateStr} do`);
result += state.block(() => renderStatements(state, node.statements));
result += state.line(`end`);

return result;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import luau from "LuauAST";
import { assert } from "LuauAST/util/assert";
import { render, RenderState } from "LuauRenderer";
import { renderRightHandSide } from "LuauRenderer/util/renderRightHandSide";

export function renderVariableDeclaration(state: RenderState, node: luau.VariableDeclaration) {
let leftStr: string;
Expand All @@ -11,8 +12,7 @@ export function renderVariableDeclaration(state: RenderState, node: luau.Variabl
leftStr = render(state, node.left);
}
if (node.right) {
const rightStr = render(state, node.right);
return state.line(`local ${leftStr} = ${rightStr}`, node);
return state.line(renderRightHandSide(state, `local ${leftStr} = `, node.right), node);
} else {
return state.line(`local ${leftStr}`, node);
}
Expand Down
9 changes: 9 additions & 0 deletions src/LuauRenderer/util/isFormattable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const PRINT_WIDTH = 100;

/**
* Checks to see if `text` can be formatted.
* @param text The text.
*/
export function isFormattable(text: string) {
return text.length > PRINT_WIDTH;
}
5 changes: 3 additions & 2 deletions src/LuauRenderer/util/renderArguments.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import luau from "LuauAST";
import { render, RenderState } from "LuauRenderer";
import { renderFunction } from "LuauRenderer/util/renderFunction";

/** Renders the given list of expressions into a string separated by commas */
export function renderArguments(state: RenderState, expressions: luau.List<luau.Expression>) {
return luau.list.mapToArray(expressions, v => render(state, v)).join(", ");
export function renderArguments(state: RenderState, expressions: luau.List<luau.Expression>, name: string) {
return renderFunction(state, () => luau.list.mapToArray(expressions, v => render(state, v)), name);
}
15 changes: 15 additions & 0 deletions src/LuauRenderer/util/renderFunction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { RenderState } from "LuauAST";
import { isFormattable } from "LuauRenderer/util/isFormattable";

/**
* Renders function parameters and call arguments.
*
* Takes a list of string values and removes the space at the final of each string if the result is formattable.
*/
export function renderFunction(state: RenderState, renderList: () => ReadonlyArray<string>, name?: string) {
const formatStr = renderList().join(", ");
if (isFormattable(`${name ?? ""}(${formatStr})`)) {
return `\n${state.list(renderList)}${state.indented("")}`;
}
return formatStr;
}
7 changes: 4 additions & 3 deletions src/LuauRenderer/util/renderParameters.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import luau from "LuauAST";
import { render, RenderState } from "LuauRenderer";
import { renderFunction } from "LuauRenderer/util/renderFunction";

/**
* Renders the given list of identifiers inside of `node` into a string sepearted by commas
* Renders the given list of identifiers inside of `node` into a string separated by commas
*
* Adds `...` onto the end if node.hasDotDotDot is true
*/
export function renderParameters(state: RenderState, node: luau.HasParameters) {
export function renderParameters(state: RenderState, node: luau.HasParameters, name?: string) {
const paramStrs = luau.list.mapToArray(node.parameters, param => render(state, param));
if (node.hasDotDotDot) {
paramStrs.push("...");
}
return paramStrs.join(", ");
return renderFunction(state, () => paramStrs, name);
}
25 changes: 25 additions & 0 deletions src/LuauRenderer/util/renderRightHandSide.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import luau, { render, RenderState } from "LuauAST";
import { isFormattable } from "LuauRenderer/util/isFormattable";

const NON_FORMATTABLE_RHS_EXPRESSIONS = new Set([
luau.SyntaxKind.CallExpression,
luau.SyntaxKind.MethodCallExpression,
luau.SyntaxKind.Array,
luau.SyntaxKind.Map,
luau.SyntaxKind.Set,
luau.SyntaxKind.MixedTable,
]);

/** Renders statements with left and right-hand side values and formats them if necessary. */
export function renderRightHandSide(state: RenderState, lhsStr: string, rhsExpr: luau.Expression) {
const rhsStr = render(state, rhsExpr);
const isRhsFormattable = isFormattable(rhsStr);
const formatStr = `${lhsStr}${rhsStr}`;
const renderRhs = () => state.indented(render(state, rhsExpr));
if (isFormattable(formatStr) && isRhsFormattable && !NON_FORMATTABLE_RHS_EXPRESSIONS.has(rhsExpr.kind)) {
return `${state.newline(lhsStr)}${
isRhsFormattable ? state.block(() => state.block(renderRhs)) : state.block(renderRhs)
}`;
}
return formatStr;
}