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 introduce new scopes
554 shopt --set ysh: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 echo $x $[getVar('y')] $[getVar('z')]
564
565 ## STDOUT:
566 42 0 1
567 42 null null
568 ## END
569
570 #### IFS=: myproc exports when it doesn't need to
571 shopt --set parse_proc
572 shopt --set parse_brace
573
574 s='xzx zxz'
575
576 myfunc() {
577 echo myfunc IFS="$IFS"
578 argv.py $s
579 }
580
581 proc myproc() {
582 echo myproc IFS="$IFS"
583 argv.py $s
584 }
585
586 IFS=: $REPO_ROOT/spec/bin/printenv.py IFS
587
588 # default value
589 echo "$IFS" | od -A n -t x1
590
591 IFS=' z'
592 echo IFS="$IFS"
593
594 IFS=' x' myfunc
595
596 # Problem: $IFS in procs only finds GLOBAL values. But when actually
597 # splitting, $IFS is a 'shvar' which respects DYNAMIC scope.
598 # Use shvarGet('IFS') instead
599
600 IFS=' x' myproc
601
602 # Oil solution to the problem
603 shvar IFS=' x' {
604 myproc
605 }
606
607 ## STDOUT:
608 :
609 20 09 0a 0a
610 IFS= z
611 myfunc IFS= x
612 ['', 'z', 'z', 'z']
613 myproc IFS= z
614 ['', 'z', 'z', 'z']
615 myproc IFS= x
616 ['', 'z', 'z', 'z']
617 ## END
618
619 #### shvar usage
620 shopt --set oil:upgrade
621 shopt --unset errexit
622
623 # no block
624 shvar
625 echo status=$?
626
627 shvar { # no arg
628 true
629 }
630 echo status=$?
631
632 shvar foo { # should be name=value
633 true
634 }
635 echo status=$?
636 ## STDOUT:
637 status=2
638 status=2
639 status=2
640 ## END
641
642 #### shvar global
643 shopt --set oil:upgrade
644 shopt --unset nounset
645
646 echo _ESCAPER=$_ESCAPER
647 echo _DIALECT=$_DIALECT
648
649 shvar _ESCAPER=html _DIALECT=ninja {
650 echo block _ESCAPER=$_ESCAPER
651 echo block _DIALECT=$_DIALECT
652 }
653
654 echo _ESCAPER=$_ESCAPER
655 echo _DIALECT=$_DIALECT
656
657 # Now set them
658 _ESCAPER=foo
659 _DIALECT=bar
660
661 echo ___
662
663 echo _ESCAPER=$_ESCAPER
664 echo _DIALECT=$_DIALECT
665
666 shvar _ESCAPER=html _DIALECT=ninja {
667 echo block _ESCAPER=$_ESCAPER
668 echo block _DIALECT=$_DIALECT
669
670 shvar _ESCAPER=nested {
671 echo nested _ESCAPER=$_ESCAPER
672 echo nested _DIALECT=$_DIALECT
673 }
674 }
675
676 echo _ESCAPER=$_ESCAPER
677 echo _DIALECT=$_DIALECT
678
679 ## STDOUT:
680 _ESCAPER=
681 _DIALECT=
682 block _ESCAPER=html
683 block _DIALECT=ninja
684 _ESCAPER=
685 _DIALECT=
686 ___
687 _ESCAPER=foo
688 _DIALECT=bar
689 block _ESCAPER=html
690 block _DIALECT=ninja
691 nested _ESCAPER=nested
692 nested _DIALECT=ninja
693 _ESCAPER=foo
694 _DIALECT=bar
695 ## END
696
697 #### shvar local
698 shopt --set oil:upgrade # blocks
699 shopt --unset simple_word_eval # test word splitting
700
701 proc foo {
702 shvar IFS=x MYTEMP=foo {
703 echo IFS="$IFS"
704 argv.py $s
705 echo MYTEMP=${MYTEMP:-undef}
706 }
707 }
708 var s = 'a b c'
709 argv.py $s
710 foo
711 argv.py $s
712 echo MYTEMP=${MYTEMP:-undef}
713 ## STDOUT:
714 ['a', 'b', 'c']
715 IFS=x
716 ['a b c']
717 MYTEMP=foo
718 ['a', 'b', 'c']
719 MYTEMP=undef
720 ## END
721
722 #### shvar IFS
723 shopt --set oil:upgrade
724
725 proc myproc() {
726 echo "$IFS" | od -A n -t x1
727
728 local mylocal=x
729 shvar IFS=w {
730 echo inside IFS="$IFS"
731 echo mylocal="$mylocal" # I do NOT want a new scope!
732 }
733 echo "$IFS" | od -A n -t x1
734 }
735
736 myproc
737 ## STDOUT:
738 20 09 0a 0a
739 inside IFS=w
740 mylocal=x
741 20 09 0a 0a
742 ## END
743
744 #### shvarGet()
745 shopt --set parse_proc
746
747 s='xzx zxz'
748
749 proc myproc {
750 echo wrong IFS="$IFS" # NOT what's used
751 echo shvar IFS=$[shvarGet('IFS')] # what IS used: dynamic scope
752 argv.py $s
753 }
754
755 IFS=x
756 IFS=z myproc
757
758 # null
759 echo $[shvarGet('nonexistent')]
760
761 ## STDOUT:
762 wrong IFS=x
763 shvar IFS=z
764 ['x', 'x ', 'x']
765 null
766 ## END
767