dune/src/ordered_set_lang.ml

132 lines
3.8 KiB
OCaml
Raw Normal View History

2016-12-02 13:54:32 +00:00
open! Import
2017-07-05 17:12:44 +00:00
module Ast = struct
[@@@warning "-37"]
type expanded = Expanded
type unexpanded = Unexpanded
type ('a, _) t =
| Element : 'a -> ('a, _) t
| Special : Loc.t * string -> ('a, _) t
| Union : ('a, 'b) t list -> ('a, 'b) t
| Diff : ('a, 'b) t * ('a, 'b) t -> ('a, 'b) t
2017-08-23 20:56:32 +00:00
| Include : String_with_vars.t -> ('a, unexpanded) t
2017-07-05 17:12:44 +00:00
end
2016-12-02 13:54:32 +00:00
2017-07-05 17:12:44 +00:00
type t = (string, Ast.expanded) Ast.t
2016-12-02 13:54:32 +00:00
let parse_general t ~f =
2017-02-25 17:53:39 +00:00
let rec of_sexp : Sexp.Ast.t -> _ = function
| Atom (loc, "\\") -> Loc.fail loc "unexpected \\"
| Atom (_, "") as t -> Ast.Element (f t)
| Atom (loc, s) as t ->
2017-07-05 17:12:44 +00:00
if s.[0] = ':' then
Special (loc, String.sub s ~pos:1 ~len:(String.length s - 1))
2016-12-02 13:54:32 +00:00
else
Element (f t)
2017-02-25 17:53:39 +00:00
| List (_, sexps) -> of_sexps [] sexps
2016-12-02 13:54:32 +00:00
and of_sexps acc = function
2017-07-05 17:12:44 +00:00
| Atom (_, "\\") :: sexps -> Diff (Union (List.rev acc), of_sexps [] sexps)
2016-12-02 13:54:32 +00:00
| elt :: sexps ->
2017-07-05 17:12:44 +00:00
of_sexps (of_sexp elt :: acc) sexps
| [] -> Union (List.rev acc)
2016-12-02 13:54:32 +00:00
in
of_sexp t
let t t : t = parse_general t ~f:(function Atom (_, s) -> s | List _ -> assert false)
2017-07-05 17:12:44 +00:00
let eval t ~special_values =
let rec of_ast (t : t) =
let open Ast in
match t with
| Element s -> [s]
| Special (loc, name) ->
2017-08-23 20:56:32 +00:00
begin
match List.assoc name special_values with
| l -> l
| exception Not_found -> Loc.fail loc "undefined symbol %s" name;
end
2017-07-05 17:12:44 +00:00
| Union elts -> List.flatten (List.map elts ~f:of_ast)
| Diff (left, right) ->
2017-08-23 20:56:32 +00:00
let left = of_ast left in
let right = of_ast right in
List.filter left ~f:(fun acc_elt -> not (List.mem acc_elt ~set:right))
2017-07-05 17:12:44 +00:00
in
of_ast t
2016-12-02 13:54:32 +00:00
let is_standard : t -> bool = function
2017-07-05 17:12:44 +00:00
| Ast.Special (_, "standard") -> true
2016-12-02 13:54:32 +00:00
| _ -> false
let eval_with_standard t ~standard =
if is_standard t then
standard (* inline common case *)
else
eval t ~special_values:[("standard", standard)]
2017-07-05 17:12:44 +00:00
let rec map (t : t) ~f : t =
let open Ast in
2016-12-02 13:54:32 +00:00
match t with
2017-07-05 17:12:44 +00:00
| Element s -> Element (f s)
| Special _ -> t
| Union l -> Union (List.map l ~f:(map ~f))
| Diff (l, r) -> Diff (map l ~f, map r ~f)
2016-12-02 13:54:32 +00:00
2017-07-05 17:12:44 +00:00
let standard = Ast.Special (Loc.none, "standard")
2016-12-02 13:54:32 +00:00
2017-07-05 17:12:44 +00:00
let append a b = Ast.Union [a; b]
2017-02-23 10:43:51 +00:00
2016-12-02 13:54:32 +00:00
module Unexpanded = struct
type t = (Sexp.Ast.t, Ast.unexpanded) Ast.t
let t t =
let rec map (t : (Sexp.Ast.t, Ast.expanded) Ast.t) =
2017-07-05 17:12:44 +00:00
let open Ast in
match t with
| Element s -> Element s
| Union [Special (_, "include"); Element fn] ->
2017-08-23 20:56:32 +00:00
Include (String_with_vars.t fn)
| Union [Special (loc, "include"); _]
| Special (loc, "include") ->
2017-08-23 20:56:32 +00:00
Loc.fail loc "(:include expects a single element (do you need to quote the filename?)"
| Special (l, s) -> Special (l, s)
2017-07-05 17:12:44 +00:00
| Union l ->
2017-08-23 20:56:32 +00:00
Union (List.map l ~f:map)
2017-07-05 17:12:44 +00:00
| Diff (l, r) ->
2017-08-23 20:56:32 +00:00
Diff (map l, map r)
2017-07-05 17:12:44 +00:00
in
parse_general t ~f:(fun x -> x) |> map
2017-07-05 17:12:44 +00:00
2016-12-02 13:54:32 +00:00
let standard = standard
2017-02-23 10:43:51 +00:00
let append = append
2017-01-06 17:17:38 +00:00
2017-08-23 20:56:32 +00:00
let files t ~f =
2017-07-05 17:12:44 +00:00
let rec loop acc (t : t) =
let open Ast in
match t with
| Element _
| Special _ -> acc
| Include fn ->
2017-08-23 20:56:32 +00:00
String_set.add (f fn) acc
2017-07-05 17:12:44 +00:00
| Union l ->
2017-08-23 20:56:32 +00:00
List.fold_left l ~init:acc ~f:loop
2017-07-05 17:12:44 +00:00
| Diff (l, r) ->
2017-08-23 20:56:32 +00:00
loop (loop acc l) r
2016-12-02 13:54:32 +00:00
in
loop String_set.empty t
let rec expand (t : t) ~files_contents ~f : (string, Ast.expanded) Ast.t =
2017-07-05 17:12:44 +00:00
let open Ast in
2016-12-02 13:54:32 +00:00
match t with
2017-08-23 20:56:32 +00:00
| Element s -> Element (f (String_with_vars.t s))
2017-07-05 17:12:44 +00:00
| Special (l, s) -> Special (l, s)
| Include fn ->
2017-08-23 20:56:32 +00:00
parse_general (
String_map.find_exn (f fn) files_contents ~string_of_key:(sprintf "%S")
~desc:(fun _ -> "<filename to s-expression>")
) ~f:(fun s -> f (String_with_vars.t s))
2017-07-05 17:12:44 +00:00
| Union l ->
2017-08-23 20:56:32 +00:00
Union (List.map l ~f:(expand ~files_contents ~f))
2017-07-05 17:12:44 +00:00
| Diff (l, r) ->
2017-08-23 20:56:32 +00:00
Diff (expand l ~files_contents ~f, expand r ~files_contents ~f)
2016-12-02 13:54:32 +00:00
end