diff --git a/src/lib/built_ins.ml b/src/lib/built_ins.ml index 2f82878..6a2b5a3 100644 --- a/src/lib/built_ins.ml +++ b/src/lib/built_ins.ml @@ -2,6 +2,7 @@ module Options = struct type t = { noclobber : bool; pipefail : bool; + errexit : bool; no_path_expansion : bool; no_unset : bool; async : bool; @@ -11,22 +12,25 @@ module Options = struct { noclobber = false; pipefail = false; + errexit = false; no_path_expansion = false; no_unset = false; async = false; } - let with_options ?noclobber ?pipefail ?async ?no_path_expansion ?no_unset t = + let with_options ?noclobber ?pipefail ?errexit ?async ?no_path_expansion + ?no_unset t = { noclobber = Option.value ~default:t.noclobber noclobber; pipefail = Option.value ~default:t.pipefail pipefail; + errexit = Option.value ~default:t.errexit errexit; async = Option.value ~default:t.async async; no_path_expansion = Option.value ~default:t.no_path_expansion no_path_expansion; no_unset = Option.value ~default:t.no_unset no_unset; } - type posix = [ `Noclobber | `Pipefail | `Noglob | `Nounset ] + type posix = [ `Noclobber | `Pipefail | `Noglob | `Nounset | `Errexit ] type merry = [ `Async ] type option = [ posix | merry ] @@ -42,6 +46,7 @@ module Options = struct | `Pipefail -> with_options ~pipefail:true d | `Noclobber -> with_options ~noclobber:true d | `Noglob -> with_options ~no_path_expansion:true d + | `Errexit -> with_options ~errexit:true d | `Nounset -> with_options ~no_unset:true d | `Async -> with_options ~async:true d) t options @@ -51,9 +56,12 @@ module Options = struct Fmt.pf ppf "%-12s %s@." name (if value then "on" else "off") in let opts = - let { noclobber; pipefail; async; no_path_expansion; no_unset } = opt in + let { noclobber; pipefail; async; no_path_expansion; no_unset; errexit } = + opt + in [ ("pipefail", pipefail); + ("errexit", errexit); ("noclobber", noclobber); ("noglob", no_path_expansion); ("nounset", no_unset); @@ -141,6 +149,7 @@ module Set = struct [ ("pipefail", `Pipefail); ("noclobber", `Noclobber); + ("errexit", `Errexit); ("noglob", `Noglob); ("nounset", `Nounset); ("async", `Async); @@ -150,6 +159,10 @@ module Set = struct let doc = "Options." in Arg.(value & opt_all (enum enum_map) [] & info [ "o" ] ~docv:"OPTION" ~doc) + let errexit = + let doc = "Exit on error, like -o errexit." in + Arg.(value & flag & info [ "e" ] ~docv:"ERREXIT" ~doc) + let noclobber = let doc = "No clobber, like -o noclobber." in Arg.(value & flag & info [ "C" ] ~docv:"NOCLOBBER" ~doc) @@ -163,14 +176,17 @@ module Set = struct Arg.(value & flag & info [ "u" ] ~docv:"NOUNSET" ~doc) let t = - let make_set update noglob noclobber nounset = + let make_set update noglob noclobber nounset errexit = let extra = if noglob then [ `Noglob ] else [] in let extra = if noclobber then `Noclobber :: extra else extra in let extra = if nounset then `Nounset :: extra else extra in + let extra = if errexit then `Errexit :: extra else extra in let update = extra @ update in Set { update; print_options = false } in - let term = Term.(const make_set $ option $ noglob $ noclobber $ nounset) in + let term = + Term.(const make_set $ option $ noglob $ noclobber $ nounset $ errexit) + in let info = let doc = "Set or unset options and positional parameters." in Cmd.info "set" ~doc diff --git a/src/lib/built_ins.mli b/src/lib/built_ins.mli index 2836b67..f8494f4 100644 --- a/src/lib/built_ins.mli +++ b/src/lib/built_ins.mli @@ -2,6 +2,7 @@ module Options : sig type t = { noclobber : bool; pipefail : bool; + errexit : bool; no_path_expansion : bool; no_unset : bool; async : bool; @@ -9,7 +10,7 @@ module Options : sig val to_letters : t -> string - type posix = [ `Noclobber | `Pipefail | `Noglob | `Nounset ] + type posix = [ `Noclobber | `Pipefail | `Noglob | `Nounset | `Errexit ] type merry = [ `Async ] type option = [ posix | merry ] @@ -18,6 +19,7 @@ module Options : sig val with_options : ?noclobber:bool -> ?pipefail:bool -> + ?errexit:bool -> ?async:bool -> ?no_path_expansion:bool -> ?no_unset:bool -> diff --git a/test/simple.t b/test/simple.t index 8051067..f1255c2 100644 --- a/test/simple.t +++ b/test/simple.t @@ -225,6 +225,17 @@ Clobbering files and stuff. msh: cannot overwrite existing file world +Also errexit examples from the specification. + + $ sh -c "set -e; (false; echo one) | cat; echo two" + two + $ msh -c "set -e; (false; echo one) | cat; echo two" + two + $ sh -c "set -e; echo $(false; echo one) two" + one two + $ msh -c "set -e; echo $(false; echo one) two" + one two + 2.7 Sequences A simple, semicolon sequence. diff --git a/vendor/morbig.0.11.0/src/prelexerState.ml b/vendor/morbig.0.11.0/src/prelexerState.ml index ac608eb..d967c9b 100644 --- a/vendor/morbig.0.11.0/src/prelexerState.ml +++ b/vendor/morbig.0.11.0/src/prelexerState.ml @@ -26,6 +26,12 @@ type atom = and quote_kind = SingleQuote | DoubleQuote | OpeningBrace +let pp_atom ppf = function + | AssignmentMark -> Format.fprintf ppf "|=|" + | ArithmeticMark -> Format.fprintf ppf "|+|" + | QuotingMark _ -> Format.fprintf ppf "\"" + | WordComponent (c, _) -> Format.fprintf ppf "%s" c + module AtomBuffer : sig type t val get : t -> atom list @@ -317,7 +323,12 @@ let is_assignment_mark = function let recognize_assignment current = let rhs, prefix = take_until is_assignment_mark (buffer current) in - if prefix = buffer current then ( + let is_empty_assignment = + match rhs, prefix with + | [], AssignmentMark :: _ -> true + | _ -> false + in + if prefix = buffer current && not is_empty_assignment then ( current ) else let buffer = AtomBuffer.make (rhs @ List.tl prefix) in