Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

%<...>% path expansion notation #2927

Closed
wants to merge 1 commit into from
Closed
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
45 changes: 27 additions & 18 deletions src/format/opamFilter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,22 @@ let rec map_up f = function
| FUndef x -> f (FUndef (map_up f x))
| (FBool _ | FString _ | FIdent _) as flt -> f flt

(* ["%%"], ["%{xxx}%"], or ["%{xxx"] if unclosed *)
let string_interp_regex =
(* ["%%"], ["%{xxx}%"], or ["%{xxx"] if unclosed.
Path expansion versions use ['<'] and ['>'] instead of ['{'] and ['}']. *)
let (string_interp_regex, path_interp_regex) =
let open Re in
let notclose =
let notclose c =
rep (alt [
diff notnl (set "}");
seq [char '}'; alt [diff notnl (set "%"); stop] ]
diff notnl (set (String.make 1 c));
seq [char c; alt [diff notnl (set "%"); stop] ]
])
in
compile (alt [
str "%%";
seq [str "%{"; group (greedy notclose); opt (group (str "}%"))];
])
let string_interp =
[str "%%";
seq [str "%{"; group (greedy (notclose '}')); opt (group (str "}%"))]]
in
compile (alt string_interp),
compile (alt ((seq [str "%<"; group (greedy (notclose '>')); opt (group (str ">%"))])::string_interp))

let escape_expansions =
Re.replace_string Re.(compile @@ char '%') ~by:"%%"
Expand Down Expand Up @@ -204,9 +207,9 @@ let resolve_ident ?(no_undef_expand=false) env fident =
| Some (S s) -> FString s
| None -> FUndef (FIdent fident))

(* Resolves ["%{x}%"] string interpolations *)
let expand_string ?(partial=false) ?default env text =
let default fident = match default, partial with
(* Resolves ["%{x}%"] and ["%<x>%"] string interpolations *)
let rec expand_string_aux ?(regex=path_interp_regex) ?(partial=false) ?default env text =
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the use of ~regex means that this only introduces one recursive call - expansion of %{...}% within %<...>%. It doesn't add recursive expansion of variables by accident!

let default_f fident = match default, partial with
| None, false -> None
| Some df, false -> Some (df fident)
| None, true -> Some (Printf.sprintf "%%{%s}%%" fident)
Expand All @@ -222,15 +225,21 @@ let expand_string ?(partial=false) ?default env text =
let f g =
let str = Re.Group.get g 0 in
if str = "%%" then (if partial then "%%" else "%")
else if not (OpamStd.String.ends_with ~suffix:"}%" str) then
(log "ERR: Unclosed variable replacement in %S\n" str;
else if not (OpamStd.String.ends_with ~suffix:(if str.[1] = '{' then "}%" else ">%") str) then
(log "ERR: Unclosed %s in %S\n" (if str.[1] = '{' then "variable replacement" else "path expansion") str;
str)
else
let fident = String.sub str 2 (String.length str - 4) in
resolve_ident ~no_undef_expand:partial env (filter_ident_of_string fident)
|> value_string ?default:(default fident)
if str.[1] = '<' then
expand_string_aux ~regex:string_interp_regex ~partial ?default env (String.sub str 2 (String.length str - 4))
|> String.map (function '/' -> Filename.dir_sep.[0] | c -> c)
else
let fident = String.sub str 2 (String.length str - 4) in
resolve_ident ~no_undef_expand:partial env (filter_ident_of_string fident)
|> value_string ?default:(default_f fident)
in
Re.replace string_interp_regex ~f text
Re.replace regex ~f text

let expand_string = expand_string_aux ~regex:path_interp_regex

let unclosed_expansions text =
let re =
Expand Down