@@ -84,42 +84,232 @@ js-var() {
84
84
}
85
85
'
86
86
87
- banner ' STRICT UNDEF'
87
+ banner ' USE BEFORE LET'
88
+ nodejs -e '
89
+ function outer() {
90
+ // fails dynamically with ReferenceError
91
+ console.log(`use before let: x=${x}`);
92
+ let x = "foo";
93
+ }
94
+
95
+ outer();
96
+ '
97
+
98
+ echo
99
+ }
100
+
101
+ control-flow () {
102
+ banner ' BREAK'
103
+
104
+ # this is a syntax error! OK good
105
+ nodejs -e '
106
+ function f() {
107
+ break;
108
+ }
109
+ '
110
+ }
111
+
112
+ use-strict-static () {
113
+ set +o errexit
114
+
115
+ banner ' DUPE PARAMS'
88
116
nodejs -e '
89
117
"use strict";
118
+ function f(a, a) {
119
+ return 42;
120
+ }
121
+ '
90
122
91
- function outer() {
92
- let y = x + 1
93
- console.log(`x=${x}`);
123
+ banner ' OCTAL'
124
+ nodejs -e '
125
+ "use strict";
126
+ function f(a) {
127
+ return 0123;
94
128
}
95
129
'
96
130
97
- banner ' STRICT MUTATE'
131
+ banner ' WITH'
132
+
98
133
nodejs -e '
134
+ "use strict";
135
+ function f() {
136
+ with (x) {
137
+ console.log(x);
138
+ }
139
+ }
140
+ '
99
141
100
- // Use strict prevents global mutation! But only at runtime
142
+ banner ' OBJECT KEYS'
143
+
144
+ # Claude AI hallucinated this duplicate object keys, and then corrected itself
145
+ nodejs -e '
146
+ "use strict";
147
+ function f() {
148
+ return {a:1, a:2};
149
+ }
150
+ '
151
+ }
152
+
153
+ branches () {
154
+ set +o errexit
155
+
156
+ # spec/ysh-user-feedback - Julian
157
+
158
+ # JavaScript allows this because it's block scoped
159
+ banner ' IF'
160
+ nodejs -e '
161
+ function f(x) {
162
+ if (x === 2) {
163
+ let tmp = "hello"
164
+ } else {
165
+ let tmp = "world"
166
+ // This is an error
167
+ // let tmp = "z"
168
+ }
169
+ //console.log(tmp);
170
+ }
171
+
172
+ f(1);
173
+ f(2);
174
+ '
175
+
176
+ banner ' SWITCH'
177
+ nodejs -e '
178
+ function f(x) {
179
+ switch (x) {
180
+ case 1:
181
+ let tmp = "hello"
182
+ break;
183
+ case 2:
184
+ let tmp = "world"
185
+ break;
186
+ }
187
+ }
188
+
189
+ f(1);
190
+ f(2);
191
+ '
192
+
193
+ banner ' SWITCH BLOCK'
194
+ nodejs -e '
195
+ function f(x) {
196
+ switch (x) {
197
+ case 1: {
198
+ let tmp = "hello"
199
+ console.log(tmp);
200
+ break;
201
+ }
202
+ case 2: {
203
+ let tmp = "world"
204
+ console.log(tmp);
205
+ break;
206
+ }
207
+ }
208
+ }
209
+
210
+ f(1);
211
+ f(2);
212
+ '
213
+ }
214
+
215
+ loop () {
216
+ banner ' MODIFY FOR'
217
+ nodejs -e '
218
+ function f() {
219
+ for (let x of [1, 2]) {
220
+ console.log(`x = ${x}`);
221
+ x = 3;
222
+ console.log(x);
223
+ }
224
+ }
225
+
226
+ f();
227
+ '
228
+
229
+ # Hm why is this allowed?
230
+ banner ' LET LET'
231
+ nodejs -e '
232
+ function f() {
233
+ for (let x of [1, 2]) {
234
+ // console.log(`x = ${x}`);
235
+ let x = 3;
236
+ console.log(x);
237
+ }
238
+ }
239
+
240
+ f();
241
+ '
242
+ # Claude AI claims that there are two nested scopes, but I'm not so sure
243
+ # It seemed to enter an infinite loop where the code analysis didn't agree
244
+ # with it
245
+
246
+ # It also refers to "loop initialization scope" and "loop body scope"
247
+
248
+ # Another attempt:
249
+
250
+ # "What the specification actually describes is more precise and technical.
251
+ # For a for...of loop like for (let x of [1,2]) { let x = 3 }, the ECMAScript
252
+ # spec (as of ES2022) describes the behavior using concepts like:
253
+
254
+ # "Per-iteration binding instantiation - Each iteration of the loop creates a
255
+ # new lexical environment for the loop variable
256
+ #
257
+ # "Block scoping - The {} of the loop body creates its own lexical environment
258
+
259
+ # "According to the specification, for loops with let declarations create a
260
+ # fresh binding (variable) for each iteration of the loop. The loop body then
261
+ # creates another lexical environment (scope) where another binding with the
262
+ # same name can exist independently.
263
+
264
+ # "The precise section in the ECMAScript spec that addresses this is
265
+ # typically found in sections covering "for statement" execution semantics.
266
+ # The loop iteration variable and the loop body variable are in different
267
+ # lexical environments in the specification's terminology, rather than
268
+ # different "scopes" as I informally described.
269
+
270
+ banner ' LET x y'
271
+ nodejs -e '
272
+
273
+ // Uh this is weird too, y = 1?
274
+ function f() {
275
+ for (let x = 0, y = x + 1; x < 5; ++x) {
276
+ console.log(`x = ${x}, y = ${y}`);
277
+ //let x = 3;
278
+ }
279
+ }
280
+
281
+ f();
282
+ '
283
+ }
284
+
285
+
286
+ use-strict-dynamic () {
287
+ set +o errexit
288
+
289
+ banner ' STRICT UNDEF'
290
+ nodejs -e '
101
291
"use strict";
102
292
103
293
function outer() {
104
- x = "mutate"
294
+ let y = x + 1; // ReferenceError
295
+ console.log(`x=${x}`);
105
296
}
106
297
107
298
outer();
108
- console.log(`was global created? x=${x}`);
109
299
'
110
300
111
- banner ' USE BEFORE LET '
301
+ banner ' STRICT MUTATE '
112
302
nodejs -e '
303
+ // Use strict prevents global mutation! But only at runtime
304
+ "use strict";
305
+
113
306
function outer() {
114
- // fails dynamically with ReferenceError
115
- console.log(`use before let: x=${x}`);
116
- let x = "foo";
307
+ x = "mutate"
117
308
}
118
309
119
310
outer();
311
+ console.log(`was global created? x=${x}`);
120
312
'
121
-
122
- echo
123
313
}
124
314
125
315
" $@ "
0 commit comments