diff --git a/server/amqp_relay.ml b/server/amqp_relay.ml index 904f073..05a4d31 100644 --- a/server/amqp_relay.ml +++ b/server/amqp_relay.ml @@ -214,11 +214,11 @@ let make_queue_declare_ok info = let send_delivery conn consumer_tag body_sexp = match body_sexp with - | Sexp.Hint {Sexp.hint = Sexp.Str "amqp"; - Sexp.body = Sexp.Arr [Sexp.Str exchange; - Sexp.Str routing_key; - properties_sexp; - Sexp.Str body_str]} -> + | Sexp.Arr [Sexp.Hint {Sexp.hint = "amqp"; Sexp.body = ""}; + Sexp.Str exchange; + Sexp.Str routing_key; + properties_sexp; + Sexp.Str body_str] -> lwt tag = with_conn_mutex conn (fun () -> let v = conn.delivery_tag in conn.delivery_tag <- v + 1; return v) in @@ -226,7 +226,7 @@ let send_delivery conn consumer_tag body_sexp = (Basic_deliver (consumer_tag, Int64.of_int tag, false, exchange, routing_key)) (properties_of_sexp basic_class_id properties_sexp) body_str - | _ -> die internal_error "Malformed AMQP message body sexp" + | _ -> die internal_error "Malformed AMQP message body sexp" let amqp_handler conn n m_sexp = try @@ -344,11 +344,11 @@ let handle_method conn channel m = (match_lwt Node.post' sink (Sexp.Str name) - (Sexp.Hint {Sexp.hint = Sexp.Str "amqp"; - Sexp.body = Sexp.Arr [Sexp.Str exchange; - Sexp.Str routing_key; - sexp_of_properties properties; - Sexp.Str body]}) + (Sexp.Arr [Sexp.Hint {Sexp.hint = "amqp"; Sexp.body = ""}; + Sexp.Str exchange; + Sexp.Str routing_key; + sexp_of_properties properties; + Sexp.Str body]) (Sexp.Str "") with | true -> return () diff --git a/server/amqp_wireformat.ml b/server/amqp_wireformat.ml index 2b145d7..0deb634 100644 --- a/server/amqp_wireformat.ml +++ b/server/amqp_wireformat.ml @@ -231,11 +231,16 @@ let sexp_of_bit x = if x then Str "1" else Str "" let sexp_of_timestamp x = Str (Int64.to_string x) let rec - sexp_of_table x = Hint {hint = Str "table"; - body = Arr (List.map sexp_of_named_field (decoded_table x))} -and sexp_of_named_field (s, f) = Arr [Str s; sexp_of_unnamed_field f] + sexp_of_table x = Arr ((Hint {hint = "table"; body = ""}) :: + (List.map sexp_of_named_field (decoded_table x))) +and sexp_of_named_field (s, f) = + let (t, v) = tag_val f in + Arr [Str s; t; v] and sexp_of_unnamed_field f = - let h hs v = Hint {hint = Str hs; body = v} in + let (t, v) = tag_val f in + Arr [t; v] +and tag_val f = + let h hs v = (Str hs, v) in match f with | Table_bool true -> h "t" (Str "1") | Table_bool false -> h "t" (Str "") @@ -252,11 +257,11 @@ and sexp_of_unnamed_field f = | Table_decimal (scale, v) -> h "D" (Arr [Arr [Str "scale"; sexp_of_octet scale]; Arr [Str "value"; sexp_of_long v]]) | Table_short_string v -> h "s" (Str v) - | Table_string v -> Str v + | Table_string v -> h "S" (Str v) | Table_array vs -> h "A" (Arr (List.map sexp_of_unnamed_field vs)) | Table_timestamp v -> h "T" (sexp_of_longlong v) - | Table_table t -> sexp_of_table t - | Table_void -> Arr [] + | Table_table t -> h "F" (sexp_of_table t) + | Table_void -> h "V" (Arr []) let table_of_list fs = { table_body = Decoded_table fs } @@ -281,42 +286,41 @@ let timestamp_of_sexp v = match v with Str x -> Int64.of_string x | _ -> reserve let rec table_of_sexp v = match v with - | Hint {hint = Str "table"; body = Arr field_sexps} -> + | Arr ((Hint {hint = "table"; body = ""}) :: field_sexps) -> table_of_list (List.map named_sexp_field field_sexps) - | _ -> + | _ -> table_of_list [] and named_sexp_field v = match v with - | Arr [Str s; f] -> (s, field_of_sexp f) - | _ -> ("", Table_void) + | Arr [Str s; Str t; f] -> (s, untag_val (t, f)) + | _ -> ("", Table_void) and field_of_sexp v = match v with - | Hint {hint = Str "t"; body = Str x} -> - Table_bool (x <> "") - | Hint {hint = Str "b"; body = v} -> - Table_signed_byte (unsigned_to_signed (octet_of_sexp v) 256) - | Hint {hint = Str "B"; body = v} -> - Table_unsigned_byte (octet_of_sexp v) - | Hint {hint = Str "U"; body = v} -> - Table_signed_short (unsigned_to_signed (short_of_sexp v) 65536) - | Hint {hint = Str "u"; body = v} -> - Table_unsigned_short (short_of_sexp v) - | Hint {hint = Str "I"; body = v} -> Table_signed_long (long_of_sexp v) - | Hint {hint = Str "i"; body = v} -> Table_unsigned_long (long_of_sexp v) - | Hint {hint = Str "L"; body = v} -> Table_signed_longlong (longlong_of_sexp v) - | Hint {hint = Str "l"; body = v} -> Table_unsigned_longlong (longlong_of_sexp v) - | Hint {hint = Str "f"; body = (Str v)} -> Table_float v - | Hint {hint = Str "d"; body = (Str v)} -> Table_double v - | Hint {hint = Str "D"; body = (Arr [Arr [Str "scale"; scale]; - Arr [Str "value"; v]])} -> + | Arr [Str t; f] -> untag_val (t, f) + | _ -> Table_void +and untag_val (t, v) = + match (t, v) with + | ("t", Str x) -> Table_bool (x <> "") + | ("b", v) -> Table_signed_byte (unsigned_to_signed (octet_of_sexp v) 256) + | ("B", v) -> Table_unsigned_byte (octet_of_sexp v) + | ("U", v) -> Table_signed_short (unsigned_to_signed (short_of_sexp v) 65536) + | ("u", v) -> Table_unsigned_short (short_of_sexp v) + | ("I", v) -> Table_signed_long (long_of_sexp v) + | ("i", v) -> Table_unsigned_long (long_of_sexp v) + | ("L", v) -> Table_signed_longlong (longlong_of_sexp v) + | ("l", v) -> Table_unsigned_longlong (longlong_of_sexp v) + | ("f", Str v) -> Table_float v + | ("d", Str v) -> Table_double v + | ("D", Arr [Arr [Str "scale"; scale]; + Arr [Str "value"; v]]) -> Table_decimal (octet_of_sexp scale, long_of_sexp v) - | Hint {hint = Str "s"; body = (Str v)} -> Table_short_string v - | Str v -> Table_string v - | Hint {hint = Str "A"; body = Arr vs} -> Table_array (List.map field_of_sexp vs) - | Hint {hint = Str "T"; body = v} -> Table_timestamp (longlong_of_sexp v) - | Hint {hint = Str "table"; body = _} -> Table_table (table_of_sexp v) - | Arr [] -> Table_void - | _ -> Table_void + | ("s", Str v) -> Table_short_string v + | ("S", Str v) -> Table_string v + | ("A", Arr vs) -> Table_array (List.map field_of_sexp vs) + | ("T", v) -> Table_timestamp (longlong_of_sexp v) + | ("F", v) -> Table_table (table_of_sexp v) + | ("V", Arr []) -> Table_void + | _ -> Table_void let field_lookup k def fs = try List.assoc k fs diff --git a/server/sexp.ml b/server/sexp.ml index e913b32..05da56b 100644 --- a/server/sexp.ml +++ b/server/sexp.ml @@ -22,7 +22,7 @@ open Lwt_io exception Syntax_error of string -type display_hint_t = {hint : t; body : t} +type display_hint_t = {hint : string; body : string} and t = | Str of string | Hint of display_hint_t @@ -46,18 +46,22 @@ let intstr = loop (n / 10) (i + 1)) in loop n 0 +let write_simple_string write s = + lwt () = write (intstr (String.length s)) in + lwt () = write ":" in + write s + let generic_output_sexp write x = + let writestr = write_simple_string write in let rec walk x = match x with | Str s -> - lwt () = write (intstr (String.length s)) in - lwt () = write ":" in - write s + writestr s | Hint {hint = h; body = b} -> lwt () = write "[" in - lwt () = walk h in + lwt () = writestr h in lwt () = write "]" in - walk b + writestr b | Arr xs -> lwt () = write "(" in lwt () = Lwt_list.iter_s walk xs in @@ -72,17 +76,20 @@ let write_char_escaped ch c = then write ch "\\\"" else write_char ch c +let write_simple_string_human ch s = + lwt () = write_char ch '\"' in + lwt () = write ch (String.escaped s) in + write_char ch '\"' + let rec output_sexp_human ch x = match x with | Str s -> - lwt () = write_char ch '\"' in - lwt () = write ch (String.escaped s) in - write_char ch '\"' + write_simple_string_human ch s | Hint {hint = h; body = b} -> lwt () = write_char ch '[' in - lwt () = output_sexp_human ch h in + lwt () = write_simple_string_human ch h in lwt () = write_char ch ']' in - output_sexp_human ch b + write_simple_string_human ch b | Arr xs -> lwt () = write_char ch '(' in lwt () = @@ -111,7 +118,7 @@ let syntax_error explanation = raise_lwt (Syntax_error explanation) let input_sexp_outer input_char input_bytes = let rec input_simple_string len = match_lwt input_char () with - | ':' -> lwt bs = input_bytes len in return (Str bs) + | ':' -> lwt bs = input_bytes len in return bs | b when char_numeric b -> input_simple_string (len * 10 + digit_val b) | _ -> syntax_error "Bad simple-string length character" in @@ -131,7 +138,7 @@ let input_sexp_outer input_char input_bytes = | ']' -> lwt b = input_simple_string 0 in return (Some (Hint {hint = hint; body = b})) | _ -> syntax_error "Missing close-bracket in display hint") | b when char_numeric b -> - lwt s = input_simple_string (digit_val b) in return (Some s) + lwt s = input_simple_string (digit_val b) in return (Some (Str s)) | b when char_whitespace b -> (* Convenience for testing *) input_sexp_inner () diff --git a/server/sexpjson.ml b/server/sexpjson.ml index 66d06a7..ea5fc5b 100644 --- a/server/sexpjson.ml +++ b/server/sexpjson.ml @@ -2,29 +2,29 @@ open Sexp let rec sexp_of_json j = match j with - | Json.Num f -> Hint {hint = Str "num"; body = Str (Json.to_string j)} + | Json.Num f -> Hint {hint = "num"; body = Json.to_string j} | Json.Str s -> Str s | Json.Arr js -> Arr (List.map sexp_of_json js) - | Json.Rec kvs -> Hint {hint = Str "obj"; - body = Arr (List.map (fun (k, v) -> Arr [Str k; sexp_of_json v]) kvs)} - | Json.Flg f -> Hint {hint = Str "bool"; body = Str (string_of_bool f)} - | Json.Nil -> Hint {hint = Str "null"; body = Arr []} + | Json.Rec kvs -> Arr ((Hint {hint = "obj"; body = ""}) :: + (List.map (fun (k, v) -> Arr [Str k; sexp_of_json v]) kvs)) + | Json.Flg f -> Hint {hint = "bool"; body = string_of_bool f} + | Json.Nil -> Hint {hint = "null"; body = ""} let json_of_sexp x = let rec walk x = match x with - | Hint {hint = Str "num"; body = Str n} -> Json.Num (float_of_string n) + | Hint {hint = "num"; body = n} -> Json.Num (float_of_string n) | Str s -> Json.Str s - | Arr xs -> Json.Arr (List.map walk xs) - | Hint {hint = Str "obj"; body = Arr kvs} -> + | Arr ((Hint {hint = "obj"; body = ""}) :: kvs) -> Json.Rec (List.map (fun kv -> (match kv with | Arr [Str k; v] -> (k, walk v) | _ -> raise (Syntax_error "Bad JSON-SEXP key-value"))) kvs) - | Hint {hint = Str "bool"; body = Str bs} -> Json.Flg (bool_of_string bs) - | Hint {hint = Str "null"; body = Arr []} -> Json.Nil - | Hint {hint = h; body = b} -> Json.Rec ["_hint", walk h; "_body", walk b] + | Arr xs -> Json.Arr (List.map walk xs) + | Hint {hint = "bool"; body = bs} -> Json.Flg (bool_of_string bs) + | Hint {hint = "null"; body = ""} -> Json.Nil + | Hint {hint = h; body = b} -> Json.Rec ["_hint", Json.Str h; "_body", Json.Str b] in Lwt.wrap1 walk x