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