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