@@ -14,22 +14,15 @@ interface InlineBodyResult {
1414
1515// AST transformer to substitute parameter identifiers with temp variables
1616function 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+
105127export 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 ) {
0 commit comments