Skip to content

Commit

Permalink
Add an 'exec' label to execute include OCaml blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
gpetiot committed Mar 25, 2024
1 parent e2b6532 commit bf48112
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 58 deletions.
90 changes: 69 additions & 21 deletions lib/block.ml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ let locate_errors ~loc r =
(fun l -> List.map (fun (`Msg m) -> `Msg (locate_error_msg ~loc m)) l)
r

module OCaml_kind = struct
type t = Impl | Intf

let infer_from_file file =
match Filename.(remove_extension (basename file), extension file) with
| _, (".ml" | ".mlt" | ".eliom") -> Some Impl
| _, (".mli" | ".eliomi") -> Some Intf
| _ -> None
end

module Header = struct
type t = Shell of [ `Sh | `Bash ] | OCaml | Other of string

Expand Down Expand Up @@ -85,7 +95,14 @@ type ocaml_value = {
}

type toplevel_value = { env : Ocaml_env.t; non_det : Label.non_det option }
type include_ocaml_file = { part_included : string option }

type include_ocaml_file = {
part_included : string option;
ocaml_value : ocaml_value option;
kind : OCaml_kind.t;
exec : bool;
}

type include_other_file = { header : Header.t option }

type include_file_kind =
Expand Down Expand Up @@ -118,6 +135,12 @@ type t = {
value : value;
}

let get_ocaml_value t =
match t.value with
| OCaml ocaml_value -> Some ocaml_value
| Include { file_kind = Fk_ocaml { ocaml_value; _ }; _ } -> ocaml_value
| _ -> None

let dump_section = Fmt.(Dump.pair int string)

let header t =
Expand Down Expand Up @@ -190,24 +213,22 @@ let pp_error ?syntax ?delim ppf outputs =
outputs err_delim
| _ -> ()

let has_output t =
match t.value with
| OCaml { errors = []; _ } -> false
| OCaml { errors = _; _ } -> true
let has_errors t =
match get_ocaml_value t with
| Some { errors = _ :: _; _ } -> true
| _ -> false

let pp_value ?syntax ppf t =
let delim = t.delim in
match t.value with
| OCaml { errors = []; _ } -> ()
| OCaml { errors; _ } ->
match get_ocaml_value t with
| Some { errors; _ } ->
let errors = error_padding errors in
pp_error ?syntax ?delim ppf errors
| _ -> ()

let pp_footer ?syntax ppf t =
let delim =
if has_output t then (
if has_errors t then (
pp_value ?syntax ppf t;
None)
else t.delim
Expand Down Expand Up @@ -288,6 +309,13 @@ let non_det t =
| Include _ | Raw _ -> None

let skip t = t.skip

let exec t =
match t.value with
| Include { file_kind = Fk_ocaml { exec; _ }; _ } -> exec
| Include _ | Raw _ -> false
| _ -> true

let set_variables t = t.set_variables
let unset_variables t = t.unset_variables
let value t = t.value
Expand Down Expand Up @@ -349,6 +377,7 @@ type block_config = {
env : string option;
dir : string option;
skip : bool;
exec : bool;
version : (Label.Relation.t * Ocaml_version.t) option;
os_type : (Label.Relation.t * string) option;
set_variables : (string * string) list;
Expand All @@ -369,6 +398,7 @@ let get_block_config l =
env = get_label (function Env x -> Some x | _ -> None) l;
dir = get_label (function Dir x -> Some x | _ -> None) l;
skip = List.exists (function Label.Skip -> true | _ -> false) l;
exec = List.exists (function Label.Exec -> true | _ -> false) l;
version = get_label (function Version (x, y) -> Some (x, y) | _ -> None) l;
os_type = get_label (function Os_type (x, y) -> Some (x, y) | _ -> None) l;
set_variables =
Expand All @@ -378,13 +408,16 @@ let get_block_config l =
file_inc = get_label (function File x -> Some x | _ -> None) l;
}

let mk_ocaml_value env non_det errors header =
{ env = Ocaml_env.mk env; non_det; errors; header }

let mk_ocaml ~loc ~config ~header ~contents ~errors =
let kind = "OCaml" in
match config with
| { file_inc = None; part = None; env; non_det; _ } -> (
(* TODO: why does this call guess_ocaml_kind when infer_block already did? *)
match guess_ocaml_kind contents with
| `Code -> Ok (OCaml { env = Ocaml_env.mk env; non_det; errors; header })
| `Code -> Ok (OCaml (mk_ocaml_value env non_det errors header))
| `Toplevel ->
loc_error ~loc "toplevel syntax is not allowed in OCaml blocks.")
| { file_inc = Some _; _ } -> label_not_allowed ~loc ~label:"file" ~kind
Expand Down Expand Up @@ -422,23 +455,38 @@ let mk_toplevel ~loc ~config ~contents ~errors =
let mk_include ~loc ~config ~header ~errors =
let kind = "include" in
match config with
| { file_inc = Some file_included; part; non_det = None; env = None; _ } -> (
let* () = check_no_errors ~loc errors in
match header with
| Some Header.OCaml ->
let file_kind = Fk_ocaml { part_included = part } in
| { file_inc = Some file_included; part; non_det; env; exec; _ } -> (
let kind =
match header with
| Some Header.OCaml -> `OCaml
| None -> (
match OCaml_kind.infer_from_file file_included with
| Some _ -> `OCaml
| None -> `Other)
| _ -> `Other
in
match kind with
| `OCaml ->
let kind =
Util.Option.value ~default:OCaml_kind.Impl
(OCaml_kind.infer_from_file file_included)
in
let part_included = part in
let ocaml_value =
match kind with
| Impl -> Some (mk_ocaml_value env non_det errors header)
| Intf -> None
in
let file_kind = Fk_ocaml { part_included; ocaml_value; kind; exec } in
Ok (Include { file_included; file_kind })
| _ -> (
| `Other -> (
match part with
| None ->
let file_kind = Fk_other { header } in
Ok (Include { file_included; file_kind })
| Some _ ->
label_not_allowed ~loc ~label:"part" ~kind:"non-OCaml include"))
| { file_inc = None; _ } -> label_required ~loc ~label:"file" ~kind
| { non_det = Some _; _ } ->
label_not_allowed ~loc ~label:"non-deterministic" ~kind
| { env = Some _; _ } -> label_not_allowed ~loc ~label:"env" ~kind

let infer_block ~loc ~config ~header ~contents ~errors =
match config with
Expand Down Expand Up @@ -523,12 +571,12 @@ let from_raw raw =
~delim:None

let is_active ?section:s t =
let active =
let active_section =
match s with
| Some p -> (
match t.section with
| Some s -> Re.execp (Re.Perl.compile_pat p) (snd s)
| None -> Re.execp (Re.Perl.compile_pat p) "")
| None -> true
in
active && t.version_enabled && t.os_type_enabled && not t.skip
active_section && t.version_enabled && t.os_type_enabled && not t.skip
10 changes: 10 additions & 0 deletions lib/block.mli
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

(** Code blocks headers. *)

module OCaml_kind : sig
type t = Impl | Intf
end

module Header : sig
type t = Shell of [ `Sh | `Bash ] | OCaml | Other of string

Expand Down Expand Up @@ -47,6 +51,9 @@ type include_ocaml_file = {
part_included : string option;
(** [part_included] is the part of the file to synchronize with.
If lines is not specified synchronize the whole file. *)
ocaml_value : ocaml_value option;
kind : OCaml_kind.t;
exec : bool;
}

type include_other_file = { header : Header.t option }
Expand Down Expand Up @@ -168,6 +175,9 @@ val unset_variables : t -> string list
val skip : t -> bool
(** [skip t] is true iff [skip] is in the labels of [t]. *)

val exec : t -> bool
(** [exec t] is true iff [exec] is in the labels of [t]. *)

val value : t -> value
(** [value t] is [t]'s value. *)

Expand Down
15 changes: 8 additions & 7 deletions lib/dep.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@

type t = File of string | Dir of string

let of_block block =
let of_block b =
let open Block in
match (directory block, file block, skip block) with
| Some d, Some f, false -> Some (File (Filename.concat d f))
| Some d, None, false -> Some (Dir d)
| None, Some f, false -> Some (File f)
| None, None, false -> None
| _, _, true -> None
let block b = (not (skip b)) || exec b in
match (directory b, file b, block b) with
| Some d, Some f, true -> Some (File (Filename.concat d f))
| Some d, None, true -> Some (Dir d)
| None, Some f, true -> Some (File f)
| None, None, true -> None
| _, _, false -> None

let of_lines =
let open Document in
Expand Down
3 changes: 3 additions & 0 deletions lib/label.ml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ type t =
| Part of string
| Env of string
| Skip
| Exec
| Non_det of non_det option
| Version of Relation.t * Ocaml_version.t
| Os_type of Relation.t * string
Expand All @@ -111,6 +112,7 @@ let pp ppf = function
| Part p -> Fmt.pf ppf "part=%s" p
| Env e -> Fmt.pf ppf "env=%s" e
| Skip -> Fmt.string ppf "skip"
| Exec -> Fmt.string ppf "exec"
| Non_det None -> Fmt.string ppf "non-deterministic"
| Non_det (Some Nd_output) -> Fmt.string ppf "non-deterministic=output"
| Non_det (Some Nd_command) -> Fmt.string ppf "non-deterministic=command"
Expand Down Expand Up @@ -159,6 +161,7 @@ let requires_eq_value ~label ~value f =
let interpret label value =
match label with
| "skip" -> doesnt_accept_value ~label ~value Skip
| "exec" -> doesnt_accept_value ~label ~value Exec
| "ocaml" -> doesnt_accept_value ~label ~value (Block_kind OCaml)
| "cram" -> doesnt_accept_value ~label ~value (Block_kind Cram)
| "toplevel" -> doesnt_accept_value ~label ~value (Block_kind Toplevel)
Expand Down
1 change: 1 addition & 0 deletions lib/label.mli
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type t =
| Part of string
| Env of string
| Skip
| Exec (** Only for include blocks. *)
| Non_det of non_det option
| Version of Relation.t * Ocaml_version.t
| Os_type of Relation.t * string
Expand Down
Loading

0 comments on commit bf48112

Please sign in to comment.