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 (setitem)
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 (setitem)
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 #### mixing assignment builtins and YSH assignment
270 shopt -s ysh:all parse_equals
271
272 proc local-var {
273 local x=1
274 var x = 2
275 echo x=$x
276 }
277
278 proc readonly-var {
279 readonly x=1
280 var x = 2
281 echo x=$x
282 }
283
284 try { eval 'local-var' }
285 echo status=$_status
286 try { eval 'readonly-var' }
287 echo status=$_status
288
289 ## STDOUT:
290 x=2
291 status=0
292 status=1
293 ## END
294
295 #### circular dict - TODO 2023-06 REGRESS
296 var d = {name: 'foo'}
297 pp line (d)
298
299 setvar d['name'] = 123
300 pp line (d)
301
302 setvar d['name'] = 'mystr'
303 pp line (d)
304
305 setvar d['name'] = d
306 pp line (d)
307
308 # This used to print ...
309
310 ## STDOUT:
311 (OrderedDict) <'name': 'foo'>
312 (OrderedDict) <'name': 123>
313 (OrderedDict) <'name': 'mystr'>
314 (OrderedDict) <'name': ...>
315 ## END
316
317 #### circular list - TODO 2023-06 REGRESS
318 var L = [1,2,3]
319 = L
320 #setvar L[0] = L
321 #= L
322 ## STDOUT:
323 (List) [1, 2, 3]
324 (List) [[...], 2, 3]
325 ## END
326
327
328 #### exit code of var, const, setvar with command sub
329
330 # NOTE: This feels PROBLEMATIC without command_sub_errexit feels like it should
331 # be the last one ...
332
333 run() {
334 $REPO_ROOT/bin/osh -O parse_proc -c "$@"
335
336 # Identical
337 # $SH +O ysh:all -O parse_proc -c "$@"
338 }
339
340 set +o errexit
341
342 run '
343 var x = $(false)
344 echo inside1=$?
345 '
346 echo outside1=$?
347
348 run '
349 setvar x = $(false)
350 echo inside2=$?
351 '
352 echo outside2=$?
353
354 # Argument list
355 run '
356 call split( $(false) )
357 echo inside3=$?
358 '
359 echo outside3=$?
360
361 # Place expression
362 run '
363 var d = {}
364 setvar d[ $(false) ] = 42
365 echo inside4=$?
366 '
367 echo outside4=$?
368
369 ## STDOUT:
370 outside1=1
371 outside2=1
372 outside3=1
373 outside4=1
374 ## END
375
376 #### setvar obj[INVALID TYPE] =
377
378 set +o errexit
379
380 $SH -c '
381 var d = {}
382 setvar d["key"] = 5
383 echo "d.key = $[d.key]"
384 setvar d[42] = 6
385 echo "should not get here"
386 '
387 echo outside1=$?
388
389 $SH -c '
390 var L = [42]
391 setvar L[0] = 43
392 echo "L[0] = $[L[0]]"
393 setvar L["key"] = 44
394 '
395 echo outside2=$?
396
397 ## STDOUT:
398 d.key = 5
399 outside1=3
400 L[0] = 43
401 outside2=3
402 ## END