1 # Demonstrations for users. Could go in docs.
2
3 #### GetValue scope and shopt --unset dynamic_scope
4 shopt --set parse_proc
5
6 f() {
7 echo "sh x=$x"
8 }
9
10 proc p {
11 echo "oil x=$x"
12 }
13
14 demo() {
15 local x=dynamic
16 f
17 p
18
19 shopt --unset dynamic_scope
20 f
21 }
22
23 x=global
24 demo
25 echo x=$x
26
27 ## STDOUT:
28 sh x=dynamic
29 oil x=global
30 sh x=global
31 x=global
32 ## END
33
34
35 #### SetValue scope and shopt --unset dynamic_scope
36 shopt --set parse_proc
37
38 f() {
39 x=f
40 }
41
42 proc p {
43 x=p
44 }
45
46 demo() {
47 local x=stack
48 echo x=$x
49 echo ---
50
51 f
52 echo f x=$x
53
54 x=stack
55 p
56 echo p x=$x
57
58 shopt --unset dynamic_scope
59 x=stack
60 f
61 echo funset x=$x
62 }
63
64 x=global
65 demo
66
67 echo ---
68 echo x=$x
69
70 ## STDOUT:
71 x=stack
72 ---
73 f x=f
74 p x=stack
75 funset x=stack
76 ---
77 x=global
78 ## END
79
80 #### read scope (setref)
81 set -o errexit
82
83 read-x() {
84 echo dynamic-scope | read x
85 }
86 demo() {
87 local x=42
88 echo x_before=$x
89 read-x
90 echo x_after=$x
91 }
92 demo
93 echo x=$x
94
95 echo ---
96
97 # Now 'read x' creates a local variable
98 shopt --unset dynamic_scope
99 demo
100 echo x=$x
101
102 ## STDOUT:
103 x_before=42
104 x_after=dynamic-scope
105 x=
106 ---
107 x_before=42
108 x_after=42
109 x=
110 ## END
111
112 #### printf -v x respects dynamic_scope
113 set -o errexit
114
115 set-x() {
116 printf -v x "%s" dynamic-scope
117 }
118 demo() {
119 local x=42
120 echo x=$x
121 set-x
122 echo x=$x
123 }
124 demo
125 echo x=$x
126
127 echo ---
128
129 shopt --unset dynamic_scope # should NOT affect read
130 demo
131 echo x=$x
132
133 ## STDOUT:
134 x=42
135 x=dynamic-scope
136 x=
137 ---
138 x=42
139 x=42
140 x=
141 ## END
142
143 #### printf -v a[i] respects dynamic_scope
144 set -o errexit
145
146 set-item() {
147 printf -v 'a[1]' "%s" dynamic-scope
148 }
149 demo() {
150 local -a a=(41 42 43)
151 echo "a[1]=${a[1]}"
152 set-item
153 echo "a[1]=${a[1]}"
154 }
155 demo
156 echo "a[1]=${a[1]}"
157
158 echo ---
159
160 shopt --unset dynamic_scope # should NOT affect read
161 demo
162 echo "a[1]=${a[1]}"
163
164 ## STDOUT:
165 a[1]=42
166 a[1]=dynamic-scope
167 a[1]=
168 ---
169 a[1]=42
170 a[1]=42
171 a[1]=
172 ## END
173
174 #### ${undef=a} and shopt --unset dynamic_scope
175
176 set-x() {
177 : ${x=new}
178 }
179 demo() {
180 local x
181 echo x=$x
182 set-x
183 echo x=$x
184 }
185
186 demo
187 echo x=$x
188
189 echo ---
190
191 # Now this IS affected?
192 shopt --unset dynamic_scope
193 demo
194 echo x=$x
195 ## STDOUT:
196 x=
197 x=new
198 x=
199 ---
200 x=
201 x=
202 x=
203 ## END
204
205 #### declare -p respects it
206 __g=G
207 show-vars() {
208 local __x=X
209 declare -p | grep '__'
210 echo status=$?
211
212 echo -
213 declare -p __y | grep '__'
214 echo status=$?
215 }
216
217 demo() {
218 local __y=Y
219
220 show-vars
221 echo ---
222 shopt --unset dynamic_scope
223 show-vars
224 }
225
226 demo
227
228 ## STDOUT:
229 declare -- __g=G
230 declare -- __x=X
231 declare -- __y=Y
232 status=0
233 -
234 declare -- __y=Y
235 status=0
236 ---
237 declare -- __g=G
238 declare -- __x=X
239 status=0
240 -
241 status=1
242 ## END
243
244
245 #### OshLanguageSetValue constructs
246
247 f() {
248 (( x = 42 ))
249 }
250 demo() {
251 f
252 echo x=$x
253 }
254
255 demo
256
257 echo ---
258
259 shopt --unset dynamic_scope
260
261 unset x
262
263 demo
264
265 echo --- global
266 echo x=$x
267 ## STDOUT:
268 x=42
269 ---
270 x=
271 --- global
272 x=
273 ## END
274
275
276 #### shell assignments 'neutered' inside 'proc'
277 shopt --set parse_proc
278
279 # They can't mutate globals or anything higher on the stack
280
281 proc p {
282 g=PROC
283 export e=PROC
284 }
285
286 f() {
287 g=SH
288 export e=SH
289 }
290
291 e=E
292 g=G
293 p
294 echo e=$e g=$g
295
296 p
297 echo e=$e g=$g
298
299 f
300 echo e=$e g=$g
301
302 ## STDOUT:
303 e=E g=G
304 e=E g=G
305 e=SH g=SH
306 ## END
307
308 #### setglobal still allows setting globals
309 shopt --set parse_proc
310
311 proc p {
312 setglobal new_global = 'p'
313 setglobal g = 'p'
314 }
315
316 var g = 'G'
317
318 p
319
320 echo g=$g new_global=$new_global
321 ## STDOUT:
322 g=p new_global=p
323 ## END
324
325 #### setref with out Ref param
326 shopt --set parse_proc
327
328 proc set-it(s Ref, val) {
329 # s param is rewritten to __s to avoid name conflict
330 #pp cell __s
331 setref s = "foo-$val"
332 }
333
334 proc demo {
335 if true; then
336 var s = 'abc'
337 set-it :s SS
338 echo $s
339 fi
340
341 var t = 'def'
342 set-it :t TT
343 echo $t
344 }
345
346 demo
347
348 ## STDOUT:
349 foo-SS
350 foo-TT
351 ## END
352
353 #### setref with conflicting variable name
354 shopt --set parse_proc
355
356 proc set-it(s Ref, val) {
357 #pp cell __s
358
359 # This breaks it!
360 var oops = ''
361 setref s = "foo-$val"
362 }
363
364 proc demo {
365 var oops = ''
366 set-it :oops zz
367 echo oops=$oops
368 }
369
370 demo
371
372 ## STDOUT:
373 oops=foo-zz
374 ## END
375
376
377 #### setref of regular param is a fatal error
378 shopt --set parse_proc
379
380 proc set-it(s Ref, val) {
381 setref val = 'oops'
382 }
383
384 var s = 'abc'
385 set-it :s SS
386 echo $s
387
388 ## status: 1
389 ## STDOUT:
390 ## END
391
392 #### setref equivalent without pgen2 syntax, using open proc
393 shopt --set parse_proc
394
395 # This is kind of what we compile to. Ref params get an extra __ prefix? then
396 # that means you can't really READ them either? I think that's OK.
397
398 # At call time, param binding time:
399 # If the PARAM has a colon prefix:
400 # Assert that the ARG has a colon prefix. Don't remove it.
401 # Set the cell.nameref flag.
402 #
403 # At Setref time:
404 # Check that it's cell.nameref.
405 # Add extra : to lvalue.{Named,Indexed,Keyed} and perform it.
406 #
407 # The __ avoids the nameref cycle check.
408 # And we probably disallow reading from the ref. That's OK. The caller can
409 # pass it in as a regular value!
410
411 proc set-it {
412 local -n __s=$1 # nameref flag needed with setref
413 local val=$2
414
415 # well this part requires pgen2
416 setref s = "foo-$val"
417 }
418
419 var s = 'abc'
420 var t = 'def'
421 set-it s SS
422 set-it t TT # no colon here
423 echo $s
424 echo $t
425
426 ## STDOUT:
427 foo-SS
428 foo-TT
429 ## END
430
431 #### setref a, b = 'one', 'two'
432 shopt --set parse_proc
433
434 proc p(x, a Ref, b Ref) {
435 setref a, b = "${x}1", "${x}2"
436 }
437
438 p foo :c :d
439 echo c=$c d=$d
440 ## STDOUT:
441 c=foo1 d=foo2
442 ## END
443
444 #### setref a[i]
445
446 # You can do this in bash/mksh. See nameref!
447
448 proc set1(:a, item) {
449 setref a[1] = item
450 }
451
452 var a = %(one two three)
453 var myarray = %(a b c)
454
455 set1 :a zzz
456 set1 :myarray z
457
458 shopt --set oil:upgrade
459 #write -- @a
460 write -- @myarray
461
462 ## STDOUT:
463 a
464 z
465 c
466 ## END
467
468 #### unset inside proc uses local scope
469 shopt --set parse_brace
470 shopt --set parse_proc
471
472 f() {
473 unset x
474 }
475
476 proc p() {
477 unset x
478 }
479
480 proc p2() {
481 shopt --set dynamic_scope { # turn it back on
482 unset x
483 }
484 }
485
486 x=foo
487 f
488 echo f x=$x
489
490 x=bar
491 p
492 echo p x=$x
493
494 x=spam
495 p2
496 echo p2 x=$x
497
498 ## STDOUT:
499 f x=
500 p x=bar
501 p2 x=
502 ## END
503
504 #### unset composes when you turn on dynamic scope
505 shopt -s oil:all
506
507 proc unset-two {
508 shopt --set dynamic_scope {
509 unset $1
510 unset $2
511 }
512 }
513
514 demo() {
515 local x=X
516 local y=Y
517
518 echo "x=$x y=$y"
519
520 unset-two x y
521
522 shopt --unset nounset
523 echo "x=$x y=$y"
524 }
525
526 demo
527 ## STDOUT:
528 x=X y=Y
529 x= y=
530 ## END
531
532 #### Temp Bindings
533 shopt --set parse_proc
534
535 myfunc() {
536 echo myfunc FOO=$FOO
537 }
538 proc myproc() {
539 echo myproc FOO=$FOO
540 }
541
542 FOO=bar myfunc
543 FOO=bar myproc
544 FOO=bar echo inline FOO=$FOO
545 FOO=bar printenv.py FOO
546
547 ## STDOUT:
548 myfunc FOO=bar
549 myproc FOO=
550 inline FOO=
551 bar
552 ## END
553
554 #### cd blocks don't introduce new scopes
555 shopt --set oil:upgrade
556
557 var x = 42
558 cd / {
559 var y, z = 0, 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 # - TODO: shvar_get('IFS')
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 #### shvar_get()
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=$[shvar_get('IFS')] # what IS used: dynamic scope
753 argv.py $s
754 }
755
756 IFS=x
757 IFS=z myproc
758 ## STDOUT:
759 wrong IFS=x
760 shvar IFS=z
761 ['x', 'x ', 'x']
762 ## END