···2948294829492949no_descriptor:
29502950 if (existing <= 0) goto create_new;
29512951-29522952- if (is_const_prop(js, existing)) {
29532953- if (js->flags & F_STRICT) return js_mkerr(js, "assignment to constant");
29542954- return mkval(T_PROP, existing);
29552955- }
29512951+ if (is_const_prop(js, existing)) return js_mkerr(js, "assignment to constant");
2956295229572953 saveval(js, existing + sizeof(jsoff_t) * 2, v);
29582954 if (vtype(obj) != T_ARR || klen == 0 || key[0] < '0' || key[0] > '9') goto done_update;
···50034999 if (vtype(lhs) != T_PROP) {
50045000 if (js->flags & F_STRICT) {
50055001 return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid left-hand side in assignment");
50065006- }
50075007- return val;
50025002+ } return val;
50085003 }
5009500450105005 jsoff_t propoff = (jsoff_t) vdata(lhs);
50115011-50125006 jsoff_t koff = loadoff(js, propoff + sizeof(jsoff_t));
50135007 jsoff_t klen = offtolen(loadoff(js, koff));
50085008+50145009 const char *key = (char *)&js->mem[koff + sizeof(jsoff_t)];
50155015-50165016- if (is_const_prop(js, propoff)) {
50175017- if (js->flags & F_STRICT) return js_mkerr(js, "assignment to constant");
50185018- return mkval(T_PROP, propoff);
50195019- }
50105010+ if (is_const_prop(js, propoff)) return js_mkerr(js, "assignment to constant");
5020501150215012 if ((klen == 9 && memcmp(key, "undefined", 9) == 0) ||
50225013 (klen == 3 && memcmp(key, "NaN", 3) == 0) ||
···6087607860886079 jsval_t saved_scope = js->scope;
60896080 if (global_scope_stack == NULL) utarray_new(global_scope_stack, &jsoff_icd);
60906090- utarray_push_back(global_scope_stack, &parent_scope_offset);
60916081 jsval_t function_scope = mkobj(js, parent_scope_offset);
60826082+ jsoff_t function_scope_offset = (jsoff_t) vdata(function_scope);
60836083+ utarray_push_back(global_scope_stack, &function_scope_offset);
60926084 js->scope = function_scope;
6093608560946086 jsval_t slot_name = get_slot(js, func_val, SLOT_NAME);
···66596651 uint8_t lhs_type = vtype(lhs);
66606652 if (lhs_type != T_PROP && lhs_type != T_PROPREF)
66616653 return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid left-hand side expression in postfix operation");
66626662- do_assign_op(js, op == TOK_POSTINC ? TOK_PLUS_ASSIGN : TOK_MINUS_ASSIGN, lhs, tov(1));
66546654+ jsval_t assign_res = do_assign_op(js, op == TOK_POSTINC ? TOK_PLUS_ASSIGN : TOK_MINUS_ASSIGN, lhs, tov(1));
66556655+ if (is_err(assign_res)) return assign_res;
66636656 return l;
66646657 }
66656658···87578750 if (js->flags & F_NOEXEC) return operand;
87588751 jsval_t resolved = resolveprop(js, operand);
87598752 if (vtype(operand) == T_PROP || vtype(operand) == T_PROPREF) {
87608760- do_assign_op(js, op == TOK_POSTINC ? TOK_PLUS_ASSIGN : TOK_MINUS_ASSIGN, operand, tov(1));
87618761- } else {
87628762- return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid left-hand side in assignment");
87638763- }
87538753+ jsval_t assign_res = do_assign_op(js, op == TOK_POSTINC ? TOK_PLUS_ASSIGN : TOK_MINUS_ASSIGN, operand, tov(1));
87548754+ if (is_err(assign_res)) return assign_res;
87558755+ } else return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid left-hand side in assignment");
87648756 return do_op(js, op == TOK_POSTINC ? TOK_PLUS : TOK_MINUS, resolved, tov(1));
87658757 }
87668758···1015110143 } else if (next(js) == TOK_OF) {
1015210144 is_for_of = true;
1015310145 js->consumed = 1;
1014610146+ } else if (next(js) == TOK_ASSIGN) {
1014710147+ js->pos = destructure_off;
1014810148+ js->consumed = 1;
1014910149+ if (is_const_var) v = js_const(js);
1015010150+ else if (is_var_decl) v = js_var_decl(js);
1015110151+ else v = js_let(js);
1015210152+ if (is_err2(&v, &res)) goto done;
1015310153+ has_destructure = false;
1015410154 } else {
1015510155- res = js_mkerr_typed(js, JS_ERR_SYNTAX, "expected 'in' or 'of' after destructuring pattern");
1015510155+ res = js_mkerr_typed(js, JS_ERR_SYNTAX, "expected 'in', 'of', or '=' after destructuring pattern");
1015610156 goto done;
1015710157 }
1015810158 } else if (next(js) == TOK_IDENTIFIER) {
···1017210172 } else {
1017310173 js->pos = var_name_off;
1017410174 js->consumed = 1;
1017510175- if (is_const_var) {
1017610176- v = js_const(js);
1017710177- } else if (is_var_decl) {
1017810178- v = js_var_decl(js);
1017910179- } else {
1018010180- v = js_let(js);
1018110181- }
1017510175+ if (is_const_var) v = js_const(js);
1017610176+ else if (is_var_decl) v = js_var_decl(js);
1017710177+ else v = js_let(js);
1018210178 if (is_err2(&v, &res)) goto done;
1018310179 }
1018410180 }
···11653116491165411650 js->consumed = 1;
1165511651 for (;;) {
1165611656- EXPECT_IDENT();
1165711657- js->consumed = 0;
1165811658- jsoff_t noff = js->toff, nlen = js->tlen;
1165911659- char *name = (char *) &js->code[noff];
1165211652+ uint8_t tok = next(js);
11660116531166111661- if (exe && (js->flags & F_STRICT) && is_strict_restricted(name, nlen)) {
1166211662- return js_mkerr_typed(js, JS_ERR_SYNTAX, "cannot use '%.*s' as variable name in strict mode", (int) nlen, name);
1166311663- }
1166411664-1166511665- if (exe && (js->flags & F_STRICT) && is_strict_reserved(name, nlen)) {
1166611666- return js_mkerr_typed(js, JS_ERR_SYNTAX, "'%.*s' is reserved in strict mode", (int) nlen, name);
1166711667- }
1166811668-1166911669- jsval_t v = js_mkundef();
1167011670- bool has_initializer = false;
1167111671- js->consumed = 1;
1167211672- if (next(js) == TOK_ASSIGN) {
1165411654+ if (tok == TOK_LBRACKET || tok == TOK_LBRACE) {
1165511655+ jsoff_t pattern_start = js->toff;
1165611656+ uint8_t close_tok = (tok == TOK_LBRACKET) ? TOK_RBRACKET : TOK_RBRACE;
1165711657+1165811658+ js->consumed = 1;
1165911659+ int depth = 1;
1166011660+ while (depth > 0 && next(js) != TOK_EOF) {
1166111661+ if (js->tok == tok) depth++;
1166211662+ else if (js->tok == close_tok) depth--;
1166311663+ if (depth > 0) js->consumed = 1;
1166411664+ }
1167311665 js->consumed = 1;
1167411674- v = js_expr(js);
1166611666+ jsoff_t pattern_end = js->pos;
1166711667+ jsoff_t pattern_len = pattern_end - pattern_start;
1166811668+1166911669+ if (next(js) != TOK_ASSIGN) {
1167011670+ return js_mkerr_typed(js, JS_ERR_SYNTAX, "destructuring requires assignment");
1167111671+ } js->consumed = 1;
1167211672+1167311673+ jsval_t v = js_expr(js);
1167511674 if (is_err(v)) return v;
1167611676- has_initializer = true;
1167711677- }
1167811678-1167911679- if (exe) {
1168011680- char decoded_name[256];
1168111681- size_t decoded_len = decode_ident_escapes(name, nlen, decoded_name, sizeof(decoded_name));
1167511675+1167611676+ if (exe) {
1167711677+ jsval_t val = resolveprop(js, v);
1167811678+ jsval_t r = bind_destruct_pattern(js, &js->code[pattern_start], pattern_len, val, var_scope);
1167911679+ if (is_err(r)) return r;
1168011680+ }
1168111681+ } else {
1168211682+ EXPECT_IDENT();
1168311683+ js->consumed = 0;
1168411684+ jsoff_t noff = js->toff, nlen = js->tlen;
1168511685+ char *name = (char *) &js->code[noff];
1168611686+1168711687+ if (exe && (js->flags & F_STRICT) && is_strict_restricted(name, nlen)) {
1168811688+ return js_mkerr_typed(js, JS_ERR_SYNTAX, "cannot use '%.*s' as variable name in strict mode", (int) nlen, name);
1168911689+ }
1169011690+1169111691+ if (exe && (js->flags & F_STRICT) && is_strict_reserved(name, nlen)) {
1169211692+ return js_mkerr_typed(js, JS_ERR_SYNTAX, "'%.*s' is reserved in strict mode", (int) nlen, name);
1169311693+ }
1169411694+1169511695+ jsval_t v = js_mkundef();
1169611696+ bool has_initializer = false;
1169711697+ js->consumed = 1;
1169811698+ if (next(js) == TOK_ASSIGN) {
1169911699+ js->consumed = 1;
1170011700+ v = js_expr(js);
1170111701+ if (is_err(v)) return v;
1170211702+ has_initializer = true;
1170311703+ }
11682117041168311683- jsoff_t existing_off = lkp(js, var_scope, decoded_name, decoded_len);
1168411684- if (existing_off > 0) {
1168511685- if (has_initializer && !is_err(v)) {
1168611686- jsval_t key_val = js_mkstr(js, decoded_name, decoded_len);
1168711687- setprop(js, var_scope, key_val, resolveprop(js, v));
1170511705+ if (exe) {
1170611706+ char decoded_name[256];
1170711707+ size_t decoded_len = decode_ident_escapes(name, nlen, decoded_name, sizeof(decoded_name));
1170811708+1170911709+ jsoff_t existing_off = lkp(js, var_scope, decoded_name, decoded_len);
1171011710+ if (existing_off > 0) {
1171111711+ if (has_initializer && !is_err(v)) {
1171211712+ jsval_t key_val = js_mkstr(js, decoded_name, decoded_len);
1171311713+ setprop(js, var_scope, key_val, resolveprop(js, v));
1171411714+ }
1171511715+ } else {
1171611716+ jsval_t x = mkprop(js, var_scope, js_mkstr(js, decoded_name, decoded_len), resolveprop(js, v), 0);
1171711717+ if (is_err(x)) return x;
1168811718 }
1168911689- } else {
1169011690- jsval_t x = mkprop(js, var_scope, js_mkstr(js, decoded_name, decoded_len), resolveprop(js, v), 0);
1169111691- if (is_err(x)) return x;
1169211719 }
1169311720 }
1169411721···2118921216 jsoff_t existing = lkp(js, obj, key, key_len);
2119021217 if (existing > 0) {
2119121218 if (is_const_prop(js, existing)) {
2119221192- if (js->flags & F_STRICT) js_mkerr(js, "assignment to constant");
2121921219+ js_mkerr(js, "assignment to constant");
2119321220 return;
2119421221 }
2119521222 saveval(js, existing + sizeof(jsoff_t) * 2, val);
···2120221229 jsoff_t existing = lkp(js, func_obj, key, key_len);
2120321230 if (existing > 0) {
2120421231 if (is_const_prop(js, existing)) {
2120521205- if (js->flags & F_STRICT) js_mkerr(js, "assignment to constant");
2123221232+ js_mkerr(js, "assignment to constant");
2120621233 return;
2120721234 }
2120821235 saveval(js, existing + sizeof(jsoff_t) * 2, val);
···2173021757 mkscope(js);
2173121758 js->flags = saved_flags;
21732217592176021760+ if (global_scope_stack == NULL) utarray_new(global_scope_stack, &jsoff_icd);
2176121761+ jsoff_t function_scope_offset = (jsoff_t) vdata(js->scope);
2176221762+2176321763+ utarray_push_back(global_scope_stack, &function_scope_offset);
2176421764+ hoist_var_declarations_from_slot(js, js->scope, func_obj);
2176521765+2173321766 parsed_func_t *pf = get_or_parse_func(fn, fnlen);
2173421767 if (!pf) {
2173521735- delscope(js);
2173621736- js->scope = saved_scope;
2176821768+ if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack);
2176921769+ delscope(js); js->scope = saved_scope;
2173721770 if (combined_args) free(combined_args);
2173821771 js->gc_suppress = saved_gc_suppress;
2173921772 return js_mkerr(js, "failed to parse function");
···2180721840 js->flags = caller_flags;
21808218412180921842 js->this_val = saved_this;
2181021810- delscope(js);
2181121811- js->scope = saved_scope;
2184321843+ if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack);
2184421844+ delscope(js); js->scope = saved_scope;
2181221845 if (combined_args) free(combined_args);
21813218462181421847 js->gc_suppress = saved_gc_suppress;
+2-2
src/repl.c
···331331 if (c == '\r' || c == '\n') return (key_event_t){ KEY_ENTER, 0 };
332332 if (c == 3) { ctrl_c_pressed++; return (key_event_t){ KEY_EOF, 0 }; }
333333 if (c == 4 || c == 26) return (key_event_t){ KEY_EOF, 0 };
334334- if (isprint(c)) return (key_event_t){ KEY_CHAR, c };
334334+ if (isprint(c) || (unsigned char)c >= 0x80) return (key_event_t){ KEY_CHAR, c };
335335 return (key_event_t){ KEY_NONE, 0 };
336336}
337337#define TERM_INIT()
···356356 }
357357 if (c == 127 || c == 8) return (key_event_t){ KEY_BACKSPACE, 0 };
358358 if (c == '\n' || c == '\r') return (key_event_t){ KEY_ENTER, 0 };
359359- if (isprint(c)) return (key_event_t){ KEY_CHAR, c };
359359+ if (isprint(c) || (unsigned char)c >= 0x80) return (key_event_t){ KEY_CHAR, c };
360360 return (key_event_t){ KEY_NONE, 0 };
361361}
362362#define TERM_INIT() do { \
+388
tests/var.js
···11+// ============================================
22+// COMPREHENSIVE VAR DECLARATION BUG TEST
33+// ============================================
44+55+console.log('=== TEST 1: Regular IIFE (baseline) ===');
66+(function () {
77+ var a = 1;
88+ var b = 2,
99+ c = 3;
1010+ if (true) {
1111+ var d = 4;
1212+ }
1313+ {
1414+ var e = 5;
1515+ }
1616+ for (var f = 6; f < 7; f++) {
1717+ var g = 7;
1818+ }
1919+ while (false) {
2020+ var h = 8;
2121+ }
2222+ do {
2323+ var i = 9;
2424+ } while (false);
2525+ try {
2626+ var j = 10;
2727+ } catch (err) {
2828+ var k = 11;
2929+ }
3030+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' e=' + e + ' f=' + f + ' g=' + g + ' h=' + h + ' i=' + i + ' j=' + j + ' k=' + k);
3131+})();
3232+3333+console.log('\n=== TEST 2: Arrow IIFE ===');
3434+(() => {
3535+ var a = 1;
3636+ var b = 2,
3737+ c = 3;
3838+ if (true) {
3939+ var d = 4;
4040+ }
4141+ {
4242+ var e = 5;
4343+ }
4444+ for (var f = 6; f < 7; f++) {
4545+ var g = 7;
4646+ }
4747+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' e=' + e + ' f=' + f + ' g=' + g);
4848+})();
4949+5050+console.log('\n=== TEST 3: User-defined callback ===');
5151+function callFn(cb) {
5252+ cb(100);
5353+}
5454+callFn(function (x) {
5555+ var a = 1;
5656+ var b = 2,
5757+ c = 3;
5858+ if (true) {
5959+ var d = 4;
6060+ }
6161+ for (var f = 6; f < 7; f++) {
6262+ var g = 7;
6363+ }
6464+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' f=' + f + ' g=' + g + ' x=' + x);
6565+});
6666+6767+console.log('\n=== TEST 4: User-defined callback (arrow) ===');
6868+callFn(x => {
6969+ var a = 1;
7070+ var b = 2,
7171+ c = 3;
7272+ if (true) {
7373+ var d = 4;
7474+ }
7575+ for (var f = 6; f < 7; f++) {
7676+ var g = 7;
7777+ }
7878+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' f=' + f + ' g=' + g + ' x=' + x);
7979+});
8080+8181+console.log('\n=== TEST 5: forEach with regular function ===');
8282+[1].forEach(function (x, idx, arr) {
8383+ var a = 1;
8484+ var b = 2,
8585+ c = 3;
8686+ if (true) {
8787+ var d = 4;
8888+ }
8989+ {
9090+ var e = 5;
9191+ }
9292+ for (var f = 6; f < 7; f++) {
9393+ var g = 7;
9494+ }
9595+ while (false) {
9696+ var h = 8;
9797+ }
9898+ do {
9999+ var i = 9;
100100+ } while (false);
101101+ try {
102102+ var j = 10;
103103+ } catch (err) {
104104+ var k = 11;
105105+ }
106106+ switch (1) {
107107+ case 1:
108108+ var l = 12;
109109+ break;
110110+ }
111111+ console.log(
112112+ ' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' e=' + e + ' f=' + f + ' g=' + g + ' h=' + h + ' i=' + i + ' j=' + j + ' k=' + k + ' l=' + l
113113+ );
114114+});
115115+116116+console.log('\n=== TEST 6: forEach with arrow function ===');
117117+[1].forEach((x, idx, arr) => {
118118+ var a = 1;
119119+ var b = 2,
120120+ c = 3;
121121+ if (true) {
122122+ var d = 4;
123123+ }
124124+ {
125125+ var e = 5;
126126+ }
127127+ for (var f = 6; f < 7; f++) {
128128+ var g = 7;
129129+ }
130130+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' e=' + e + ' f=' + f + ' g=' + g);
131131+});
132132+133133+console.log('\n=== TEST 7: map with regular function ===');
134134+[1].map(function (x) {
135135+ var a = 1;
136136+ if (true) {
137137+ var b = 2;
138138+ }
139139+ for (var c = 3; c < 4; c++) {
140140+ var d = 4;
141141+ }
142142+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d);
143143+ return x;
144144+});
145145+146146+console.log('\n=== TEST 8: filter with regular function ===');
147147+[1].filter(function (x) {
148148+ var a = 1;
149149+ if (true) {
150150+ var b = 2;
151151+ }
152152+ for (var c = 3; c < 4; c++) {
153153+ var d = 4;
154154+ }
155155+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d);
156156+ return true;
157157+});
158158+159159+console.log('\n=== TEST 9: reduce with regular function ===');
160160+[1, 2].reduce(function (acc, x) {
161161+ var a = 1;
162162+ if (true) {
163163+ var b = 2;
164164+ }
165165+ for (var c = 3; c < 4; c++) {
166166+ var d = 4;
167167+ }
168168+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' acc=' + acc + ' x=' + x);
169169+ return acc + x;
170170+}, 0);
171171+172172+console.log('\n=== TEST 10: find with regular function ===');
173173+[1].find(function (x) {
174174+ var a = 1;
175175+ for (var b = 2; b < 3; b++) {
176176+ var c = 3;
177177+ }
178178+ console.log(' a=' + a + ' b=' + b + ' c=' + c);
179179+ return true;
180180+});
181181+182182+console.log('\n=== TEST 11: some with regular function ===');
183183+[1].some(function (x) {
184184+ var a = 1;
185185+ for (var b = 2; b < 3; b++) {
186186+ var c = 3;
187187+ }
188188+ console.log(' a=' + a + ' b=' + b + ' c=' + c);
189189+ return true;
190190+});
191191+192192+console.log('\n=== TEST 12: every with regular function ===');
193193+[1].every(function (x) {
194194+ var a = 1;
195195+ for (var b = 2; b < 3; b++) {
196196+ var c = 3;
197197+ }
198198+ console.log(' a=' + a + ' b=' + b + ' c=' + c);
199199+ return true;
200200+});
201201+202202+console.log('\n=== TEST 13: sort with regular function ===');
203203+[2, 1].sort(function (a, b) {
204204+ var v = 1;
205205+ for (var i = 0; i < 1; i++) {
206206+ var w = 2;
207207+ }
208208+ console.log(' v=' + v + ' i=' + i + ' w=' + w);
209209+ return a - b;
210210+});
211211+212212+console.log('\n=== TEST 14: flatMap with regular function ===');
213213+[1].flatMap(function (x) {
214214+ var a = 1;
215215+ for (var b = 2; b < 3; b++) {
216216+ var c = 3;
217217+ }
218218+ console.log(' a=' + a + ' b=' + b + ' c=' + c);
219219+ return [x];
220220+});
221221+222222+console.log('\n=== TEST 15: findIndex with regular function ===');
223223+[1].findIndex(function (x) {
224224+ var a = 1;
225225+ for (var b = 2; b < 3; b++) {
226226+ var c = 3;
227227+ }
228228+ console.log(' a=' + a + ' b=' + b + ' c=' + c);
229229+ return true;
230230+});
231231+232232+console.log('\n=== TEST 16: let/const in forEach (should work) ===');
233233+[1].forEach(function (x) {
234234+ let a = 1;
235235+ const b = 2;
236236+ let c = 3,
237237+ d = 4;
238238+ if (true) {
239239+ let e = 5;
240240+ var f = 6;
241241+ }
242242+ for (let g = 7; g < 8; g++) {
243243+ let h = 8;
244244+ var i = 9;
245245+ }
246246+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' f=' + f + ' i=' + i);
247247+});
248248+249249+console.log('\n=== TEST 17: Nested forEach ===');
250250+[1].forEach(function (x) {
251251+ var outer = 'outer';
252252+ [2].forEach(function (y) {
253253+ var inner = 'inner';
254254+ for (var z = 0; z < 1; z++) {
255255+ var inFor = 'inFor';
256256+ }
257257+ console.log(' outer=' + outer + ' inner=' + inner + ' z=' + z + ' inFor=' + inFor);
258258+ });
259259+});
260260+261261+console.log('\n=== TEST 18: setTimeout callback ===');
262262+setTimeout(function () {
263263+ var a = 1;
264264+ if (true) {
265265+ var b = 2;
266266+ }
267267+ for (var c = 3; c < 4; c++) {
268268+ var d = 4;
269269+ }
270270+ console.log(' setTimeout: a=' + a + ' b=' + b + ' c=' + c + ' d=' + d);
271271+}, 0);
272272+273273+console.log('\n=== TEST 19: Promise.then callback ===');
274274+Promise.resolve(1).then(function (x) {
275275+ var a = 1;
276276+ if (true) {
277277+ var b = 2;
278278+ }
279279+ for (var c = 3; c < 4; c++) {
280280+ var d = 4;
281281+ }
282282+ console.log(' Promise.then: a=' + a + ' b=' + b + ' c=' + c + ' d=' + d);
283283+});
284284+285285+console.log('\n=== TEST 20: Object methods ===');
286286+Object.keys({ a: 1 }).forEach(function (k) {
287287+ var v = 'test';
288288+ for (var i = 0; i < 1; i++) {
289289+ var w = 'for';
290290+ }
291291+ console.log(' Object.keys.forEach: v=' + v + ' i=' + i + ' w=' + w);
292292+});
293293+294294+console.log('\n=== TEST 21: String methods ===');
295295+'abc'.split('').forEach(function (c) {
296296+ var v = 'test';
297297+ for (var i = 0; i < 1; i++) {
298298+ var w = 'for';
299299+ }
300300+ console.log(' String.split.forEach: v=' + v + ' i=' + i + ' w=' + w + ' c=' + c);
301301+});
302302+303303+console.log('\n=== TEST 22: Map.forEach ===');
304304+new Map([['a', 1]]).forEach(function (v, k) {
305305+ var a = 1;
306306+ for (var i = 0; i < 1; i++) {
307307+ var b = 2;
308308+ }
309309+ console.log(' Map.forEach: a=' + a + ' i=' + i + ' b=' + b);
310310+});
311311+312312+console.log('\n=== TEST 23: Set.forEach ===');
313313+new Set([1]).forEach(function (v) {
314314+ var a = 1;
315315+ for (var i = 0; i < 1; i++) {
316316+ var b = 2;
317317+ }
318318+ console.log(' Set.forEach: a=' + a + ' i=' + i + ' b=' + b);
319319+});
320320+321321+console.log('\n=== TEST 24: for...of loop ===');
322322+for (var item of [1, 2]) {
323323+ var a = 'test';
324324+ console.log(' for...of: item=' + item + ' a=' + a);
325325+}
326326+327327+console.log('\n=== TEST 25: for...in loop ===');
328328+for (var key in { a: 1, b: 2 }) {
329329+ var v = 'test';
330330+ console.log(' for...in: key=' + key + ' v=' + v);
331331+}
332332+333333+console.log('\n=== TEST 26: Nested functions in forEach ===');
334334+[1].forEach(function (x) {
335335+ var outer = 'outer';
336336+ function inner() {
337337+ var innerVar = 'inner';
338338+ console.log(' nested fn: outer=' + outer + ' innerVar=' + innerVar);
339339+ }
340340+ inner();
341341+ console.log(' forEach body: outer=' + outer);
342342+});
343343+344344+console.log('\n=== TEST 27: var in different for variants ===');
345345+[1].forEach(function (x) {
346346+ for (var a = 0; a < 1; a++) {}
347347+ for (var b in { x: 1 }) {
348348+ }
349349+ for (var c of [1]) {
350350+ }
351351+ var d = 'plain';
352352+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d);
353353+});
354354+355355+console.log('\n=== TEST 28: Hoisting test ===');
356356+[1].forEach(function (x) {
357357+ console.log(' before: a=' + a + ' b=' + b);
358358+ var a = 1;
359359+ for (var b = 2; b < 3; b++) {}
360360+ console.log(' after: a=' + a + ' b=' + b);
361361+});
362362+363363+console.log('\n=== TEST 29: Function expression assignment ===');
364364+[1].forEach(function (x) {
365365+ var fn = function () {
366366+ return 'test';
367367+ };
368368+ for (var i = 0; i < 1; i++) {
369369+ var fn2 = function () {
370370+ return 'for';
371371+ };
372372+ }
373373+ console.log(' fn=' + fn + ' fn()=' + (fn ? fn() : 'N/A') + ' fn2()=' + (fn2 ? fn2() : 'N/A'));
374374+});
375375+376376+console.log('\n=== TEST 30: Destructuring var ===');
377377+try {
378378+ [1].forEach(function (x) {
379379+ var [a, b] = [1, 2];
380380+ var { c, d } = { c: 3, d: 4 };
381381+ for (var [e] = [5]; e < 6; e++) {}
382382+ console.log(' a=' + a + ' b=' + b + ' c=' + c + ' d=' + d + ' e=' + e);
383383+ });
384384+} catch (e) {
385385+ console.log(' destructuring error: ' + e.message);
386386+}
387387+388388+console.log('\n=== ASYNC TESTS (will print after) ===');