@@ -699,13 +699,19 @@ export class LuaTransformer {
699699
700700 let restParamName : tstl . Identifier ;
701701 let dotsLiteral : tstl . DotsLiteral ;
702+ let identifierIndex = 0 ;
702703
703704 // Only push parameter name to paramName array if it isn't a spread parameter
704705 for ( const param of parameters ) {
705706 if ( ts . isIdentifier ( param . name ) && param . name . originalKeywordKind === ts . SyntaxKind . ThisKeyword ) {
706707 continue ;
707708 }
708- const paramName = this . transformIdentifier ( param . name as ts . Identifier ) ;
709+
710+ // Binding patterns become ____TS_bindingPattern0, ____TS_bindingPattern1, etc as function parameters
711+ // See transformFunctionBody for how these values are destructured
712+ const paramName = ts . isObjectBindingPattern ( param . name ) || ts . isArrayBindingPattern ( param . name )
713+ ? tstl . createIdentifier ( `____TS_bindingPattern${ identifierIndex ++ } ` )
714+ : this . transformIdentifier ( param . name as ts . Identifier ) ;
709715
710716 // This parameter is a spread parameter (...param)
711717 if ( ! param . dotDotDotToken ) {
@@ -737,6 +743,18 @@ export class LuaTransformer {
737743
738744 headerStatements . push ( ...defaultValueDeclarations ) ;
739745
746+ // Add object binding patterns
747+ let identifierIndex = 0 ;
748+ const bindingPatternDeclarations : tstl . Statement [ ] = [ ] ;
749+ parameters . forEach ( binding => {
750+ if ( ts . isObjectBindingPattern ( binding . name ) || ts . isArrayBindingPattern ( binding . name ) ) {
751+ const identifier = tstl . createIdentifier ( `____TS_bindingPattern${ identifierIndex ++ } ` ) ;
752+ bindingPatternDeclarations . push ( ...this . transformBindingPattern ( binding . name , identifier ) ) ;
753+ }
754+ } ) ;
755+
756+ headerStatements . push ( ...bindingPatternDeclarations ) ;
757+
740758 // Push spread operator here
741759 if ( spreadIdentifier ) {
742760 const spreadTable = this . wrapInTable ( tstl . createDotsLiteral ( ) ) ;
@@ -766,6 +784,57 @@ export class LuaTransformer {
766784 return tstl . createIfStatement ( nilCondition , ifBlock , undefined , declaration ) ;
767785 }
768786
787+ public * transformBindingPattern (
788+ pattern : ts . BindingPattern ,
789+ table : tstl . Identifier ,
790+ propertyAccessStack : ts . PropertyName [ ] = [ ]
791+ ) : IterableIterator < tstl . Statement >
792+ {
793+ const isObjectBindingPattern = ts . isObjectBindingPattern ( pattern ) ;
794+ for ( let index = 0 ; index < pattern . elements . length ; index ++ ) {
795+ const element = pattern . elements [ index ] ;
796+ if ( ts . isBindingElement ( element ) ) {
797+ if ( ts . isArrayBindingPattern ( element . name ) || ts . isObjectBindingPattern ( element . name ) ) {
798+ // nested binding pattern
799+ const propertyName = isObjectBindingPattern
800+ ? element . propertyName
801+ : ts . createNumericLiteral ( String ( index + 1 ) ) ;
802+ propertyAccessStack . push ( propertyName ) ;
803+ yield * this . transformBindingPattern ( element . name , table , propertyAccessStack ) ;
804+ } else {
805+ // Disallow ellipsis destructure
806+ if ( element . dotDotDotToken ) {
807+ throw TSTLErrors . ForbiddenEllipsisDestruction ( element ) ;
808+ }
809+ // Build the path to the table
810+ let tableExpression : tstl . Expression = table ;
811+ propertyAccessStack . forEach ( property => {
812+ const propertyName = ts . isPropertyName ( property )
813+ ? this . transformPropertyName ( property )
814+ : this . transformNumericLiteral ( property ) ;
815+ tableExpression = tstl . createTableIndexExpression ( tableExpression , propertyName ) ;
816+ } ) ;
817+ // The identifier of the new variable
818+ const variableName = this . transformIdentifier ( element . name as ts . Identifier ) ;
819+ // The field to extract
820+ const propertyName = this . transformIdentifier (
821+ ( element . propertyName || element . name ) as ts . Identifier ) ;
822+ const expression = isObjectBindingPattern
823+ ? tstl . createTableIndexExpression ( tableExpression , tstl . createStringLiteral ( propertyName . text ) )
824+ : tstl . createTableIndexExpression ( tableExpression , tstl . createNumericLiteral ( index + 1 ) ) ;
825+ if ( element . initializer ) {
826+ const defaultExpression = tstl . createBinaryExpression ( expression ,
827+ this . transformExpression ( element . initializer ) , tstl . SyntaxKind . OrOperator ) ;
828+ yield * this . createLocalOrExportedOrGlobalDeclaration ( variableName , defaultExpression ) ;
829+ } else {
830+ yield * this . createLocalOrExportedOrGlobalDeclaration ( variableName , expression ) ;
831+ }
832+ }
833+ }
834+ }
835+ propertyAccessStack . pop ( ) ;
836+ }
837+
769838 public transformModuleDeclaration ( statement : ts . ModuleDeclaration ) : tstl . Statement [ ] {
770839 const decorators = tsHelper . getCustomDecorators ( this . checker . getTypeAtLocation ( statement ) , this . checker ) ;
771840 // If phantom namespace elide the declaration and return the body
@@ -976,8 +1045,25 @@ export class LuaTransformer {
9761045 statement
9771046 ) ;
9781047 }
979- } else if ( ts . isArrayBindingPattern ( statement . name ) ) {
980- // Destructuring type
1048+ } else if ( ts . isArrayBindingPattern ( statement . name ) || ts . isObjectBindingPattern ( statement . name ) ) {
1049+ // Destructuring types
1050+
1051+ // For nested bindings and object bindings, fall back to transformBindingPattern
1052+ if ( ts . isObjectBindingPattern ( statement . name )
1053+ || statement . name . elements . some ( elem => ! ts . isBindingElement ( elem ) || ! ts . isIdentifier ( elem . name ) ) ) {
1054+ const statements = [ ] ;
1055+ let table : tstl . Identifier ;
1056+ if ( ts . isIdentifier ( statement . initializer ) ) {
1057+ table = this . transformIdentifier ( statement . initializer ) ;
1058+ } else {
1059+ // Contain the expression in a temporary variable
1060+ table = tstl . createIdentifier ( "____" ) ;
1061+ statements . push ( tstl . createVariableDeclarationStatement (
1062+ table , this . transformExpression ( statement . initializer ) ) ) ;
1063+ }
1064+ statements . push ( ...this . transformBindingPattern ( statement . name , table ) ) ;
1065+ return statements ;
1066+ }
9811067
9821068 // Disallow ellipsis destruction
9831069 if ( statement . name . elements . some ( elem => ! ts . isBindingElement ( elem ) || elem . dotDotDotToken !== undefined ) ) {
@@ -1009,8 +1095,6 @@ export class LuaTransformer {
10091095 statement
10101096 ) ;
10111097 }
1012- } else {
1013- throw TSTLErrors . UnsupportedKind ( "variable declaration" , statement . name . kind , statement ) ;
10141098 }
10151099 }
10161100
0 commit comments