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 #### 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 var 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, not in
386 var d = [1,2,3]
387 var b = 1 in d
388 echo $b
389 setvar b = 0 in d
390 echo $b
391 setvar b = 0 not in d
392 echo $b
393 ## STDOUT:
394 true
395 false
396 true
397 ## END
398
399 #### dict with 'bare word' keys
400 var d0 = {}
401 echo len=$[len(d0)]
402 var d1 = {name: "hello"}
403 echo len=$[len(d1)]
404 var d2 = {name: "hello", other: 2}
405 echo len=$[len(d2)]
406 ## STDOUT:
407 len=0
408 len=1
409 len=2
410 ## END
411
412 #### dict with expression keys
413 var d1 = {['name']: "hello"}
414 echo len=$[len(d1)]
415 var v = d1['name']
416 echo $v
417
418 var key='k'
419 var d2 = {["$key"]: "bar"}
420 echo len=$[len(d2)]
421 var v2 = d2['k']
422 echo $v2
423
424 ## STDOUT:
425 len=1
426 hello
427 len=1
428 bar
429 ## END
430
431
432 #### dict literal with implicit value
433 var name = 'foo'
434 var d1 = {name}
435 echo len=$[len(d1)]
436 var v1 = d1['name']
437 echo $v1
438
439 var d2 = {name, other: 'val'}
440 echo len=$[len(d2)]
441 var v2 = d2['name']
442 echo $v2
443
444 ## STDOUT:
445 len=1
446 foo
447 len=2
448 foo
449 ## END
450
451 #### Dict literal with string keys
452 var d = {'sq': 123}
453 var v = d['sq']
454 echo $v
455
456 var x = "q"
457 var d2 = {"d$x": 456}
458 var v2 = d2["dq"]
459 echo $v2
460 ## STDOUT:
461 123
462 456
463 ## END
464
465 #### Bitwise logical
466 var a = 0b0101 & 0b0011
467 echo $a
468 var b = 0b0101 | 0b0011
469 echo $b
470 var c = 0b0101 ^ 0b0011
471 echo $c
472 var d = ~b
473 echo $d
474 ## STDOUT:
475 1
476 7
477 6
478 -8
479 ## END
480
481 #### Shift operators
482 var a = 1 << 4
483 echo $a
484 var b = 16 >> 4
485 echo $b
486 ## STDOUT:
487 16
488 1
489 ## END
490
491 #### Exponentiation with **
492 var x = 2**3
493 echo $x
494
495 var y = 2.0 ** 3.0 # NOT SUPPORTED
496 echo 'should not get here'
497
498 ## status: 3
499 ## STDOUT:
500 8
501 ## END
502
503 #### Two Kinds of Division
504 var x = 5/2
505 echo $x
506 var y = 5 // 2
507 echo $y
508 ## STDOUT:
509 2.5
510 2
511 ## END
512
513 #### mod operator
514 = 5 % 3
515 = -5 % 3
516 ## STDOUT:
517 (Int) 2
518 (Int) 1
519 ## END
520
521 #### multiline strings, list, tuple syntax for list, etc.
522 var dq = "
523 dq
524 2
525 "
526 echo dq=$[len(dq)]
527
528 var sq = '
529 sq
530 2
531 '
532 echo sq=$[len(sq)]
533
534 var mylist = [
535 1,
536 2,
537 3,
538 ]
539 echo mylist=$[len(mylist)]
540
541 var mytuple = (1,
542 2, 3)
543 echo mytuple=$[len(mytuple)]
544
545 ## STDOUT:
546 dq=6
547 sq=6
548 mylist=3
549 mytuple=3
550 ## END
551
552 #### multiline dict
553
554 # Note: a pair has to be all on one line. We could relax that but there isn't
555 # a strong reason to now.
556
557 var mydict = { a:1,
558 b: 2,
559 }
560 echo mydict=$[len(mydict)]
561 ## STDOUT:
562 mydict=2
563 ## END
564
565 #### multiline array and command sub (only here docs disallowed)
566 var array = %(
567 one
568 two
569 three
570 )
571 echo array=$[len(array)]
572
573 var comsub = $(
574 echo hi
575 echo bye
576 )
577 echo comsub=$[len(comsub)]
578
579 ## STDOUT:
580 array=3
581 comsub=6
582 ## END
583
584 #### obj->method()
585 var s = 'hi'
586
587 # TODO: This does a bound method thing we probably don't want
588 var s2 = s->upper()
589 echo $s2
590 ## STDOUT:
591 HI
592 ## END
593
594 #### obj->method does NOT give you a bound method
595 var s = 'hi'
596 var method = s->upper
597 echo $method
598 ## status: 3
599 ## stdout-json: ""
600
601 #### d.key
602 var d = {name: 'andy'}
603 var x = d.name
604 echo $x
605 ## STDOUT:
606 andy
607 ## END
608
609 #### a ++ b for string/list concatenation
610 var i = 'abc'
611 var j = 'de'
612 var k = i ++ j
613 echo $k
614
615 var a = [1, 2]
616 var b = [3]
617 var c = a ++ b
618 echo len=$[len(c)]
619
620 ## STDOUT:
621 abcde
622 len=3
623 ## END
624
625 #### s ~~ glob and s !~~ glob
626 shopt -s oil:all
627
628 if ('foo.py' ~~ '*.py') {
629 echo yes
630 }
631 if ('foo.py' !~~ '*.sh') {
632 echo no
633 }
634 ## STDOUT:
635 yes
636 no
637 ## END
638
639 #### Type Errors
640 shopt --set parse_brace
641
642 # TODO: It might be nice to get a message
643 try {
644 var x = {} + []
645 }
646 echo $_status
647
648 try {
649 setvar x = {} + 3
650 }
651 echo $_status
652
653 try {
654 _ 'foo' ++ 3
655 }
656 echo $_status
657
658 try {
659 = 'foo' ++ 3
660 }
661 echo $_status
662
663 ## STDOUT:
664 3
665 3
666 3
667 3
668 ## END
669
670
671 #### can't use ++ on integers
672 var x = 12 ++ 3
673 echo $x
674 ## status: 3
675 ## STDOUT:
676 ## END
677
678 #### can't do mystr ++ mylist
679 = ["s"] + "t"
680 ## status: 3
681 ## STDOUT:
682 ## END
683
684
685