src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/compile_effect_test.elvts (about) 1 ///////// 2 # chunk # 3 ///////// 4 5 ## empty chunk ## 6 ~> 7 8 ## outputs of pipelines in a chunk are concatenated ## 9 ~> put x; put y; put z 10 ▶ x 11 ▶ y 12 ▶ z 13 14 ## a failed pipeline cause the whole chunk to fail ## 15 ~> put a; fail bad; put b 16 ▶ a 17 Exception: bad 18 [tty]:1:8-15: put a; fail bad; put b 19 20 //////////// 21 # pipeline # 22 //////////// 23 24 ## pure byte pipeline on Unix ## 25 //only-on unix 26 ~> echo "Albert\nAllan\nAlbraham\nBerlin" | sed s/l/1/g | grep e 27 A1bert 28 Ber1in 29 30 ## pure byte pipeline on Windows ## 31 //only-on windows 32 ~> echo "Albert\nAllan\nAlbraham\nBerlin" | findstr e 33 Albert 34 Berlin 35 36 ## pure value pipeline ## 37 ~> put 233 42 19 | each {|x|+ $x 10} 38 ▶ (num 243) 39 ▶ (num 52) 40 ▶ (num 29) 41 42 ## pipeline draining ## 43 ~> range 100 | put x 44 ▶ x 45 46 // TODO: Add a useful hybrid pipeline sample 47 48 ## reader gone ## 49 // Internal commands writing to byte output raises ReaderGone when the reader has 50 // exited, which is then suppressed by the pipeline. 51 ~> while $true { echo y } | nop 52 ~> var reached = $false 53 { while $true { echo y }; reached = $true } | nop 54 put $reached 55 ▶ $false 56 // Similar for value output. 57 ~> while $true { put y } | nop 58 ~> var reached = $false 59 { while $true { put y }; reached = $true } | nop 60 put $reached 61 ▶ $false 62 63 ## reader gone from SIGPIPE ## 64 //only-on unix 65 // External commands terminated by SIGPIPE due to reader exiting early raise 66 // ReaderGone, which is then suppressed by the pipeline. 67 ~> yes | true 68 ~> var reached = $false 69 { yes; reached = $true } | true 70 put $reached 71 ▶ $false 72 73 /////////////////////// 74 # background pipeline # 75 /////////////////////// 76 77 //each:eval use file 78 79 ## basic behavior ## 80 ~> set notify-bg-job-success = $false 81 var p = (file:pipe) 82 { print foo > $p; file:close $p[w] }& 83 slurp < $p; file:close $p[r] 84 ▶ foo 85 86 ## notification ## 87 //recv-bg-job-notification-in-global 88 ~> set notify-bg-job-success = $true 89 var p = (file:pipe) 90 fn f { file:close $p[w] } 91 f & 92 slurp < $p; file:close $p[r] 93 recv-bg-job-notification 94 ▶ '' 95 ▶ 'job f & finished' 96 97 ## notification with exception ## 98 //recv-bg-job-notification-in-global 99 ~> set notify-bg-job-success = $true 100 var p = (file:pipe) 101 fn f { file:close $p[w]; fail foo } 102 f & 103 slurp < $p; file:close $p[r] 104 recv-bg-job-notification 105 ▶ '' 106 ▶ 'job f & finished, errors = foo' 107 108 /////////// 109 # command # 110 /////////// 111 112 ~> put foo 113 ▶ foo 114 115 ## error conditions ## 116 // head is not a single value 117 ~> {put put} foo 118 Exception: arity mismatch: command must be 1 value, but is 2 values 119 [tty]:1:1-9: {put put} foo 120 // head is not callable or string containing slash 121 ~> [] foo 122 Exception: bad value: command must be callable or string containing slash, but is [] 123 [tty]:1:1-2: [] foo 124 // argument throws 125 ~> put [][1] 126 Exception: out of range: index must be from 0 to -1, but is 1 127 [tty]:1:5-9: put [][1] 128 // option key is not string 129 ~> put &[]=[] 130 Exception: bad value: option key must be string, but is list 131 [tty]:1:1-10: put &[]=[] 132 // option evaluation throws 133 ~> put &x=[][1] 134 Exception: out of range: index must be from 0 to -1, but is 1 135 [tty]:1:8-12: put &x=[][1] 136 137 ## regression test for b.elv.sh/1204 ## 138 // Ensure that the arguments of special forms are not accidentally compiled 139 // twice. 140 ~> nop (and (use builtin)) 141 nop $builtin:echo~ 142 143 ///////////////////////////// 144 # external command as value # 145 ///////////////////////////// 146 ~> kind-of (external true) 147 ▶ fn 148 ~> repr (external true) 149 <external true> 150 ~> put [&(external true)=$true][(external true)] 151 ▶ $true 152 153 //////////////////////////////// 154 # external commands invocation # 155 //////////////////////////////// 156 157 ## common behavior ## 158 // Doesn't support options 159 ~> (external foo) &option 160 Exception: external commands don't accept elvish options 161 [tty]:1:1-22: (external foo) &option 162 163 ## external command from PATH ## 164 //in-temp-dir 165 //unset-env PATH 166 ~> use os 167 os:mkdir bin 168 to-lines ['#!/bin/sh' 'echo hello'] > bin/say-hello 169 os:chmod 0o700 bin/say-hello 170 to-lines ['@echo hello'] > bin/say-hello.bat 171 set paths = [$pwd/bin] 172 ~> say-hello 173 hello 174 // Explicit e: 175 ~> e:say-hello 176 hello 177 // Dynamic string does not work for finding external commands from PATH 178 ~> var x = say-hello 179 $x 180 Exception: bad value: command must be callable or string containing slash, but is say-hello 181 [tty]:2:1-2: $x 182 // Command searching is affected by the unknown-command pragma 183 ~> { pragma unknown-command = disallow; say-hello } 184 Compilation error: unknown command disallowed by current pragma 185 [tty]:1:38-46: { pragma unknown-command = disallow; say-hello } 186 ~> { pragma unknown-command = disallow; { say-hello } } 187 Compilation error: unknown command disallowed by current pragma 188 [tty]:1:40-48: { pragma unknown-command = disallow; { say-hello } } 189 ~> { pragma unknown-command = external; say-hello } 190 hello 191 // But explicit e: is always allowed 192 ~> { pragma unknown-command = disallow; e:say-hello } 193 hello 194 195 ## external command relative to working directory ## 196 //in-temp-dir 197 ~> use os 198 fn make-echo-script {|name msg| 199 to-lines ['#!/bin/sh' 'echo '$msg] > $name 200 os:chmod 0o700 $name 201 to-lines ['@echo '$msg] > $name.bat 202 } 203 make-echo-script say-hello hello 204 os:mkdir lorem 205 make-echo-script lorem/ipsum 'lorem ipsum' 206 ~> ./say-hello 207 hello 208 ~> ./lorem/ipsum 209 lorem ipsum 210 ~> lorem/ipsum 211 lorem ipsum 212 // Explicit e: 213 ~> e:./say-hello 214 hello 215 ~> e:./lorem/ipsum 216 lorem ipsum 217 ~> e:lorem/ipsum 218 lorem ipsum 219 // Dynamic string 220 ~> var x = ./say-hello 221 $x 222 hello 223 ~> var x = ./lorem/ipsum 224 $x 225 lorem ipsum 226 ~> var x = lorem/ipsum 227 $x 228 lorem ipsum 229 // Relative external commands are not affected by the unknown-command pragma 230 ~> { pragma unknown-command = disallow; ./say-hello } 231 hello 232 ~> { pragma unknown-command = disallow; lorem/ipsum } 233 lorem ipsum 234 ~> { pragma unknown-command = disallow; var x = ./say-hello; $x } 235 hello 236 237 ## non-existent command on Unix ## 238 //only-on unix 239 //unset-env PATH 240 ~> set paths = [] 241 ~> nonexistent-command 242 Exception: exec: "nonexistent-command": executable file not found in $PATH 243 [tty]:1:1-19: nonexistent-command 244 245 ## non-existent command on Windows ## 246 //only-on windows 247 //unset-env PATH 248 ~> set paths = [] 249 ~> nonexistent-command 250 Exception: exec: "nonexistent-command": executable file not found in %PATH% 251 [tty]:1:1-19: nonexistent-command 252 253 /////////////// 254 # implicit cd # 255 /////////////// 256 257 //in-temp-dir 258 //with-deprecation-level 21 259 ~> use os 260 use path 261 os:mkdir new-dir 262 var old-pwd = $pwd 263 ~> ./new-dir 264 Deprecation: implicit cd is deprecated; use cd or location mode instead 265 [tty]:1:1-9: ./new-dir 266 ~> eq $pwd (path:join $old-pwd new-dir) 267 ▶ $true 268 269 ////////////////////////////////////// 270 # legacy temporary assignment syntax # 271 ////////////////////////////////////// 272 273 ~> var a b = alice bob; {a,@b}=(put amy ben) put $a $@b; put $a $b 274 ▶ amy 275 ▶ ben 276 ▶ alice 277 ▶ bob 278 Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead 279 [tty]:1:22-41: var a b = alice bob; {a,@b}=(put amy ben) put $a $@b; put $a $b 280 281 ## temporary assignment of list element ## 282 ~> var l = [a]; l[0]=x put $l[0]; put $l[0] 283 ▶ x 284 ▶ a 285 Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead 286 [tty]:1:14-19: var l = [a]; l[0]=x put $l[0]; put $l[0] 287 288 ## temporary assignment of map element ## 289 ~> var m = [&k=v]; m[k]=v2 put $m[k]; put $m[k] 290 ▶ v2 291 ▶ v 292 Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead 293 [tty]:1:17-23: var m = [&k=v]; m[k]=v2 put $m[k]; put $m[k] 294 295 ## temporary assignment before special form ## 296 ~> li=[foo bar] for x $li { put $x } 297 ▶ foo 298 ▶ bar 299 Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead 300 [tty]:1:1-12: li=[foo bar] for x $li { put $x } 301 302 ## multiple LHSs in temporary assignments. ## 303 ~> {a b}={foo bar} put $a $b 304 ▶ foo 305 ▶ bar 306 Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead 307 [tty]:1:1-15: {a b}={foo bar} put $a $b 308 309 ## rest variable ## 310 ~> @a=(put a b) put $@a 311 ▶ a 312 ▶ b 313 Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead 314 [tty]:1:1-12: @a=(put a b) put $@a 315 316 ## non-rest and rest variable ## 317 ~> {a,@b}=(put a b c) put $@b 318 ▶ b 319 ▶ c 320 Deprecation: the legacy temporary assignment syntax is deprecated; use "tmp" instead 321 [tty]:1:1-18: {a,@b}=(put a b c) put $@b 322 323 ## using syntax of temporary assignment for non-temporary assignment no longer compiles ## 324 ~> x=y 325 Compilation error: using the syntax of temporary assignment for non-temporary assignment is no longer supported; use "var" or "set" instead 326 [tty]:1:1-3: x=y 327 328 /////////////// 329 # redirection # 330 /////////////// 331 332 //each:in-temp-dir 333 334 ## output and input redirection ## 335 ~> echo 233 > out1 336 slurp < out1 337 ▶ "233\n" 338 339 ## append ## 340 ~> echo 1 > out; echo 2 >> out; slurp < out 341 ▶ "1\n2\n" 342 343 ## read and write ## 344 // TODO: Add a meaningful use case that actually uses both read and write. 345 ~> echo 233 <> out1 346 slurp < out1 347 ▶ "233\n" 348 349 ## redirections from special form ## 350 ~> for x [lorem ipsum] { echo $x } > out2 351 slurp < out2 352 ▶ "lorem\nipsum\n" 353 354 ## using numeric FDs as source and destination ## 355 ~> { echo foobar >&2 } 2> out3 356 slurp < out3 357 ▶ "foobar\n" 358 359 ## using named FDs as source and destination ## 360 ~> echo 233 stdout> out1 361 slurp stdin< out1 362 ▶ "233\n" 363 364 ## using named FDs (stderr) as source and destination ## 365 ~> { echo foobar >&stderr } stderr> out4 366 slurp < out4 367 ▶ "foobar\n" 368 369 ## using a new FD as source throws an exception ## 370 ~> echo foo >&4 371 Exception: invalid fd: 4 372 [tty]:1:10-12: echo foo >&4 373 374 ## using a new FD as destination is OK, and makes it available ## 375 ~> { echo foo >&4 } 4>out5 376 slurp < out5 377 ▶ "foo\n" 378 379 ## using a new FD for external command is OK ## 380 // Regression test against b.elv.sh/788. 381 //only-on unix 382 // TODO: Enable for Windows too. 383 ~> /bin/sh -c 'echo ok' 5</dev/null 384 ok 385 386 ## redirections from file objects ## 387 ~> use file 388 echo haha > out3 389 var f = (file:open out3) 390 slurp <$f 391 file:close $f 392 ▶ "haha\n" 393 394 ## redirections from pipe objects ## 395 ~> use file 396 var p = (file:pipe) 397 echo haha > $p 398 file:close $p[w] 399 slurp < $p 400 file:close $p[r] 401 ▶ "haha\n" 402 403 ## regression test for b.elv.sh/1010 ## 404 // Don't hang when iterating over input from a file. 405 ~> echo abc > bytes 406 each $echo~ < bytes 407 abc 408 ~> echo def > bytes 409 only-values < bytes | count 410 ▶ (num 0) 411 412 ## writing value output to file throws an exception ## 413 ~> put foo >a 414 Exception: port does not support value output 415 [tty]:1:1-10: put foo >a 416 417 ## writing value output to closed port throws an exception ## 418 ~> put foo >&- 419 Exception: port does not support value output 420 [tty]:1:1-11: put foo >&- 421 422 ## invalid redirection destination ## 423 ~> echo []> test 424 Exception: bad value: redirection destination must be fd name or number, but is [] 425 [tty]:1:6-7: echo []> test 426 427 ## invalid fd redirection source ## 428 ~> echo >&test 429 Exception: bad value: redirection source must be fd name or number or '-', but is test 430 [tty]:1:8-11: echo >&test 431 432 ## invalid redirection source ## 433 ~> echo > [] 434 Exception: bad value: redirection source must be string, file or map, but is list 435 [tty]:1:8-9: echo > [] 436 437 ## invalid map for redirection ## 438 ~> echo < [&] 439 Exception: bad value: map for input redirection must be map with file in the 'r' field, but is [&] 440 [tty]:1:8-10: echo < [&] 441 ~> echo > [&] 442 Exception: bad value: map for output redirection must be map with file in the 'w' field, but is [&] 443 [tty]:1:8-10: echo > [&] 444 445 ## exception when evaluating source or destination ## 446 ~> echo > (fail foo) 447 Exception: foo 448 [tty]:1:9-16: echo > (fail foo) 449 ~> echo (fail foo)> file 450 Exception: foo 451 [tty]:1:7-14: echo (fail foo)> file 452 453 //////////////// 454 # stack traces # 455 //////////////// 456 457 // Stack traces of increasing depths. 458 ~> fail oops 459 Exception: oops 460 [tty]:1:1-9: fail oops 461 ~> fn f { fail oops } 462 f 463 Exception: oops 464 [tty]:1:8-17: fn f { fail oops } 465 [tty]:2:1-1: f 466 ~> fn f { fail oops } 467 fn g { f } 468 g 469 Exception: oops 470 [tty]:1:8-17: fn f { fail oops } 471 [tty]:2:8-9: fn g { f } 472 [tty]:3:1-1: g 473 // Error thrown before execution. 474 ~> fn f { } 475 f a 476 Exception: arity mismatch: arguments must be 0 values, but is 1 value 477 [tty]:2:1-3: f a 478 // Error from builtin. 479 ~> count 1 2 3 480 Exception: arity mismatch: arguments must be 0 to 1 values, but is 3 values 481 [tty]:1:1-11: count 1 2 3