aboutsummaryrefslogtreecommitdiffstats
path: root/lib/concepts/Configuration.ml
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/concepts/Configuration.ml71
-rw-r--r--lib/concepts/Configuration.mli15
2 files changed, 83 insertions, 3 deletions
diff --git a/lib/concepts/Configuration.ml b/lib/concepts/Configuration.ml
index 06434c2..5ca95d5 100644
--- a/lib/concepts/Configuration.ml
+++ b/lib/concepts/Configuration.ml
@@ -1 +1,70 @@
-type configuration = unit
+open Sexplib.Sexp
+
+type term = Sexplib.Sexp.t
+
+module Error = struct
+ open Condition
+
+ let missing_key key =
+ condition "missing-key" "An expected key was not found" ("key" |=| Value.String key)
+
+ let mismatched_tag expected actual =
+ condition "mismatched-tag" "A tag did not match what was expected"
+ ("expected" |=| Value.String expected & "actual" |=| Value.String actual)
+
+ let syntax_error form =
+ condition "syntax-error" "Syntax error"
+ ("form" |=| Value.String (Sexplib.Sexp.to_string_hum form))
+
+ let tagless_form form =
+ condition "tagless-form" "Cannot take tag of an atom or an empty list"
+ ~parent:(syntax_error form) empty
+
+ let bodyless_form form =
+ condition "bodyless-form" "Cannot take body of an atom or an empty list"
+ ~parent:(syntax_error form) empty
+
+ let malformed_pair form =
+ condition "malformed-pair" "Expected a pair of key and value" ~parent:(syntax_error form) empty
+
+ let expected_atom form =
+ condition "expected-atom" "Expected atom but got list structure" ~parent:(syntax_error form)
+ empty
+
+ let not_a_number form =
+ condition "not-a-number" "Could not parse value as number" ~parent:(syntax_error form) empty
+end
+
+let term_of_sexp t = t
+let tag_of = function List (Atom tag :: _) -> Ok tag | form -> Error (Error.tagless_form form)
+let body_of = function List (_ :: body) -> Ok body | form -> Error (Error.bodyless_form form)
+
+type dictionary = (string, term) BatMap.t
+
+let value_for k ?default d =
+ let default = Option.to_result ~none:(Error.missing_key k) default in
+ BatMap.find_opt k d |> Option.map (fun x -> Ok x) |> Option.value ~default
+
+let as_dictionary t tag : (dictionary, Condition.condition) result =
+ let open Utilities.Result in
+ let strip_tag (tag : string) (t : term) =
+ let* tag' = tag_of t in
+ if tag' = tag then body_of t else Error (Error.mismatched_tag tag tag')
+ in
+ let as_dictionary' pairs =
+ List.fold_right
+ (fun term dict ->
+ let* dict = dict in
+ match term with
+ | List [Atom k; v] -> Ok (BatMap.add k v dict)
+ | p -> Error (Error.malformed_pair p) )
+ pairs (Ok BatMap.empty)
+ in
+ strip_tag tag t |> fmap as_dictionary'
+
+let as_string = function Atom s -> Ok s | form -> Error (Error.expected_atom form)
+
+let as_int f =
+ let open Utilities.Result in
+ let* s = as_string f in
+ int_of_string_opt s |> Option.to_result ~none:(Error.not_a_number f)
diff --git a/lib/concepts/Configuration.mli b/lib/concepts/Configuration.mli
index 5e16ff9..d633f5c 100644
--- a/lib/concepts/Configuration.mli
+++ b/lib/concepts/Configuration.mli
@@ -1,2 +1,13 @@
-(** an abstract representation for a system configuration *)
-type configuration
+(** an abstract representation of a system configuration expression *)
+type term
+
+val term_of_sexp : Sexplib.Sexp.t -> term
+val tag_of : term -> (string, Condition.condition) result
+
+(** an abstract type associating strings to configuration values *)
+type dictionary
+
+val value_for : string -> ?default:term -> dictionary -> (term, Condition.condition) result
+val as_dictionary : term -> string -> (dictionary, Condition.condition) result
+val as_int : term -> (int, Condition.condition) result
+val as_string : term -> (string, Condition.condition) result