···9191 | Eval of string list
9292 | Echo of string list
9393 | Trap of trap * [ `Signal of Eunix.Signals.t | `Exit ] list
9494+ | Return of int
9595+9696+let pp_args = Fmt.(list ~sep:(Fmt.any " ") string)
9797+9898+let to_string = function
9999+ | Cd { path = None } -> "cd"
100100+ | Cd { path = Some path } -> Fmt.str "cd %s" path
101101+ | Pwd -> "pwd"
102102+ | Exit n -> Fmt.str "exit %i" n
103103+ | Wait n -> Fmt.str "wait %i" n
104104+ | Return n -> Fmt.str "return %i" n
105105+ | Dot s -> Fmt.str "source %s" s
106106+ | Unset (`Variables vs) -> Fmt.str "unset %a" pp_args vs
107107+ | Unset (`Functions vs) -> Fmt.str "unset %a" pp_args vs
108108+ | Hash _ -> "hash"
109109+ | Command { args; _ } -> Fmt.str "command %a" pp_args args
110110+ | Alias -> "alias"
111111+ | Unalias -> "unalias"
112112+ | Eval s -> Fmt.str "eval %a" pp_args s
113113+ | Echo s -> Fmt.str "echo %a" pp_args s
114114+ | Trap _ -> "trap"
115115+ | Set _ -> "set"
9411695117(* Change Directory *)
96118module Cd = struct
···407429 let name = "dot"
408430end)
409431432432+module Return = struct
433433+ open Cmdliner
434434+435435+ let exit_code =
436436+ let doc = "Exit code." in
437437+ Arg.(value & pos 0 int 0 & info [] ~docv:"EXIT_CODE" ~doc)
438438+439439+ let t =
440440+ let make_return n = Return n in
441441+ let term = Term.(const make_return $ exit_code) in
442442+ let info =
443443+ let doc = "Return from a function or exit code." in
444444+ Cmd.info "return" ~doc
445445+ in
446446+ Cmd.v info term
447447+end
448448+410449let of_args (w : string list) =
411450 let open Cmdliner in
412451 let exec_cmd cmd v =
···433472 | "eval" :: _ as cmd -> exec_cmd cmd Eval.t
434473 | "echo" :: _ as cmd -> exec_cmd cmd Echo.t
435474 | "trap" :: _ as cmd -> exec_cmd cmd Trap.t
475475+ | "return" :: _ as cmd -> exec_cmd cmd Return.t
436476 | _ -> None
+4
src/lib/built_ins.mli
···5050 | Eval of string list
5151 | Echo of string list
5252 | Trap of trap * [ `Signal of Eunix.Signals.t | `Exit ] list
5353+ | Return of int
5454+5555+val to_string : t -> string
5656+(** Serialises a built-in to a string *)
53575458val of_args : string list -> (t, string) result option
5559(** Parses a command-line to the built-ins, errors are returned if parsing. *)
···264264 stdout);
265265 (ctx, Error (127, `Not_found))
266266 | _, (ctx, Some full_path) ->
267267+ Debug.Log.debug (fun f ->
268268+ f "executing %a" Fmt.(list string) (executable :: args));
267269 ( ctx,
268270 E.exec ctx.executor ~delay_reap:(fst reap) ~fds ?stdin ~stdout
269271 ~pgid ~mode ~cwd:(cwd_of_ctx ctx)
···287289 let loop = loop pipeline_switch in
288290 match c with
289291 | Ast.SimpleCommand (Prefixed (prefix, None, _suffix)) :: rest ->
292292+ Debug.Log.debug (fun f ->
293293+ f "assignment-only: %a" yojson_pp
294294+ (Ast.cmd_prefix_to_yojson prefix));
290295 let ctx = collect_assignments ctx prefix in
291296 let job = handle_job job (`Built_in (Exit.ignore ctx)) in
292297 loop (Exit.value ctx) job stdout_of_previous rest
···359364 (true, args, print_command)
360365 | _ -> (false, [], false)
361366 in
362362- (* We handle the [export] built_in explicitly as we need access to the
363363- raw CST *)
367367+ (* We handle the [export] built_in explicitly as we
368368+ need access to the raw CST *)
364369 match executable with
365370 | "export" ->
366371 let updated =
···11351140 | Exit.Zero ctx -> (
11361141 let ctx, cst = word_expansion ctx wc in
11371142 let cst = Ast.Fragment.handle_joins cst in
11381138- (* Fmt.pr "Expanding: %a\n%!" Fmt.(list Ast.Fragment.pp) cst; *)
11391143 match ctx with
11401144 | Exit.Nonzero _ as ctx -> (ctx, acc)
11411145 | Exit.Zero _ as ctx -> (ctx, acc @ cst))))
11421146 (Exit.zero ctx, [])
11431147 swc
11441148 in
11451145- (* Fmt.pr "Arguments: %a\n%!" Fmt.(list Ast.Fragment.pp) fs; *)
11461149 (ctx, List.map Ast.Fragment.to_string fs)
1147115011481151 and handle_built_in ~rdrs ~(stdout : Eio_unix.sink_ty Eio.Flow.sink)
11491152 (ctx : ctx) v =
11501153 let rdrs = ctx.rdrs @ rdrs in
11541154+ Debug.Log.debug (fun f -> f "built-in: %s" (Built_ins.to_string v));
11511155 Eunix.with_redirections rdrs @@ fun () ->
11521156 match v with
11531157 | Built_ins.Cd { path } ->
···11811185 { Exit.default_should_exit with interactive = `Yes }
11821186 in
11831187 Exit.nonzero ~should_exit ctx n
11881188+ | Return n -> Exit.nonzero ctx n
11841189 | Set { update; print_options } ->
11851190 let v =
11861191 Exit.zero
+1
src/lib/merry.ml
···88module Interactive = Interactive
99module Built_ins = Built_ins
1010module History = History
1111+module Debug = Debug
11121213module Variable = struct
1314 type t
+1
src/lib/merry.mli
···77module Interactive = Interactive
88module Built_ins = Built_ins
99module History = History
1010+module Debug = Debug
10111112module Variable : sig
1213 type t