2016-12-02 13:54:32 +00:00
|
|
|
open! Import
|
|
|
|
|
2017-02-25 17:53:39 +00:00
|
|
|
type t = Sexp.Ast.t
|
2016-12-02 13:54:32 +00:00
|
|
|
|
|
|
|
let t t = t
|
|
|
|
|
|
|
|
let eval t ~special_values =
|
2017-02-25 17:53:39 +00:00
|
|
|
let rec of_sexp : Sexp.Ast.t -> _ = function
|
|
|
|
| Atom (loc, "\\") -> Loc.fail loc "unexpected \\"
|
|
|
|
| Atom (loc, s) ->
|
2016-12-02 13:54:32 +00:00
|
|
|
let len = String.length s in
|
|
|
|
if len > 0 && s.[0] = ':' then
|
|
|
|
let name = String.sub s ~pos:1 ~len:(len - 1) in
|
|
|
|
match List.assoc name special_values with
|
|
|
|
| l -> l
|
2017-02-25 17:53:39 +00:00
|
|
|
| exception Not_found -> Loc.fail loc "undefined symbol %s" s;
|
2016-12-02 13:54:32 +00:00
|
|
|
else
|
|
|
|
[s]
|
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-02-25 17:53:39 +00:00
|
|
|
| Atom (_, "\\") :: sexps -> of_sexps_negative acc sexps
|
2016-12-02 13:54:32 +00:00
|
|
|
| elt :: sexps ->
|
|
|
|
let elts = of_sexp elt in
|
|
|
|
of_sexps (List.rev_append elts acc) sexps
|
|
|
|
| [] -> List.rev acc
|
|
|
|
and of_sexps_negative acc = function
|
2017-02-25 17:53:39 +00:00
|
|
|
| Atom (_, "\\") :: sexps -> of_sexps_negative acc sexps
|
2016-12-02 13:54:32 +00:00
|
|
|
| elt :: sexps ->
|
|
|
|
let elts = of_sexp elt in
|
|
|
|
let acc = List.filter acc ~f:(fun acc_elt -> not (List.mem acc_elt ~set:elts)) in
|
|
|
|
of_sexps_negative acc sexps
|
|
|
|
| [] -> List.rev acc
|
|
|
|
in
|
|
|
|
of_sexp t
|
|
|
|
|
|
|
|
let is_standard : t -> bool = function
|
2017-02-25 17:53:39 +00:00
|
|
|
| Atom (_, ":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)]
|
|
|
|
|
|
|
|
let rec map (t : t) ~f =
|
|
|
|
match t with
|
2017-02-25 17:53:39 +00:00
|
|
|
| Atom (loc, s) ->
|
2016-12-02 13:54:32 +00:00
|
|
|
let len = String.length s in
|
|
|
|
if len > 0 && s.[0] = ':' then
|
|
|
|
t
|
|
|
|
else
|
2017-02-25 17:53:39 +00:00
|
|
|
Atom (loc, f s)
|
|
|
|
| List (loc, l) -> List (loc, List.map l ~f:(map ~f))
|
2016-12-02 13:54:32 +00:00
|
|
|
|
2017-02-25 17:53:39 +00:00
|
|
|
let standard : t = Atom (Loc.none, ":standard")
|
2016-12-02 13:54:32 +00:00
|
|
|
|
2017-02-25 17:53:39 +00:00
|
|
|
let append a b : t = List (Loc.none, [a; b])
|
2017-02-23 10:43:51 +00:00
|
|
|
|
2016-12-02 13:54:32 +00:00
|
|
|
module Unexpanded = struct
|
|
|
|
type nonrec t = t
|
|
|
|
let t t = t
|
|
|
|
let standard = standard
|
|
|
|
|
2017-02-23 10:43:51 +00:00
|
|
|
let append = append
|
2017-01-06 17:17:38 +00:00
|
|
|
|
2016-12-02 13:54:32 +00:00
|
|
|
let files t =
|
|
|
|
let rec loop acc : t -> _ = function
|
|
|
|
| Atom _ -> acc
|
2017-02-25 17:53:39 +00:00
|
|
|
| List (_, [Atom (_, ":include"); Atom (_, fn)]) -> String_set.add fn acc
|
|
|
|
| List (_, l) -> List.fold_left l ~init:acc ~f:loop
|
2016-12-02 13:54:32 +00:00
|
|
|
in
|
|
|
|
loop String_set.empty t
|
|
|
|
|
|
|
|
let rec expand (t : t) ~files_contents =
|
|
|
|
match t with
|
|
|
|
| Atom _ -> t
|
2017-02-25 17:53:39 +00:00
|
|
|
| List (_, [Atom (_, ":include"); Atom (_, fn)]) ->
|
2016-12-02 13:54:32 +00:00
|
|
|
String_map.find_exn fn files_contents ~string_of_key:(sprintf "%S")
|
|
|
|
~desc:(fun _ -> "<filename to s-expression>")
|
2017-02-25 17:53:39 +00:00
|
|
|
| List (loc, l) -> List (loc, List.map l ~f:(expand ~files_contents))
|
2016-12-02 13:54:32 +00:00
|
|
|
end
|