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 #### Backslash char literal (is an integer)
317 const newline = \n
318 const backslash = \\
319 const sq = \'
320 const dq = \"
321 echo "$newline $backslash $sq $dq"
322 ## STDOUT:
323 10 92 39 34
324 ## END
325
326 #### \u{3bc} is char literal
327 shopt -s oil:all
328
329 var mu = \u{3bc}
330 if (mu === 0x3bc) { # this is the same!
331 echo 'yes'
332 }
333 echo "mu $mu"
334 ## STDOUT:
335 yes
336 mu 956
337 ## END
338
339 #### Exponentiation with **
340 var x = 2**3
341 echo $x
342
343 var y = 2.0 ** 3.0 # NOT SUPPORTED
344 echo 'should not get here'
345
346 ## status: 3
347 ## STDOUT:
348 8
349 ## END
350
351 #### Float Division
352 pp line (5/2)
353 pp line (-5/2)
354 pp line (5/-2)
355 pp line (-5/-2)
356
357 echo ---
358
359 var x = 9
360 setvar x /= 2
361 pp line (x)
362
363 var x = -9
364 setvar x /= 2
365 pp line (x)
366
367 var x = 9
368 setvar x /= -2
369 pp line (x)
370
371 var x = -9
372 setvar x /= -2
373 pp line (x)
374
375
376 ## STDOUT:
377 (Float) 2.5
378 (Float) -2.5
379 (Float) -2.5
380 (Float) 2.5
381 ---
382 (Float) 4.5
383 (Float) -4.5
384 (Float) -4.5
385 (Float) 4.5
386 ## END
387
388 #### Integer Division (rounds toward zero)
389 pp line (5//2)
390 pp line (-5//2)
391 pp line (5//-2)
392 pp line (-5//-2)
393
394 echo ---
395
396 var x = 9
397 setvar x //= 2
398 pp line (x)
399
400 var x = -9
401 setvar x //= 2
402 pp line (x)
403
404 var x = 9
405 setvar x //= -2
406 pp line (x)
407
408 var x = -9
409 setvar x //= -2
410 pp line (x)
411
412 ## STDOUT:
413 (Int) 2
414 (Int) -2
415 (Int) -2
416 (Int) 2
417 ---
418 (Int) 4
419 (Int) -4
420 (Int) -4
421 (Int) 4
422 ## END
423
424 #### % operator is remainder
425 pp line ( 5 % 3)
426 pp line (-5 % 3)
427
428 # negative divisor illegal (tested in test/ysh-runtime-errors.sh)
429 #pp line ( 5 % -3)
430 #pp line (-5 % -3)
431
432 var z = 10
433 setvar z %= 3
434 pp line (z)
435
436 var z = -10
437 setvar z %= 3
438 pp line (z)
439
440 ## STDOUT:
441 (Int) 2
442 (Int) -2
443 (Int) 1
444 (Int) -1
445 ## END
446
447 #### Bitwise logical
448 var a = 0b0101 & 0b0011
449 echo $a
450 var b = 0b0101 | 0b0011
451 echo $b
452 var c = 0b0101 ^ 0b0011
453 echo $c
454 var d = ~b
455 echo $d
456 ## STDOUT:
457 1
458 7
459 6
460 -8
461 ## END
462
463 #### Shift operators
464 var a = 1 << 4
465 echo $a
466 var b = 16 >> 4
467 echo $b
468 ## STDOUT:
469 16
470 1
471 ## END
472
473 #### multiline strings, list, tuple syntax for list, etc.
474 var dq = "
475 dq
476 2
477 "
478 echo dq=$[len(dq)]
479
480 var sq = '
481 sq
482 2
483 '
484 echo sq=$[len(sq)]
485
486 var mylist = [
487 1,
488 2,
489 3,
490 ]
491 echo mylist=$[len(mylist)]
492
493 var mytuple = (1,
494 2, 3)
495 echo mytuple=$[len(mytuple)]
496
497 ## STDOUT:
498 dq=6
499 sq=6
500 mylist=3
501 mytuple=3
502 ## END
503
504 #### multiline dict
505
506 # Note: a pair has to be all on one line. We could relax that but there isn't
507 # a strong reason to now.
508
509 var mydict = { a:1,
510 b: 2,
511 }
512 echo mydict=$[len(mydict)]
513 ## STDOUT:
514 mydict=2
515 ## END
516
517 #### multiline array and command sub (only here docs disallowed)
518 var array = %(
519 one
520 two
521 three
522 )
523 echo array=$[len(array)]
524
525 var comsub = $(
526 echo hi
527 echo bye
528 )
529 echo comsub=$[len(comsub)]
530
531 ## STDOUT:
532 array=3
533 comsub=6
534 ## END
535
536 #### obj->method()
537 var s = 'hi'
538
539 # TODO: This does a bound method thing we probably don't want
540 var s2 = s=>upper()
541 echo $s2
542 ## STDOUT:
543 HI
544 ## END
545
546 #### obj->method does NOT give you a bound method
547 var s = 'hi'
548 var method = s->upper
549 echo $method
550 ## status: 3
551 ## stdout-json: ""
552
553 #### d.key
554 var d = {name: 'andy'}
555 var x = d.name
556 echo $x
557 ## STDOUT:
558 andy
559 ## END
560
561 #### a ++ b for string/list concatenation
562 shopt -s parse_brace
563
564 var i = 'abc'
565 var j = 'de'
566 var k = i ++ j
567 echo string $k
568
569
570 var a = [1, 2]
571 var b = [3]
572 var c = a ++ b
573 echo list len=$[len(c)]
574
575 echo ---
576
577 try {
578 = 'ab' ++ 3
579 }
580 echo Str Int $_status
581
582 try {
583 = [1, 2] ++ 3
584 }
585 echo List Int $_status
586
587 try {
588 = 3 ++ 'ab'
589 }
590 echo Int Str $_status
591
592 ## STDOUT:
593 string abcde
594 list len=3
595 ---
596 Str Int 3
597 List Int 3
598 Int Str 3
599 ## END
600
601 #### s ~~ glob and s !~~ glob
602 shopt -s oil:all
603
604 if ('foo.py' ~~ '*.py') {
605 echo yes
606 }
607 if ('foo.py' !~~ '*.sh') {
608 echo no
609 }
610 ## STDOUT:
611 yes
612 no
613 ## END
614
615 #### Type Errors
616 shopt --set parse_brace
617
618 # TODO: It might be nice to get a message
619 try {
620 var x = {} + []
621 }
622 echo $_status
623
624 try {
625 setvar x = {} + 3
626 }
627 echo $_status
628
629 try {
630 = 'foo' ++ 3
631 }
632 echo $_status
633
634 try {
635 = 'foo' ++ 3
636 }
637 echo $_status
638
639 ## STDOUT:
640 3
641 3
642 3
643 3
644 ## END
645
646
647 #### can't use ++ on integers
648 var x = 12 ++ 3
649 echo $x
650 ## status: 3
651 ## STDOUT:
652 ## END
653
654 #### can't do mystr ++ mylist
655 = ["s"] + "t"
656 ## status: 3
657 ## STDOUT:
658 ## END
659
660
661 #### expression literals
662 var e = ^[1 + 2]
663
664 echo type=$[type(e)]
665 echo $[evalExpr(e)]
666
667 var e = ^[2 < 1]
668 echo $[evalExpr(e)]
669
670 var x = 42
671 var e = ^[42 === x and true]
672 echo $[evalExpr(e)]
673
674 var mylist = ^[3, 4]
675 pp line (evalExpr(mylist))
676
677 ## STDOUT:
678 type=Expr
679 3
680 false
681 true
682 (List) [3,4]
683 ## END
684
685 #### No list comprehension in ^[]
686
687 var mylist = ^[x for x in y]
688 pp line (evalExpr(mylist))
689
690 ## status: 2
691 ## STDOUT:
692 ## END
693
694
695 #### expression literals, evaluation failure
696 var e = ^[1 / 0]
697 call evalExpr(e)
698 ## status: 3
699 ## STDOUT:
700 ## END
701
702 #### expression literals, lazy evaluation
703 var x = 0
704 var e = ^[x]
705
706 setvar x = 1
707 echo result=$[evalExpr(e)]
708 ## STDOUT:
709 result=1
710 ## END
711
712 #### expression literals, sugar for strings
713 var x = 0
714 var e = ^"x is $x"
715
716 setvar x = 1
717 echo result=$[evalExpr(e)]
718 ## STDOUT:
719 result=x is 1
720 ## END