dune/src/meta.ml

122 lines
3.1 KiB
OCaml
Raw Normal View History

2016-11-13 10:01:32 +00:00
open Import
2016-11-12 11:48:24 +00:00
type t =
2016-11-13 10:01:32 +00:00
{ name : string
; entries : entry list
2016-11-12 11:48:24 +00:00
}
2016-11-13 10:01:32 +00:00
and entry =
| Comment of string
2016-11-13 11:13:47 +00:00
| Var of var
2016-11-13 10:01:32 +00:00
| Package of t
2016-11-12 11:48:24 +00:00
2016-11-13 11:13:47 +00:00
and var = string * predicate list * action * string
2016-11-13 10:01:32 +00:00
and action = Set | Add
2016-11-12 11:48:24 +00:00
and predicate =
2016-11-13 10:03:07 +00:00
| P of string
| A of string
2016-11-13 10:01:32 +00:00
module Parse = struct
2016-11-13 11:13:47 +00:00
let error = Loc.fail_lex
2016-11-13 10:01:32 +00:00
let next = Meta_lexer.token
let package_name lb =
match next lb with
| String s ->
if String.contains s '.' then
error lb "'.' not allowed in sub-package names";
s
| _ -> error lb "package name expected"
let string lb =
2016-11-13 11:27:31 +00:00
match next lb with
2016-11-13 10:01:32 +00:00
| String s -> s
| _ -> error lb "string expected"
let lparen lb =
match next lb with
| Lparen -> ()
| _ -> error lb "'(' expected"
let action lb =
match next lb with
| Equal -> Set
| Plus_equal -> Add
| _ -> error lb "'=' or '+=' expected"
let rec predicates_and_action lb acc =
match next lb with
| Rparen -> (List.rev acc, action lb)
2016-11-13 12:37:18 +00:00
| Name n -> after_predicate lb (P n :: acc)
2016-11-13 10:01:32 +00:00
| Minus ->
let n =
match next lb with
| Name p -> p
| _ -> error lb "name expected"
in
2016-11-13 12:37:18 +00:00
after_predicate lb (A n :: acc)
2016-11-13 10:01:32 +00:00
| _ -> error lb "name, '-' or ')' expected"
2016-11-13 12:37:18 +00:00
and after_predicate lb acc =
match next lb with
| Rparen -> (List.rev acc, action lb)
| Comma -> predicates_and_action lb acc
| _ -> error lb "')' or ',' expected"
2016-11-13 10:01:32 +00:00
let rec entries lb depth acc =
match next lb with
| Rparen ->
if depth > 0 then
List.rev acc
else
error lb "closing parenthesis without matching opening one"
2016-11-13 12:37:18 +00:00
| Eof ->
if depth = 0 then
List.rev acc
else
error lb "%d closing parentheses missing" depth
2016-11-13 10:01:32 +00:00
| Name "package" ->
let name = package_name lb in
lparen lb;
2016-11-13 11:27:31 +00:00
let sub_entries = entries lb (depth + 1) [] in
entries lb depth (Package { name; entries = sub_entries } :: acc)
2016-11-13 10:01:32 +00:00
| Name var ->
let preds, action =
match next lb with
| Equal -> ([], Set)
| Plus_equal -> ([], Add)
| Lparen -> predicates_and_action lb []
| _ -> error lb "'=', '+=' or '(' expected"
in
let value = string lb in
2016-11-13 11:27:31 +00:00
entries lb depth (Var (var, preds, action, value) :: acc)
2016-11-13 10:01:32 +00:00
| _ ->
error lb "'package' or variable name expected"
end
2016-11-12 11:48:24 +00:00
2016-11-13 10:03:07 +00:00
let load fn =
2016-11-13 10:01:32 +00:00
with_lexbuf_from_file fn ~f:(fun lb ->
Parse.entries lb 0 [])
2016-11-13 11:13:47 +00:00
let flatten t =
let rec loop path acc_vars acc_pkgs entries =
match entries with
| [] -> (List.rev acc_vars, acc_pkgs)
| entry :: rest ->
match entry with
| Comment _ ->
loop path acc_vars acc_pkgs rest
| Var v ->
loop path (v :: acc_vars) acc_pkgs rest
| Package { name; entries } ->
let sub_path = sprintf "%s.%s" path name in
let sub_vars, acc_pkgs = loop sub_path [] acc_pkgs entries in
let acc_pkgs = (sub_path, sub_vars) :: acc_pkgs in
loop path acc_vars acc_pkgs rest
in
let vars, pkgs = loop t.name [] [] t.entries in
(t.name, vars) :: pkgs