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 #### nested expr contexts
130 var s = "123"
131
132 # lex_mode_e.ShCommand -> Expr -> ShCommand -> Expr
133 var x = $(echo $'len\n' $len(s))
134 echo $x
135 ## STDOUT:
136 len 3
137 ## END
138
139
140 # TODO:
141 # - test keyword args
142 # - test splatting *args, **kwargs
143 # - Multiline parsing
144 #
145 # var x = max(
146 # 1+2,
147 # 3+4,
148 # )
149 # echo $x $max(
150 # 1+2,
151 # 3+4,
152 # )
153
154 #### Test value.Obj inside shell arithmetic
155 var w = "3"
156 echo lt=$(( w < 4 ))
157 echo gt=$(( w > 4 ))
158
159 var z = 3
160 echo lt=$(( z < 4 ))
161 echo gt=$(( z > 4 ))
162 ## STDOUT:
163 lt=1
164 gt=0
165 lt=1
166 gt=0
167 ## END
168
169 #### Parse { var x = 42 }
170 shopt -s oil:upgrade
171 g() { var x = 42 }
172
173 var x = 1
174 f() { var x = 42; setvar x = 43 }
175 f
176 echo x=$x
177 ## STDOUT:
178 x=1
179 ## END
180
181 #### double quoted
182 var foo = "bar"
183 var x = "-$foo-${foo}-${undef:-default}-"
184 echo $x
185 ## STDOUT:
186 -bar-bar-default-
187 ## END
188
189 #### double quoted respects strict_array
190 shopt -s strict:all
191 var a = %(one two three)
192 var x = "-${a[@]}-"
193 echo $x
194 ## status: 1
195 ## stdout-json: ""
196
197 #### simple var sub $name $0 $1 $? etc.
198 ( exit 42 )
199 var status = $?
200 echo status=$status
201
202 set -- a b c
203 var one = $1
204 var two = $2
205 echo $one $two
206
207 var named = "$one" # equivalent to 'one'
208 echo named=$named
209
210 ## STDOUT:
211 status=42
212 a b
213 named=a
214 ## END
215
216 #### braced var sub ${x:-default}
217
218 # without double quotes
219
220 var b = ${foo:-default}
221 echo $b
222 var c = ${bar:-"-$b-"}
223 echo $c
224
225 var d = "${bar:-"-$c-"}" # another one
226 echo $d
227
228 ## STDOUT:
229 default
230 -default-
231 --default--
232 ## END
233
234 #### braced var sub respects strict_array
235 set -- a b c
236 var x = ${undef:-"$@"}
237 echo $x
238 shopt -s strict_array
239 setvar x = ${undef:-"$@"}
240 echo $x
241 ## status: 1
242 ## STDOUT:
243 a b c
244 ## END
245
246
247 #### null / true / false
248 shopt -s oil:upgrade
249 var n = null
250 if (n) {
251 echo yes
252 } else {
253 echo no
254 }
255 var t = true
256 if (t) {
257 echo yes
258 } else {
259 echo no
260 }
261 var f = false
262 if (f) {
263 echo yes
264 } else {
265 echo no
266 }
267 ## STDOUT:
268 no
269 yes
270 no
271 ## END
272
273 #### Integer literals
274 var d = 123
275 var b = 0b11
276 var o = 0o123
277 var h = 0xff
278 echo $d $b $o $h
279 ## STDOUT:
280 123 3 83 255
281 ## END
282
283 #### Integer literals with underscores
284 const dec = 65_536
285 const bin = 0b0001_0101
286 const oct = 0o001_755
287 const hex = 0x0001_000f
288
289 echo SHELL
290 echo $dec
291 echo $bin
292 echo $oct
293 echo $hex
294 const x = 1_1 + 0b1_1 + 0o1_1 + 0x1_1
295 echo sum $x
296
297 # This works under Python 3.6, but the continuous build has earlier versions
298 if false; then
299 echo ---
300 echo PYTHON
301
302 python3 -c '
303 print(65_536)
304 print(0b0001_0101)
305 print(0o001_755)
306 print(0x0001_000f)
307
308 # Weird syntax
309 print("sum", 1_1 + 0b1_1 + 0o1_1 + 0x1_1)
310 '
311 fi
312
313 ## STDOUT:
314 SHELL
315 65536
316 21
317 1005
318 65551
319 sum 40
320 ## END
321
322 #### Backslash char literal (is an integer)
323 const newline = \n
324 const backslash = \\
325 const sq = \'
326 const dq = \"
327 echo "$newline $backslash $sq $dq"
328 ## STDOUT:
329 10 92 39 34
330 ## END
331
332 #### \u{3bc} is char literal
333 shopt -s oil:all
334
335 var mu = \u{3bc}
336 if (mu === 0x3bc) { # this is the same!
337 echo 'yes'
338 }
339 echo "mu $mu"
340 ## STDOUT:
341 yes
342 mu 956
343 ## END
344
345 #### Pound char literal (is an integer)
346 const a = #'a'
347 const A = #'A'
348 echo "$a $A"
349 ## STDOUT:
350 97 65
351 ## END
352
353 #### The literal #''' isn't accepted (use \' instead)
354
355 # This looks too much like triple quoted strings!
356
357 echo nope
358 const bad = #'''
359 echo "$bad"
360
361 ## status: 2
362 ## STDOUT:
363 nope
364 ## END
365
366 #### Float Literals
367 shopt -s oil:upgrade
368 # 1+2 2.3
369 var x = 1.2 + 23.0e-1 # 3.5
370 if (x < 3.9) {
371 echo less
372 }
373 if (x > 3.4) {
374 echo great
375 }
376 ## STDOUT:
377 less
378 great
379 ## END
380
381 #### Float Literals with _ (requires re2c refinement)
382 shopt -s oil:upgrade
383 # 1+2 + 2.3
384 # add this _ here
385 var x = 1.2 + 2_3.0e-1 # 3.5
386 if (x < 3.9) {
387 echo less
388 }
389 if (x > 3.4) {
390 echo great
391 }
392 ## STDOUT:
393 less
394 great
395 ## END
396
397 #### Tuples
398 var zero = ()
399 var one = tup(42)
400 var two = (1,2)
401 echo $len(zero)
402 echo $len(one)
403 echo $len(two)
404 ## STDOUT:
405 0
406 1
407 2
408 ## END
409
410 #### in, not in
411 var d = [1,2,3]
412 var b = 1 in d
413 echo $b
414 setvar b = 0 in d
415 echo $b
416 setvar b = 0 not in d
417 echo $b
418 ## STDOUT:
419 true
420 false
421 true
422 ## END
423
424 #### dict with 'bare word' keys
425 var d0 = {}
426 echo len=$len(d0)
427 var d1 = {name: "hello"}
428 echo len=$len(d1)
429 var d2 = {name: "hello", other: 2}
430 echo len=$len(d2)
431 ## STDOUT:
432 len=0
433 len=1
434 len=2
435 ## END
436
437 #### dict with expression keys
438 var d1 = {['name']: "hello"}
439 echo len=$len(d1)
440 var v = d1['name']
441 echo $v
442
443 var key='k'
444 var d2 = {["$key"]: "bar"}
445 echo len=$len(d2)
446 var v2 = d2['k']
447 echo $v2
448
449 ## STDOUT:
450 len=1
451 hello
452 len=1
453 bar
454 ## END
455
456
457 #### dict literal with implicit value
458 var name = 'foo'
459 var d1 = {name}
460 echo len=$len(d1)
461 var v1 = d1['name']
462 echo $v1
463
464 var d2 = {name, other: 'val'}
465 echo len=$len(d2)
466 var v2 = d2['name']
467 echo $v2
468
469 ## STDOUT:
470 len=1
471 foo
472 len=2
473 foo
474 ## END
475
476 #### Dict literal with string keys
477 var d = {'sq': 123}
478 var v = d['sq']
479 echo $v
480
481 var x = "q"
482 var d2 = {"d$x": 456}
483 var v2 = d2["dq"]
484 echo $v2
485 ## STDOUT:
486 123
487 456
488 ## END
489
490 #### Bitwise logical
491 var a = 0b0101 & 0b0011
492 echo $a
493 var b = 0b0101 | 0b0011
494 echo $b
495 var c = 0b0101 ^ 0b0011
496 echo $c
497 var d = ~b
498 echo $d
499 ## STDOUT:
500 1
501 7
502 6
503 -8
504 ## END
505
506 #### Shift operators
507 var a = 1 << 4
508 echo $a
509 var b = 16 >> 4
510 echo $b
511 ## STDOUT:
512 16
513 1
514 ## END
515
516 #### Exponentiation with **
517 var x = 2**3
518 echo $x
519
520 var y = 2.0 ** 3.0 # NOT SUPPORTED
521 echo 'should not get here'
522
523 ## status: 3
524 ## STDOUT:
525 8
526 ## END
527
528 #### Two Kinds of Division
529 var x = 5/2
530 echo $x
531 var y = 5 // 2
532 echo $y
533 ## STDOUT:
534 2.5
535 2
536 ## END
537
538 #### mod operator
539 = 5 % 3
540 = -5 % 3
541 ## STDOUT:
542 (Int) 2
543 (Int) 1
544 ## END
545
546 #### Logical operators
547 var a = not true
548 echo $a
549 var b = true and false
550 echo $b
551 var c = true or false
552 echo $c
553
554 # TODO: These should be spelled 'false' 'false' 'true'?
555
556 ## STDOUT:
557 false
558 false
559 true
560 ## END
561
562 #### x if b else y
563 var b = true
564 var i = 42
565 var t = i+1 if b else i-1
566 echo $t
567 var f = i+1 if false else i-1
568 echo $f
569 ## STDOUT:
570 43
571 41
572 ## END
573
574 #### multiline strings, list, tuples, etc.
575 var dq = "
576 dq
577 2
578 "
579 echo dq=$len(dq)
580
581 var sq = '
582 sq
583 2
584 '
585 echo sq=$len(sq)
586
587 var mylist = [
588 1,
589 2,
590 3,
591 ]
592 echo mylist=$len(mylist)
593
594 var mytuple = (1,
595 2, 3)
596 echo mytuple=$len(mytuple)
597
598 ## STDOUT:
599 dq=6
600 sq=6
601 mylist=3
602 mytuple=3
603 ## END
604
605 #### multiline dict
606
607 # Note: a pair has to be all on one line. We could relax that but there isn't
608 # a strong reason to now.
609
610 var mydict = { a:1,
611 b: 2,
612 }
613 echo mydict=$len(mydict)
614 ## STDOUT:
615 mydict=2
616 ## END
617
618 #### multiline array and command sub (only here docs disallowed)
619 var array = %(
620 one
621 two
622 three
623 )
624 echo array=$len(array)
625
626 var comsub = $(
627 echo hi
628 echo bye
629 )
630 echo comsub=$len(comsub)
631
632 ## STDOUT:
633 array=3
634 comsub=6
635 ## END
636
637 #### obj.attr and obj.method()
638 var s = 'hi'
639
640 # TODO: This does a bound method thing we probably don't want
641 var s2 = s.upper()
642 echo $s2
643 ## STDOUT:
644 HI
645 ## END
646
647 #### obj.method does NOT give you a bound method
648 var s = 'hi'
649 var method = s.upper
650 echo $method
651 ## status: 2
652 ## stdout-json: ""
653
654 #### d->key
655 var d = {name: 'andy'}
656 var x = d->name
657 echo $x
658 ## STDOUT:
659 andy
660 ## END
661
662 #### a ++ b for string/list concatenation
663 var i = 'abc'
664 var j = 'de'
665 var k = i ++ j
666 echo $k
667
668 var a = [1, 2]
669 var b = [3]
670 var c = a ++ b
671 echo len=$len(c)
672
673 ## STDOUT:
674 abcde
675 len=3
676 ## END
677
678 #### s ~~ glob and s !~~ glob
679 shopt -s oil:all
680
681 if ('foo.py' ~~ '*.py') {
682 echo yes
683 }
684 if ('foo.py' !~~ '*.sh') {
685 echo no
686 }
687 ## STDOUT:
688 yes
689 no
690 ## END
691
692 #### Type Errors
693 shopt --set parse_brace
694
695 # TODO: It might be nice to get a message
696 try {
697 var x = {} + []
698 }
699 echo $_status
700
701 try {
702 setvar x = {} + 3
703 }
704 echo $_status
705
706 try {
707 _ 'foo' ++ 3
708 }
709 echo $_status
710
711 try {
712 = 'foo' ++ 3
713 }
714 echo $_status
715
716 ## STDOUT:
717 3
718 3
719 3
720 3
721 ## END
722
723
724 #### can't use ++ on integers
725 var x = 12 ++ 3
726 echo $x
727 ## status: 3
728 ## STDOUT:
729 ## END
730
731 #### can't do mystr ++ mylist
732 = ["s"] + "t"
733 ## status: 3
734 ## STDOUT:
735 ## END
736
737
738