1 ## oils_failures_allowed: 0
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
210 ___g=G
211
212 show-vars() {
213 local ___x=X
214 declare -p | grep '___'
215 echo status=$?
216
217 echo -
218 declare -p ___y | grep '___'
219 echo status=$?
220 }
221
222 demo() {
223 local ___y=Y
224
225 show-vars
226 echo ---
227 shopt --unset dynamic_scope
228 show-vars
229 }
230
231 demo
232
233 ## STDOUT:
234 declare -- ___g=G
235 declare -- ___x=X
236 declare -- ___y=Y
237 status=0
238 -
239 declare -- ___y=Y
240 status=0
241 ---
242 declare -- ___g=G
243 declare -- ___x=X
244 status=0
245 -
246 status=1
247 ## END
248
249
250 #### OshLanguageSetValue constructs
251
252 f() {
253 (( x = 42 ))
254 }
255 demo() {
256 f
257 echo x=$x
258 }
259
260 demo
261
262 echo ---
263
264 shopt --unset dynamic_scope
265
266 unset x
267
268 demo
269
270 echo --- global
271 echo x=$x
272 ## STDOUT:
273 x=42
274 ---
275 x=
276 --- global
277 x=
278 ## END
279
280
281 #### shell assignments 'neutered' inside 'proc'
282 shopt --set parse_proc
283
284 # They can't mutate globals or anything higher on the stack
285
286 proc p {
287 declare g=PROC
288 export e=PROC
289 }
290
291 f() {
292 g=SH
293 export e=SH
294 }
295
296 e=E
297 g=G
298 p
299 echo e=$e g=$g
300
301 p
302 echo e=$e g=$g
303
304 f
305 echo e=$e g=$g
306
307 ## STDOUT:
308 e=E g=G
309 e=E g=G
310 e=SH g=SH
311 ## END
312
313 #### setglobal still allows setting globals
314 shopt --set parse_proc
315
316 proc p {
317 setglobal new_global = 'p'
318 setglobal g = 'p'
319 }
320
321 var g = 'G'
322
323 p
324
325 echo g=$g new_global=$new_global
326 ## STDOUT:
327 g=p new_global=p
328 ## END
329
330 #### setglobal d[key] inside proc should mutate global (bug #1841)
331
332 shopt -s ysh:upgrade
333
334 var g = {}
335
336 proc mutate {
337 var g = {'local': 1} # shadows global var
338
339 setglobal g.key = 'mutated'
340 setglobal g['key2'] = 'mutated'
341
342 echo 'local that is ignored'
343 pp test_ (g)
344 }
345
346 echo 'BEFORE mutate global'
347 pp test_ (g)
348
349 mutate
350
351 echo 'AFTER mutate global'
352 pp test_ (g)
353
354 ## STDOUT:
355 BEFORE mutate global
356 (Dict) {}
357 local that is ignored
358 (Dict) {"local":1}
359 AFTER mutate global
360 (Dict) {"key":"mutated","key2":"mutated"}
361 ## END
362
363 #### setglobal a[i] inside proc
364 shopt -s ysh:upgrade
365
366 var a = [0]
367
368 proc mutate {
369 var a = [1] # shadows global var
370
371 echo 'local that is ignored'
372 setglobal a[0] = 42
373
374 pp test_ (a)
375 }
376
377 echo 'BEFORE mutate global'
378 pp test_ (a)
379
380 mutate
381
382 echo 'AFTER mutate global'
383 pp test_ (a)
384
385 ## STDOUT:
386 BEFORE mutate global
387 (List) [0]
388 local that is ignored
389 (List) [1]
390 AFTER mutate global
391 (List) [42]
392 ## END
393
394 #### setglobal a[i] += and d.key +=
395 shopt -s ysh:upgrade
396
397 var mylist = [0]
398 var mydict = {k: 0}
399
400 proc mutate {
401 # these locals are ignored
402 var mylist = []
403 var mydict = {}
404
405 setglobal mylist[0] += 5
406 setglobal mydict['k'] += 5
407 }
408
409 mutate
410
411 pp test_ (mylist)
412 pp test_ (mydict)
413
414 ## STDOUT:
415 (List) [5]
416 (Dict) {"k":5}
417 ## END
418
419 #### setglobal a[i] - i can be local or global
420 shopt -s ysh:upgrade
421
422 var mylist = [0, 1]
423 var mydict = {k: 0, n: 1}
424
425 var i = 0
426 var key = 'k'
427
428 proc mutate1 {
429 var mylist = [] # IGNORED
430 var mydict = {} # IGNORED
431
432 var i = 1
433 var key = 'n'
434
435 setglobal mylist[i] = 11
436 setglobal mydict[key] = 11
437 }
438
439 # Same thing without locals
440 proc mutate2 {
441 var mylist = [] # IGNORED
442 var mydict = {} # IGNORED
443
444 setglobal mylist[i] = 22
445 setglobal mydict[key] = 22
446 }
447
448 mutate1
449
450 pp test_ (mylist)
451 pp test_ (mydict)
452 echo
453
454 mutate2
455
456 pp test_ (mylist)
457 pp test_ (mydict)
458
459 ## STDOUT:
460 (List) [0,11]
461 (Dict) {"k":0,"n":11}
462
463 (List) [22,11]
464 (Dict) {"k":22,"n":11}
465 ## END
466
467 #### unset inside proc uses local scope
468 shopt --set parse_brace
469 shopt --set parse_proc
470
471 f() {
472 unset x
473 }
474
475 proc p() {
476 unset x
477 }
478
479 proc p2() {
480 shopt --set dynamic_scope { # turn it back on
481 unset x
482 }
483 }
484
485 x=foo
486 f
487 echo f x=$x
488
489 x=bar
490 p
491 echo p x=$x
492
493 x=spam
494 p2
495 echo p2 x=$x
496
497 ## STDOUT:
498 f x=
499 p x=bar
500 p2 x=
501 ## END
502
503 #### unset composes when you turn on dynamic scope
504 shopt -s ysh:all
505
506 proc unset-two (v, w) {
507 shopt --set dynamic_scope {
508 unset $v
509 unset $w
510 }
511 }
512
513 demo() {
514 local x=X
515 local y=Y
516
517 echo "x=$x y=$y"
518
519 unset-two x y
520
521 shopt --unset nounset
522 echo "x=$x y=$y"
523 }
524
525 demo
526 ## STDOUT:
527 x=X y=Y
528 x= y=
529 ## END
530
531 #### Temp Bindings
532 shopt --set parse_proc
533
534 myfunc() {
535 echo myfunc FOO=$FOO
536 }
537 proc myproc() {
538 echo myproc FOO=$FOO
539 }
540
541 FOO=bar myfunc
542 FOO=bar myproc
543 FOO=bar echo inline FOO=$FOO
544 FOO=bar printenv.py FOO
545
546 ## STDOUT:
547 myfunc FOO=bar
548 myproc FOO=
549 inline FOO=
550 bar
551 ## END
552
553 #### cd blocks don't introduce new scopes
554 shopt --set oil:upgrade
555
556 var x = 42
557 cd / {
558 var y = 0
559 var z = 1
560 echo $x $y $z
561 setvar y = 43
562 }
563 setvar z = 44
564 echo $x $y $z
565
566 ## STDOUT:
567 42 0 1
568 42 43 44
569 ## END
570
571 #### IFS=: myproc exports when it doesn't need to
572 shopt --set parse_proc
573 shopt --set parse_brace
574
575 s='xzx zxz'
576
577 myfunc() {
578 echo myfunc IFS="$IFS"
579 argv.py $s
580 }
581
582 proc myproc() {
583 echo myproc IFS="$IFS"
584 argv.py $s
585 }
586
587 IFS=: $REPO_ROOT/spec/bin/printenv.py IFS
588
589 # default value
590 echo "$IFS" | od -A n -t x1
591
592 IFS=' z'
593 echo IFS="$IFS"
594
595 IFS=' x' myfunc
596
597 # Problem: $IFS in procs only finds GLOBAL values. But when actually
598 # splitting, $IFS is a 'shvar' which respects DYNAMIC scope.
599 # Use shvarGet('IFS') instead
600
601 IFS=' x' myproc
602
603 # Oil solution to the problem
604 shvar IFS=' x' {
605 myproc
606 }
607
608 ## STDOUT:
609 :
610 20 09 0a 0a
611 IFS= z
612 myfunc IFS= x
613 ['', 'z', 'z', 'z']
614 myproc IFS= z
615 ['', 'z', 'z', 'z']
616 myproc IFS= x
617 ['', 'z', 'z', 'z']
618 ## END
619
620 #### shvar usage
621 shopt --set oil:upgrade
622 shopt --unset errexit
623
624 # no block
625 shvar
626 echo status=$?
627
628 shvar { # no arg
629 true
630 }
631 echo status=$?
632
633 shvar foo { # should be name=value
634 true
635 }
636 echo status=$?
637 ## STDOUT:
638 status=2
639 status=2
640 status=2
641 ## END
642
643 #### shvar global
644 shopt --set oil:upgrade
645 shopt --unset nounset
646
647 echo _ESCAPER=$_ESCAPER
648 echo _DIALECT=$_DIALECT
649
650 shvar _ESCAPER=html _DIALECT=ninja {
651 echo block _ESCAPER=$_ESCAPER
652 echo block _DIALECT=$_DIALECT
653 }
654
655 echo _ESCAPER=$_ESCAPER
656 echo _DIALECT=$_DIALECT
657
658 # Now set them
659 _ESCAPER=foo
660 _DIALECT=bar
661
662 echo ___
663
664 echo _ESCAPER=$_ESCAPER
665 echo _DIALECT=$_DIALECT
666
667 shvar _ESCAPER=html _DIALECT=ninja {
668 echo block _ESCAPER=$_ESCAPER
669 echo block _DIALECT=$_DIALECT
670
671 shvar _ESCAPER=nested {
672 echo nested _ESCAPER=$_ESCAPER
673 echo nested _DIALECT=$_DIALECT
674 }
675 }
676
677 echo _ESCAPER=$_ESCAPER
678 echo _DIALECT=$_DIALECT
679
680 ## STDOUT:
681 _ESCAPER=
682 _DIALECT=
683 block _ESCAPER=html
684 block _DIALECT=ninja
685 _ESCAPER=
686 _DIALECT=
687 ___
688 _ESCAPER=foo
689 _DIALECT=bar
690 block _ESCAPER=html
691 block _DIALECT=ninja
692 nested _ESCAPER=nested
693 nested _DIALECT=ninja
694 _ESCAPER=foo
695 _DIALECT=bar
696 ## END
697
698 #### shvar local
699 shopt --set oil:upgrade # blocks
700 shopt --unset simple_word_eval # test word splitting
701
702 proc foo {
703 shvar IFS=x MYTEMP=foo {
704 echo IFS="$IFS"
705 argv.py $s
706 echo MYTEMP=${MYTEMP:-undef}
707 }
708 }
709 var s = 'a b c'
710 argv.py $s
711 foo
712 argv.py $s
713 echo MYTEMP=${MYTEMP:-undef}
714 ## STDOUT:
715 ['a', 'b', 'c']
716 IFS=x
717 ['a b c']
718 MYTEMP=foo
719 ['a', 'b', 'c']
720 MYTEMP=undef
721 ## END
722
723 #### shvar IFS
724 shopt --set oil:upgrade
725
726 proc myproc() {
727 echo "$IFS" | od -A n -t x1
728
729 local mylocal=x
730 shvar IFS=w {
731 echo inside IFS="$IFS"
732 echo mylocal="$mylocal" # I do NOT want a new scope!
733 }
734 echo "$IFS" | od -A n -t x1
735 }
736
737 myproc
738 ## STDOUT:
739 20 09 0a 0a
740 inside IFS=w
741 mylocal=x
742 20 09 0a 0a
743 ## END
744
745 #### shvarGet()
746 shopt --set parse_proc
747
748 s='xzx zxz'
749
750 proc myproc {
751 echo wrong IFS="$IFS" # NOT what's used
752 echo shvar IFS=$[shvarGet('IFS')] # what IS used: dynamic scope
753 argv.py $s
754 }
755
756 IFS=x
757 IFS=z myproc
758
759 # null
760 echo $[shvarGet('nonexistent')]
761
762 ## STDOUT:
763 wrong IFS=x
764 shvar IFS=z
765 ['x', 'x ', 'x']
766 null
767 ## END
768