@@ -3055,4 +3055,194 @@ namespace ts {
3055
3055
function tryGetModuleNameFromDeclaration ( declaration : ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration , host : EmitHost , resolver : EmitResolver , compilerOptions : CompilerOptions ) {
3056
3056
return tryGetModuleNameFromFile ( resolver . getExternalModuleFileFromDeclaration ( declaration ) , host , compilerOptions ) ;
3057
3057
}
3058
+
3059
+ export function convertForOf ( node : ForOfStatement , convertedLoopBodyStatements : Statement [ ] ,
3060
+ visitor : ( node : Node ) => VisitResult < Node > ,
3061
+ enableSubstitutionsForBlockScopedBindings : ( ) => void ,
3062
+ context : TransformationContext ,
3063
+ convertObjectRest ?: boolean ) : ForStatement | ForOfStatement {
3064
+ // The following ES6 code:
3065
+ //
3066
+ // for (let v of expr) { }
3067
+ //
3068
+ // should be emitted as
3069
+ //
3070
+ // for (var _i = 0, _a = expr; _i < _a.length; _i++) {
3071
+ // var v = _a[_i];
3072
+ // }
3073
+ //
3074
+ // where _a and _i are temps emitted to capture the RHS and the counter,
3075
+ // respectively.
3076
+ // When the left hand side is an expression instead of a let declaration,
3077
+ // the "let v" is not emitted.
3078
+ // When the left hand side is a let/const, the v is renamed if there is
3079
+ // another v in scope.
3080
+ // Note that all assignments to the LHS are emitted in the body, including
3081
+ // all destructuring.
3082
+ // Note also that because an extra statement is needed to assign to the LHS,
3083
+ // for-of bodies are always emitted as blocks.
3084
+
3085
+ const expression = visitNode ( node . expression , visitor , isExpression ) ;
3086
+ const initializer = node . initializer ;
3087
+ const statements : Statement [ ] = [ ] ;
3088
+
3089
+ // In the case where the user wrote an identifier as the RHS, like this:
3090
+ //
3091
+ // for (let v of arr) { }
3092
+ //
3093
+ // we don't want to emit a temporary variable for the RHS, just use it directly.
3094
+ const counter = convertObjectRest ? undefined : createLoopVariable ( ) ;
3095
+ const rhsReference = expression . kind === SyntaxKind . Identifier
3096
+ ? createUniqueName ( ( < Identifier > expression ) . text )
3097
+ : createTempVariable ( /*recordTempVariable*/ undefined ) ;
3098
+ const elementAccess = convertObjectRest ? rhsReference : createElementAccess ( rhsReference , counter ) ;
3099
+
3100
+ // Initialize LHS
3101
+ // var v = _a[_i];
3102
+ if ( isVariableDeclarationList ( initializer ) ) {
3103
+ if ( initializer . flags & NodeFlags . BlockScoped ) {
3104
+ enableSubstitutionsForBlockScopedBindings ( ) ;
3105
+ }
3106
+
3107
+ const firstOriginalDeclaration = firstOrUndefined ( initializer . declarations ) ;
3108
+ if ( firstOriginalDeclaration && isBindingPattern ( firstOriginalDeclaration . name ) ) {
3109
+ // This works whether the declaration is a var, let, or const.
3110
+ // It will use rhsIterationValue _a[_i] as the initializer.
3111
+ const declarations = flattenVariableDestructuring (
3112
+ firstOriginalDeclaration ,
3113
+ elementAccess ,
3114
+ visitor ,
3115
+ /*recordTempVariable*/ undefined ,
3116
+ convertObjectRest
3117
+ ) ;
3118
+
3119
+ const declarationList = createVariableDeclarationList ( declarations , /*location*/ initializer ) ;
3120
+ setOriginalNode ( declarationList , initializer ) ;
3121
+
3122
+ // Adjust the source map range for the first declaration to align with the old
3123
+ // emitter.
3124
+ const firstDeclaration = declarations [ 0 ] ;
3125
+ const lastDeclaration = lastOrUndefined ( declarations ) ;
3126
+ setSourceMapRange ( declarationList , createRange ( firstDeclaration . pos , lastDeclaration . end ) ) ;
3127
+
3128
+ statements . push (
3129
+ createVariableStatement (
3130
+ /*modifiers*/ undefined ,
3131
+ declarationList
3132
+ )
3133
+ ) ;
3134
+ }
3135
+ else {
3136
+ // The following call does not include the initializer, so we have
3137
+ // to emit it separately.
3138
+ statements . push (
3139
+ createVariableStatement (
3140
+ /*modifiers*/ undefined ,
3141
+ setOriginalNode (
3142
+ createVariableDeclarationList ( [
3143
+ createVariableDeclaration (
3144
+ firstOriginalDeclaration ? firstOriginalDeclaration . name : createTempVariable ( /*recordTempVariable*/ undefined ) ,
3145
+ /*type*/ undefined ,
3146
+ createElementAccess ( rhsReference , counter )
3147
+ )
3148
+ ] , /*location*/ moveRangePos ( initializer , - 1 ) ) ,
3149
+ initializer
3150
+ ) ,
3151
+ /*location*/ moveRangeEnd ( initializer , - 1 )
3152
+ )
3153
+ ) ;
3154
+ }
3155
+ }
3156
+ else {
3157
+ // Initializer is an expression. Emit the expression in the body, so that it's
3158
+ // evaluated on every iteration.
3159
+ const assignment = createAssignment ( initializer , elementAccess ) ;
3160
+ if ( isDestructuringAssignment ( assignment ) ) {
3161
+ // This is a destructuring pattern, so we flatten the destructuring instead.
3162
+ statements . push (
3163
+ createStatement (
3164
+ flattenDestructuringAssignment (
3165
+ context ,
3166
+ assignment ,
3167
+ /*needsValue*/ false ,
3168
+ context . hoistVariableDeclaration ,
3169
+ visitor ,
3170
+ convertObjectRest
3171
+ )
3172
+ )
3173
+ ) ;
3174
+ }
3175
+ else {
3176
+ // Currently there is not way to check that assignment is binary expression of destructing assignment
3177
+ // so we have to cast never type to binaryExpression
3178
+ ( < BinaryExpression > assignment ) . end = initializer . end ;
3179
+ statements . push ( createStatement ( assignment , /*location*/ moveRangeEnd ( initializer , - 1 ) ) ) ;
3180
+ }
3181
+ }
3182
+
3183
+ let bodyLocation : TextRange ;
3184
+ let statementsLocation : TextRange ;
3185
+ if ( convertedLoopBodyStatements ) {
3186
+ addRange ( statements , convertedLoopBodyStatements ) ;
3187
+ }
3188
+ else {
3189
+ const statement = visitNode ( node . statement , visitor , isStatement ) ;
3190
+ if ( isBlock ( statement ) ) {
3191
+ addRange ( statements , statement . statements ) ;
3192
+ bodyLocation = statement ;
3193
+ statementsLocation = statement . statements ;
3194
+ }
3195
+ else {
3196
+ statements . push ( statement ) ;
3197
+ }
3198
+ }
3199
+
3200
+ // The old emitter does not emit source maps for the expression
3201
+ setEmitFlags ( expression , EmitFlags . NoSourceMap | getEmitFlags ( expression ) ) ;
3202
+
3203
+ // The old emitter does not emit source maps for the block.
3204
+ // We add the location to preserve comments.
3205
+ const body = createBlock (
3206
+ createNodeArray ( statements , /*location*/ statementsLocation ) ,
3207
+ /*location*/ bodyLocation
3208
+ ) ;
3209
+
3210
+ setEmitFlags ( body , EmitFlags . NoSourceMap | EmitFlags . NoTokenSourceMaps ) ;
3211
+
3212
+ let forStatement : ForStatement | ForOfStatement ;
3213
+ if ( convertObjectRest ) {
3214
+
3215
+ forStatement = createForOf (
3216
+ createVariableDeclarationList ( [
3217
+ createVariableDeclaration ( rhsReference , /*type*/ undefined , /*initializer*/ undefined , /*location*/ node . expression )
3218
+ ] , /*location*/ node . expression ) ,
3219
+ node . expression ,
3220
+ body ,
3221
+ /*location*/ node
3222
+ ) ;
3223
+ }
3224
+ else {
3225
+ forStatement = createFor (
3226
+ setEmitFlags (
3227
+ createVariableDeclarationList ( [
3228
+ createVariableDeclaration ( counter , /*type*/ undefined , createLiteral ( 0 ) , /*location*/ moveRangePos ( node . expression , - 1 ) ) ,
3229
+ createVariableDeclaration ( rhsReference , /*type*/ undefined , expression , /*location*/ node . expression )
3230
+ ] , /*location*/ node . expression ) ,
3231
+ EmitFlags . NoHoisting
3232
+ ) ,
3233
+ createLessThan (
3234
+ counter ,
3235
+ createPropertyAccess ( rhsReference , "length" ) ,
3236
+ /*location*/ node . expression
3237
+ ) ,
3238
+ createPostfixIncrement ( counter , /*location*/ node . expression ) ,
3239
+ body ,
3240
+ /*location*/ node
3241
+ ) ;
3242
+ }
3243
+
3244
+ // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter.
3245
+ setEmitFlags ( forStatement , EmitFlags . NoTokenTrailingSourceMaps ) ;
3246
+ return forStatement ;
3247
+ }
3058
3248
}
0 commit comments