Shells in OCaml
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

If statements

Relatively straightforward to implement now that we have so much of the
machinery!

+55 -5
+1 -1
TODO.md
··· 13 13 - [ ] Loops 14 14 - [x] For loops 15 15 - [ ] While/Until loops 16 - - [ ] Conditionals 16 + - [x] Conditionals 17 17 - [ ] Substitutions 18 18 - [ ] Globs 19 19 - [x] Simple support via glob(3)
+28 -4
src/lib/eval.ml
··· 302 302 let _rdrs = 303 303 List.map (handle_one_redirection ~sw:local_switch ctx) rdrs 304 304 in 305 - let ctx = handle_compound_command ~sw:local_switch ctx c in 305 + let ctx = handle_compound_command ctx c in 306 306 ctx 307 307 | v :: _ -> 308 308 Fmt.epr "TODO: %a" Yojson.Safe.pp (Ast.command_to_yojson v); ··· 376 376 | Ast.For_Name_DoGroup (_, (term, sep)) -> exec ctx (term, Some sep) 377 377 | Ast.For_Name_In_WordList_DoGroup (Name name, wdlist, (term, sep)) -> 378 378 let wdlist = Nlist.flatten @@ Nlist.map (word_glob_expand ctx) wdlist in 379 - (* Fmt.pr "List [%a]\n%!" Fmt.(list (list ~sep:Fmt.comma string)) (Nlist.to_list wdlist); *) 380 379 Nlist.fold_left 381 380 (fun _ word -> 382 - (* let words = List.map (fun s -> Ast.WordLiteral s) words in *) 383 381 let s = S.update ctx.state ~param:name [ Ast.WordLiteral word ] in 384 382 let ctx = { ctx with state = s } in 385 383 exec ctx (term, Some sep)) 386 384 (Exit.zero ctx) wdlist 387 385 388 - and handle_compound_command ~sw:_ ctx = function 386 + and handle_if_clause ctx = function 387 + | Ast.If_then ((e1, sep1), (e2, sep2)) -> ( 388 + let ctx = exec ctx (e1, Some sep1) in 389 + match ctx with 390 + | Exit.Zero ctx -> exec ctx (e2, Some sep2) 391 + | Exit.Nonzero { value = ctx; _ } -> Exit.zero ctx) 392 + | Ast.If_then_else ((e1, sep1), (e2, sep2), else_part) -> ( 393 + let ctx = exec ctx (e1, Some sep1) in 394 + match ctx with 395 + | Exit.Zero ctx -> exec ctx (e2, Some sep2) 396 + | Exit.Nonzero { value = ctx; _ } -> handle_else_part ctx else_part) 397 + 398 + and handle_else_part ctx = function 399 + | Ast.Else (c, sep) -> exec ctx (c, Some sep) 400 + | Ast.Elif_then ((e1, sep1), (e2, sep2)) -> ( 401 + let ctx = exec ctx (e1, Some sep1) in 402 + match ctx with 403 + | Exit.Zero ctx -> exec ctx (e2, Some sep2) 404 + | Exit.Nonzero { value = ctx; _ } -> Exit.zero ctx) 405 + | Ast.Elif_then_else ((e1, sep1), (e2, sep2), else_part) -> ( 406 + let ctx = exec ctx (e1, Some sep1) in 407 + match ctx with 408 + | Exit.Zero ctx -> exec ctx (e2, Some sep2) 409 + | Exit.Nonzero { value = ctx; _ } -> handle_else_part ctx else_part) 410 + 411 + and handle_compound_command ctx = function 389 412 | Ast.ForClause fc -> handle_for_clause ctx fc 413 + | Ast.IfClause if_ -> handle_if_clause ctx if_ 390 414 | _ as c -> 391 415 Fmt.failwith "Compound command not supported: %a" yojson_pp 392 416 (Ast.compound_command_to_yojson c)
+26
test/if.t
··· 1 + Testing if-then-else constructs 2 + 3 + $ cat > test.sh <<EOF 4 + > if echo hello 5 + > then 6 + > echo world 7 + > fi 8 + > EOF 9 + 10 + $ osh test.sh 11 + hello 12 + world 13 + 14 + $ cat > test.sh <<EOF 15 + > if ls --malformed-option 2>1 > /dev/null 16 + > then 17 + > echo world 18 + > else 19 + > echo goodbye 20 + > fi 21 + > EOF 22 + 23 + $ sh test.sh 24 + goodbye 25 + $ osh test.sh 26 + goodbye