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 __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 = {'local': 1} # shadows global var
336
337 setglobal g.key = 'mutated'
338 setglobal g['key2'] = 'mutated'
339
340 echo 'local that is ignored'
341 pp test_ (g)
342 }
343
344 echo 'BEFORE mutate global'
345 pp test_ (g)
346
347 mutate
348
349 echo 'AFTER mutate global'
350 pp test_ (g)
351
352 ## STDOUT:
353 BEFORE mutate global
354 (Dict) {}
355 local that is ignored
356 (Dict) {"local":1}
357 AFTER mutate global
358 (Dict) {"key":"mutated","key2":"mutated"}
359 ## END
360
361 #### setglobal a[i] inside proc
362 shopt -s ysh:upgrade
363
364 var a = [0]
365
366 proc mutate {
367 var a = [1] # shadows global var
368
369 echo 'local that is ignored'
370 setglobal a[0] = 42
371
372 pp test_ (a)
373 }
374
375 echo 'BEFORE mutate global'
376 pp test_ (a)
377
378 mutate
379
380 echo 'AFTER mutate global'
381 pp test_ (a)
382
383 ## STDOUT:
384 BEFORE mutate global
385 (List) [0]
386 local that is ignored
387 (List) [1]
388 AFTER mutate global
389 (List) [42]
390 ## END
391
392 #### setglobal a[i] += and d.key +=
393 shopt -s ysh:upgrade
394
395 var mylist = [0]
396 var mydict = {k: 0}
397
398 proc mutate {
399 # these locals are ignored
400 var mylist = []
401 var mydict = {}
402
403 setglobal mylist[0] += 5
404 setglobal mydict['k'] += 5
405 }
406
407 mutate
408
409 pp test_ (mylist)
410 pp test_ (mydict)
411
412 ## STDOUT:
413 (List) [5]
414 (Dict) {"k":5}
415 ## END
416
417 #### setglobal a[i] - i can be local or global
418 shopt -s ysh:upgrade
419
420 var mylist = [0, 1]
421 var mydict = {k: 0, n: 1}
422
423 var i = 0
424 var key = 'k'
425
426 proc mutate1 {
427 var mylist = [] # IGNORED
428 var mydict = {} # IGNORED
429
430 var i = 1
431 var key = 'n'
432
433 setglobal mylist[i] = 11
434 setglobal mydict[key] = 11
435 }
436
437 # Same thing without locals
438 proc mutate2 {
439 var mylist = [] # IGNORED
440 var mydict = {} # IGNORED
441
442 setglobal mylist[i] = 22
443 setglobal mydict[key] = 22
444 }
445
446 mutate1
447
448 pp test_ (mylist)
449 pp test_ (mydict)
450 echo
451
452 mutate2
453
454 pp test_ (mylist)
455 pp test_ (mydict)
456
457 ## STDOUT:
458 (List) [0,11]
459 (Dict) {"k":0,"n":11}
460
461 (List) [22,11]
462 (Dict) {"k":22,"n":11}
463 ## END
464
465 #### unset inside proc uses local scope
466 shopt --set parse_brace
467 shopt --set parse_proc
468
469 f() {
470 unset x
471 }
472
473 proc p() {
474 unset x
475 }
476
477 proc p2() {
478 shopt --set dynamic_scope { # turn it back on
479 unset x
480 }
481 }
482
483 x=foo
484 f
485 echo f x=$x
486
487 x=bar
488 p
489 echo p x=$x
490
491 x=spam
492 p2
493 echo p2 x=$x
494
495 ## STDOUT:
496 f x=
497 p x=bar
498 p2 x=
499 ## END
500
501 #### unset composes when you turn on dynamic scope
502 shopt -s ysh:all
503
504 proc unset-two (v, w) {
505 shopt --set dynamic_scope {
506 unset $v
507 unset $w
508 }
509 }
510
511 demo() {
512 local x=X
513 local y=Y
514
515 echo "x=$x y=$y"
516
517 unset-two x y
518
519 shopt --unset nounset
520 echo "x=$x y=$y"
521 }
522
523 demo
524 ## STDOUT:
525 x=X y=Y
526 x= y=
527 ## END
528
529 #### Temp Bindings
530 shopt --set parse_proc
531
532 myfunc() {
533 echo myfunc FOO=$FOO
534 }
535 proc myproc() {
536 echo myproc FOO=$FOO
537 }
538
539 FOO=bar myfunc
540 FOO=bar myproc
541 FOO=bar echo inline FOO=$FOO
542 FOO=bar printenv.py FOO
543
544 ## STDOUT:
545 myfunc FOO=bar
546 myproc FOO=
547 inline FOO=
548 bar
549 ## END
550
551 #### cd blocks don't introduce new scopes
552 shopt --set oil:upgrade
553
554 var x = 42
555 cd / {
556 var y = 0
557 var z = 1
558 echo $x $y $z
559 setvar y = 43
560 }
561 setvar z = 44
562 echo $x $y $z
563
564 ## STDOUT:
565 42 0 1
566 42 43 44
567 ## END
568
569 #### IFS=: myproc exports when it doesn't need to
570 shopt --set parse_proc
571 shopt --set parse_brace
572
573 source --builtin ysh/shvar.ysh
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 source --builtin ysh/shvar.ysh
625
626 # no block
627 shvar
628 echo status=$?
629
630 shvar { # no arg
631 true
632 }
633 echo status=$?
634
635 shvar foo { # should be name=value
636 true
637 }
638 echo status=$?
639 ## STDOUT:
640 status=2
641 status=2
642 status=2
643 ## END
644
645 #### shvar global
646 shopt --set oil:upgrade
647 shopt --unset nounset
648
649 source --builtin ysh/shvar.ysh
650
651 echo _ESCAPER=$_ESCAPER
652 echo _DIALECT=$_DIALECT
653
654 shvar _ESCAPER=html _DIALECT=ninja {
655 echo block _ESCAPER=$_ESCAPER
656 echo block _DIALECT=$_DIALECT
657 }
658
659 echo _ESCAPER=$_ESCAPER
660 echo _DIALECT=$_DIALECT
661
662 # Now set them
663 _ESCAPER=foo
664 _DIALECT=bar
665
666 echo ___
667
668 echo _ESCAPER=$_ESCAPER
669 echo _DIALECT=$_DIALECT
670
671 shvar _ESCAPER=html _DIALECT=ninja {
672 echo block _ESCAPER=$_ESCAPER
673 echo block _DIALECT=$_DIALECT
674
675 shvar _ESCAPER=nested {
676 echo nested _ESCAPER=$_ESCAPER
677 echo nested _DIALECT=$_DIALECT
678 }
679 }
680
681 echo _ESCAPER=$_ESCAPER
682 echo _DIALECT=$_DIALECT
683
684 ## STDOUT:
685 _ESCAPER=
686 _DIALECT=
687 block _ESCAPER=html
688 block _DIALECT=ninja
689 _ESCAPER=
690 _DIALECT=
691 ___
692 _ESCAPER=foo
693 _DIALECT=bar
694 block _ESCAPER=html
695 block _DIALECT=ninja
696 nested _ESCAPER=nested
697 nested _DIALECT=ninja
698 _ESCAPER=foo
699 _DIALECT=bar
700 ## END
701
702 #### shvar local
703 shopt --set oil:upgrade # blocks
704 shopt --unset simple_word_eval # test word splitting
705
706 source --builtin ysh/shvar.ysh
707
708 proc foo {
709 shvar IFS=x MYTEMP=foo {
710 echo IFS="$IFS"
711 argv.py $s
712 echo MYTEMP=${MYTEMP:-undef}
713 }
714 }
715 var s = 'a b c'
716 argv.py $s
717 foo
718 argv.py $s
719 echo MYTEMP=${MYTEMP:-undef}
720 ## STDOUT:
721 ['a', 'b', 'c']
722 IFS=x
723 ['a b c']
724 MYTEMP=foo
725 ['a', 'b', 'c']
726 MYTEMP=undef
727 ## END
728
729 #### shvar IFS
730 shopt --set oil:upgrade
731
732 source --builtin ysh/shvar.ysh
733
734 proc myproc() {
735 echo "$IFS" | od -A n -t x1
736
737 local mylocal=x
738 shvar IFS=w {
739 echo inside IFS="$IFS"
740 echo mylocal="$mylocal" # I do NOT want a new scope!
741 }
742 echo "$IFS" | od -A n -t x1
743 }
744
745 myproc
746 ## STDOUT:
747 20 09 0a 0a
748 inside IFS=w
749 mylocal=x
750 20 09 0a 0a
751 ## END
752
753 #### shvarGet()
754 shopt --set parse_proc
755
756 s='xzx zxz'
757
758 proc myproc {
759 echo wrong IFS="$IFS" # NOT what's used
760 echo shvar IFS=$[shvarGet('IFS')] # what IS used: dynamic scope
761 argv.py $s
762 }
763
764 IFS=x
765 IFS=z myproc
766
767 # null
768 echo $[shvarGet('nonexistent')]
769
770 ## STDOUT:
771 wrong IFS=x
772 shvar IFS=z
773 ['x', 'x ', 'x']
774 null
775 ## END
776