@@ -145,11 +145,12 @@ type EvaluatableOps = ExprLikeOps | StatLikeOps
145
145
type PairOp = BaseOp < O . pair >
146
146
type RefOp = BaseOp < O . ref >
147
147
type ArrayHoleOp = BaseLiteralOp < L . array_hole >
148
- interface DestructurePairOp extends BaseOp < O . pair > { readonly x : DeclareOp ; readonly y : null }
148
+ interface DestructurePairOp extends BaseOp < O . pair > { readonly x : DeclareOp | DestructuringComposedOp ; readonly y : null }
149
149
interface RefAssignOp extends BaseOp < O . assign > { readonly y : RefOp | DestructuringComposedOp }
150
150
interface PlainRefAssignOp extends RefAssignOp { readonly y : RefOp }
151
151
interface BaseDestructuringComposedOp < T extends "[" | "{" > extends BaseOp < O . composed > {
152
- readonly q : readonly ( T extends "[" ? DeclareOp | ArrayHoleOp : RefOp | PlainRefAssignOp | DestructurePairOp ) [ ]
152
+ readonly q : T extends "[" ? readonly ( DeclareOp | DestructuringComposedOp | ArrayHoleOp ) [ ]
153
+ : readonly ( RefOp | PlainRefAssignOp | DestructurePairOp ) [ ]
153
154
readonly x : T
154
155
readonly y : AnalysedVars
155
156
}
@@ -243,13 +244,6 @@ const isArray = Array.isArray as { <T> (x: readonly T[] | CoreOp<keyof OpValues>
243
244
const isVarAction = < K extends AllStatPrefix > ( s : K ) : s is K & VarActions => "let,const,var" . includes ( s )
244
245
const resetRe_ = ( ) : true => ( < RegExpOne > / a ? / ) . test ( "" ) as true
245
246
const objCreate = DefaultObject . create as { ( proto : null ) : VarDict ; < T > ( o : null ) : SafeDict < T > }
246
- const objEntries = ! ( Build . BTypes & BrowserType . Chrome )
247
- || Build . MinCVer >= BrowserVer . MinEnsuredES$Object$$values$and$$entries ? DefaultObject . entries ! as never
248
- : DefaultObject . entries as unknown as undefined || ( < T extends string > ( object : object ) : [ T , unknown ] [ ] => {
249
- const entries : ReturnType < ObjectConstructor [ "entries" ] > = [ ]
250
- for ( const name of DefaultObject . keys ( object ) ) { entries . push ( [ name , ( object as Dict < unknown > ) [ name ] ] ) }
251
- return entries as [ T , unknown ] [ ]
252
- } )
253
247
const throwSyntax = ( error : string ) : never => { throw new SyntaxError ( error ) }
254
248
const ValueProperty = ( value : unknown , writable : boolean , enumerable : boolean , config : boolean ) : PropertyDescriptor =>
255
249
( { value, writable, enumerable, configurable : config } )
@@ -280,6 +274,20 @@ if (!kHasMap) {
280
274
Map2 . prototype . set = function < K extends string , V > ( this : Map2 < K , V > , k : K , v : V ) { this . m ! [ k ] = v }
281
275
}
282
276
277
+ const collectEnumerable = ( src : any , filterKey : ( key : string | symbol ) => boolean
278
+ , props : { [ s : string | number | symbol ] : PropertyDescriptor & Partial < SafeObject > } ) => {
279
+ const kSymbol = ! ( Build . BTypes & BrowserType . Chrome ) || Build . MinCVer >= BrowserVer . MinEnsuredES6$ForOf$Map$SetAnd$Symbol
280
+ const GetSymbols = DefaultObject . getOwnPropertySymbols
281
+ for ( const symbol of ( Object . keys ( src as object ) as ( string | symbol ) [ ] )
282
+ . concat ( kSymbol || GetSymbols ? GetSymbols ! ( src ) : [ ] ) ) {
283
+ const prop = filterKey ( symbol ) ? DefaultObject . getOwnPropertyDescriptor ( src , symbol as symbol ) : null
284
+ if ( prop ?. enumerable ) {
285
+ props [ symbol ] = ValueProperty ( prop . writable !== void 0 ? prop . value : ( src as any ) [ symbol ]
286
+ , true , true , true )
287
+ }
288
+ }
289
+ }
290
+
283
291
//#endregion helper functions
284
292
285
293
//#region tokenize
@@ -724,13 +732,16 @@ const parseTree = (tokens_: readonly Token[], inNewFunc: boolean | null | undefi
724
732
const getEscapeAnalyser = ( ) : ( func : BaseOp < O . fn > ) => void => {
725
733
interface WritableTempBlockOp extends Pick < BaseOp < O . block > , "o" | "q" > {
726
734
/** consts */ x : VarName [ ] | null , /** lets */ y : VarName [ ] | null }
727
- const ToVarNames = ( out : VarName [ ] , ops : readonly ( DeclareOp | DestructurePairOp | ArrayHoleOp ) [ ] ) : VarName [ ] => {
735
+ const ToVarNames = ( out : VarName [ ]
736
+ , ops : readonly ( DeclareOp | DestructurePairOp | DestructuringComposedOp | ArrayHoleOp ) [ ] ) : VarName [ ] => {
728
737
for ( let op of ops ) {
729
738
op = op . o === O . pair ? op . x : op
730
739
if ( op . o === O . ref ) {
731
- out . push ( op . q )
740
+ op . q !== kDots && out . push ( op . q )
732
741
} else if ( op . o === O . literal ) { /* empty */ }
733
- else if ( op . y . o === O . ref ) {
742
+ else if ( op . o === O . composed ) {
743
+ ToVarNames ( out , op . q )
744
+ } else if ( op . y . o === O . ref ) {
734
745
out . push ( op . y . q )
735
746
} else {
736
747
ToVarNames ( out , op . y . q )
@@ -1109,70 +1120,72 @@ const evalLet = (action: VarActions | "arg", declarations: readonly DeclareOp[],
1109
1120
1110
1121
const evalDestructuring = ( destructOp : DestructuringComposedOp , composed_value : any , parentOp : RefAssignOp | null ) :void => {
1111
1122
if ( destructOp . x === "[" ) {
1112
- let index = 0 , iterator = evalIter ( composed_value , parentOp ? parentOp . x : )
1123
+ const iterator = evalIter ( composed_value , parentOp ? parentOp . x : Op ( O . ref , kUnknown as VarName , 0 , 0 ) )
1124
+ let index = 0 , cur : IteratorResult < any > = { value : void 0 , done : false }
1113
1125
for ( const op of destructOp . q ) {
1114
- if ( op . o === O . ref && op . q === kDots ) {
1115
- const { y , i } = _resolveVarRef ( destructOp . q [ index + 1 ] as RefOp , R . eveNotInited )
1116
- y [ i ] = [ ] . slice . call ( composed_value , index ) as unknown as number
1117
- break
1126
+ if ( ! cur . done ) {
1127
+ cur = Build . BTypes & BrowserType . Chrome && Build . MinCVer < BrowserVer . MinEnsuredES6$ForOf$Map$SetAnd$Symbol
1128
+ && ! kIterator ? index < composed_value . length ? { value : composed_value [ index ] , done : false }
1129
+ : { value : void 0 , done : true } : iterator ! . next ( )
1118
1130
}
1119
1131
if ( op . o === O . literal ) {
1120
1132
if ( 0 ) { op . q satisfies L . array_hole }
1121
-
1122
- continue
1123
- }
1124
- const keyOp = op . o === O . ref ? op . q : op . o === O . assign ? op . y . o === O . ref ? op . y . q : index : op . q
1125
- const key : string | number | symbol = evalAccessKey ( typeof keyOp === "object" ? opEvals [ keyOp . o ] ( keyOp ) : keyOp )
1126
- const target : DeclareOp = op . o === O . pair ? op . x : op
1127
- let value = composed_value [ key ]
1128
- const useDefault = value === void 0 && target . o === O . assign
1129
- if ( useDefault ) {
1130
- value = opEvals [ target . x . o ] ( target . x )
1131
- }
1132
- const ref = target . o === O . ref ? _resolveVarRef ( target , R . eveNotInited )
1133
- : target . y . o === O . ref ? _resolveVarRef ( target . y , R . eveNotInited )
1134
- : null
1135
- if ( ref !== null ) {
1136
- ref . y [ ref . i ] = value
1133
+ } else if ( op . o === O . ref && op . q === kDots ) { // q[index + 1]: RefOp | DestructuringComposedOp
1134
+ const arr = cur . done ? [ ] : [ cur . value ]
1135
+ if ( Build . BTypes & BrowserType . Chrome && Build . MinCVer < BrowserVer . MinEnsuredES6$ForOf$Map$SetAnd$Symbol
1136
+ && ! kIterator ) {
1137
+ while ( ++ index < composed_value . length ) { arr . push ( composed_value [ index ] ) }
1138
+ } else {
1139
+ while ( ! ( cur = iterator ! . next ( ) ) . done ) { arr . push ( cur . value ) }
1140
+ }
1141
+ iter ( kDots , destructOp . q [ index + 1 ] as Exclude < typeof destructOp . q [ 0 ] , ArrayHoleOp > , arr )
1142
+ break
1137
1143
} else {
1138
- evalDestructuring ( ( target as Exclude < typeof target , RefOp > & { y : BaseOp < O . composed > } ) . y , value
1139
- , useDefault ? target : Op ( O . assign , "=" , Op ( O . access , "["
1140
- , parentOp ? parentOp . x : Op ( O . ref , `(${ kDots } )` as VarName , 0 , 0 )
1141
- , typeof keyOp === "object" ? keyOp : Op ( O . literal , L . plain , keyOp , null ) )
1142
- , target . y as DestructuringComposedOp ) as RefAssignOp )
1144
+ iter ( index , op , cur . value )
1143
1145
}
1144
1146
index ++
1145
1147
}
1146
-
1148
+ } else if ( isLooselyNull ( composed_value ) ) {
1149
+ const first = destructOp . q [ 0 ] , desc = first . o == O . ref ? first . q !== kDots ? first . q : ""
1150
+ : first . o === O . pair && ( typeof first . q !== "object" || first . q . o !== O . comma ) && first . x . o !== O . assign
1151
+ ? typeof first . q === "object" ? evalLiteral ( first . q ) : first . q : ""
1152
+ throwType ( "Cannot destructure " + ( desc ? "property '" + desc + "' of '" : "'" )
1153
+ + ( parentOp && ToString ( parentOp . x , ( 1 << O . call ) | ( 1 << O . access ) | ( 1 << O . unary ) ) || kUnknown )
1154
+ + "' as it is " + composed_value + "." )
1147
1155
} else {
1148
1156
const visited = new Map2 < string , 1 > ( )
1149
1157
for ( const op of destructOp . q ) {
1150
1158
if ( op . o === O . ref && op . q === kDots ) {
1151
- // @todo
1159
+ const props : Parameters < typeof collectEnumerable > [ 2 ] = objCreate ( null ) as any
1160
+ collectEnumerable ( composed_value , key => ! visited . get ( key as string ) , props )
1161
+ const sub_value = ( objCreate as typeof DefaultObject . create ) ( DefaultObject . prototype , props )
1162
+ iter ( kDots , destructOp . q [ destructOp . q . length - 1 ] as RefOp , sub_value )
1152
1163
break
1153
1164
}
1154
1165
const keyOp : string | ExprLikeOps = op . o === O . ref ? op . q : op . o === O . assign ? op . y . q : op . q
1155
1166
const key : string | number | symbol = evalAccessKey ( typeof keyOp === "object" ? opEvals [ keyOp . o ] ( keyOp ) : keyOp )
1156
- const target : DeclareOp = op . o === O . pair ? op . x : op
1157
- let value = composed_value [ key ]
1167
+ iter ( keyOp , op . o === O . pair ? op . x : op , composed_value [ key ] )
1168
+ visited . set ( key as string , 1 )
1169
+ }
1170
+ }
1171
+ function iter ( keyOp : string | number | ExprLikeOps , target : DeclareOp | DestructuringComposedOp , value : any ) {
1158
1172
const useDefault = value === void 0 && target . o === O . assign
1159
1173
if ( useDefault ) {
1160
1174
value = opEvals [ target . x . o ] ( target . x )
1161
1175
}
1162
1176
const ref = target . o === O . ref ? _resolveVarRef ( target , R . eveNotInited )
1163
- : target . y . o === O . ref ? _resolveVarRef ( target . y , R . eveNotInited )
1177
+ : target . o === O . assign && target . y . o === O . ref ? _resolveVarRef ( target . y , R . eveNotInited )
1164
1178
: null
1165
1179
if ( ref !== null ) {
1166
1180
ref . y [ ref . i ] = value
1167
1181
} else {
1168
- evalDestructuring ( ( target as Exclude < typeof target , RefOp > & { y : BaseOp < O . composed > } ) . y , value
1182
+ evalDestructuring ( target . o === O . composed ? target
1183
+ : ( target as Exclude < typeof target , RefOp > & { y : BaseOp < O . composed > } ) . y , value
1169
1184
, useDefault ? target : Op ( O . assign , "=" , Op ( O . access , "["
1170
- , parentOp ? parentOp . x : Op ( O . ref , `( ${ kDots } )` as VarName , 0 , 0 )
1185
+ , parentOp ? parentOp . x : Op ( O . ref , kUnknown as VarName , 0 , 0 )
1171
1186
, typeof keyOp === "object" ? keyOp : Op ( O . literal , L . plain , keyOp , null ) )
1172
1187
, target . y as DestructuringComposedOp ) as RefAssignOp )
1173
1188
}
1174
- visited . set ( key as string , 1 )
1175
- }
1176
1189
}
1177
1190
}
1178
1191
@@ -1400,19 +1413,8 @@ const evalNever = (op: BaseOp<KStatLikeO | O.pair | O.fnDesc>): void => {
1400
1413
if ( isRef && item . q === kDots ) {
1401
1414
i ++
1402
1415
const src = opEvals [ arr [ i ] . o ] ( arr [ i ] )
1403
- if ( typeof src === "object" && src !== null ) {
1404
- const HasSymbol = ! ( Build . BTypes & BrowserType . Chrome )
1405
- || Build . MinCVer >= BrowserVer . MinEnsuredES6$ForOf$Map$SetAnd$Symbol
1406
- const GetSymbols = HasSymbol ? 0 as never : DefaultObject . getOwnPropertySymbols
1407
- const symbols = HasSymbol ? DefaultObject . getOwnPropertySymbols ! ( src ) : GetSymbols ? GetSymbols ( src ) : [ ]
1408
- for ( const item of objEntries ( src as object ) ) { props [ item [ 0 ] ] = ValueProperty ( item [ 1 ] , true , true , true ) }
1409
- for ( const symbol of symbols ) {
1410
- const prop = DefaultObject . getOwnPropertyDescriptor ( src , symbol )
1411
- if ( prop ?. enumerable ) {
1412
- props [ symbol ] = ValueProperty ( prop . writable !== void 0 ? prop . value : ( src as any ) [ symbol ]
1413
- , true , true , true )
1414
- }
1415
- }
1416
+ if ( typeof src === "object" && ! isLooselyNull ( src ) ) {
1417
+ collectEnumerable ( src , ( ) => true , props )
1416
1418
}
1417
1419
continue
1418
1420
}
@@ -1432,7 +1434,7 @@ const evalNever = (op: BaseOp<KStatLikeO | O.pair | O.fnDesc>): void => {
1432
1434
newProto = value as object | null // a second key of the "__proto__" literal is a syntax error on Chrome 96
1433
1435
}
1434
1436
}
1435
- return DefaultObject . create ( newProto , props )
1437
+ return ( objCreate as typeof DefaultObject . create ) ( newProto , props )
1436
1438
} , evalLiteral = ( op : LiteralOp ) : unknown => {
1437
1439
switch ( op . q ) {
1438
1440
case L . plain : return op . x
0 commit comments