diff --git a/src/lib/eval.ml b/src/lib/eval.ml index dad3df3..54d15f6 100644 --- a/src/lib/eval.ml +++ b/src/lib/eval.ml @@ -453,7 +453,7 @@ module Make (S : Types.State) (E : Types.Exec) = struct | Some s when kind = `Smallest -> (so_far, Some s) | _ -> ( let s = so_far ^ String.make 1 c in - match Glob.test ~pattern [ s ] with + match Glob.tests ~pattern [ s ] with | [ s ] -> (s, Some s) | _ -> (s, acc))) ("", None) param @@ -468,7 +468,7 @@ module Make (S : Types.State) (E : Types.Exec) = struct | Some s when kind = `Smallest -> (so_far, Some s) | _ -> ( let s = String.make 1 c ^ so_far in - match Glob.test ~pattern [ s ] with + match Glob.tests ~pattern [ s ] with | [ s ] -> (s, Some s) | _ -> (s, acc))) ("", None) @@ -711,16 +711,51 @@ module Make (S : Types.State) (E : Types.Exec) = struct | Exit.Zero ctx -> exec ctx (e2, Some sep2) | Exit.Nonzero { value = ctx; _ } -> handle_else_part ctx else_part) + and handle_case_clause ctx = function + | Ast.Case _ -> Exit.zero ctx + | Cases (word, case_list) -> ( + let ctx, word = expand_cst ctx word in + let scrutinee = Ast.word_components_to_string word in + let res = + Nlist.fold_left + (fun acc pat -> + match acc with + | Some _ as ctx -> ctx + | None -> ( + match pat with + | Ast.Case_pattern _ -> assert false + | Ast.Case_compound (p, sub) -> + Nlist.fold_left + (fun inner_acc pattern -> + match inner_acc with + | Some _ as v -> v + | None -> + let ctx, pattern = expand_cst ctx pattern in + let pattern = + Ast.word_components_to_string pattern + in + if Glob.test ~pattern scrutinee then begin + Some (exec_subshell ctx sub) + end + else inner_acc) + None p)) + None case_list + in + match res with Some ctx -> ctx | None -> Exit.zero ctx) + + and exec_subshell ctx (term, sep) = + let saved_ctx = ctx in + let e = exec ctx (term, Some sep) in + let v = e >|= fun _ -> saved_ctx in + v + and handle_compound_command ctx v : ctx Exit.t = match v with | Ast.ForClause fc -> handle_for_clause ctx fc | Ast.IfClause if_ -> handle_if_clause ctx if_ | Ast.BraceGroup (term, sep) -> exec ctx (term, Some sep) - | Ast.Subshell (term, sep) -> - let saved_ctx = ctx in - let e = exec ctx (term, Some sep) in - let v = e >|= fun _ -> saved_ctx in - v + | Ast.Subshell s -> exec_subshell ctx s + | Ast.CaseClause cases -> handle_case_clause ctx cases | _ as c -> Fmt.epr "Compound command not supported: %a\n%!" yojson_pp (Ast.compound_command_to_yojson c); diff --git a/src/lib/import.ml b/src/lib/import.ml index c22b088..a2d88e9 100644 --- a/src/lib/import.ml +++ b/src/lib/import.ml @@ -75,6 +75,10 @@ module String = struct end module Glob = struct - let test ~pattern s = List.filter Glob.(test (of_string pattern)) s - let glob_dir ~pattern dir = test ~pattern (Eio.Path.read_dir dir) + let tests ~pattern s = List.filter Glob.(test (of_string pattern)) s + + let test ~pattern s = + match tests ~pattern [ s ] with [ _ ] -> true | _ :: _ | [] -> false + + let glob_dir ~pattern dir = tests ~pattern (Eio.Path.read_dir dir) end diff --git a/test/cases.t b/test/cases.t new file mode 100644 index 0000000..1dce083 --- /dev/null +++ b/test/cases.t @@ -0,0 +1,39 @@ +Case compound command + + $ cat > test.sh << EOF + > + > service () { + > case "\$1" in + > start|begin) + > echo "Starting up service..." + > ;; + > status) + > echo "All good..." + > ;; + > stop) + > echo "Stopping service" + > ;; + > *) + > echo "Unknown command: \$1" + > ;; + > esac + > } + > + > service start + > service status + > service stop + > service foo + > + > EOF + + $ sh test.sh + Starting up service... + All good... + Stopping service + Unknown command: foo + + $ msh test.sh + Starting up service... + All good... + Stopping service + Unknown command: foo