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 oil:basic
216 var a = %(one two three)
217 var x = "-${a[@]}-"
218 echo $x
219 ## status: 1
220 ## stdout-json: ""
221
222 #### single quoted -- implicit and explicit raw
223 var x = 'foo bar'
224 echo $x
225 setvar x = r'foo bar' # Same string
226 echo $x
227 setvar x = r'\t\n' # This is raw
228 echo $x
229 ## STDOUT:
230 foo bar
231 foo bar
232 \t\n
233 ## END
234
235 #### Implicit raw single quote with backslash is a syntax error
236 var x = '\t\n'
237 echo $x
238 ## status: 2
239 ## stdout-json: ""
240
241 #### single quoted C strings: c'foo\n' and $'foo\n'
242 var x = c'foo\nbar'
243 echo "$x"
244 var y = $'foo\nbar'
245 echo "$y"
246 ## STDOUT:
247 foo
248 bar
249 foo
250 bar
251 ## END
252
253 #### simple var sub $name $0 $1 $? etc.
254 ( exit 42 )
255 var status = $?
256 echo status=$status
257
258 set -- a b c
259 var one = $1
260 var two = $2
261 echo $one $two
262
263 var named = $one # equivalent to 'one'
264 echo named=$named
265
266 ## STDOUT:
267 status=42
268 a b
269 named=a
270 ## END
271
272 #### braced var sub ${x:-default}
273
274 # without double quotes
275
276 var b = ${foo:-default}
277 echo $b
278 var c = ${bar:-"-$b-"}
279 echo $c
280
281 var d = "${bar:-"-$c-"}" # another one
282 echo $d
283
284 ## STDOUT:
285 default
286 -default-
287 --default--
288 ## END
289
290 #### braced var sub respects strict_array
291 set -- a b c
292 var x = ${undef:-"$@"}
293 echo $x
294 shopt -s strict_array
295 setvar x = ${undef:-"$@"}
296 echo $x
297 ## status: 1
298 ## STDOUT:
299 a b c
300 ## END
301
302
303 #### null / true / false
304 shopt -s oil:basic
305 var n = null
306 if (n) {
307 echo yes
308 } else {
309 echo no
310 }
311 var t = true
312 if (t) {
313 echo yes
314 } else {
315 echo no
316 }
317 var f = false
318 if (f) {
319 echo yes
320 } else {
321 echo no
322 }
323 ## STDOUT:
324 no
325 yes
326 no
327 ## END
328
329 #### Integer literals
330 var d = 123
331 var b = 0b11
332 var o = 0o123
333 var h = 0xff
334 echo $d $b $o $h
335 ## STDOUT:
336 123 3 83 255
337 ## END
338
339 #### Float Literals
340 shopt -s oil:basic
341 # 1+2 2.3
342 var x = 1.2 + 23.0e-1 # 3.5
343 if (x < 3.9) {
344 echo less
345 }
346 if (x > 3.4) {
347 echo great
348 }
349 ## STDOUT:
350 less
351 great
352 ## END
353
354 #### Float Literals with _ (requires re2c refinement)
355 shopt -s oil:basic
356 # 1+2 + 2.3
357 # add this _ here
358 var x = 1.2 + 2_3.0e-1 # 3.5
359 if (x < 3.9) {
360 echo less
361 }
362 if (x > 3.4) {
363 echo great
364 }
365 ## STDOUT:
366 less
367 great
368 ## END
369
370 #### Tuples
371 var zero = ()
372 var one = tup(42)
373 var two = (1,2)
374 echo $len(zero)
375 echo $len(one)
376 echo $len(two)
377 ## STDOUT:
378 0
379 1
380 2
381 ## END
382
383 #### List comprehension (deferred)
384 shopt -s oil:all
385
386 var n = [i*2 for i in range(5)]
387 write -sep ' ' @n
388
389 # TODO: Test this
390 #var n = [i*2 for i,j in range(5)]
391
392 var even = [i*2 for i in range(5) if i % 2 == 0]
393 write -sep ' ' @even
394 ## STDOUT:
395 0 2 4 6 8
396 0 4 8
397 ## END
398
399 #### in, not in
400 var d = [1,2,3]
401 var b = 1 in d
402 echo $b
403 setvar b = 0 in d
404 echo $b
405 setvar b = 0 not in d
406 echo $b
407 ## STDOUT:
408 true
409 false
410 true
411 ## END
412
413 #### Chained Comparisons
414 shopt -s oil:basic
415 if (1 < 2 < 3) {
416 echo '123'
417 }
418 if (1 < 2 <= 2 <= 3 < 4) {
419 echo '123'
420 }
421
422 if (1 < 2 < 2) {
423 echo '123'
424 } else {
425 echo 'no'
426 }
427 ## STDOUT:
428 123
429 123
430 no
431 ## END
432
433 #### dict with 'bare word' keys
434 var d0 = {}
435 echo len=$len(d0)
436 var d1 = {name: "hello"}
437 echo len=$len(d1)
438 var d2 = {name: "hello", other: 2}
439 echo len=$len(d2)
440 ## STDOUT:
441 len=0
442 len=1
443 len=2
444 ## END
445
446 #### dict with expression keys
447 var d1 = {['name']: "hello"}
448 echo len=$len(d1)
449 var v = d1['name']
450 echo $v
451
452 var key='k'
453 var d2 = {["$key"]: "bar"}
454 echo len=$len(d2)
455 var v2 = d2['k']
456 echo $v2
457
458 ## STDOUT:
459 len=1
460 hello
461 len=1
462 bar
463 ## END
464
465
466 #### dict literal with implicit value
467 var name = 'foo'
468 var d1 = {name}
469 echo len=$len(d1)
470 var v1 = d1['name']
471 echo $v1
472
473 var d2 = {name, other: 'val'}
474 echo len=$len(d2)
475 var v2 = d2['name']
476 echo $v2
477
478 ## STDOUT:
479 len=1
480 foo
481 len=2
482 foo
483 ## END
484
485 #### Dict literal with string keys
486 var d = {'sq': 123}
487 var v = d['sq']
488 echo $v
489
490 var x = "q"
491 var d2 = {"d$x": 456}
492 var v2 = d2["dq"]
493 echo $v2
494 ## STDOUT:
495 123
496 456
497 ## END
498
499 #### Bitwise logical
500 var a = 0b0101 & 0b0011
501 echo $a
502 var b = 0b0101 | 0b0011
503 echo $b
504 var c = 0b0101 ^ 0b0011
505 echo $c
506 var d = ~b
507 echo $d
508 ## STDOUT:
509 1
510 7
511 6
512 -8
513 ## END
514
515 #### Shift operators
516 var a = 1 << 4
517 echo $a
518 var b = 16 >> 4
519 echo $b
520 ## STDOUT:
521 16
522 1
523 ## END
524
525 #### Exponentiation with **
526 var x = 2**3
527 echo $x
528 var y = 2.0**3.0
529 echo $y
530 ## STDOUT:
531 8
532 8.0
533 ## END
534
535 #### Two Kinds of Division
536 var x = 5/2
537 echo $x
538 var y = 5 // 2
539 echo $y
540 ## STDOUT:
541 2.5
542 2
543 ## END
544
545 #### mod operator
546 = 5 % 3
547 = -5 % 3
548 ## STDOUT:
549 (Int) 2
550 (Int) 1
551 ## END
552
553 #### Logical operators
554 var a = not true
555 echo $a
556 var b = true and false
557 echo $b
558 var c = true or false
559 echo $c
560
561 # TODO: These should be spelled 'false' 'false' 'true'?
562
563 ## STDOUT:
564 false
565 false
566 true
567 ## END
568
569 #### x if b else y
570 var b = true
571 var i = 42
572 var t = i+1 if b else i-1
573 echo $t
574 var f = i+1 if false else i-1
575 echo $f
576 ## STDOUT:
577 43
578 41
579 ## END
580
581 #### multiline strings, list, tuples, etc.
582 var dq = "
583 dq
584 2
585 "
586 echo dq=$len(dq)
587
588 var sq = '
589 sq
590 2
591 '
592 echo sq=$len(sq)
593
594 var mylist = [
595 1,
596 2,
597 3,
598 ]
599 echo mylist=$len(mylist)
600
601 var mytuple = (1,
602 2, 3)
603 echo mytuple=$len(mytuple)
604
605 ## STDOUT:
606 dq=6
607 sq=6
608 mylist=3
609 mytuple=3
610 ## END
611
612 #### multiline dict
613
614 # Note: a pair has to be all on one line. We could relax that but there isn't
615 # a strong reason to now.
616
617 var mydict = { a:1,
618 b: 2,
619 }
620 echo mydict=$len(mydict)
621 ## STDOUT:
622 mydict=2
623 ## END
624
625 #### multiline array and command sub (only here docs disallowed)
626 var array = %(
627 one
628 two
629 three
630 )
631 echo array=$len(array)
632
633 var comsub = $(
634 echo hi
635 echo bye
636 )
637 echo comsub=$len(comsub)
638
639 ## STDOUT:
640 array=3
641 comsub=6
642 ## END
643
644 #### obj.attr and obj.method()
645 var s = 'hi'
646
647 # TODO: This does a bound method thing we probably don't want
648 var s2 = s.upper()
649 echo $s2
650 ## STDOUT:
651 HI
652 ## END
653
654 #### obj.method does NOT give you a bound method
655
656 # TODO: Not sure how to implement this
657
658 var s = 'hi'
659 var method = s.upper
660 echo $method
661 ## STDOUT:
662 ## END
663
664
665
666 #### d->key
667 var d = {name: 'andy'}
668 var x = d->name
669 echo $x
670 ## STDOUT:
671 andy
672 ## END
673
674 #### a ++ b for string/list concatenation
675 var i = 'abc'
676 var j = 'de'
677 var k = i ++ j
678 echo $k
679
680 var a = [1, 2]
681 var b = [3]
682 var c = a ++ b
683 echo len=$len(c)
684
685 ## STDOUT:
686 abcde
687 len=3
688 ## END
689
690 #### s ~~ glob and s !~~ glob
691 shopt -s oil:all
692
693 if ('foo.py' ~~ '*.py') {
694 echo yes
695 }
696 if ('foo.py' !~~ '*.sh') {
697 echo no
698 }
699 ## STDOUT:
700 yes
701 no
702 ## END
703
704 #### 3 ~== '3'
705 shopt -s oil:all
706
707 # TODO: should we have !~== too?
708 # Or just make it not (a ~== b)
709
710 if (3 ~== 3) {
711 echo exact
712 }
713 if (1 ~== 3) {
714 echo FAIL
715 }
716
717 if (3 ~== '3') {
718 echo int-str
719 }
720 if (3 ~== '4') {
721 echo FAIL
722 }
723
724 if (42 ~== 42.0) {
725 echo int-float
726 }
727 if (42 ~== 43.0) {
728 echo FAIL
729 }
730
731 if ('42' ~== 42.0) {
732 echo str-float
733 }
734 if ('42' ~== 43.0) {
735 echo FAIL
736 }
737
738 if (42 ~== '42.0') {
739 echo int-str-float
740 }
741 if (42 ~== '43.0') {
742 echo FAIL
743 }
744
745 ## STDOUT:
746 exact
747 int-str
748 int-float
749 str-float
750 int-str-float
751 ## END
752