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 param
326 shopt --set parse_proc
327
328 proc set-it(:s, val) {
329 #pp cell __s
330 setref s = "foo-$val"
331 }
332
333 proc demo {
334 # TODO: Our bad implementation causes a recursion problem here because we use
335 # the name 's'.
336 if true; then
337 var s = 'abc'
338 set-it :s SS
339 echo $s
340 fi
341
342 var t = 'def'
343 set-it :t TT
344 echo $t
345 }
346
347 demo
348
349 ## STDOUT:
350 foo-SS
351 foo-TT
352 ## END
353
354 #### setref with conflicting variable name
355 shopt --set parse_proc
356
357 proc set-it(:s, val) {
358 #pp cell __s
359
360 # This breaks it!
361 var oops = ''
362 setref s = "foo-$val"
363 }
364
365 proc demo {
366 var oops = ''
367 set-it :oops zz
368 echo oops=$oops
369 }
370
371 demo
372
373 ## STDOUT:
374 oops=foo-zz
375 ## END
376
377
378 #### setref of regular param is a fatal error
379 shopt --set parse_proc
380
381 proc set-it(:s, val) {
382 setref val = 'oops'
383 }
384
385 var s = 'abc'
386 set-it :s SS
387 echo $s
388
389 ## status: 1
390 ## STDOUT:
391 ## END
392
393 #### setref equivalent without pgen2 syntax, using open proc
394 shopt --set parse_proc
395
396 # This is kind of what we compile to. Ref params get an extra __ prefix? then
397 # that means you can't really READ them either? I think that's OK.
398
399 # At call time, param binding time:
400 # If the PARAM has a colon prefix:
401 # Assert that the ARG has a colon prefix. Don't remove it.
402 # Set the cell.nameref flag.
403 #
404 # At Setref time:
405 # Check that it's cell.nameref.
406 # Add extra : to lvalue.{Named,Indexed,Keyed} and perform it.
407 #
408 # The __ avoids the nameref cycle check.
409 # And we probably disallow reading from the ref. That's OK. The caller can
410 # pass it in as a regular value!
411
412 proc set-it {
413 local -n __s=$1 # nameref flag needed with setref
414 local val=$2
415
416 # well this part requires pgen2
417 setref s = "foo-$val"
418 }
419
420 var s = 'abc'
421 var t = 'def'
422 set-it s SS
423 set-it t TT # no colon here
424 echo $s
425 echo $t
426
427 ## STDOUT:
428 foo-SS
429 foo-TT
430 ## END
431
432 #### setref a, b = 'one', 'two'
433 shopt --set parse_proc
434
435 proc p(x, :a, :b) {
436 setref a, b = "${x}1", "${x}2"
437 }
438
439 p foo :c :d
440 echo c=$c d=$d
441 ## STDOUT:
442 c=foo1 d=foo2
443 ## END
444
445 #### setref a[i]
446
447 # You can do this in bash/mksh. See nameref!
448
449 proc set1(:a, item) {
450 setref a[1] = item
451 }
452
453 var a = %(one two three)
454 var myarray = %(a b c)
455
456 set1 :a zzz
457 set1 :myarray z
458
459 shopt --set oil:upgrade
460 #write -- @a
461 write -- @myarray
462
463 ## STDOUT:
464 a
465 z
466 c
467 ## END
468
469 #### unset inside proc uses local scope
470 shopt --set parse_brace
471 shopt --set parse_proc
472
473 f() {
474 unset x
475 }
476
477 proc p() {
478 unset x
479 }
480
481 proc p2() {
482 shopt --set dynamic_scope { # turn it back on
483 unset x
484 }
485 }
486
487 x=foo
488 f
489 echo f x=$x
490
491 x=bar
492 p
493 echo p x=$x
494
495 x=spam
496 p2
497 echo p2 x=$x
498
499 ## STDOUT:
500 f x=
501 p x=bar
502 p2 x=
503 ## END
504
505 #### unset composes when you turn on dynamic scope
506 shopt -s oil:all
507
508 proc unset-two {
509 shopt --set dynamic_scope {
510 unset $1
511 unset $2
512 }
513 }
514
515 demo() {
516 local x=X
517 local y=Y
518
519 echo "x=$x y=$y"
520
521 unset-two x y
522
523 shopt --unset nounset
524 echo "x=$x y=$y"
525 }
526
527 demo
528 ## STDOUT:
529 x=X y=Y
530 x= y=
531 ## END
532
533 #### Temp Bindings
534 shopt --set parse_proc
535
536 myfunc() {
537 echo myfunc FOO=$FOO
538 }
539 proc myproc() {
540 echo myproc FOO=$FOO
541 }
542
543 FOO=bar myfunc
544 FOO=bar myproc
545 FOO=bar echo inline FOO=$FOO
546 FOO=bar printenv.py FOO
547
548 ## STDOUT:
549 myfunc FOO=bar
550 myproc FOO=
551 inline FOO=
552 bar
553 ## END
554
555 #### cd blocks don't introduce new scopes
556 shopt --set oil:upgrade
557
558 var x = 42
559 cd / {
560 var y, z = 0, 1
561 echo $x $y $z
562 setvar y = 43
563 }
564 setvar z = 44
565 echo $x $y $z
566
567 ## STDOUT:
568 42 0 1
569 42 43 44
570 ## END
571
572 #### IFS=: myproc exports when it doesn't need to
573 shopt --set parse_proc
574 shopt --set parse_brace
575
576 s='xzx zxz'
577
578 myfunc() {
579 echo myfunc IFS="$IFS"
580 argv.py $s
581 }
582
583 proc myproc() {
584 echo myproc IFS="$IFS"
585 argv.py $s
586 }
587
588 IFS=: $REPO_ROOT/spec/bin/printenv.py IFS
589
590 # default value
591 echo "$IFS" | od -A n -t x1
592
593 IFS=' z'
594 echo IFS="$IFS"
595
596 IFS=' x' myfunc
597
598 # Problem: $IFS in procs only finds GLOBAL values. But when actually
599 # splitting, $IFS is a 'shvar' which respects DYNAMIC scope.
600 # - TODO: shvar_get('IFS')
601
602 IFS=' x' myproc
603
604 # Oil solution to the problem
605 shvar IFS=' x' {
606 myproc
607 }
608
609 ## STDOUT:
610 :
611 20 09 0a 0a
612 IFS= z
613 myfunc IFS= x
614 ['', 'z', 'z', 'z']
615 myproc IFS= z
616 ['', 'z', 'z', 'z']
617 myproc IFS= x
618 ['', 'z', 'z', 'z']
619 ## END
620
621 #### shvar usage
622 shopt --set oil:upgrade
623 shopt --unset errexit
624
625 # no block
626 shvar
627 echo status=$?
628
629 shvar { # no arg
630 true
631 }
632 echo status=$?
633
634 shvar foo { # should be name=value
635 true
636 }
637 echo status=$?
638 ## STDOUT:
639 status=2
640 status=2
641 status=2
642 ## END
643
644 #### shvar global
645 shopt --set oil:upgrade
646 shopt --unset nounset
647
648 echo _ESCAPER=$_ESCAPER
649 echo _DIALECT=$_DIALECT
650
651 shvar _ESCAPER=html _DIALECT=ninja {
652 echo block _ESCAPER=$_ESCAPER
653 echo block _DIALECT=$_DIALECT
654 }
655
656 echo _ESCAPER=$_ESCAPER
657 echo _DIALECT=$_DIALECT
658
659 # Now set them
660 _ESCAPER=foo
661 _DIALECT=bar
662
663 echo ___
664
665 echo _ESCAPER=$_ESCAPER
666 echo _DIALECT=$_DIALECT
667
668 shvar _ESCAPER=html _DIALECT=ninja {
669 echo block _ESCAPER=$_ESCAPER
670 echo block _DIALECT=$_DIALECT
671
672 shvar _ESCAPER=nested {
673 echo nested _ESCAPER=$_ESCAPER
674 echo nested _DIALECT=$_DIALECT
675 }
676 }
677
678 echo _ESCAPER=$_ESCAPER
679 echo _DIALECT=$_DIALECT
680
681 ## STDOUT:
682 _ESCAPER=
683 _DIALECT=
684 block _ESCAPER=html
685 block _DIALECT=ninja
686 _ESCAPER=
687 _DIALECT=
688 ___
689 _ESCAPER=foo
690 _DIALECT=bar
691 block _ESCAPER=html
692 block _DIALECT=ninja
693 nested _ESCAPER=nested
694 nested _DIALECT=ninja
695 _ESCAPER=foo
696 _DIALECT=bar
697 ## END
698
699 #### shvar local
700 shopt --set oil:upgrade # blocks
701 shopt --unset simple_word_eval # test word splitting
702
703 proc foo {
704 shvar IFS=x MYTEMP=foo {
705 echo IFS="$IFS"
706 argv.py $s
707 echo MYTEMP=${MYTEMP:-undef}
708 }
709 }
710 var s = 'a b c'
711 argv.py $s
712 foo
713 argv.py $s
714 echo MYTEMP=${MYTEMP:-undef}
715 ## STDOUT:
716 ['a', 'b', 'c']
717 IFS=x
718 ['a b c']
719 MYTEMP=foo
720 ['a', 'b', 'c']
721 MYTEMP=undef
722 ## END
723
724 #### shvar IFS
725 shopt --set oil:upgrade
726
727 proc myproc() {
728 echo "$IFS" | od -A n -t x1
729
730 local mylocal=x
731 shvar IFS=w {
732 echo inside IFS="$IFS"
733 echo mylocal="$mylocal" # I do NOT want a new scope!
734 }
735 echo "$IFS" | od -A n -t x1
736 }
737
738 myproc
739 ## STDOUT:
740 20 09 0a 0a
741 inside IFS=w
742 mylocal=x
743 20 09 0a 0a
744 ## END
745
746 #### shvar_get()
747 shopt --set parse_proc
748
749 s='xzx zxz'
750
751 proc myproc {
752 echo wrong IFS="$IFS" # NOT what's used
753 echo shvar IFS=$shvar_get('IFS') # what IS used: dynamic scope
754 argv.py $s
755 }
756
757 IFS=x
758 IFS=z myproc
759 ## STDOUT:
760 wrong IFS=x
761 shvar IFS=z
762 ['x', 'x ', 'x']
763 ## END