Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/changes/added/13395.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Allow enabling extensions with `(using ..)` in `dune-workspace` files
(#13395, @spiessimon)
87 changes: 49 additions & 38 deletions src/dune_lang/dune_project.ml
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ include Versioned_file.Make (struct
type t = Stanza.Parser.t list
end)

let workspace_instance ~syntax ~version = { Lang.Instance.syntax; version; data = [] }

let default_dune_language_version =
ref (Syntax.greatest_supported_version_exn Stanza.syntax)
;;
Expand Down Expand Up @@ -321,29 +323,54 @@ module Extension = struct
| Deleted_in _ -> acc
| Extension e -> Not_selected e :: acc))
;;

let explicit_extensions_map explicit_extensions =
match
String.Map.of_list
(List.map explicit_extensions ~f:(fun (e : instance) ->
let syntax =
let (Packed e) = e.extension in
e.syntax
in
Syntax.name syntax, e))
with
| Error (name, _, ext) ->
User_error.raise
~loc:ext.loc
[ Pp.textf "Extension %S specified for the second time." name ]
| Ok map -> map
;;

let parse_extensions ~lang_version =
let open Decoder in
let* explicit_extensions =
multi_field
"using"
(let+ loc = loc
and+ name = located string
and+ ver = located Syntax.Version.decode
and+ parse_args = capture in
(* We don't parse the arguments quite yet as we want to set the
version of extensions before parsing them. *)
instantiate ~dune_lang_ver:lang_version ~loc ~parse_args name ver)
in
String_with_vars.set_decoding_env
(let extensions =
List.map explicit_extensions ~f:(fun (instance : instance) ->
let (Packed { syntax; _ }) = instance.extension in
syntax, instance.version)
in
Pform.Env.initial ~stanza:lang_version ~extensions)
@@
let explicit_extensions_map = explicit_extensions_map explicit_extensions in
return (explicit_extensions_map, explicit_extensions)
;;
end

module Melange_syntax = struct
let name = "melange"
end

let explicit_extensions_map explicit_extensions =
match
String.Map.of_list
(List.map explicit_extensions ~f:(fun (e : Extension.instance) ->
let syntax =
let (Packed e) = e.extension in
e.syntax
in
Syntax.name syntax, e))
with
| Error (name, _, ext) ->
User_error.raise
~loc:ext.loc
[ Pp.textf "Extension %S specified for the second time." name ]
| Ok map -> map
;;

let make_parsing_context ~(lang : Lang.Instance.t) extensions =
let init =
let init = Univ_map.singleton (Syntax.key lang.syntax) (Active lang.version) in
Expand Down Expand Up @@ -382,6 +409,7 @@ let make_parsing_context ~(lang : Lang.Instance.t) extensions =
;;

let interpret_lang_and_extensions ~(lang : Lang.Instance.t) ~explicit_extensions =
let explicit_extensions = Extension.explicit_extensions_map explicit_extensions in
let extensions = Extension.automatic ~explicitly_selected:explicit_extensions in
let parsing_context = make_parsing_context ~lang extensions in
let extension_args, extension_stanzas =
Expand Down Expand Up @@ -520,7 +548,7 @@ let infer ~dir info packages =
let lang = get_dune_lang () in
let name = default_name ~dir ~packages in
let parsing_context, stanza_parser, extension_args =
interpret_lang_and_extensions ~lang ~explicit_extensions:String.Map.empty
interpret_lang_and_extensions ~lang ~explicit_extensions:[]
in
let implicit_transitive_deps = Implicit_transitive_deps.Stanza.default ~lang in
let wrapped_executables = wrapped_executables_default ~lang in
Expand Down Expand Up @@ -885,26 +913,9 @@ let parse ~dir ~(lang : Lang.Instance.t) ~file =
let open Decoder in
fields
@@
let* explicit_extensions =
multi_field
"using"
(let+ loc = loc
and+ name = located string
and+ ver = located Syntax.Version.decode
and+ parse_args = capture in
(* We don't parse the arguments quite yet as we want to set the
version of extensions before parsing them. *)
Extension.instantiate ~dune_lang_ver:lang.version ~loc ~parse_args name ver)
let* explicit_extensions_map, explicit_extensions =
Extension.parse_extensions ~lang_version:lang.version
in
String_with_vars.set_decoding_env
(let extensions =
List.map explicit_extensions ~f:(fun (instance : Extension.instance) ->
let (Extension.Packed { syntax; _ }) = instance.extension in
syntax, instance.version)
in
Pform.Env.initial ~stanza:lang.version ~extensions)
@@
let explicit_extensions = explicit_extensions_map explicit_extensions in
let parsing_context, stanza_parser, extension_args =
interpret_lang_and_extensions ~lang ~explicit_extensions
in
Expand Down Expand Up @@ -1040,7 +1051,7 @@ let parse ~dir ~(lang : Lang.Instance.t) ~file =
let root = dir in
let dialects =
let dialects =
match String.Map.find explicit_extensions Melange_syntax.name with
match String.Map.find explicit_extensions_map Melange_syntax.name with
| Some extension -> (extension.loc, Dialect.rescript) :: dialects
| None -> dialects
in
Expand Down
20 changes: 20 additions & 0 deletions src/dune_lang/dune_project.mli
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ module Lang : sig
what stanzas the user can write in [dune] files. *)

val register : Syntax.t -> Stanza.Parser.t list -> unit

module Instance : sig
type t
end
end

val workspace_instance : syntax:Syntax.t -> version:Syntax.Version.t -> Lang.Instance.t

module Extension : sig
type 'a t

Expand All @@ -76,8 +82,22 @@ module Extension : sig

(** Register experimental extensions that were deleted *)
val register_deleted : name:string -> deleted_in:Syntax.Version.t -> unit

(** An instantiated extension with captured arguments *)
type instance

val parse_extensions
: lang_version:Syntax.Version.t
-> (instance String.Map.t * instance list) Decoder.fields_parser
end

(** Interpret extensions and build parsing context. Returns the parsing context,
stanza parser, and extension arguments. *)
val interpret_lang_and_extensions
: lang:Lang.Instance.t
-> explicit_extensions:Extension.instance list
-> Univ_map.t * Stanza.t list Decoder.t * Univ_map.t

(** Create an anonymous project at the given directory

Optional arguments:
Expand Down
4 changes: 2 additions & 2 deletions src/dune_sexp/syntax.ml
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,8 @@ module Error = struct
User_error.raise
~loc
([ Pp.textf
"%s is available only when %s is enabled in the dune-project file. You must \
enable it using (using %s %s) in your dune-project file."
"%s is available only when %s is enabled in the dune-project or workspace \
file. You must enable it using (using %s %s) in the file."
what
t.name
t.name
Expand Down
21 changes: 18 additions & 3 deletions src/source/workspace.ml
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,8 @@ let find_lock_dir t path =

let add_repo t repo = { t with repos = repo :: t.repos }

(* Why do we even have a separate versioned file here if we're using the same
syntax as the dune project? *)
include Dune_lang.Versioned_file.Make (struct
type t = unit
end)
Expand Down Expand Up @@ -979,7 +981,7 @@ let check_lock_dirs_no_dupes lock_dirs =
]
;;

let step1 clflags =
let step1 ~(lang : Lang.Instance.t) clflags =
let { Clflags.x
; profile = cl_profile
; instrument_with = cl_instrument_with
Expand Down Expand Up @@ -1009,6 +1011,19 @@ let step1 clflags =
let+ x = field in
lazy (Option.value cl ~default:(Lazy.force x))
in
(* This is all dodgy but we get away with it because we don't really allow
extensions to inject their own stanza into the workspace. *)
let* parsing_context, _stanza_parser, _extension_args =
let+ _, explicit_extensions =
Dune_project.Extension.parse_extensions ~lang_version:lang.version
in
let lang =
Dune_project.workspace_instance ~syntax:lang.syntax ~version:lang.version
in
Dune_lang.Dune_project.interpret_lang_and_extensions ~lang ~explicit_extensions
in
Dune_lang.Decoder.set_many parsing_context
@@
Comment thread
rgrinberg marked this conversation as resolved.
let* () = Dune_lang.Versioned_file.no_more_lang
and+ env = env_field_lazy
and+ profile =
Expand Down Expand Up @@ -1111,7 +1126,7 @@ let step1 clflags =
{ Step1.t; config }
;;

let step1 clflags = fields (step1 clflags)
let step1 ~lang clflags = fields (step1 ~lang clflags)

let default clflags =
let { Clflags.x
Expand Down Expand Up @@ -1157,7 +1172,7 @@ let load_step1 clflags p =
parse_contents lb ~f:(fun lang ->
String_with_vars.set_decoding_env
(Pform.Env.initial ~stanza:lang.version ~extensions:[])
(step1 clflags)))
(step1 ~lang clflags)))
;;

let filename = "dune-workspace"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ at the current language version:
File "dune", line 1, characters 0-5:
1 | (mdx)
^^^^^
Error: 'mdx' is available only when mdx is enabled in the dune-project file.
You must enable it using (using mdx ..) in your dune-project file.
Error: 'mdx' is available only when mdx is enabled in the dune-project or
workspace file. You must enable it using (using mdx ..) in the file.
Note however that the currently selected version of dune (1.0) does not
support this plugin. The first version of this plugin is 0.1 and was
introduced in dune 2.4.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Without the toggle, we get an error message for using the new mode subfield
11 | (mode native)
^^^^^^^^^^^^^
Error: 'mode' is available only when mode_specific_stubs is enabled in the
dune-project file. You must enable it using (using mode_specific_stubs 0.1)
in your dune-project file.
dune-project or workspace file. You must enable it using (using
mode_specific_stubs 0.1) in the file.

But the toggle only exists in Dune 3.5
$ cat >dune-project <<EOF
Expand Down
2 changes: 1 addition & 1 deletion test/blackbox-tests/test-cases/github1529.t/run.t
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ file is present.
1 | (menhir (modules parser))
^^^^^^^^^^^^^^^^^^^^^^^^^
Error: 'menhir' is available only when menhir is enabled in the dune-project
file. You must enable it using (using menhir <version>) in your dune-project file.
or workspace file. You must enable it using (using menhir <version>) in the file.
[1]
4 changes: 2 additions & 2 deletions test/blackbox-tests/test-cases/mdx-stanza/using-mdx.t/run.t
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ dune-project
File "dune", line 1, characters 0-5:
1 | (mdx)
^^^^^
Error: 'mdx' is available only when mdx is enabled in the dune-project file.
You must enable it using (using mdx 0.1) in your dune-project file.
Error: 'mdx' is available only when mdx is enabled in the dune-project or
workspace file. You must enable it using (using mdx 0.1) in the file.
[1]
10 changes: 5 additions & 5 deletions test/blackbox-tests/test-cases/menhir/flags-in-workspace.t
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ See #9024.
> EOF

$ dune build 2>&1 | head -n 5
Internal error, please report upstream including the contents of _build/log.
Description:
("Syntax identifier is unset",
{ name = "menhir"
; supported_versions =
File "dune-workspace", line 3, characters 7-29:
3 | (test (menhir_flags --table)))
^^^^^^^^^^^^^^^^^^^^^^
Error: 'menhir_flags' is available only when menhir is enabled in the
dune-project or workspace file. You must enable it using (using menhir 2.1)
[1]
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ It should fail because the syntax extension wasn't enabled in `dune-project`:
1 | (library (name lib) (parameters a))
^^^^^^^^^^^^^^
Error: 'parameters' is available only when oxcaml is enabled in the
dune-project file. You must enable it using (using oxcaml 0.1) in your
dune-project file.
dune-project or workspace file. You must enable it using (using oxcaml 0.1)
in the file.
Note however that oxcaml is experimental and might change without notice in
the future.
[1]
Expand Down
4 changes: 2 additions & 2 deletions test/blackbox-tests/test-cases/oxcaml/library_parameter.t
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ The test build should fails because the oxcaml extension is not available.
2 | (public_name param.intf)
3 | (name param_intf))
Error: 'library_parameter' is available only when oxcaml is enabled in the
dune-project file. You must enable it using (using oxcaml 0.1) in your
dune-project file.
dune-project or workspace file. You must enable it using (using oxcaml 0.1)
in the file.
Note however that oxcaml is experimental and might change without notice in
the future.
[1]
Expand Down
Loading