1 ## oils_failures_allowed: 2
2
3 # Demonstrations for users. Could go in docs.
4
5 #### GetValue scope and shopt --unset dynamic_scope
6 shopt --set parse_proc
7
8 f() {
9 echo "sh x=$x"
10 }
11
12 proc p {
13 echo "oil x=$x"
14 }
15
16 demo() {
17 local x=dynamic
18 f
19 p
20
21 shopt --unset dynamic_scope
22 f
23 }
24
25 x=global
26 demo
27 echo x=$x
28
29 ## STDOUT:
30 sh x=dynamic
31 oil x=global
32 sh x=global
33 x=global
34 ## END
35
36
37 #### SetValue scope and shopt --unset dynamic_scope
38 shopt --set parse_proc
39
40 f() {
41 x=f
42 }
43
44 proc p {
45 # x=p not allowed at parse time
46 declare x=p
47 }
48
49 demo() {
50 local x=stack
51 echo x=$x
52 echo ---
53
54 f
55 echo f x=$x
56
57 x=stack
58 p
59 echo p x=$x
60
61 shopt --unset dynamic_scope
62 x=stack
63 f
64 echo funset x=$x
65 }
66
67 x=global
68 demo
69
70 echo ---
71 echo x=$x
72
73 ## STDOUT:
74 x=stack
75 ---
76 f x=f
77 p x=stack
78 funset x=stack
79 ---
80 x=global
81 ## END
82
83 #### read scope
84 set -o errexit
85
86 read-x() {
87 echo dynamic-scope | read x
88 }
89 demo() {
90 local x=42
91 echo x_before=$x
92 read-x
93 echo x_after=$x
94 }
95 demo
96 echo x=$x
97
98 echo ---
99
100 # Now 'read x' creates a local variable
101 shopt --unset dynamic_scope
102 demo
103 echo x=$x
104
105 ## STDOUT:
106 x_before=42
107 x_after=dynamic-scope
108 x=
109 ---
110 x_before=42
111 x_after=42
112 x=
113 ## END
114
115 #### printf -v x respects dynamic_scope
116 set -o errexit
117
118 set-x() {
119 printf -v x "%s" dynamic-scope
120 }
121 demo() {
122 local x=42
123 echo x=$x
124 set-x
125 echo x=$x
126 }
127 demo
128 echo x=$x
129
130 echo ---
131
132 shopt --unset dynamic_scope # should NOT affect read
133 demo
134 echo x=$x
135
136 ## STDOUT:
137 x=42
138 x=dynamic-scope
139 x=
140 ---
141 x=42
142 x=42
143 x=
144 ## END
145
146 #### printf -v a[i] respects dynamic_scope
147 set -o errexit
148
149 set-item() {
150 printf -v 'a[1]' "%s" dynamic-scope
151 }
152 demo() {
153 local -a a=(41 42 43)
154 echo "a[1]=${a[1]}"
155 set-item
156 echo "a[1]=${a[1]}"
157 }
158 demo
159 echo "a[1]=${a[1]}"
160
161 echo ---
162
163 shopt --unset dynamic_scope # should NOT affect read
164 demo
165 echo "a[1]=${a[1]}"
166
167 ## STDOUT:
168 a[1]=42
169 a[1]=dynamic-scope
170 a[1]=
171 ---
172 a[1]=42
173 a[1]=42
174 a[1]=
175 ## END
176
177 #### ${undef=a} and shopt --unset dynamic_scope
178
179 set-x() {
180 : ${x=new}
181 }
182 demo() {
183 local x
184 echo x=$x
185 set-x
186 echo x=$x
187 }
188
189 demo
190 echo x=$x
191
192 echo ---
193
194 # Now this IS affected?
195 shopt --unset dynamic_scope
196 demo
197 echo x=$x
198 ## STDOUT:
199 x=
200 x=new
201 x=
202 ---
203 x=
204 x=
205 x=
206 ## END
207
208 #### declare -p respects it
209 __g=G
210 show-vars() {
211 local __x=X
212 declare -p | grep '__'
213 echo status=$?
214
215 echo -
216 declare -p __y | grep '__'
217 echo status=$?
218 }
219
220 demo() {
221 local __y=Y
222
223 show-vars
224 echo ---
225 shopt --unset dynamic_scope
226 show-vars
227 }
228
229 demo
230
231 ## STDOUT:
232 declare -- __g=G
233 declare -- __x=X
234 declare -- __y=Y
235 status=0
236 -
237 declare -- __y=Y
238 status=0
239 ---
240 declare -- __g=G
241 declare -- __x=X
242 status=0
243 -
244 status=1
245 ## END
246
247
248 #### OshLanguageSetValue constructs
249
250 f() {
251 (( x = 42 ))
252 }
253 demo() {
254 f
255 echo x=$x
256 }
257
258 demo
259
260 echo ---
261
262 shopt --unset dynamic_scope
263
264 unset x
265
266 demo
267
268 echo --- global
269 echo x=$x
270 ## STDOUT:
271 x=42
272 ---
273 x=
274 --- global
275 x=
276 ## END
277
278
279 #### shell assignments 'neutered' inside 'proc'
280 shopt --set parse_proc
281
282 # They can't mutate globals or anything higher on the stack
283
284 proc p {
285 declare g=PROC
286 export e=PROC
287 }
288
289 f() {
290 g=SH
291 export e=SH
292 }
293
294 e=E
295 g=G
296 p
297 echo e=$e g=$g
298
299 p
300 echo e=$e g=$g
301
302 f
303 echo e=$e g=$g
304
305 ## STDOUT:
306 e=E g=G
307 e=E g=G
308 e=SH g=SH
309 ## END
310
311 #### setglobal still allows setting globals
312 shopt --set parse_proc
313
314 proc p {
315 setglobal new_global = 'p'
316 setglobal g = 'p'
317 }
318
319 var g = 'G'
320
321 p
322
323 echo g=$g new_global=$new_global
324 ## STDOUT:
325 g=p new_global=p
326 ## END
327
328 #### setglobal d[key] inside proc should mutate global (bug #1841)
329
330 shopt -s ysh:upgrade
331
332 var g = {}
333
334 proc mutate {
335 var g = {} # shadows global var
336
337 echo 'hi from mutate'
338 setglobal g.key = 'mutated'
339 setglobal g['key2'] = 'mutated'
340
341
342 pp line (g)
343 }
344
345 echo 'BEFORE mutate'
346 pp line (g)
347
348 mutate
349
350 echo 'AFTER mutate'
351 pp line (g)
352
353 ## STDOUT:
354 BEFORE mutate
355 (Dict) {}
356 hi from mutate
357 (Dict) {"key":"mutated","key2":"mutated"}
358 AFTER mutate
359 (Dict) {"key":"mutated","key2":"mutated"}
360 ## END
361
362 #### setglobal a[i] inside proc
363
364 shopt -s ysh:upgrade
365
366 var a = [0]
367
368 proc mutate {
369 var a = [1] # shadows global var
370
371 echo 'hi from mutate'
372 setglobal a[0] = 42
373
374 pp line (a)
375 }
376
377 echo 'BEFORE mutate'
378 pp line (a)
379
380 mutate
381
382 echo 'AFTER mutate'
383 pp line (a)
384
385 ## STDOUT:
386 BEFORE mutate
387 (List) [0]
388 hi from mutate
389 (List) [42]
390 AFTER mutate
391 (List) [42]
392 ## END
393
394
395 #### unset inside proc uses local scope
396 shopt --set parse_brace
397 shopt --set parse_proc
398
399 f() {
400 unset x
401 }
402
403 proc p() {
404 unset x
405 }
406
407 proc p2() {
408 shopt --set dynamic_scope { # turn it back on
409 unset x
410 }
411 }
412
413 x=foo
414 f
415 echo f x=$x
416
417 x=bar
418 p
419 echo p x=$x
420
421 x=spam
422 p2
423 echo p2 x=$x
424
425 ## STDOUT:
426 f x=
427 p x=bar
428 p2 x=
429 ## END
430
431 #### unset composes when you turn on dynamic scope
432 shopt -s oil:all
433
434 proc unset-two {
435 shopt --set dynamic_scope {
436 unset $1
437 unset $2
438 }
439 }
440
441 demo() {
442 local x=X
443 local y=Y
444
445 echo "x=$x y=$y"
446
447 unset-two x y
448
449 shopt --unset nounset
450 echo "x=$x y=$y"
451 }
452
453 demo
454 ## STDOUT:
455 x=X y=Y
456 x= y=
457 ## END
458
459 #### Temp Bindings
460 shopt --set parse_proc
461
462 myfunc() {
463 echo myfunc FOO=$FOO
464 }
465 proc myproc() {
466 echo myproc FOO=$FOO
467 }
468
469 FOO=bar myfunc
470 FOO=bar myproc
471 FOO=bar echo inline FOO=$FOO
472 FOO=bar printenv.py FOO
473
474 ## STDOUT:
475 myfunc FOO=bar
476 myproc FOO=
477 inline FOO=
478 bar
479 ## END
480
481 #### cd blocks don't introduce new scopes
482 shopt --set oil:upgrade
483
484 var x = 42
485 cd / {
486 var y = 0
487 var z = 1
488 echo $x $y $z
489 setvar y = 43
490 }
491 setvar z = 44
492 echo $x $y $z
493
494 ## STDOUT:
495 42 0 1
496 42 43 44
497 ## END
498
499 #### IFS=: myproc exports when it doesn't need to
500 shopt --set parse_proc
501 shopt --set parse_brace
502
503 s='xzx zxz'
504
505 myfunc() {
506 echo myfunc IFS="$IFS"
507 argv.py $s
508 }
509
510 proc myproc() {
511 echo myproc IFS="$IFS"
512 argv.py $s
513 }
514
515 IFS=: $REPO_ROOT/spec/bin/printenv.py IFS
516
517 # default value
518 echo "$IFS" | od -A n -t x1
519
520 IFS=' z'
521 echo IFS="$IFS"
522
523 IFS=' x' myfunc
524
525 # Problem: $IFS in procs only finds GLOBAL values. But when actually
526 # splitting, $IFS is a 'shvar' which respects DYNAMIC scope.
527 # Use shvarGet('IFS') instead
528
529 IFS=' x' myproc
530
531 # Oil solution to the problem
532 shvar IFS=' x' {
533 myproc
534 }
535
536 ## STDOUT:
537 :
538 20 09 0a 0a
539 IFS= z
540 myfunc IFS= x
541 ['', 'z', 'z', 'z']
542 myproc IFS= z
543 ['', 'z', 'z', 'z']
544 myproc IFS= x
545 ['', 'z', 'z', 'z']
546 ## END
547
548 #### shvar usage
549 shopt --set oil:upgrade
550 shopt --unset errexit
551
552 # no block
553 shvar
554 echo status=$?
555
556 shvar { # no arg
557 true
558 }
559 echo status=$?
560
561 shvar foo { # should be name=value
562 true
563 }
564 echo status=$?
565 ## STDOUT:
566 status=2
567 status=2
568 status=2
569 ## END
570
571 #### shvar global
572 shopt --set oil:upgrade
573 shopt --unset nounset
574
575 echo _ESCAPER=$_ESCAPER
576 echo _DIALECT=$_DIALECT
577
578 shvar _ESCAPER=html _DIALECT=ninja {
579 echo block _ESCAPER=$_ESCAPER
580 echo block _DIALECT=$_DIALECT
581 }
582
583 echo _ESCAPER=$_ESCAPER
584 echo _DIALECT=$_DIALECT
585
586 # Now set them
587 _ESCAPER=foo
588 _DIALECT=bar
589
590 echo ___
591
592 echo _ESCAPER=$_ESCAPER
593 echo _DIALECT=$_DIALECT
594
595 shvar _ESCAPER=html _DIALECT=ninja {
596 echo block _ESCAPER=$_ESCAPER
597 echo block _DIALECT=$_DIALECT
598
599 shvar _ESCAPER=nested {
600 echo nested _ESCAPER=$_ESCAPER
601 echo nested _DIALECT=$_DIALECT
602 }
603 }
604
605 echo _ESCAPER=$_ESCAPER
606 echo _DIALECT=$_DIALECT
607
608 ## STDOUT:
609 _ESCAPER=
610 _DIALECT=
611 block _ESCAPER=html
612 block _DIALECT=ninja
613 _ESCAPER=
614 _DIALECT=
615 ___
616 _ESCAPER=foo
617 _DIALECT=bar
618 block _ESCAPER=html
619 block _DIALECT=ninja
620 nested _ESCAPER=nested
621 nested _DIALECT=ninja
622 _ESCAPER=foo
623 _DIALECT=bar
624 ## END
625
626 #### shvar local
627 shopt --set oil:upgrade # blocks
628 shopt --unset simple_word_eval # test word splitting
629
630 proc foo {
631 shvar IFS=x MYTEMP=foo {
632 echo IFS="$IFS"
633 argv.py $s
634 echo MYTEMP=${MYTEMP:-undef}
635 }
636 }
637 var s = 'a b c'
638 argv.py $s
639 foo
640 argv.py $s
641 echo MYTEMP=${MYTEMP:-undef}
642 ## STDOUT:
643 ['a', 'b', 'c']
644 IFS=x
645 ['a b c']
646 MYTEMP=foo
647 ['a', 'b', 'c']
648 MYTEMP=undef
649 ## END
650
651 #### shvar IFS
652 shopt --set oil:upgrade
653
654 proc myproc() {
655 echo "$IFS" | od -A n -t x1
656
657 local mylocal=x
658 shvar IFS=w {
659 echo inside IFS="$IFS"
660 echo mylocal="$mylocal" # I do NOT want a new scope!
661 }
662 echo "$IFS" | od -A n -t x1
663 }
664
665 myproc
666 ## STDOUT:
667 20 09 0a 0a
668 inside IFS=w
669 mylocal=x
670 20 09 0a 0a
671 ## END
672
673 #### shvarGet()
674 shopt --set parse_proc
675
676 s='xzx zxz'
677
678 proc myproc {
679 echo wrong IFS="$IFS" # NOT what's used
680 echo shvar IFS=$[shvarGet('IFS')] # what IS used: dynamic scope
681 argv.py $s
682 }
683
684 IFS=x
685 IFS=z myproc
686 ## STDOUT:
687 wrong IFS=x
688 shvar IFS=z
689 ['x', 'x ', 'x']
690 ## END
691