@@ -54,22 +54,42 @@ let invalid_variable_error ~loc variable =
5454 [ Pp. textf " Variable %S is not supported." (OpamVariable. to_string variable) ]
5555;;
5656
57- let opam_variable_to_slang ~loc packages variable =
57+ let opam_variable_to_slang ~loc ~ packages_in_solution ~ for_string_interp packages variable =
5858 let variable_string = OpamVariable. to_string variable in
59+ let variable_name = Package_variable_name. of_string variable_string in
5960 let convert_with_package_name package_name =
6061 match is_valid_package_variable_name variable_string with
6162 | false -> Error (invalid_variable_error ~loc variable)
6263 | true ->
63- let pform =
64- let name = Package_variable_name. of_string variable_string in
65- let scope : Package_variable.Scope.t =
66- match package_name with
67- | None -> Self
68- | Some p -> Package (Package_name. of_opam_package_name p)
69- in
70- Package_variable. to_pform { Package_variable. name; scope }
71- in
72- Ok (Slang. pform pform)
64+ (match package_name with
65+ | Some p ->
66+ let pkg_name = Package_name. of_opam_package_name p in
67+ if Package_name.Map. mem packages_in_solution pkg_name
68+ then (
69+ let pform =
70+ Package_variable. to_pform
71+ { Package_variable. name = variable_name; scope = Package pkg_name }
72+ in
73+ Ok (Slang. pform pform))
74+ else if for_string_interp
75+ then (
76+ let value =
77+ Package_variable_name. absent_package_value variable_name
78+ |> Option. value ~default: " "
79+ in
80+ Ok (Slang. text value))
81+ else (
82+ let pform =
83+ Package_variable. to_pform
84+ { Package_variable. name = variable_name; scope = Package pkg_name }
85+ in
86+ Ok (Slang. pform pform))
87+ | None ->
88+ let pform =
89+ Package_variable. to_pform
90+ { Package_variable. name = variable_name; scope = Self }
91+ in
92+ Ok (Slang. pform pform))
7393 in
7494 match packages with
7595 | [] ->
@@ -114,12 +134,21 @@ let desugar_special_string_interpolation_syntax
114134 | _ -> fident
115135;;
116136
117- let opam_fident_to_slang ~loc fident =
137+ let opam_fident_to_slang ~loc ~ packages_in_solution ~ for_string_interp fident =
118138 let open Result.O in
119139 let packages, variable, string_converter =
120140 OpamFilter. desugar_fident fident |> desugar_special_string_interpolation_syntax
121141 in
122- let + slang = opam_variable_to_slang ~loc packages variable in
142+ (* When there's a string_converter (?then:else syntax), don't substitute
143+ absent package values - let catch_undefined_var handle it at build time. *)
144+ let for_string_interp =
145+ match string_converter with
146+ | Some _ -> false
147+ | None -> for_string_interp
148+ in
149+ let + slang =
150+ opam_variable_to_slang ~loc ~packages_in_solution ~for_string_interp packages variable
151+ in
123152 match string_converter with
124153 | None -> slang
125154 | Some (then_ , else_ ) ->
@@ -133,11 +162,12 @@ let opam_fident_to_slang ~loc fident =
133162 Slang. if_ condition ~then_: (Slang. text then_) ~else_: (Slang. text else_)
134163;;
135164
136- let opam_raw_fident_to_slang ~loc raw_ident =
137- OpamTypesBase. filter_ident_of_string raw_ident |> opam_fident_to_slang ~loc
165+ let opam_raw_fident_to_slang ~loc ~packages_in_solution ~for_string_interp raw_ident =
166+ OpamTypesBase. filter_ident_of_string raw_ident
167+ |> opam_fident_to_slang ~loc ~packages_in_solution ~for_string_interp
138168;;
139169
140- let opam_string_to_slang ~package ~loc opam_string =
170+ let opam_string_to_slang ~packages_in_solution ~ package ~loc opam_string =
141171 Re.Seq. split_full OpamFilter. string_interp_regex opam_string
142172 |> Seq. map ~f: (function
143173 | `Text text -> Ok (Slang. text text)
@@ -148,7 +178,7 @@ let opam_string_to_slang ~package ~loc opam_string =
148178 when String. starts_with ~prefix: " %{" interp
149179 && String. ends_with ~suffix: " }%" interp ->
150180 let ident = String. sub ~pos: 2 ~len: (String. length interp - 4 ) interp in
151- opam_raw_fident_to_slang ~loc ident
181+ opam_raw_fident_to_slang ~loc ~packages_in_solution ~for_string_interp: true ident
152182 | other ->
153183 Error
154184 (User_error. make
@@ -220,11 +250,13 @@ let resolve_depopts ~resolve depopts =
220250 These two Slang operators are used to emulate Opam's undefined value
221251 semantics.
222252*)
223- let filter_to_blang ~package ~loc filter =
253+ let filter_to_blang ~packages_in_solution ~ package ~loc filter =
224254 let filter_to_slang (filter : OpamTypes.filter ) =
225255 match filter with
226- | FString s -> opam_string_to_slang ~package ~loc s
227- | FIdent fident -> opam_fident_to_slang ~loc fident
256+ | FString s -> opam_string_to_slang ~packages_in_solution ~package ~loc s
257+ | FIdent fident ->
258+ (* FIdent in filter context is truthy, so don't substitute absent values *)
259+ opam_fident_to_slang ~loc ~packages_in_solution ~for_string_interp: false fident
228260 | other ->
229261 Code_error. raise
230262 " The opam file parser should only allow identifiers and strings in places where \
@@ -273,6 +305,7 @@ let filter_to_blang ~package ~loc filter =
273305;;
274306
275307let opam_commands_to_actions
308+ ~packages_in_solution
276309 get_solver_var
277310 loc
278311 package
@@ -293,8 +326,13 @@ let opam_commands_to_actions
293326 let slang =
294327 let + slang =
295328 match simple_arg with
296- | CString s -> opam_string_to_slang ~package ~loc s
297- | CIdent ident -> opam_raw_fident_to_slang ~loc ident
329+ | CString s -> opam_string_to_slang ~packages_in_solution ~package ~loc s
330+ | CIdent ident ->
331+ opam_raw_fident_to_slang
332+ ~loc
333+ ~packages_in_solution
334+ ~for_string_interp: true
335+ ident
298336 in
299337 Slang. simplify slang
300338 in
@@ -304,7 +342,8 @@ let opam_commands_to_actions
304342 | None -> slang
305343 | Some filter ->
306344 let + filter_blang =
307- filter_to_blang ~package ~loc filter >> | Slang. simplify_blang
345+ filter_to_blang ~packages_in_solution ~package ~loc filter
346+ >> | Slang. simplify_blang
308347 and + slang = slang in
309348 let filter_blang_handling_undefined =
310349 (* Wrap the blang filter so that if any undefined
@@ -331,7 +370,8 @@ let opam_commands_to_actions
331370 | None -> Ok action
332371 | Some filter ->
333372 let + condition =
334- filter_to_blang ~package ~loc filter >> | Slang. simplify_blang
373+ filter_to_blang ~packages_in_solution ~package ~loc filter
374+ >> | Slang. simplify_blang
335375 in
336376 Action. When (condition, action)
337377 in
@@ -358,14 +398,15 @@ let opam_commands_to_actions
358398 solving. Opam allows depexts to be filtered by arbitrary filter expressions,
359399 which is why the slang dsl is needed as opposed to (say) a map from
360400 distro/version to depext name. *)
361- let depexts_to_conditional_external_dependencies package depexts =
401+ let depexts_to_conditional_external_dependencies ~ packages_in_solution package depexts =
362402 let open Result.O in
363403 List. map depexts ~f: (fun (sys_pkgs , filter ) ->
364404 let external_package_names =
365405 OpamSysPkg.Set. to_list_map OpamSysPkg. to_string sys_pkgs
366406 in
367407 let + condition =
368- filter_to_blang ~package ~loc: Loc. none filter >> | Slang. simplify_blang
408+ filter_to_blang ~packages_in_solution ~package ~loc: Loc. none filter
409+ >> | Slang. simplify_blang
369410 in
370411 let enabled_if =
371412 if Slang.Blang. equal condition Slang.Blang. true_
@@ -468,6 +509,7 @@ let opam_package_to_lock_file_pkg
468509 Solver_stats.Updater. expand_variable stats_updater variable_name;
469510 Solver_env. get solver_env variable_name
470511 in
512+ let packages_in_solution = version_by_package_name in
471513 let * build_command =
472514 if Resolved_package. dune_build resolved_package
473515 then Ok (Some Lock_dir.Build_command. Dune )
@@ -491,13 +533,18 @@ let opam_package_to_lock_file_pkg
491533 | None -> Ok action
492534 | Some filter ->
493535 let + blang =
494- filter_to_blang ~package: opam_package ~loc: Loc. none filter
536+ filter_to_blang
537+ ~packages_in_solution
538+ ~package: opam_package
539+ ~loc: Loc. none
540+ filter
495541 >> | Slang. simplify_blang
496542 in
497543 Action. When (blang, action))
498544 |> Result.List. all
499545 and + build_step =
500546 opam_commands_to_actions
547+ ~packages_in_solution
501548 get_solver_var
502549 loc
503550 opam_package
@@ -528,6 +575,7 @@ let opam_package_to_lock_file_pkg
528575 if portable_lock_dir
529576 then
530577 depexts_to_conditional_external_dependencies
578+ ~packages_in_solution
531579 opam_package
532580 (OpamFile.OPAM. depexts opam_file)
533581 else (
@@ -549,7 +597,7 @@ let opam_package_to_lock_file_pkg
549597 in
550598 let + install_command =
551599 OpamFile.OPAM. install opam_file
552- |> opam_commands_to_actions get_solver_var loc opam_package
600+ |> opam_commands_to_actions ~packages_in_solution get_solver_var loc opam_package
553601 >> | make_action
554602 >> | Option. map ~f: (fun action -> lockfile_field_choice (build_env action))
555603 >> | Option. value ~default: Lock_dir.Conditional_choice. empty
0 commit comments