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