Add a user context to Of_sexp.t

Signed-off-by: Jeremie Dimino <jeremie@dimino.org>
This commit is contained in:
Jeremie Dimino 2018-06-19 11:53:16 +01:00
parent 4922faf18a
commit 0c6edde131
16 changed files with 91 additions and 52 deletions

View File

@ -626,7 +626,8 @@ module Promotion = struct
let load_db () = let load_db () =
if Path.exists db_file then if Path.exists db_file then
Sexp.Of_sexp.( Sexp.Of_sexp.(
parse (list File.t) (Io.Sexp.load db_file ~mode:Many_as_one)) parse (list File.t) Univ_map.empty
(Io.Sexp.load db_file ~mode:Many_as_one))
else else
[] []

View File

@ -19,7 +19,7 @@ module Promoted_to_delete = struct
let load () = let load () =
if Path.exists fn then if Path.exists fn then
Io.Sexp.load fn ~mode:Many Io.Sexp.load fn ~mode:Many
|> List.map ~f:(Sexp.Of_sexp.parse Path.t) |> List.map ~f:(Sexp.Of_sexp.parse Path.t Univ_map.empty)
else else
[] []
@ -1220,7 +1220,8 @@ let update_universe t =
Utils.Cached_digest.remove universe_file; Utils.Cached_digest.remove universe_file;
let n = let n =
if Path.exists universe_file then if Path.exists universe_file then
Sexp.Of_sexp.(parse int) (Io.Sexp.load ~mode:Single universe_file) + 1 Sexp.Of_sexp.(parse int) Univ_map.empty
(Io.Sexp.load ~mode:Single universe_file) + 1
else else
0 0
in in

View File

@ -115,7 +115,7 @@ let user_config_file =
"dune/config" "dune/config"
let load_config_file p = let load_config_file p =
(Sexp.Of_sexp.parse t) (Io.Sexp.load p ~mode:Many_as_one) (Sexp.Of_sexp.parse t Univ_map.empty) (Io.Sexp.load p ~mode:Many_as_one)
let load_user_config_file () = let load_user_config_file () =
if Path.exists user_config_file then if Path.exists user_config_file then

View File

@ -425,7 +425,7 @@ let create_for_opam ?root ~env ~targets ~profile ~switch ~name
>>= fun s -> >>= fun s ->
let vars = let vars =
Usexp.parse_string ~fname:"<opam output>" ~mode:Single s Usexp.parse_string ~fname:"<opam output>" ~mode:Single s
|> Sexp.Of_sexp.(parse (list (pair string string))) |> Sexp.Of_sexp.(parse (list (pair string string)) Univ_map.empty)
|> Env.Map.of_list_multi |> Env.Map.of_list_multi
|> Env.Map.mapi ~f:(fun var values -> |> Env.Map.mapi ~f:(fun var values ->
match List.rev values with match List.rev values with

View File

@ -143,7 +143,7 @@ module Lang = struct
} = first_line } = first_line
in in
let ver = let ver =
Sexp.Of_sexp.parse Syntax.Version.t Sexp.Of_sexp.parse Syntax.Version.t Univ_map.empty
(Atom (ver_loc, Sexp.Atom.of_string ver)) in (Atom (ver_loc, Sexp.Atom.of_string ver)) in
match Hashtbl.find langs name with match Hashtbl.find langs name with
| None -> | None ->
@ -269,7 +269,8 @@ let load_dune_project ~dir packages =
Io.with_lexbuf_from_file fname ~f:(fun lb -> Io.with_lexbuf_from_file fname ~f:(fun lb ->
let lang_stanzas = Lang.parse (Dune_lexer.first_line lb) in let lang_stanzas = Lang.parse (Dune_lexer.first_line lb) in
let sexp = Sexp.Parser.parse lb ~mode:Many_as_one in let sexp = Sexp.Parser.parse lb ~mode:Many_as_one in
Sexp.Of_sexp.parse (parse ~dir ~lang_stanzas ~packages ~file:fname) sexp) Sexp.Of_sexp.parse (parse ~dir ~lang_stanzas ~packages ~file:fname)
Univ_map.empty sexp)
let make_jbuilder_project ~dir packages = let make_jbuilder_project ~dir packages =
let t = let t =

View File

@ -60,7 +60,7 @@ module Dune_file = struct
List.partition_map sexps ~f:(fun sexp -> List.partition_map sexps ~f:(fun sexp ->
match (sexp : Sexp.Ast.t) with match (sexp : Sexp.Ast.t) with
| List (_, (Atom (_, A "ignored_subdirs") :: _)) -> | List (_, (Atom (_, A "ignored_subdirs") :: _)) ->
Left (Sexp.Of_sexp.parse stanza sexp) Left (Sexp.Of_sexp.parse stanza Univ_map.empty sexp)
| _ -> Right sexp) | _ -> Right sexp)
in in
let ignored_subdirs = let ignored_subdirs =

View File

@ -3,7 +3,8 @@ open Import
let parse_sub_systems sexps = let parse_sub_systems sexps =
List.filter_map sexps ~f:(fun sexp -> List.filter_map sexps ~f:(fun sexp ->
let name, ver, data = let name, ver, data =
Sexp.Of_sexp.(parse (triple string (located Syntax.Version.t) raw)) sexp Sexp.Of_sexp.(parse (triple string (located Syntax.Version.t) raw)
Univ_map.empty) sexp
in in
match Sub_system_name.get name with match Sub_system_name.get name with
| None -> | None ->
@ -24,7 +25,7 @@ let parse_sub_systems sexps =
Syntax.Versioned_parser.find_exn M.parsers ~loc:vloc Syntax.Versioned_parser.find_exn M.parsers ~loc:vloc
~data_version:ver ~data_version:ver
in in
M.T (Sexp.Of_sexp.parse parser data)) M.T (Sexp.Of_sexp.parse parser Univ_map.empty data))
let of_sexp = let of_sexp =
let open Sexp.Of_sexp in let open Sexp.Of_sexp in
@ -42,7 +43,8 @@ let of_sexp =
parse_sub_systems l) parse_sub_systems l)
] ]
let load fname = Sexp.Of_sexp.parse of_sexp (Io.Sexp.load ~mode:Single fname) let load fname =
Sexp.Of_sexp.parse of_sexp Univ_map.empty (Io.Sexp.load ~mode:Single fname)
let gen confs = let gen confs =
let sexps = let sexps =

View File

@ -1354,7 +1354,7 @@ module Stanzas = struct
exception Include_loop of Path.t * (Loc.t * Path.t) list exception Include_loop of Path.t * (Loc.t * Path.t) list
let rec parse stanza_parser ~current_file ~include_stack sexps = let rec parse stanza_parser ~current_file ~include_stack sexps =
List.concat_map sexps ~f:(Sexp.Of_sexp.parse stanza_parser) List.concat_map sexps ~f:(Sexp.Of_sexp.parse stanza_parser Univ_map.empty)
|> List.concat_map ~f:(function |> List.concat_map ~f:(function
| Include (loc, fn) -> | Include (loc, fn) ->
let include_stack = (loc, current_file) :: include_stack in let include_stack = (loc, current_file) :: include_stack in

View File

@ -181,7 +181,7 @@ module Unexpanded = struct
match t with match t with
| Element x -> Element x | Element x -> Element x
| Union [Special (_, "include"); Element fn] -> | Union [Special (_, "include"); Element fn] ->
Include (Sexp.Of_sexp.parse String_with_vars.t fn) Include (Sexp.Of_sexp.parse String_with_vars.t Univ_map.empty fn)
| Union [Special (loc, "include"); _] | Union [Special (loc, "include"); _]
| Special (loc, "include") -> | Special (loc, "include") ->
Loc.fail loc "(:include expects a single element (do you need to quote the filename?)" Loc.fail loc "(:include expects a single element (do you need to quote the filename?)"
@ -246,7 +246,8 @@ module Unexpanded = struct
let open Ast in let open Ast in
match t with match t with
| Element s -> | Element s ->
Element (Sexp.Ast.loc s, f (Sexp.Of_sexp.parse String_with_vars.t s)) Element (Sexp.Ast.loc s,
f (Sexp.Of_sexp.parse String_with_vars.t Univ_map.empty s))
| Special (l, s) -> Special (l, s) | Special (l, s) -> Special (l, s)
| Include fn -> | Include fn ->
let sexp = let sexp =
@ -262,7 +263,8 @@ module Unexpanded = struct
] ]
in in
parse_general sexp ~f:(fun sexp -> parse_general sexp ~f:(fun sexp ->
(Sexp.Ast.loc sexp, f (Sexp.Of_sexp.parse String_with_vars.t sexp))) (Sexp.Ast.loc sexp,
f (Sexp.Of_sexp.parse String_with_vars.t Univ_map.empty sexp)))
| Union l -> Union (List.map l ~f:expand) | Union l -> Union (List.map l ~f:expand)
| Diff (l, r) -> | Diff (l, r) ->
Diff (expand l, expand r) Diff (expand l, expand r)

View File

@ -182,7 +182,7 @@ module Jbuild_driver = struct
let make name info : (Pp.t * Driver.t) Lazy.t = lazy ( let make name info : (Pp.t * Driver.t) Lazy.t = lazy (
let info = let info =
Sexp.parse_string ~mode:Single ~fname:"<internal>" info Sexp.parse_string ~mode:Single ~fname:"<internal>" info
|> Sexp.Of_sexp.parse Driver.Info.parse |> Sexp.Of_sexp.parse Driver.Info.parse Univ_map.empty
in in
(Pp.of_string name, (Pp.of_string name,
{ info { info

View File

@ -100,11 +100,15 @@ module Of_sexp = struct
; known : string list ; known : string list
} }
(* The two arguments are the location of the whole list as well as (* Arguments are:
the first atom when either parsing a constructor or a field. *)
- the location of the whole list
- the first atom when parsing a constructor or a field
- the universal map holding the user context
*)
type 'kind context = type 'kind context =
| Values : Loc.t * string option -> values context | Values : Loc.t * string option * Univ_map.t -> values context
| Fields : Loc.t * string option -> fields context | Fields : Loc.t * string option * Univ_map.t -> fields context
type ('a, 'kind) parser = 'kind context -> 'kind -> 'a * 'kind type ('a, 'kind) parser = 'kind context -> 'kind -> 'a * 'kind
@ -123,10 +127,24 @@ module Of_sexp = struct
b ctx state b ctx state
let map t ~f = t >>| f let map t ~f = t >>| f
let get_user_context : type k. k context -> Univ_map.t = function
| Values (_, _, uc) -> uc
| Fields (_, _, uc) -> uc
let get key ctx state = (Univ_map.find (get_user_context ctx) key, state)
let set : type a b k. a Univ_map.Key.t -> a -> (b, k) parser -> (b, k) parser
= fun key v t ctx state ->
match ctx with
| Values (loc, cstr, uc) ->
t (Values (loc, cstr, Univ_map.add uc key v)) state
| Fields (loc, cstr, uc) ->
t (Fields (loc, cstr, Univ_map.add uc key v)) state
let loc : type k. k context -> k -> Loc.t * k = fun ctx state -> let loc : type k. k context -> k -> Loc.t * k = fun ctx state ->
match ctx with match ctx with
| Values (loc, _) -> (loc, state) | Values (loc, _, _) -> (loc, state)
| Fields (loc, _) -> (loc, state) | Fields (loc, _, _) -> (loc, state)
let eos : type k. k context -> k -> bool * k = fun ctx state -> let eos : type k. k context -> k -> bool * k = fun ctx state ->
match ctx with match ctx with
@ -146,7 +164,7 @@ module Of_sexp = struct
let result : type a k. k context -> a * k -> a = let result : type a k. k context -> a * k -> a =
fun ctx (v, state) -> fun ctx (v, state) ->
match ctx with match ctx with
| Values (_, cstr) -> begin | Values (_, cstr, _) -> begin
match state with match state with
| [] -> v | [] -> v
| sexp :: _ -> | sexp :: _ ->
@ -169,11 +187,11 @@ module Of_sexp = struct
name_loc "Unknown field %s" name name_loc "Unknown field %s" name
end end
let parse t sexp = let parse t context sexp =
let ctx = Values (Ast.loc sexp, None) in let ctx = Values (Ast.loc sexp, None, context) in
result ctx (t ctx [sexp]) result ctx (t ctx [sexp])
let end_of_list (Values (loc, cstr)) = let end_of_list (Values (loc, cstr, _)) =
match cstr with match cstr with
| None -> | None ->
let loc = { loc with start = loc.stop } in let loc = { loc with start = loc.stop } in
@ -188,6 +206,12 @@ module Of_sexp = struct
| sexp :: sexps -> (f sexp, sexps) | sexp :: sexps -> (f sexp, sexps)
[@@inline always] [@@inline always]
let next_with_user_context f ctx sexps =
match sexps with
| [] -> end_of_list ctx
| sexp :: sexps -> (f (get_user_context ctx) sexp, sexps)
[@@inline always]
let peek t ctx sexps = let peek t ctx sexps =
let x, _ = t ctx sexps in let x, _ = t ctx sexps in
(x, sexps) (x, sexps)
@ -201,9 +225,10 @@ module Of_sexp = struct
| List (loc, _) -> of_sexp_error loc "Atom or quoted string expected") | List (loc, _) -> of_sexp_error loc "Atom or quoted string expected")
let enter t = let enter t =
next (function next_with_user_context (fun uc sexp ->
match sexp with
| List (loc, l) -> | List (loc, l) ->
let ctx = Values (loc, None) in let ctx = Values (loc, None, uc) in
result ctx (t ctx l) result ctx (t ctx l)
| sexp -> | sexp ->
of_sexp_error (Ast.loc sexp) "List expected") of_sexp_error (Ast.loc sexp) "List expected")
@ -219,7 +244,7 @@ module Of_sexp = struct
| sexp :: rest when rest == state2 -> (* common case *) | sexp :: rest when rest == state2 -> (* common case *)
((Ast.loc sexp, x), state2) ((Ast.loc sexp, x), state2)
| [] -> | [] ->
let (Values (loc, _)) = ctx in let (Values (loc, _, _)) = ctx in
(({ loc with start = loc.stop }, x), state2) (({ loc with start = loc.stop }, x), state2)
| sexp :: rest -> | sexp :: rest ->
let loc = Ast.loc sexp in let loc = Ast.loc sexp in
@ -229,7 +254,7 @@ module Of_sexp = struct
else else
match l with match l with
| [] -> | [] ->
let (Values (loc, _)) = ctx in let (Values (loc, _, _)) = ctx in
(({ (Ast.loc sexp) with stop = loc.stop }, x), state2) (({ (Ast.loc sexp) with stop = loc.stop }, x), state2)
| sexp :: rest -> | sexp :: rest ->
search sexp rest search sexp rest
@ -318,10 +343,10 @@ module Of_sexp = struct
"Unknown constructor %s" name "Unknown constructor %s" name
let sum cstrs = let sum cstrs =
next (fun sexp -> next_with_user_context (fun uc sexp ->
match sexp with match sexp with
| Atom (loc, A s) -> | Atom (loc, A s) ->
find_cstr cstrs loc s (Values (loc, Some s)) [] find_cstr cstrs loc s (Values (loc, Some s, uc)) []
| Quoted_string (loc, _) -> | Quoted_string (loc, _) ->
of_sexp_error loc "Atom expected" of_sexp_error loc "Atom expected"
| List (loc, []) -> | List (loc, []) ->
@ -331,7 +356,7 @@ module Of_sexp = struct
| Quoted_string (loc, _) | List (loc, _) -> | Quoted_string (loc, _) | List (loc, _) ->
of_sexp_error loc "Atom expected" of_sexp_error loc "Atom expected"
| Atom (s_loc, A s) -> | Atom (s_loc, A s) ->
find_cstr cstrs s_loc s (Values (loc, Some s)) args) find_cstr cstrs s_loc s (Values (loc, Some s, uc)) args)
let enum cstrs = let enum cstrs =
next (function next (function
@ -377,7 +402,7 @@ module Of_sexp = struct
Int.compare a.Loc.start.pos_cnum b.start.pos_cnum) Int.compare a.Loc.start.pos_cnum b.start.pos_cnum)
with with
| [] -> | [] ->
let (Fields (loc, _)) = ctx in let (Fields (loc, _, _)) = ctx in
loc loc
| first :: l -> | first :: l ->
let last = List.fold_left l ~init:first ~f:(fun _ x -> x) in let last = List.fold_left l ~init:first ~f:(fun _ x -> x) in
@ -385,7 +410,7 @@ module Of_sexp = struct
in in
of_sexp_errorf loc "%s" msg of_sexp_errorf loc "%s" msg
let field_missing (Fields (loc, _)) name = let field_missing loc name =
of_sexp_errorf loc "field %s missing" name of_sexp_errorf loc "field %s missing" name
[@@inline never] [@@inline never]
@ -407,21 +432,21 @@ module Of_sexp = struct
| _ -> ()); | _ -> ());
res res
let field name ?default t ctx state = let field name ?default t (Fields (loc, _, uc)) state =
match find_single state name with match find_single state name with
| Some { values; entry; _ } -> | Some { values; entry; _ } ->
let ctx = Values (Ast.loc entry, Some name) in let ctx = Values (Ast.loc entry, Some name, uc) in
let x = result ctx (t ctx values) in let x = result ctx (t ctx values) in
(x, consume name state) (x, consume name state)
| None -> | None ->
match default with match default with
| Some v -> (v, add_known name state) | Some v -> (v, add_known name state)
| None -> field_missing ctx name | None -> field_missing loc name
let field_o name t _ctx state = let field_o name t (Fields (_, _, uc)) state =
match find_single state name with match find_single state name with
| Some { values; entry; _ } -> | Some { values; entry; _ } ->
let ctx = Values (Ast.loc entry, Some name) in let ctx = Values (Ast.loc entry, Some name, uc) in
let x = result ctx (t ctx values) in let x = result ctx (t ctx values) in
(Some x, consume name state) (Some x, consume name state)
| None -> | None ->
@ -433,19 +458,19 @@ module Of_sexp = struct
| true -> return true | true -> return true
| _ -> bool) | _ -> bool)
let multi_field name t _ctx state = let multi_field name t (Fields (_, _, uc)) state =
let rec loop acc field = let rec loop acc field =
match field with match field with
| None -> acc | None -> acc
| Some { values; prev; entry } -> | Some { values; prev; entry } ->
let ctx = Values (Ast.loc entry, Some name) in let ctx = Values (Ast.loc entry, Some name, uc) in
let x = result ctx (t ctx values) in let x = result ctx (t ctx values) in
loop (x :: acc) prev loop (x :: acc) prev
in in
let res = loop [] (Name_map.find state.unparsed name) in let res = loop [] (Name_map.find state.unparsed name) in
(res, consume name state) (res, consume name state)
let fields t (Values (loc, cstr)) sexps = let fields t (Values (loc, cstr, uc)) sexps =
let unparsed = let unparsed =
List.fold_left sexps ~init:Name_map.empty ~f:(fun acc sexp -> List.fold_left sexps ~init:Name_map.empty ~f:(fun acc sexp ->
match sexp with match sexp with
@ -464,7 +489,7 @@ module Of_sexp = struct
of_sexp_error (Ast.loc sexp) of_sexp_error (Ast.loc sexp)
"S-expression of the form (<name> <values>...) expected") "S-expression of the form (<name> <values>...) expected")
in in
let ctx = Fields (loc, cstr) in let ctx = Fields (loc, cstr, uc) in
let x = result ctx (t ctx { unparsed; known = [] }) in let x = result ctx (t ctx { unparsed; known = [] }) in
(x, []) (x, [])

View File

@ -94,8 +94,11 @@ module Of_sexp : sig
type 'a t = ('a, values) parser type 'a t = ('a, values) parser
type 'a fields_parser = ('a, fields) parser type 'a fields_parser = ('a, fields) parser
(** Parse a S-expression using the following parser *) (** [parse parser context sexp] parse a S-expression using the
val parse : 'a t -> ast -> 'a following parser. The input consist of a single
S-expression. [context] allows to pass extra informations such as
versions to individual parsers. *)
val parse : 'a t -> Univ_map.t -> ast -> 'a
val return : 'a -> ('a, _) parser val return : 'a -> ('a, _) parser
val (>>=) : ('a, 'k) parser -> ('a -> ('b, 'k) parser) -> ('b, 'k) parser val (>>=) : ('a, 'k) parser -> ('a -> ('b, 'k) parser) -> ('b, 'k) parser
@ -103,6 +106,10 @@ module Of_sexp : sig
val (>>>) : (unit, 'k) parser -> ('a, 'k) parser -> ('a, 'k) parser val (>>>) : (unit, 'k) parser -> ('a, 'k) parser -> ('a, 'k) parser
val map : ('a, 'k) parser -> f:('a -> 'b) -> ('b, 'k) parser val map : ('a, 'k) parser -> f:('a -> 'b) -> ('b, 'k) parser
(** Access to the context *)
val get : 'a Univ_map.Key.t -> ('a option, _) parser
val set : 'a Univ_map.Key.t -> 'a -> ('b, 'k) parser -> ('b, 'k) parser
(** Return the location of the list currently being parsed. *) (** Return the location of the list currently being parsed. *)
val loc : (Loc.t, _) parser val loc : (Loc.t, _) parser

View File

@ -66,7 +66,7 @@ module Make
struct struct
module Of_sexp = struct module Of_sexp = struct
include F(Sexp.Of_sexp) include F(Sexp.Of_sexp)
let t _ sexp = Sexp.Of_sexp.parse t sexp let t _ sexp = Sexp.Of_sexp.parse t Univ_map.empty sexp
end end
module To_sexp = struct module To_sexp = struct
include F(Sexp.To_sexp) include F(Sexp.To_sexp)

View File

@ -111,7 +111,7 @@ let t ?x ?profile:cmdline_profile sexps =
let defined_names = ref String.Set.empty in let defined_names = ref String.Set.empty in
let profiles, contexts = let profiles, contexts =
List.partition_map sexps ~f:(fun sexp -> List.partition_map sexps ~f:(fun sexp ->
match Sexp.Of_sexp.parse item_of_sexp sexp with match Sexp.Of_sexp.parse item_of_sexp Univ_map.empty sexp with
| Profile (loc, p) -> Left (loc, p) | Profile (loc, p) -> Left (loc, p)
| Context c -> Right c) | Context c -> Right c)
in in
@ -130,7 +130,7 @@ let t ?x ?profile:cmdline_profile sexps =
} }
in in
List.fold_left contexts ~init ~f:(fun t sexp -> List.fold_left contexts ~init ~f:(fun t sexp ->
let ctx = Sexp.Of_sexp.parse (Context.t ~profile) sexp in let ctx = Sexp.Of_sexp.parse (Context.t ~profile) Univ_map.empty sexp in
let ctx = let ctx =
match x with match x with
| None -> ctx | None -> ctx

View File

@ -8,7 +8,7 @@ open Stdune;;
(* Jbuild.Executables.Link_mode.t *) (* Jbuild.Executables.Link_mode.t *)
let test s = let test s =
Sexp.Of_sexp.parse Jbuild.Executables.Link_mode.t Sexp.Of_sexp.parse Jbuild.Executables.Link_mode.t Univ_map.empty
(Sexp.parse_string ~fname:"" ~mode:Sexp.Parser.Mode.Single s) (Sexp.parse_string ~fname:"" ~mode:Sexp.Parser.Mode.Single s)
[%%expect{| [%%expect{|
val test : string -> Dune.Jbuild.Executables.Link_mode.t = <fun> val test : string -> Dune.Jbuild.Executables.Link_mode.t = <fun>

View File

@ -24,7 +24,7 @@ val sexp : Usexp.Ast.t = ((foo 1) (foo 2))
|}] |}]
let of_sexp = record (field "foo" int) let of_sexp = record (field "foo" int)
let x = parse of_sexp sexp let x = parse of_sexp Univ_map.empty sexp
[%%expect{| [%%expect{|
val of_sexp : int Stdune.Sexp.Of_sexp.t = <abstr> val of_sexp : int Stdune.Sexp.Of_sexp.t = <abstr>
Exception: Exception:
@ -33,7 +33,7 @@ Stdune__Sexp.Of_sexp.Of_sexp (<abstr>,
|}] |}]
let of_sexp = record (multi_field "foo" int) let of_sexp = record (multi_field "foo" int)
let x = parse of_sexp sexp let x = parse of_sexp Univ_map.empty sexp
[%%expect{| [%%expect{|
val of_sexp : int list Stdune.Sexp.Of_sexp.t = <abstr> val of_sexp : int list Stdune.Sexp.Of_sexp.t = <abstr>
val x : int list = [1; 2] val x : int list = [1; 2]