1 # Test var / setvar / etc.
2
3 ## our_shell: ysh
4 ## oils_failures_allowed: 2
5
6 #### proc static check: const can't be mutated
7 proc f {
8 const x = 'local'
9 echo x=$x
10 setvar x = 'mutated'
11 echo x=$x
12 }
13 ## status: 2
14 ## STDOUT:
15 ## END
16
17 #### top-level dynamic check: const can't be be mutated
18 shopt -s ysh:all
19
20 const x = 'foo'
21 echo x=$x
22 const x = 'bar'
23 echo x=$x
24 ## status: 1
25 ## STDOUT:
26 x=foo
27 ## END
28
29 #### top level: var can be redefined by var/const
30 var x = "global"
31 echo x=$x
32 f() {
33 var x = "local"
34 echo x=$x
35 }
36 f
37 var x = "g2"
38 echo x=$x
39 const x = 'now-const'
40 echo x=$x
41 const x = 'oops'
42 echo x=$x
43 ## status: 1
44 ## STDOUT:
45 x=global
46 x=local
47 x=g2
48 x=now-const
49 ## END
50
51 #### setvar mutates local
52 proc f {
53 var x = 'local'
54 echo x=$x
55 setvar x = 'mutated'
56 echo x=$x
57 }
58
59 var x = 'global'
60 echo x=$x
61 f
62 echo x=$x
63 ## STDOUT:
64 x=global
65 x=local
66 x=mutated
67 x=global
68 ## END
69
70 #### top level: setvar creates global
71 setvar x = 'global'
72 echo x=$x
73 setvar x = 'g2'
74 echo x=$x
75 ## STDOUT:
76 x=global
77 x=g2
78 ## END
79
80 #### top level: setvar mutates var
81 var x = 1
82 setvar x = 42 # this is allowed
83 echo $x
84 setvar y = 50 # error because it's not declared
85 echo $y
86 ## STDOUT:
87 42
88 50
89 ## END
90
91 #### proc static check: variable changed by setvar must be declared
92 shopt -s ysh:all
93
94 var x = 1
95 f() {
96 # setting global is OK
97 setglobal x = 'XX'
98 echo x=$x
99
100 # local NOT DECLARED
101 setvar x = 'YY'
102 echo y=$y
103 }
104 ## status: 2
105 ## STDOUT:
106 ## END
107
108 #### setglobal
109 f() {
110 var x = 'local'
111 echo x=$x
112 setglobal x = 'mutated'
113 }
114 var x = 'global'
115 echo x=$x
116 f
117 echo x=$x
118 ## STDOUT:
119 x=global
120 x=local
121 x=mutated
122 ## END
123
124 #### setglobal of undeclared var is allowed
125 var x = 'XX'
126 echo x=$x
127 setglobal x = 'xx'
128 echo x=$x
129
130 # fatal error
131 setglobal y = 'YY'
132
133 ## STDOUT:
134 x=XX
135 x=xx
136 ## END
137
138 #### var a, b does implicit null init
139
140 var x
141 var a, b
142
143 var c: Int, d: Int
144
145 echo $x $a $b $c $d
146
147 ## STDOUT:
148 null null null null null
149 ## END
150
151 #### var x, y = f()
152
153 # The syntax consistent with JavaScript would be
154 # var x = 1, y = 2;
155
156 var x, y = 1, 2
157 echo "x=$x y=$y"
158
159 func f() {
160 # this syntax would be nice, but is illegal
161 # return (3, 4)
162 return ([3, 4])
163 }
164
165 var a, b = f()
166 echo "a=$a b=$b"
167
168
169 ## STDOUT:
170 x=1 y=2
171 a=3 b=4
172 ## END
173
174 #### const x, y = f()
175
176 func f() {
177 # this syntax would be nice, but is illegal
178 # return (3, 4)
179 return ([3, 4])
180 }
181
182
183 const a, b = f()
184 echo "a=$a b=$b"
185
186 setvar a = 9 # error
187
188 ## status: 1
189 ## STDOUT:
190 a=3 b=4
191 ## END
192
193
194 #### setvar x, y = 1, 2
195
196 # Python doesn't allow you to have annotation on each variable!
197 # https://www.python.org/dev/peps/pep-0526/#where-annotations-aren-t-allowed
198 var x Int = 3
199 var y Int = 4
200 echo "x=$x y=$y"
201
202 setvar x, y = 1, 9
203 echo "x=$x y=$y"
204
205 setvar y, x = x, y
206 echo "x=$x y=$y"
207
208 setvar x, y = x*2, x*3
209 echo "x=$x y=$y"
210
211 ## STDOUT:
212 x=3 y=4
213 x=1 y=9
214 x=9 y=1
215 x=18 y=27
216 ## END
217
218 #### setvar to swap List and Dict elements
219 var x = [1, 2, 3]
220 echo @x
221
222 setvar x[0], x[1] = x[1], x[0]
223
224 echo @x
225
226 var d = {int: 42}
227
228 setvar x[0], d.int = d.int, x[0]
229
230 echo @x
231 json write (d)
232
233 ## STDOUT:
234 1 2 3
235 2 1 3
236 42 1 3
237 {
238 "int": 2
239 }
240 ## END
241
242 #### setvar d.key = 42
243 shopt -s ysh:all
244
245 var d = {}
246 setvar d['f2'] = 42
247 setvar d.f3 = 43
248
249 # Use the opposite thing to retrieve
250 var f3 = d['f3']
251 var f2 = d.f2
252 echo f3=$f3
253 echo f2=$f2
254 ## STDOUT:
255 f3=43
256 f2=42
257 ## END
258
259 #### setvar mylist[1] = 42
260 shopt -s ysh:all
261 var mylist = [1,2,3]
262 setvar mylist[1] = 42
263
264 write --sep ' ' @mylist
265 ## STDOUT:
266 1 42 3
267 ## END
268
269 #### setvar mylist[99] out of range
270 shopt -s ysh:all
271 var mylist = [4,5,6]
272 try {
273 setvar mylist[99] = 42
274 }
275 echo $[_error.code]
276
277 try {
278 setvar mylist[-99] = 42
279 }
280 echo $[_error.code]
281
282 write --sep ' ' @mylist
283
284 ## STDOUT:
285 3
286 3
287 4 5 6
288 ## END
289
290 #### mixing assignment builtins and YSH assignment
291 shopt -s ysh:all parse_equals
292
293 proc local-var {
294 local x=1
295 var x = 2
296 echo x=$x
297 }
298
299 proc readonly-var {
300 readonly x=1
301 var x = 2
302 echo x=$x
303 }
304
305 try { eval 'local-var' }
306 echo status=$_status
307 try { eval 'readonly-var' }
308 echo status=$_status
309
310 ## STDOUT:
311 x=2
312 status=0
313 status=1
314 ## END
315
316 #### circular dict - TODO 2023-06 REGRESS
317 var d = {name: 'foo'}
318 pp test_ (d)
319
320 setvar d['name'] = 123
321 pp test_ (d)
322
323 setvar d['name'] = 'mystr'
324 pp test_ (d)
325
326 setvar d['name'] = d
327 pp test_ (d)
328
329 # This used to print ...
330
331 ## STDOUT:
332 (OrderedDict) <'name': 'foo'>
333 (OrderedDict) <'name': 123>
334 (OrderedDict) <'name': 'mystr'>
335 (OrderedDict) <'name': ...>
336 ## END
337
338 #### circular list - TODO 2023-06 REGRESS
339 var L = [1,2,3]
340 = L
341 #setvar L[0] = L
342 #= L
343 ## STDOUT:
344 (List) [1, 2, 3]
345 (List) [[...], 2, 3]
346 ## END
347
348
349 #### exit code of var, const, setvar with command sub
350
351 # NOTE: This feels PROBLEMATIC without command_sub_errexit feels like it should
352 # be the last one ...
353
354 run() {
355 $REPO_ROOT/bin/osh -O parse_proc -c "$@"
356
357 # Identical
358 # $SH +O ysh:all -O parse_proc -c "$@"
359 }
360
361 set +o errexit
362
363 run '
364 var x = $(false)
365 echo inside1=$?
366 '
367 echo outside1=$?
368
369 run '
370 setvar x = $(false)
371 echo inside2=$?
372 '
373 echo outside2=$?
374
375 # Argument list
376 run '
377 call split( $(false) )
378 echo inside3=$?
379 '
380 echo outside3=$?
381
382 # Place expression
383 run '
384 var d = {}
385 setvar d[ $(false) ] = 42
386 echo inside4=$?
387 '
388 echo outside4=$?
389
390 ## STDOUT:
391 outside1=1
392 outside2=1
393 outside3=1
394 outside4=1
395 ## END
396
397 #### setvar obj[INVALID TYPE] =
398
399 set +o errexit
400
401 $SH -c '
402 var d = {}
403 setvar d["key"] = 5
404 echo "d.key = $[d.key]"
405 setvar d[42] = 6
406 echo "should not get here"
407 '
408 echo outside1=$?
409
410 $SH -c '
411 var L = [42]
412 setvar L[0] = 43
413 echo "L[0] = $[L[0]]"
414 setvar L["key"] = 44
415 '
416 echo outside2=$?
417
418 ## STDOUT:
419 d.key = 5
420 outside1=3
421 L[0] = 43
422 outside2=3
423 ## END