1
2 #### command sub $(echo hi)
3 var x = $(echo hi)
4 var y = $(echo '')
5 # Make sure we can operate on these values
6 echo x=${x:-default} y=${y:-default}
7 ## STDOUT:
8 x=hi y=default
9 ## END
10
11 #### shell array %(a 'b c')
12 shopt -s parse_at
13 var x = %(a 'b c')
14 var empty = %()
15 argv.py / @x @empty /
16
17 ## STDOUT:
18 ['/', 'a', 'b c', '/']
19 ## END
20
21 #### empty array and simple_word_eval (regression test)
22 shopt -s parse_at simple_word_eval
23 var empty = :| |
24 echo len=$[len(empty)]
25 argv.py / @empty /
26
27 ## STDOUT:
28 len=0
29 ['/', '/']
30 ## END
31
32 #### Empty array and assignment builtin (regression)
33 # Bug happens with shell arrays too
34 empty=()
35 declare z=1 "${empty[@]}"
36 echo z=$z
37 ## STDOUT:
38 z=1
39 ## END
40
41 #### Shell arrays support tilde detection, static globbing, brace detection
42 shopt -s parse_at simple_word_eval
43 touch {foo,bar}.py
44 HOME=/home/bob
45 no_dynamic_glob='*.py'
46
47 var x = %(~/src *.py {andy,bob}@example.com $no_dynamic_glob)
48 argv.py @x
49 ## STDOUT:
50 ['/home/bob/src', 'bar.py', 'foo.py', 'andy@example.com', 'bob@example.com', '*.py']
51 ## END
52
53 #### Set $HOME using 'var' (i.e. Oil string var in word evaluator)
54 var HOME = "foo"
55 echo $HOME
56 echo ~
57 ## STDOUT:
58 foo
59 foo
60 ## END
61
62 #### Use shell var in Oil expression
63 x='abc'
64 var length = len(x) # length in BYTES, unlike ${#x}
65 echo $length
66 ## STDOUT:
67 3
68 ## END
69
70 #### Length doesn't apply to BashArray
71 x=(a b c)
72 x[10]=A
73 x[20]=B
74
75 # shell style: length is 5
76 echo shell=${#x[@]}
77
78 # Length could be 20, but we may change the representation to Dict[int, str]
79 echo ysh=$[len(x)]
80
81 ## status: 3
82 ## STDOUT:
83 shell=5
84 ## END
85
86 #### $[len(x)] inside strings
87 var s = "abc"
88 echo -$[len(s)]-
89
90 # This already has a meaning ...
91 #echo "-$len(x)-"
92 #echo "-${len}(x)-"
93
94 ## STDOUT:
95 -3-
96 ## END
97
98 #### Func with multiple args in multiple contexts
99 shopt --set ysh:upgrade # needed for math.ysh
100
101 source $LIB_YSH/math.ysh
102
103 var x = max(1+2, 3+4)
104 echo $x $[max(1+2, 3+4)]
105
106 ## STDOUT:
107 7 7
108 ## END
109
110
111 #### Trailing Comma in Param list
112 shopt --set ysh:upgrade # needed for math.ysh
113
114 source $LIB_YSH/math.ysh
115
116 var x = max(1+2, 3+4,)
117 echo $x $[max(1+2, 3+4,)]
118
119 ## STDOUT:
120 7 7
121 ## END
122
123 #### nested expr contexts
124 var s = "123"
125
126 # lex_mode_e.ShCommand -> Expr -> ShCommand -> Expr
127 var x = $(echo $'len\n' $[len(s)])
128 echo $x
129 ## STDOUT:
130 len 3
131 ## END
132
133
134 # TODO:
135 # - test keyword args
136 # - test splatting *args, **kwargs
137 # - Multiline parsing
138 #
139 # var x = max(
140 # 1+2,
141 # 3+4,
142 # )
143 # echo $x $max(
144 # 1+2,
145 # 3+4,
146 # )
147
148 #### YSH var used with shell arithmetic
149 var w = "3"
150 echo lt=$(( w < 4 ))
151 echo gt=$(( w > 4 ))
152
153 var z = 3
154 echo lt=$(( z < 4 ))
155 echo gt=$(( z > 4 ))
156 ## STDOUT:
157 lt=1
158 gt=0
159 lt=1
160 gt=0
161 ## END
162
163 #### Parse { var x = 42 }
164 shopt -s oil:upgrade
165 g() { var x = 42 }
166
167 var x = 1
168 f() { var x = 42; setvar x = 43 }
169 f
170 echo x=$x
171 ## STDOUT:
172 x=1
173 ## END
174
175 #### double quoted
176 var foo = "bar"
177 var x = "-$foo-${foo}-${undef:-default}-"
178 echo $x
179 ## STDOUT:
180 -bar-bar-default-
181 ## END
182
183 #### double quoted respects strict_array
184 shopt -s strict:all
185 declare -a a=(one two three)
186 var x = "-${a[@]}-"
187 echo $x
188 ## status: 1
189 ## stdout-json: ""
190
191 #### simple var sub $name $0 $1 $? etc.
192 ( exit 42 )
193 var status = $?
194 echo status=$status
195
196 set -- a b c
197 var one = $1
198 var two = $2
199 echo $one $two
200
201 var named = "$one" # equivalent to 'one'
202 echo named=$named
203
204 ## STDOUT:
205 status=42
206 a b
207 named=a
208 ## END
209
210 #### braced var sub ${x:-default}
211
212 # without double quotes
213
214 var b = ${foo:-default}
215 echo $b
216 var c = ${bar:-"-$b-"}
217 echo $c
218
219 var d = "${bar:-"-$c-"}" # another one
220 echo $d
221
222 ## STDOUT:
223 default
224 -default-
225 --default--
226 ## END
227
228 #### braced var sub respects strict_array
229 set -- a b c
230 var x = ${undef:-"$@"}
231 echo $x
232 shopt -s strict_array
233 setvar x = ${undef:-"$@"}
234 echo $x
235 ## status: 1
236 ## STDOUT:
237 a b c
238 ## END
239
240
241 #### null / true / false
242 shopt -s oil:upgrade
243 var n = null
244 if (n) {
245 echo yes
246 } else {
247 echo no
248 }
249 var t = true
250 if (t) {
251 echo yes
252 } else {
253 echo no
254 }
255 var f = false
256 if (f) {
257 echo yes
258 } else {
259 echo no
260 }
261 ## STDOUT:
262 no
263 yes
264 no
265 ## END
266
267 #### Integer literals
268 var d = 123
269 var b = 0b11
270 var o = 0o123
271 var h = 0xff
272 echo $d $b $o $h
273 ## STDOUT:
274 123 3 83 255
275 ## END
276
277 #### Integer literals with underscores
278 const dec = 65_536
279 const bin = 0b0001_0101
280 const oct = 0o001_755
281 const hex = 0x0001_000f
282
283 echo SHELL
284 echo $dec
285 echo $bin
286 echo $oct
287 echo $hex
288 const x = 1_1 + 0b1_1 + 0o1_1 + 0x1_1
289 echo sum $x
290
291 # This works under Python 3.6, but the continuous build has earlier versions
292 if false; then
293 echo ---
294 echo PYTHON
295
296 python3 -c '
297 print(65_536)
298 print(0b0001_0101)
299 print(0o001_755)
300 print(0x0001_000f)
301
302 # Weird syntax
303 print("sum", 1_1 + 0b1_1 + 0o1_1 + 0x1_1)
304 '
305 fi
306
307 ## STDOUT:
308 SHELL
309 65536
310 21
311 1005
312 65551
313 sum 40
314 ## END
315
316 #### Exponentiation with **
317 var x = 2**3
318 echo $x
319
320 var y = 2.0 ** 3.0 # NOT SUPPORTED
321 echo 'should not get here'
322
323 ## status: 3
324 ## STDOUT:
325 8
326 ## END
327
328 #### Float Division
329 pp line (5/2)
330 pp line (-5/2)
331 pp line (5/-2)
332 pp line (-5/-2)
333
334 echo ---
335
336 var x = 9
337 setvar x /= 2
338 pp line (x)
339
340 var x = -9
341 setvar x /= 2
342 pp line (x)
343
344 var x = 9
345 setvar x /= -2
346 pp line (x)
347
348 var x = -9
349 setvar x /= -2
350 pp line (x)
351
352
353 ## STDOUT:
354 (Float) 2.5
355 (Float) -2.5
356 (Float) -2.5
357 (Float) 2.5
358 ---
359 (Float) 4.5
360 (Float) -4.5
361 (Float) -4.5
362 (Float) 4.5
363 ## END
364
365 #### Integer Division (rounds toward zero)
366 pp line (5//2)
367 pp line (-5//2)
368 pp line (5//-2)
369 pp line (-5//-2)
370
371 echo ---
372
373 var x = 9
374 setvar x //= 2
375 pp line (x)
376
377 var x = -9
378 setvar x //= 2
379 pp line (x)
380
381 var x = 9
382 setvar x //= -2
383 pp line (x)
384
385 var x = -9
386 setvar x //= -2
387 pp line (x)
388
389 ## STDOUT:
390 (Int) 2
391 (Int) -2
392 (Int) -2
393 (Int) 2
394 ---
395 (Int) 4
396 (Int) -4
397 (Int) -4
398 (Int) 4
399 ## END
400
401 #### % operator is remainder
402 pp line ( 5 % 3)
403 pp line (-5 % 3)
404
405 # negative divisor illegal (tested in test/ysh-runtime-errors.sh)
406 #pp line ( 5 % -3)
407 #pp line (-5 % -3)
408
409 var z = 10
410 setvar z %= 3
411 pp line (z)
412
413 var z = -10
414 setvar z %= 3
415 pp line (z)
416
417 ## STDOUT:
418 (Int) 2
419 (Int) -2
420 (Int) 1
421 (Int) -1
422 ## END
423
424 #### Bitwise logical
425 var a = 0b0101 & 0b0011
426 echo $a
427 var b = 0b0101 | 0b0011
428 echo $b
429 var c = 0b0101 ^ 0b0011
430 echo $c
431 var d = ~b
432 echo $d
433 ## STDOUT:
434 1
435 7
436 6
437 -8
438 ## END
439
440 #### Shift operators
441 var a = 1 << 4
442 echo $a
443 var b = 16 >> 4
444 echo $b
445 ## STDOUT:
446 16
447 1
448 ## END
449
450 #### multiline strings, list, tuple syntax for list, etc.
451 var dq = "
452 dq
453 2
454 "
455 echo dq=$[len(dq)]
456
457 var sq = '
458 sq
459 2
460 '
461 echo sq=$[len(sq)]
462
463 var mylist = [
464 1,
465 2,
466 3,
467 ]
468 echo mylist=$[len(mylist)]
469
470 var mytuple = (1,
471 2, 3)
472 echo mytuple=$[len(mytuple)]
473
474 ## STDOUT:
475 dq=6
476 sq=6
477 mylist=3
478 mytuple=3
479 ## END
480
481 #### multiline dict
482
483 # Note: a pair has to be all on one line. We could relax that but there isn't
484 # a strong reason to now.
485
486 var mydict = { a:1,
487 b: 2,
488 }
489 echo mydict=$[len(mydict)]
490 ## STDOUT:
491 mydict=2
492 ## END
493
494 #### multiline array and command sub (only here docs disallowed)
495 var array = %(
496 one
497 two
498 three
499 )
500 echo array=$[len(array)]
501
502 var comsub = $(
503 echo hi
504 echo bye
505 )
506 echo comsub=$[len(comsub)]
507
508 ## STDOUT:
509 array=3
510 comsub=6
511 ## END
512
513 #### obj->method()
514 var s = 'hi'
515
516 # TODO: This does a bound method thing we probably don't want
517 var s2 = s=>upper()
518 echo $s2
519 ## STDOUT:
520 HI
521 ## END
522
523 #### obj->method does NOT give you a bound method
524 var s = 'hi'
525 var method = s->upper
526 echo $method
527 ## status: 3
528 ## stdout-json: ""
529
530 #### d.key
531 var d = {name: 'andy'}
532 var x = d.name
533 echo $x
534 ## STDOUT:
535 andy
536 ## END
537
538 #### a ++ b for string/list concatenation
539 shopt -s parse_brace
540
541 var i = 'abc'
542 var j = 'de'
543 var k = i ++ j
544 echo string $k
545
546
547 var a = [1, 2]
548 var b = [3]
549 var c = a ++ b
550 echo list len=$[len(c)]
551
552 echo ---
553
554 try {
555 = 'ab' ++ 3
556 }
557 echo Str Int $_status
558
559 try {
560 = [1, 2] ++ 3
561 }
562 echo List Int $_status
563
564 try {
565 = 3 ++ 'ab'
566 }
567 echo Int Str $_status
568
569 ## STDOUT:
570 string abcde
571 list len=3
572 ---
573 Str Int 3
574 List Int 3
575 Int Str 3
576 ## END
577
578 #### s ~~ glob and s !~~ glob
579 shopt -s oil:all
580
581 if ('foo.py' ~~ '*.py') {
582 echo yes
583 }
584 if ('foo.py' !~~ '*.sh') {
585 echo no
586 }
587 ## STDOUT:
588 yes
589 no
590 ## END
591
592 #### Type Errors
593 shopt --set parse_brace
594
595 # TODO: It might be nice to get a message
596 try {
597 var x = {} + []
598 }
599 echo $_status
600
601 try {
602 setvar x = {} + 3
603 }
604 echo $_status
605
606 try {
607 = 'foo' ++ 3
608 }
609 echo $_status
610
611 try {
612 = 'foo' ++ 3
613 }
614 echo $_status
615
616 ## STDOUT:
617 3
618 3
619 3
620 3
621 ## END
622
623
624 #### can't use ++ on integers
625 var x = 12 ++ 3
626 echo $x
627 ## status: 3
628 ## STDOUT:
629 ## END
630
631 #### can't do mystr ++ mylist
632 = ["s"] + "t"
633 ## status: 3
634 ## STDOUT:
635 ## END
636
637
638 #### expression literals
639 var e = ^[1 + 2]
640
641 echo type=$[type(e)]
642 echo $[evalExpr(e)]
643
644 var e = ^[2 < 1]
645 echo $[evalExpr(e)]
646
647 var x = 42
648 var e = ^[42 === x and true]
649 echo $[evalExpr(e)]
650
651 var mylist = ^[3, 4]
652 pp line (evalExpr(mylist))
653
654 ## STDOUT:
655 type=Expr
656 3
657 false
658 true
659 (List) [3,4]
660 ## END
661
662 #### No list comprehension in ^[]
663
664 var mylist = ^[x for x in y]
665 pp line (evalExpr(mylist))
666
667 ## status: 2
668 ## STDOUT:
669 ## END
670
671
672 #### expression literals, evaluation failure
673 var e = ^[1 / 0]
674 call evalExpr(e)
675 ## status: 3
676 ## STDOUT:
677 ## END
678
679 #### expression literals, lazy evaluation
680 var x = 0
681 var e = ^[x]
682
683 setvar x = 1
684 echo result=$[evalExpr(e)]
685 ## STDOUT:
686 result=1
687 ## END
688
689 #### expression literals, sugar for strings
690 var x = 0
691 var e = ^"x is $x"
692
693 setvar x = 1
694 echo result=$[evalExpr(e)]
695 ## STDOUT:
696 result=x is 1
697 ## END