1 ## oils_failures_allowed: 0
2
3 #### Open proc (any number of args)
4 shopt --set parse_proc
5
6 proc f {
7 var x = 42
8 return $x
9 }
10 # this gets called with 3 args then?
11 f a b c
12 echo status=$?
13 ## STDOUT:
14 status=42
15 ## END
16
17 #### Closed proc with no args, passed too many
18 shopt --set parse_proc
19
20 proc f() {
21 return 42
22 }
23 f
24 echo status=$?
25
26 f a b # status 2
27
28 ## status: 3
29 ## STDOUT:
30 status=42
31 ## END
32
33 #### Open proc has ARGV
34 shopt -s ysh:all
35 proc foo {
36 echo ARGV @ARGV
37 # do we care about this? I think we want to syntactically remove it from YSH
38 # but it can still be used for legacy
39 echo dollar-at "$@"
40 }
41 builtin set -- a b c
42 foo x y z
43 ## STDOUT:
44 ARGV x y z
45 dollar-at a b c
46 ## END
47
48 #### Closed proc has empty "$@" or ARGV
49 shopt -s ysh:all
50
51 proc foo(d, e, f) {
52 write params $d $e $f
53 argv.py dollar-at "$@"
54 argv.py ARGV @ARGV
55 }
56 builtin set -- a b c
57 foo x y z
58 ## STDOUT:
59 params
60 x
61 y
62 z
63 ['dollar-at', 'a', 'b', 'c']
64 ['ARGV']
65 ## END
66
67 #### Proc with default args
68 shopt --set parse_proc
69
70 proc f(x='foo') {
71 echo x=$x
72 }
73 f
74 ## STDOUT:
75 x=foo
76 ## END
77
78 #### Proc with word params
79 shopt --set parse_proc
80
81 # doesn't require ysh:all
82 proc f(x, y, z) {
83 echo $x $y $z
84 var ret = 42
85 return $ret
86 }
87 # this gets called with 3 args then?
88 f a b c
89 echo status=$?
90 ## STDOUT:
91 a b c
92 status=42
93 ## END
94
95 #### Proc with ... "rest" word params
96
97 # TODO: opts goes with this
98 # var opt = grep_opts.parse(ARGV)
99 #
100 # func(**opt) # Assumes keyword args match?
101 # parse :grep_opts :opt @ARGV
102
103 shopt -s ysh:all
104
105 proc f(...names) {
106 write names: @names
107 }
108 # this gets called with 3 args then?
109 f a b c
110 echo status=$?
111 ## STDOUT:
112 names:
113 a
114 b
115 c
116 status=0
117 ## END
118
119 #### word rest params 2
120 shopt --set ysh:all
121
122 proc f(first, ...rest) { # @ means "the rest of the arguments"
123 write --sep ' ' -- $first
124 write --sep ' ' -- @rest # @ means "splice this array"
125 }
126 f a b c
127 ## STDOUT:
128 a
129 b c
130 ## END
131
132 #### proc with typed args
133 shopt --set ysh:upgrade
134
135 # TODO: duplicate param names aren't allowed
136 proc p (a; mylist, mydict; opt Int = 42) {
137 pp test_ (a)
138 pp test_ (mylist)
139 pp test_ (mydict)
140 #pp test_ (opt)
141 }
142
143 p WORD ([1,2,3], {name: 'bob'})
144
145 echo ---
146
147 p x (:| a b |, {bob: 42}, a = 5)
148
149 ## STDOUT:
150 (Str) "WORD"
151 (List) [1,2,3]
152 (Dict) {"name":"bob"}
153 ---
154 (Str) "x"
155 (List) ["a","b"]
156 (Dict) {"bob":42}
157 ## END
158
159 #### Proc name-with-hyphen
160 shopt --set parse_proc parse_at
161
162 proc name-with-hyphen {
163 echo @ARGV
164 }
165 name-with-hyphen x y z
166 ## STDOUT:
167 x y z
168 ## END
169
170 #### Proc with block arg
171 shopt --set ysh:upgrade
172
173 # TODO: Test more of this
174 proc f(x, y ; ; ; block) {
175 echo f word $x $y
176
177 if (block) {
178 eval (block)
179 }
180 }
181 f a b { echo FFF }
182
183 # With varargs and block
184 shopt --set parse_proc
185
186 proc g(x, y, ...rest ; ; ; block) {
187 echo g word $x $y
188 echo g rest @rest
189
190 if (block) {
191 eval (block)
192 }
193 }
194 g a b c d {
195 echo GGG
196 }
197
198 ## STDOUT:
199 f word a b
200 FFF
201 g word a b
202 g rest c d
203 GGG
204 ## END
205
206 #### proc returning wrong type
207 shopt --set parse_proc
208
209 # this should print an error message
210 proc f {
211 var a = %(one two)
212 return $a
213 }
214 f
215 ## status: 3
216 ## STDOUT:
217 ## END
218
219 #### proc returning invalid string
220 shopt --set parse_proc
221
222 # this should print an error message
223 proc f {
224 var s = 'not an integer status'
225 return $s
226 }
227 f
228 ## status: 1
229 ## STDOUT:
230 ## END
231
232 #### 'return' doesn't accept expressions
233 proc p {
234 return 1 + 2
235 }
236 p
237 ## status: 2
238 ## STDOUT:
239 ## END
240
241 #### declare -F prints procs and shell-funcs
242 shopt --set parse_proc
243
244 myfunc() {
245 echo hi
246 }
247
248 proc myproc {
249 echo hi
250 }
251
252 declare -F
253
254 ## status: 0
255 ## STDOUT:
256 declare -f myfunc
257 declare -f myproc
258 ## END
259
260 #### procs are in same namespace as variables
261 shopt --set parse_proc
262
263 proc myproc {
264 echo hi
265 }
266
267 echo "myproc is a $[type(myproc)]"
268
269 ## STDOUT:
270 myproc is a Proc
271 ## END
272
273 #### Nested proc is disallowed at parse time
274 shopt --set parse_proc
275
276 # NOTE: we can disallow this in Oil statically ...
277 proc f {
278 proc g {
279 echo 'G'
280 }
281 g
282 }
283 f
284 g
285 ## status: 2
286 ## stdout-json: ""
287
288 #### Procs defined inside compound statements (with redefine_proc)
289
290 shopt --set ysh:upgrade
291 shopt --set redefine_proc_func
292
293 for x in 1 2 {
294 proc p {
295 echo 'loop'
296 }
297 }
298 p
299
300 {
301 proc p {
302 echo 'brace'
303 }
304 }
305 p
306
307 ## STDOUT:
308 loop
309 brace
310 ## END
311
312 #### Block can be passed literally, or as expression in third arg group
313 shopt --set ysh:upgrade
314
315 proc p ( ; ; ; block) {
316 eval (block)
317 }
318
319 p { echo literal }
320
321 var block = ^(echo expression)
322 p (; ; block)
323
324 ## STDOUT:
325 literal
326 expression
327 ## END
328
329 #### Pass through all 4 kinds of args
330
331 shopt --set ysh:upgrade
332
333 proc p2 (...words; ...typed; ...named; block) {
334 pp test_ (words)
335 pp test_ (typed)
336 pp test_ (named)
337 #pp test_ (block)
338 # To avoid <Block 0x??> - could change pp test_
339 echo $[type(block)]
340 }
341
342 proc p1 (...words; ...typed; ...named; block) {
343 p2 @words (...typed; ...named; block)
344 }
345
346 p2 a b ('c', 'd', n=99) {
347 echo literal
348 }
349 echo
350
351 # Same thing
352 var block = ^(echo expression)
353
354 # Note: you need the second explicit ;
355
356 p2 a b ('c', 'd'; n=99; block)
357 echo
358
359 # what happens when you do this?
360 p2 a b ('c', 'd'; n=99; block) {
361 echo duplicate
362 }
363
364 ## status: 1
365 ## STDOUT:
366 (List) ["a","b"]
367 (List) ["c","d"]
368 (Dict) {"n":99}
369 Block
370
371 (List) ["a","b"]
372 (List) ["c","d"]
373 (Dict) {"n":99}
374 Command
375
376 ## END
377
378 #### Global and local ARGV, like "$@"
379 shopt -s parse_at
380 argv.py "$@"
381 argv.py @ARGV
382 #argv.py "${ARGV[@]}" # not useful, but it works!
383
384 set -- 'a b' c
385 argv.py "$@"
386 argv.py @ARGV # separate from the argv stack
387
388 f() {
389 argv.py "$@"
390 argv.py @ARGV # separate from the argv stack
391 }
392 f 1 '2 3'
393 ## STDOUT:
394 []
395 []
396 ['a b', 'c']
397 []
398 ['1', '2 3']
399 []
400 ## END
401
402
403 #### Mutating global ARGV
404
405 $SH -c '
406 shopt -s ysh:upgrade
407
408 argv.py global @ARGV
409
410 # should not be ignored
411 call ARGV->append("GG")
412
413 argv.py global @ARGV
414 '
415 ## STDOUT:
416 ['global']
417 ['global', 'GG']
418 ## END
419
420 #### Mutating local ARGV
421
422 $SH -c '
423 shopt -s ysh:upgrade
424
425 argv.py global @ARGV
426
427 proc p {
428 argv.py @ARGV
429 call ARGV->append("LL")
430 argv.py @ARGV
431 }
432
433 p local @ARGV
434
435 argv.py global @ARGV
436
437 ' dummy0 'a b' c
438
439 ## STDOUT:
440 ['global', 'a b', 'c']
441 ['local', 'a b', 'c']
442 ['local', 'a b', 'c', 'LL']
443 ['global', 'a b', 'c']
444 ## END
445
446
447 #### typed proc allows all kinds of args
448 shopt -s ysh:upgrade
449
450 typed proc p (w; t; n; block) {
451 pp test_ (w)
452 pp test_ (t)
453 pp test_ (n)
454 echo $[type(block)]
455 }
456
457 p word (42, n=99) {
458 echo block
459 }
460
461
462 ## STDOUT:
463 (Str) "word"
464 (Int) 42
465 (Int) 99
466 Block
467 ## END
468
469 #### can unset procs without -f
470 shopt -s ysh:upgrade
471
472 proc foo() {
473 echo bar
474 }
475
476 try { foo }
477 echo status=$[_error.code]
478
479 # TODO: should we abandon declare -F in favour of `pp proc`?
480 declare -F
481 unset foo
482 declare -F
483
484 try { foo }
485 echo status=$[_error.code]
486
487 ## STDOUT:
488 bar
489 status=0
490 declare -f foo
491 status=127
492 ## END
493
494 #### procs shadow sh-funcs
495 shopt -s ysh:upgrade redefine_proc_func
496
497 f() {
498 echo sh-func
499 }
500
501 proc f {
502 echo proc
503 }
504
505 f
506 ## STDOUT:
507 proc
508 ## END
509
510 #### first word skips non-proc variables
511 shopt -s ysh:upgrade
512
513 grep() {
514 echo 'sh-func grep'
515 }
516
517 var grep = 'variable grep'
518
519 grep
520
521 # We first find `var grep`, but it's a Str not a Proc, so we skip it and then
522 # find `function grep`.
523
524 ## STDOUT:
525 sh-func grep
526 ## END