1 ## oils_failures_allowed: 1
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 #### setref equivalent without pgen2 syntax, using open proc
329 shopt --set parse_proc
330
331 # This is kind of what we compile to. Ref params get an extra __ prefix? then
332 # that means you can't really READ them either? I think that's OK.
333
334 # At call time, param binding time:
335 # If the PARAM has a colon prefix:
336 # Assert that the ARG has a colon prefix. Don't remove it.
337 # Set the cell.nameref flag.
338 #
339 # At Setref time:
340 # Check that it's cell.nameref.
341 # Add extra : to lvalue.{Named,Indexed,Keyed} and perform it.
342 #
343 # The __ avoids the nameref cycle check.
344 # And we probably disallow reading from the ref. That's OK. The caller can
345 # pass it in as a regular value!
346
347 proc set-it {
348 local -n __s=$1 # nameref flag needed with setref
349 local val=$2
350
351 # well this part requires pgen2
352 setref s = "foo-$val"
353 }
354
355 var s = 'abc'
356 var t = 'def'
357 set-it s SS
358 set-it t TT # no colon here
359 echo $s
360 echo $t
361
362 ## STDOUT:
363 foo-SS
364 foo-TT
365 ## END
366
367 #### unset inside proc uses local scope
368 shopt --set parse_brace
369 shopt --set parse_proc
370
371 f() {
372 unset x
373 }
374
375 proc p() {
376 unset x
377 }
378
379 proc p2() {
380 shopt --set dynamic_scope { # turn it back on
381 unset x
382 }
383 }
384
385 x=foo
386 f
387 echo f x=$x
388
389 x=bar
390 p
391 echo p x=$x
392
393 x=spam
394 p2
395 echo p2 x=$x
396
397 ## STDOUT:
398 f x=
399 p x=bar
400 p2 x=
401 ## END
402
403 #### unset composes when you turn on dynamic scope
404 shopt -s oil:all
405
406 proc unset-two {
407 shopt --set dynamic_scope {
408 unset $1
409 unset $2
410 }
411 }
412
413 demo() {
414 local x=X
415 local y=Y
416
417 echo "x=$x y=$y"
418
419 unset-two x y
420
421 shopt --unset nounset
422 echo "x=$x y=$y"
423 }
424
425 demo
426 ## STDOUT:
427 x=X y=Y
428 x= y=
429 ## END
430
431 #### Temp Bindings
432 shopt --set parse_proc
433
434 myfunc() {
435 echo myfunc FOO=$FOO
436 }
437 proc myproc() {
438 echo myproc FOO=$FOO
439 }
440
441 FOO=bar myfunc
442 FOO=bar myproc
443 FOO=bar echo inline FOO=$FOO
444 FOO=bar printenv.py FOO
445
446 ## STDOUT:
447 myfunc FOO=bar
448 myproc FOO=
449 inline FOO=
450 bar
451 ## END
452
453 #### cd blocks don't introduce new scopes
454 shopt --set oil:upgrade
455
456 var x = 42
457 cd / {
458 var y = 0
459 var z = 1
460 echo $x $y $z
461 setvar y = 43
462 }
463 setvar z = 44
464 echo $x $y $z
465
466 ## STDOUT:
467 42 0 1
468 42 43 44
469 ## END
470
471 #### IFS=: myproc exports when it doesn't need to
472 shopt --set parse_proc
473 shopt --set parse_brace
474
475 s='xzx zxz'
476
477 myfunc() {
478 echo myfunc IFS="$IFS"
479 argv.py $s
480 }
481
482 proc myproc() {
483 echo myproc IFS="$IFS"
484 argv.py $s
485 }
486
487 IFS=: $REPO_ROOT/spec/bin/printenv.py IFS
488
489 # default value
490 echo "$IFS" | od -A n -t x1
491
492 IFS=' z'
493 echo IFS="$IFS"
494
495 IFS=' x' myfunc
496
497 # Problem: $IFS in procs only finds GLOBAL values. But when actually
498 # splitting, $IFS is a 'shvar' which respects DYNAMIC scope.
499 # Use shvarGet('IFS') instead
500
501 IFS=' x' myproc
502
503 # Oil solution to the problem
504 shvar IFS=' x' {
505 myproc
506 }
507
508 ## STDOUT:
509 :
510 20 09 0a 0a
511 IFS= z
512 myfunc IFS= x
513 ['', 'z', 'z', 'z']
514 myproc IFS= z
515 ['', 'z', 'z', 'z']
516 myproc IFS= x
517 ['', 'z', 'z', 'z']
518 ## END
519
520 #### shvar usage
521 shopt --set oil:upgrade
522 shopt --unset errexit
523
524 # no block
525 shvar
526 echo status=$?
527
528 shvar { # no arg
529 true
530 }
531 echo status=$?
532
533 shvar foo { # should be name=value
534 true
535 }
536 echo status=$?
537 ## STDOUT:
538 status=2
539 status=2
540 status=2
541 ## END
542
543 #### shvar global
544 shopt --set oil:upgrade
545 shopt --unset nounset
546
547 echo _ESCAPER=$_ESCAPER
548 echo _DIALECT=$_DIALECT
549
550 shvar _ESCAPER=html _DIALECT=ninja {
551 echo block _ESCAPER=$_ESCAPER
552 echo block _DIALECT=$_DIALECT
553 }
554
555 echo _ESCAPER=$_ESCAPER
556 echo _DIALECT=$_DIALECT
557
558 # Now set them
559 _ESCAPER=foo
560 _DIALECT=bar
561
562 echo ___
563
564 echo _ESCAPER=$_ESCAPER
565 echo _DIALECT=$_DIALECT
566
567 shvar _ESCAPER=html _DIALECT=ninja {
568 echo block _ESCAPER=$_ESCAPER
569 echo block _DIALECT=$_DIALECT
570
571 shvar _ESCAPER=nested {
572 echo nested _ESCAPER=$_ESCAPER
573 echo nested _DIALECT=$_DIALECT
574 }
575 }
576
577 echo _ESCAPER=$_ESCAPER
578 echo _DIALECT=$_DIALECT
579
580 ## STDOUT:
581 _ESCAPER=
582 _DIALECT=
583 block _ESCAPER=html
584 block _DIALECT=ninja
585 _ESCAPER=
586 _DIALECT=
587 ___
588 _ESCAPER=foo
589 _DIALECT=bar
590 block _ESCAPER=html
591 block _DIALECT=ninja
592 nested _ESCAPER=nested
593 nested _DIALECT=ninja
594 _ESCAPER=foo
595 _DIALECT=bar
596 ## END
597
598 #### shvar local
599 shopt --set oil:upgrade # blocks
600 shopt --unset simple_word_eval # test word splitting
601
602 proc foo {
603 shvar IFS=x MYTEMP=foo {
604 echo IFS="$IFS"
605 argv.py $s
606 echo MYTEMP=${MYTEMP:-undef}
607 }
608 }
609 var s = 'a b c'
610 argv.py $s
611 foo
612 argv.py $s
613 echo MYTEMP=${MYTEMP:-undef}
614 ## STDOUT:
615 ['a', 'b', 'c']
616 IFS=x
617 ['a b c']
618 MYTEMP=foo
619 ['a', 'b', 'c']
620 MYTEMP=undef
621 ## END
622
623 #### shvar IFS
624 shopt --set oil:upgrade
625
626 proc myproc() {
627 echo "$IFS" | od -A n -t x1
628
629 local mylocal=x
630 shvar IFS=w {
631 echo inside IFS="$IFS"
632 echo mylocal="$mylocal" # I do NOT want a new scope!
633 }
634 echo "$IFS" | od -A n -t x1
635 }
636
637 myproc
638 ## STDOUT:
639 20 09 0a 0a
640 inside IFS=w
641 mylocal=x
642 20 09 0a 0a
643 ## END
644
645 #### shvarGet()
646 shopt --set parse_proc
647
648 s='xzx zxz'
649
650 proc myproc {
651 echo wrong IFS="$IFS" # NOT what's used
652 echo shvar IFS=$[shvarGet('IFS')] # what IS used: dynamic scope
653 argv.py $s
654 }
655
656 IFS=x
657 IFS=z myproc
658 ## STDOUT:
659 wrong IFS=x
660 shvar IFS=z
661 ['x', 'x ', 'x']
662 ## END