@@ -33,6 +33,9 @@ export enum LuaLibFeature {
3333 ArraySlice = "ArraySlice" ,
3434 ArraySome = "ArraySome" ,
3535 ArraySplice = "ArraySplice" ,
36+ FunctionApply = "FunctionApply" ,
37+ FunctionBind = "FunctionBind" ,
38+ FunctionCall = "FunctionCall" ,
3639 InstanceOf = "InstanceOf" ,
3740 Map = "Map" ,
3841 Set = "Set" ,
@@ -784,8 +787,9 @@ export abstract class LuaTranspiler {
784787 case ts . SyntaxKind . DeleteExpression :
785788 return this . transpileExpression ( ( node as ts . DeleteExpression ) . expression ) + "=nil" ;
786789 case ts . SyntaxKind . FunctionExpression :
790+ return this . transpileFunctionExpression ( node as ts . ArrowFunction , "self" ) ;
787791 case ts . SyntaxKind . ArrowFunction :
788- return this . transpileFunctionExpression ( node as ts . ArrowFunction ) ;
792+ return this . transpileFunctionExpression ( node as ts . ArrowFunction , "_" ) ;
789793 case ts . SyntaxKind . NewExpression :
790794 return this . transpileNewExpression ( node as ts . NewExpression ) ;
791795 case ts . SyntaxKind . ComputedPropertyName :
@@ -1136,7 +1140,7 @@ export abstract class LuaTranspiler {
11361140
11371141 public transpileNewExpression ( node : ts . NewExpression ) : string {
11381142 const name = this . transpileExpression ( node . expression ) ;
1139- const params = node . arguments ? this . transpileArguments ( node . arguments , ts . createTrue ( ) ) : "true" ;
1143+ let params = node . arguments ? this . transpileArguments ( node . arguments , ts . createTrue ( ) ) : "true" ;
11401144 const type = this . checker . getTypeAtLocation ( node ) ;
11411145 const classDecorators = tsHelper . getCustomDecorators ( type , this . checker ) ;
11421146
@@ -1151,7 +1155,14 @@ export abstract class LuaTranspiler {
11511155 if ( ! customDecorator . args [ 0 ] ) {
11521156 throw TSTLErrors . InvalidDecoratorArgumentNumber ( "!CustomConstructor" , 0 , 1 , node ) ;
11531157 }
1154- return `${ customDecorator . args [ 0 ] } (${ this . transpileArguments ( node . arguments ) } )` ;
1158+ if ( ! ts . isPropertyAccessExpression ( node . expression )
1159+ && ! ts . isElementAccessExpression ( node . expression )
1160+ && ! tsHelper . getCustomDecorators ( type , this . checker ) . has ( DecoratorKind . NoContext ) ) {
1161+ params = this . transpileArguments ( node . arguments , ts . createIdentifier ( "_G" ) ) ;
1162+ } else {
1163+ params = this . transpileArguments ( node . arguments ) ;
1164+ }
1165+ return `${ customDecorator . args [ 0 ] } (${ params } )` ;
11551166 }
11561167
11571168 return `${ name } .new(${ params } )` ;
@@ -1182,7 +1193,14 @@ export abstract class LuaTranspiler {
11821193 }
11831194
11841195 callPath = this . transpileExpression ( node . expression ) ;
1185- params = this . transpileArguments ( node . arguments ) ;
1196+ const type = this . checker . getTypeAtLocation ( node . expression ) ;
1197+ if ( ! ts . isPropertyAccessExpression ( node . expression )
1198+ && ! ts . isElementAccessExpression ( node . expression )
1199+ && ! tsHelper . getCustomDecorators ( type , this . checker ) . has ( DecoratorKind . NoContext ) ) {
1200+ params = this . transpileArguments ( node . arguments , ts . createIdentifier ( "_G" ) ) ;
1201+ } else {
1202+ params = this . transpileArguments ( node . arguments ) ;
1203+ }
11861204 return isTupleReturn && ! isTupleReturnForward && ! isInDestructingAssignment && returnValueIsUsed
11871205 ? `({ ${ callPath } (${ params } ) })` : `${ callPath } (${ params } )` ;
11881206 }
@@ -1220,16 +1238,12 @@ export abstract class LuaTranspiler {
12201238 return this . transpileArrayCallExpression ( node ) ;
12211239 }
12221240
1241+ if ( tsHelper . isFunctionType ( ownerType , this . checker ) ) {
1242+ return this . transpileFunctionCallExpression ( node ) ;
1243+ }
1244+
12231245 // Get the type of the function
1224- const functionType = this . checker . getTypeAtLocation ( node . expression ) ;
1225- // Don't replace . with : for namespaces or functions defined as properties with lambdas
1226- if ( ( functionType . symbol && ! ( functionType . symbol . flags & ts . SymbolFlags . Method ) )
1227- // Check explicitly for method calls on 'this', since they don't have the Method flag set
1228- || ( node . expression . expression . kind === ts . SyntaxKind . ThisType ) ) {
1229- callPath = this . transpileExpression ( node . expression ) ;
1230- params = this . transpileArguments ( node . arguments ) ;
1231- return `${ callPath } (${ params } )` ;
1232- } else if ( node . expression . expression . kind === ts . SyntaxKind . SuperKeyword ) {
1246+ if ( node . expression . expression . kind === ts . SyntaxKind . SuperKeyword ) {
12331247 // Super calls take the format of super.call(self,...)
12341248 params = this . transpileArguments ( node . arguments , ts . createNode ( ts . SyntaxKind . ThisKeyword ) as ts . Expression ) ;
12351249 return `${ this . transpileExpression ( node . expression ) } (${ params } )` ;
@@ -1243,8 +1257,9 @@ export abstract class LuaTranspiler {
12431257 params = this . transpileArguments ( node . arguments ) ;
12441258 return `(rawget(${ expr } , ${ params } )~=nil)` ;
12451259 } else {
1246- callPath =
1247- `${ this . transpileExpression ( node . expression . expression ) } :${ name } ` ;
1260+ const type = this . checker . getTypeAtLocation ( node . expression ) ;
1261+ const op = tsHelper . getCustomDecorators ( type , this . checker ) . has ( DecoratorKind . NoContext ) ? "." : ":" ;
1262+ callPath = `${ this . transpileExpression ( node . expression . expression ) } ${ op } ${ name } ` ;
12481263 params = this . transpileArguments ( node . arguments ) ;
12491264 return `${ callPath } (${ params } )` ;
12501265 }
@@ -1364,6 +1379,23 @@ export abstract class LuaTranspiler {
13641379 }
13651380 }
13661381
1382+ public transpileFunctionCallExpression ( node : ts . CallExpression ) : string {
1383+ const expression = node . expression as ts . PropertyAccessExpression ;
1384+ const params = this . transpileArguments ( node . arguments ) ;
1385+ const caller = this . transpileExpression ( expression . expression ) ;
1386+ const expressionName = this . transpileIdentifier ( expression . name ) ;
1387+ switch ( expressionName ) {
1388+ case "apply" :
1389+ return this . transpileLuaLibFunction ( LuaLibFeature . FunctionApply , caller , params ) ;
1390+ case "bind" :
1391+ return this . transpileLuaLibFunction ( LuaLibFeature . FunctionBind , caller , params ) ;
1392+ case "call" :
1393+ return this . transpileLuaLibFunction ( LuaLibFeature . FunctionCall , caller , params ) ;
1394+ default :
1395+ throw TSTLErrors . UnsupportedProperty ( "function" , expressionName , node ) ;
1396+ }
1397+ }
1398+
13671399 public transpileArguments ( params : ts . NodeArray < ts . Expression > , context ?: ts . Expression ) : string {
13681400 const parameters : string [ ] = [ ] ;
13691401
@@ -1596,7 +1628,9 @@ export abstract class LuaTranspiler {
15961628 let result = "" ;
15971629 const methodName = this . transpileIdentifier ( node . name ) ;
15981630
1599- const [ paramNames , spreadIdentifier ] = this . transpileParameters ( node . parameters ) ;
1631+ const type = this . checker . getTypeAtLocation ( node ) ;
1632+ const context = tsHelper . getCustomDecorators ( type , this . checker ) . has ( DecoratorKind . NoContext ) ? null : "self" ;
1633+ const [ paramNames , spreadIdentifier ] = this . transpileParameters ( node . parameters , context ) ;
16001634
16011635 let prefix = this . accessPrefix ( node ) ;
16021636
@@ -1620,9 +1654,13 @@ export abstract class LuaTranspiler {
16201654 }
16211655
16221656 // Transpile a list of parameters, returns a list of transpiled parameters and an optional spread identifier
1623- public transpileParameters ( parameters : ts . NodeArray < ts . ParameterDeclaration > ) : [ string [ ] , string ] {
1657+ public transpileParameters ( parameters : ts . NodeArray < ts . ParameterDeclaration > , context : string | null )
1658+ : [ string [ ] , string ] {
16241659 // Build parameter string
16251660 const paramNames : string [ ] = [ ] ;
1661+ if ( context ) {
1662+ paramNames . push ( context ) ;
1663+ }
16261664
16271665 let spreadIdentifier = "" ;
16281666
@@ -1673,12 +1711,12 @@ export abstract class LuaTranspiler {
16731711 methodName = "__tostring" ;
16741712 }
16751713
1676- const [ paramNames , spreadIdentifier ] = this . transpileParameters ( node . parameters ) ;
1677-
1678- const selfParamNames = [ "self" ] . concat ( paramNames ) ;
1714+ const type = this . checker . getTypeAtLocation ( node ) ;
1715+ const context = tsHelper . getCustomDecorators ( type , this . checker ) . has ( DecoratorKind . NoContext ) ? null : "self" ;
1716+ const [ paramNames , spreadIdentifier ] = this . transpileParameters ( node . parameters , context ) ;
16791717
16801718 // Build function header
1681- result += this . indent + `function ${ callPath } ${ methodName } (${ selfParamNames . join ( "," ) } )\n` ;
1719+ result += this . indent + `function ${ callPath } ${ methodName } (${ paramNames . join ( "," ) } )\n` ;
16821720
16831721 this . pushIndent ( ) ;
16841722 result += this . transpileFunctionBody ( node . parameters , node . body , spreadIdentifier ) ;
@@ -1932,7 +1970,7 @@ export abstract class LuaTranspiler {
19321970 } else if ( ts . isShorthandPropertyAssignment ( element ) ) {
19331971 properties . push ( `${ name } = ${ name } ` ) ;
19341972 } else if ( ts . isMethodDeclaration ( element ) ) {
1935- const expression = this . transpileFunctionExpression ( element ) ;
1973+ const expression = this . transpileFunctionExpression ( element , "self" ) ;
19361974 properties . push ( `${ name } = ${ expression } ` ) ;
19371975 } else {
19381976 throw TSTLErrors . UnsupportedKind ( "object literal element" , element . kind , node ) ;
@@ -1942,30 +1980,15 @@ export abstract class LuaTranspiler {
19421980 return "{" + properties . join ( "," ) + "}" ;
19431981 }
19441982
1945- public transpileFunctionExpression ( node : ts . FunctionLikeDeclaration ) : string {
1983+ public transpileFunctionExpression ( node : ts . FunctionLikeDeclaration , context : string | null ) : string {
19461984 // Build parameter string
1947- const paramNames : string [ ] = [ ] ;
1948- if ( ts . isMethodDeclaration ( node ) ) {
1949- paramNames . push ( "self" ) ;
1950- }
1951- node . parameters . forEach ( param => {
1952- paramNames . push ( this . transpileIdentifier ( param . name as ts . Identifier ) ) ;
1953- } ) ;
1954-
1955- const defaultValueParams = node . parameters . filter ( declaration => declaration . initializer !== undefined ) ;
1956-
1957- if ( ts . isBlock ( node . body ) || defaultValueParams . length > 0 ) {
1958- let result = `function(${ paramNames . join ( "," ) } )\n` ;
1959- this . pushIndent ( ) ;
1960- result += this . transpileParameterDefaultValues ( defaultValueParams ) ;
1961- result += this . transpileBlock ( node . body as ts . Block ) ;
1962- this . popIndent ( ) ;
1963- return result + this . indent + "end\n" ;
1964- } else {
1965- // Transpile as return value
1966- const returnVal = this . transpileReturn ( ts . createReturn ( node . body ) ) ;
1967- return `function(${ paramNames . join ( "," ) } ) ${ returnVal } end` ;
1968- }
1985+ const [ paramNames , spreadIdentifier ] = this . transpileParameters ( node . parameters , context ) ;
1986+ let result = `function(${ paramNames . join ( "," ) } )\n` ;
1987+ this . pushIndent ( ) ;
1988+ const body = ts . isBlock ( node . body ) ? node . body : ts . createBlock ( [ ts . createReturn ( node . body ) ] ) ;
1989+ result += this . transpileFunctionBody ( node . parameters , body , spreadIdentifier ) ;
1990+ this . popIndent ( ) ;
1991+ return result + this . indent + "end" ;
19691992 }
19701993
19711994 public transpileParameterDefaultValues ( params : ts . ParameterDeclaration [ ] ) : string {
0 commit comments