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 shopt --set parse_proc
449
450 proc set1(a Ref, item) {
451 setref a[1] = item
452 }
453
454 var a = %(one two three)
455 var myarray = %(a b c)
456
457 set1 :a zzz
458 set1 :myarray z
459
460 shopt --set oil:upgrade
461 #write -- @a
462 write -- @myarray
463
464 ## STDOUT:
465 a
466 z
467 c
468 ## END
469
470 #### unset inside proc uses local scope
471 shopt --set parse_brace
472 shopt --set parse_proc
473
474 f() {
475 unset x
476 }
477
478 proc p() {
479 unset x
480 }
481
482 proc p2() {
483 shopt --set dynamic_scope { # turn it back on
484 unset x
485 }
486 }
487
488 x=foo
489 f
490 echo f x=$x
491
492 x=bar
493 p
494 echo p x=$x
495
496 x=spam
497 p2
498 echo p2 x=$x
499
500 ## STDOUT:
501 f x=
502 p x=bar
503 p2 x=
504 ## END
505
506 #### unset composes when you turn on dynamic scope
507 shopt -s oil:all
508
509 proc unset-two {
510 shopt --set dynamic_scope {
511 unset $1
512 unset $2
513 }
514 }
515
516 demo() {
517 local x=X
518 local y=Y
519
520 echo "x=$x y=$y"
521
522 unset-two x y
523
524 shopt --unset nounset
525 echo "x=$x y=$y"
526 }
527
528 demo
529 ## STDOUT:
530 x=X y=Y
531 x= y=
532 ## END
533
534 #### Temp Bindings
535 shopt --set parse_proc
536
537 myfunc() {
538 echo myfunc FOO=$FOO
539 }
540 proc myproc() {
541 echo myproc FOO=$FOO
542 }
543
544 FOO=bar myfunc
545 FOO=bar myproc
546 FOO=bar echo inline FOO=$FOO
547 FOO=bar printenv.py FOO
548
549 ## STDOUT:
550 myfunc FOO=bar
551 myproc FOO=
552 inline FOO=
553 bar
554 ## END
555
556 #### cd blocks don't introduce new scopes
557 shopt --set oil:upgrade
558
559 var x = 42
560 cd / {
561 var y = 0
562 var z = 1
563 echo $x $y $z
564 setvar y = 43
565 }
566 setvar z = 44
567 echo $x $y $z
568
569 ## STDOUT:
570 42 0 1
571 42 43 44
572 ## END
573
574 #### IFS=: myproc exports when it doesn't need to
575 shopt --set parse_proc
576 shopt --set parse_brace
577
578 s='xzx zxz'
579
580 myfunc() {
581 echo myfunc IFS="$IFS"
582 argv.py $s
583 }
584
585 proc myproc() {
586 echo myproc IFS="$IFS"
587 argv.py $s
588 }
589
590 IFS=: $REPO_ROOT/spec/bin/printenv.py IFS
591
592 # default value
593 echo "$IFS" | od -A n -t x1
594
595 IFS=' z'
596 echo IFS="$IFS"
597
598 IFS=' x' myfunc
599
600 # Problem: $IFS in procs only finds GLOBAL values. But when actually
601 # splitting, $IFS is a 'shvar' which respects DYNAMIC scope.
602 # - TODO: shvar_get('IFS')
603
604 IFS=' x' myproc
605
606 # Oil solution to the problem
607 shvar IFS=' x' {
608 myproc
609 }
610
611 ## STDOUT:
612 :
613 20 09 0a 0a
614 IFS= z
615 myfunc IFS= x
616 ['', 'z', 'z', 'z']
617 myproc IFS= z
618 ['', 'z', 'z', 'z']
619 myproc IFS= x
620 ['', 'z', 'z', 'z']
621 ## END
622
623 #### shvar usage
624 shopt --set oil:upgrade
625 shopt --unset errexit
626
627 # no block
628 shvar
629 echo status=$?
630
631 shvar { # no arg
632 true
633 }
634 echo status=$?
635
636 shvar foo { # should be name=value
637 true
638 }
639 echo status=$?
640 ## STDOUT:
641 status=2
642 status=2
643 status=2
644 ## END
645
646 #### shvar global
647 shopt --set oil:upgrade
648 shopt --unset nounset
649
650 echo _ESCAPER=$_ESCAPER
651 echo _DIALECT=$_DIALECT
652
653 shvar _ESCAPER=html _DIALECT=ninja {
654 echo block _ESCAPER=$_ESCAPER
655 echo block _DIALECT=$_DIALECT
656 }
657
658 echo _ESCAPER=$_ESCAPER
659 echo _DIALECT=$_DIALECT
660
661 # Now set them
662 _ESCAPER=foo
663 _DIALECT=bar
664
665 echo ___
666
667 echo _ESCAPER=$_ESCAPER
668 echo _DIALECT=$_DIALECT
669
670 shvar _ESCAPER=html _DIALECT=ninja {
671 echo block _ESCAPER=$_ESCAPER
672 echo block _DIALECT=$_DIALECT
673
674 shvar _ESCAPER=nested {
675 echo nested _ESCAPER=$_ESCAPER
676 echo nested _DIALECT=$_DIALECT
677 }
678 }
679
680 echo _ESCAPER=$_ESCAPER
681 echo _DIALECT=$_DIALECT
682
683 ## STDOUT:
684 _ESCAPER=
685 _DIALECT=
686 block _ESCAPER=html
687 block _DIALECT=ninja
688 _ESCAPER=
689 _DIALECT=
690 ___
691 _ESCAPER=foo
692 _DIALECT=bar
693 block _ESCAPER=html
694 block _DIALECT=ninja
695 nested _ESCAPER=nested
696 nested _DIALECT=ninja
697 _ESCAPER=foo
698 _DIALECT=bar
699 ## END
700
701 #### shvar local
702 shopt --set oil:upgrade # blocks
703 shopt --unset simple_word_eval # test word splitting
704
705 proc foo {
706 shvar IFS=x MYTEMP=foo {
707 echo IFS="$IFS"
708 argv.py $s
709 echo MYTEMP=${MYTEMP:-undef}
710 }
711 }
712 var s = 'a b c'
713 argv.py $s
714 foo
715 argv.py $s
716 echo MYTEMP=${MYTEMP:-undef}
717 ## STDOUT:
718 ['a', 'b', 'c']
719 IFS=x
720 ['a b c']
721 MYTEMP=foo
722 ['a', 'b', 'c']
723 MYTEMP=undef
724 ## END
725
726 #### shvar IFS
727 shopt --set oil:upgrade
728
729 proc myproc() {
730 echo "$IFS" | od -A n -t x1
731
732 local mylocal=x
733 shvar IFS=w {
734 echo inside IFS="$IFS"
735 echo mylocal="$mylocal" # I do NOT want a new scope!
736 }
737 echo "$IFS" | od -A n -t x1
738 }
739
740 myproc
741 ## STDOUT:
742 20 09 0a 0a
743 inside IFS=w
744 mylocal=x
745 20 09 0a 0a
746 ## END
747
748 #### shvar_get()
749 shopt --set parse_proc
750
751 s='xzx zxz'
752
753 proc myproc {
754 echo wrong IFS="$IFS" # NOT what's used
755 echo shvar IFS=$[shvar_get('IFS')] # what IS used: dynamic scope
756 argv.py $s
757 }
758
759 IFS=x
760 IFS=z myproc
761 ## STDOUT:
762 wrong IFS=x
763 shvar IFS=z
764 ['x', 'x ', 'x']
765 ## END