Skip to content

Commit 5c82357

Browse files
committed
inline v2, optimisations
1 parent 38b0715 commit 5c82357

4 files changed

Lines changed: 229 additions & 170 deletions

File tree

src/transformation/utils/inline.ts

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,15 @@ interface InlineBodyResult {
1414

1515
// AST transformer to substitute parameter identifiers with temp variables
1616
function createParameterSubstitutionTransformer(
17-
paramReplacements: Map<string, string>
17+
paramReplacements: Map<string, ts.Expression>
1818
): ts.TransformerFactory<ts.Node> {
19-
return (context: ts.TransformationContext) => {
19+
return (ctx: ts.TransformationContext) => {
2020
const visit = (node: ts.Node): ts.Node => {
21-
// Replace identifier if it matches a parameter
22-
if (ts.isIdentifier(node)) {
23-
const replacementName = paramReplacements.get(node.text);
24-
if (replacementName) {
25-
return ts.factory.createIdentifier(replacementName);
26-
}
21+
if (ts.isIdentifier(node) && paramReplacements.has(node.text)) {
22+
return paramReplacements.get(node.text)!
2723
}
28-
29-
// Recursively visit children
30-
return ts.visitEachChild(node, visit, context);
24+
return ts.visitEachChild(node, visit, ctx);
3125
};
32-
3326
return visit;
3427
};
3528
}
@@ -45,24 +38,38 @@ export function prepareInlineBody(
4538
inlineInfo.isProcessing = true;
4639
try {
4740
const { body, parameters } = inlineInfo;
48-
const paramReplacements = new Map<string, string>();
41+
42+
const paramReplacements = new Map<string, ts.Expression>();
4943
const paramAssignments: lua.Statement[] = [];
44+
const paramNames = new Set<string>();
45+
for (const param of parameters) {
46+
if (ts.isIdentifier(param.name) && param.name.text !== "this") {
47+
paramNames.add(param.name.text);
48+
}
49+
}
50+
51+
const usageCounts = countParamUsages(body, paramNames);
5052

5153
let argIndex = 0;
5254
for (const param of parameters) {
5355
if (ts.isIdentifier(param.name) && param.name.text !== "this") {
5456
const paramName = param.name.text;
55-
const tempName = context.createTempName(paramName);
56-
paramReplacements.set(paramName, tempName);
57-
5857
const arg = argIndex < args.length ? args[argIndex] : undefined;
59-
const transformedArg = arg ? context.transformExpression(arg) : lua.createNilLiteral();
60-
paramAssignments.push(
61-
lua.createVariableDeclarationStatement(
62-
lua.createIdentifier(tempName),
63-
transformedArg
64-
)
65-
);
58+
const tsArg = arg ?? ts.factory.createNull();
59+
60+
const usage = usageCounts.get(paramName) ?? 0;
61+
if (usage === 1) {
62+
// Прямая подстановка аргумента
63+
paramReplacements.set(paramName, tsArg);
64+
// temp не создаётся
65+
} else {
66+
const tempName = context.createTempName(paramName);
67+
paramReplacements.set(paramName, ts.factory.createIdentifier(tempName));
68+
const transformedArg = arg ? context.transformExpression(arg) : lua.createNilLiteral();
69+
paramAssignments.push(
70+
lua.createVariableDeclarationStatement(lua.createIdentifier(tempName), transformedArg)
71+
);
72+
}
6673
argIndex++;
6774
}
6875
}
@@ -102,6 +109,21 @@ export function prepareInlineBody(
102109
}
103110
}
104111

112+
function countParamUsages(body: ts.ConciseBody, paramNames: Set<string>): Map<string, number> {
113+
const counts = new Map<string, number>();
114+
for (const name of paramNames) counts.set(name, 0);
115+
116+
function visit(node: ts.Node) {
117+
if (ts.isIdentifier(node) && counts.has(node.text)) {
118+
counts.set(node.text, counts.get(node.text)! + 1);
119+
}
120+
ts.forEachChild(node, visit);
121+
}
122+
123+
visit(body);
124+
return counts;
125+
}
126+
105127
export function embedInlineResult(
106128
context: TransformationContext,
107129
paramAndBodyStmts: lua.Statement[],
@@ -113,6 +135,34 @@ export function embedInlineResult(
113135
},
114136
isReturnContext?: boolean // true, если вызов был внутри return
115137
): lua.Expression {
138+
// Оптимизация: если нет промежуточных стейтментов, можно обойтись без do...end
139+
if (paramAndBodyStmts.length === 0) {
140+
if (isReturnContext) {
141+
// Для return вставляем return-стейтмент напрямую, без do...end
142+
context.addPrecedingStatements([
143+
lua.createReturnStatement(hasMulti ? returnExprs : returnExprs)
144+
]);
145+
return lua.createNilLiteral();
146+
}
147+
148+
if (target) {
149+
if (target.vars.length > 1) {
150+
// Деструктуризация (обычно обрабатывается в variable-declaration, но на всякий случай)
151+
context.addPrecedingStatements([
152+
lua.createAssignmentStatement(target.vars, hasMulti ? returnExprs : [returnExprs[0]])
153+
]);
154+
return lua.createNilLiteral();
155+
} else {
156+
// Одна переменная — возвращаем значение для присваивания (используется call.ts)
157+
// Не добавляем preceding statements, возвращаем само выражение
158+
return hasMulti ? returnExprs[0] : returnExprs[0];
159+
}
160+
}
161+
162+
// Expression-контекст: просто возвращаем первое выражение
163+
return returnExprs[0];
164+
}
165+
116166
const allStmts = [...paramAndBodyStmts];
117167

118168
if (isReturnContext) {

src/transformation/visitors/function.ts

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import { transformIdentifier } from "./identifier";
2121
import { transformExpressionBodyToReturnStatement } from "./return";
2222
import { transformBindingPattern } from "./variable-declaration";
2323
import {
24-
inlineComplexBody,
2524
inlineMethodNotSupported,
2625
inlineNestedInlineCall,
2726
inlineRecursiveCall,
@@ -101,24 +100,24 @@ export function isFunctionTypeWithProperties(context: TransformationContext, fun
101100
}
102101
}
103102

104-
function validateInlineFunctionBody(_context: TransformationContext, body: ts.ConciseBody): boolean {
105-
// Arrow functions with expression bodies are always OK
106-
if (!ts.isBlock(body)) {
107-
return true;
108-
}
109-
110-
// For block bodies, check that they only contain a single return statement
111-
if (body.statements.length !== 1) {
112-
return false;
113-
}
114-
115-
const statement = body.statements[0];
116-
if (!ts.isReturnStatement(statement) || !statement.expression) {
117-
return false;
118-
}
119-
120-
return true;
121-
}
103+
// function validateInlineFunctionBody(_context: TransformationContext, body: ts.ConciseBody): boolean {
104+
// // Arrow functions with expression bodies are always OK
105+
// if (!ts.isBlock(body)) {
106+
// return true;
107+
// }
108+
//
109+
// // For block bodies, check that they only contain a single return statement
110+
// if (body.statements.length !== 1) {
111+
// return false;
112+
// }
113+
//
114+
// const statement = body.statements[0];
115+
// if (!ts.isReturnStatement(statement) || !statement.expression) {
116+
// return false;
117+
// }
118+
//
119+
// return true;
120+
// }
122121

123122
function checkInlineFunctionCalls(
124123
context: TransformationContext,
@@ -169,11 +168,11 @@ function registerInlineFunction(
169168
return false;
170169
}
171170

172-
// Validate body complexity
173-
if (node.body && !validateInlineFunctionBody(context, node.body)) {
174-
context.diagnostics.push(inlineComplexBody(node));
175-
return false;
176-
}
171+
// // Validate body complexity
172+
// if (node.body && !validateInlineFunctionBody(context, node.body)) {
173+
// context.diagnostics.push(inlineComplexBody(node));
174+
// return false;
175+
// }
177176

178177
// Check for recursive calls and calls to other inline functions
179178
if (node.body) {

src/transformation/visitors/variable-declaration.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ function transformInlineFunctionVariableDeclaration(
358358

359359
const result = prepareInlineBody(context, inlineInfo, statement.initializer.arguments);
360360

361+
if (result.paramAssignments.length === 0 && result.bodyStatements.length === 0) {
362+
const value = result.hasMultiReturn ? result.returnExpressions[0] : result.returnExpressions[0];
363+
return createLocalOrExportedOrGlobalDeclaration(context, variableName, value, statement);
364+
}
365+
361366
// Объявляем переменную с nil
362367
const localDecl = lua.createVariableDeclarationStatement(variableName, lua.createNilLiteral());
363368

@@ -406,6 +411,11 @@ function transformInlineFunctionDestructuringDeclaration(
406411

407412
const result = prepareInlineBody(context, inlineInfo, statement.initializer.arguments);
408413

414+
if (result.paramAssignments.length === 0 && result.bodyStatements.length === 0) {
415+
const value = result.hasMultiReturn ? result.returnExpressions : result.returnExpressions[0];
416+
return createLocalOrExportedOrGlobalDeclaration(context, variableNames, value, statement);
417+
}
418+
409419
// local a, b = nil, nil
410420
const localDecl = lua.createVariableDeclarationStatement(variableNames, lua.createNilLiteral());
411421

0 commit comments

Comments
 (0)