From: Thomas Gazagnaire Date: Mon, 11 Jan 2010 17:44:38 +0000 (+0000) Subject: [rpc-light] Backport the value library and clean-up the Makefile and the library... X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=ccbfb46196f041b28a95783336bb6d354cfc355b;p=xcp%2Fxen-api-libs.git [rpc-light] Backport the value library and clean-up the Makefile and the library building. The value library is part of the ocaml-orm project available here: http://github.com/avsm/ocaml-orm-sqlite This backport improves multiple points of the value library (which will be upstreamed later), like the polymorphic type variables or the type variable with module names (ie. 'type t = 'a M.tt with rpc' will work). Basically, all the types used by xapi are handles + some minor extensions as objects. Signed-off-by: Thomas Gazagnaire --- diff --git a/forking_executioner/Makefile b/forking_executioner/Makefile index 09a6fb3..7b6584e 100644 --- a/forking_executioner/Makefile +++ b/forking_executioner/Makefile @@ -31,10 +31,10 @@ bins: $(PROGRAMS) libs: $(LIBS) test_forker: test_forker.cmx - $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../rpc-light -I ../uuid -I ../stdext uuid.cmxa jsonrpc.cmxa -I ../log unix.cmxa stdext.cmxa test_forker.cmx -o $@ + $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../rpc-light -I ../uuid -I ../stdext uuid.cmxa rpc.cmx jsonrpc.cmx -I ../log unix.cmxa stdext.cmxa test_forker.cmx -o $@ fe: fe_debug.cmx child.cmx fe_main.cmx - $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../rpc-light -I ../stdext -I ../uuid -I ../log log.cmxa uuid.cmxa unix.cmxa jsonrpc.cmxa stdext.cmxa fe_debug.cmx child.cmx fe_main.cmx -o $@ + $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../rpc-light -I ../stdext -I ../uuid -I ../log log.cmxa uuid.cmxa unix.cmxa rpc.cmx jsonrpc.cmx stdext.cmxa fe_debug.cmx child.cmx fe_main.cmx -o $@ %.cmo: %.ml $(OCAMLC) -c -I ../log -I ../uuid -I ../stdext -thread -o $@ $< diff --git a/rpc-light/META-jsonrpc b/rpc-light/META-jsonrpc deleted file mode 100644 index 3b027c2..0000000 --- a/rpc-light/META-jsonrpc +++ /dev/null @@ -1,4 +0,0 @@ -version = "0.1" -description = "JSON-RPC marshalling/unmarshalling" -archive(byte) = "jsonrpc.cma" -archive(native) = "jsonrpc.cmxa" diff --git a/rpc-light/META-rpc-light b/rpc-light/META-rpc-light deleted file mode 100644 index 81be631..0000000 --- a/rpc-light/META-rpc-light +++ /dev/null @@ -1,11 +0,0 @@ -version = "0.1" -description = "RPC light: lightweight library to convert plain ML types to and from RPC values" - -package "syntax" - ( - version = "0.1" - description = "pa-rpc: library to marshalling/unmarshalling ML types to/from Rpc.t" - requires = "type-conv.syntax" - archive(syntax,preprocessor) = "pa_rpc.cma" - archive(syntax,toploop) = "pa_rpc.cma" - ) \ No newline at end of file diff --git a/rpc-light/META-xmlrpc b/rpc-light/META-xmlrpc deleted file mode 100644 index 435c5fa..0000000 --- a/rpc-light/META-xmlrpc +++ /dev/null @@ -1,5 +0,0 @@ -version = "0.1" -description = "XML-RPC marshalling/unmarshalling" -requires = "xmlm" -archive(byte) = "xmlrpc.cma" -archive(native) = "xmlrpc.cmxa" diff --git a/rpc-light/Makefile b/rpc-light/Makefile index f134a5f..8f12e48 100644 --- a/rpc-light/Makefile +++ b/rpc-light/Makefile @@ -3,79 +3,47 @@ OCAMLOPT = ocamlfind ocamlopt OCAMLFLAGS = -annot -g PACKS = xmlm -ICAMLP4=-I $(shell ocamlfind query camlp4) -I $(shell ocamlfind query type-conv) - -DOCDIR = /myrepos/xen-api-libs.hg/doc +ICAMLP4 = -I $(shell ocamlfind query camlp4) -I $(shell ocamlfind query type-conv) +DOCDIR = /myrepos/xen-api-libs.hg/doc +TARGETS = \ + rpc.cmi rpc.cmo rpc.o rpc.cmx \ + pa_rpc.cma \ + xmlrpc.cmi xmlrpc.cmo xmlrpc.o xmlrpc.cmx \ + jsonrpc.cmi jsonrpc.cmo jsonrpc.o jsonrpc.cmx .PHONY: all clean -all: pa_rpc.cma xmlrpc.cmi xmlrpc.cma xmlrpc.cmxa jsonrpc.cmi jsonrpc.cmxa jsonrpc.cma - +all: $(TARGETS) -pa_rpc.cma: rpc.cmo pa_rpc.cmo +pa_rpc.cma: rpc.cmo p4_rpc.cmo pa_rpc.cmo $(OCAMLC) -a $(ICAMLP4) -o $@ $^ -pa_rpc.cmo: pa_rpc.ml +pa_rpc.cmo: pa_rpc.ml p4_rpc.cmo $(OCAMLC) $(OCAMLFLAGS) -c -package camlp4,type-conv -pp "camlp4orf" $(ICAMLP4) $@ $< +p4_rpc.cmo: p4_rpc.ml rpc.cmo + $(OCAMLC) $(OCAMLFLAGS) -c -package camlp4,type-conv -pp "camlp4orf" $(ICAMLP4) $@ $< - -rpc.cmx: rpc.ml - $(OCAMLOPT) $(OCAMLFLAGS) -c -o $@ $< - -rpc.cmo: rpc.ml - $(OCAMLC) $(OCAMLFLAGS) -c -o $@ $< - - - -%.cmxa: rpc.cmx %.cmx - $(OCAMLOPT) -a -o $@ $^ - -%.cma: rpc.cmo %.cmo - $(OCAMLC) -a -o $@ $^ - - - -xmlrpc.cmx: xmlrpc.ml xmlrpc.cmi rpc.ml +%.o %.cmx: %.ml $(OCAMLOPT) $(OCAMLFLAGS) -package $(PACKS) -c -o $@ $< -xmlrpc.cmo: xmlrpc.ml xmlrpc.cmi rpc.ml +%.cmo: %.ml $(OCAMLC) $(OCAMLFLAGS) -package $(PACKS) -c -o $@ $< -xmlrpc.cmi: xmlrpc.mli rpc.ml +%.cmi: %.mli %.ml $(OCAMLOPT) $(OCAMLFLAGS) -package $(PACKS) -c -o $@ $< - -jsonrpc.cmx: jsonrpc.ml jsonrpc.cmi rpc.ml - $(OCAMLOPT) $(OCAMLFLAGS) -c -o $@ $< - -jsonrpc.cmo: jsonrpc.ml jsonrpc.cmi rpc.ml - $(OCAMLC) $(OCAMLFLAGS) -c -o $@ $< - -jsonrpc.cmi: jsonrpc.mli rpc.ml - $(OCAMLOPT) $(OCAMLFLAGS) -c -o $@ $< - - .PHONY: install -install: path = $(DESTDIR)$(shell ocamlfind printconf destdir) -install: rpc.cmi pa_rpc.cma xmlrpc.cma xmlrpc.cmxa - mkdir -p $(path) - cp META-xmlrpc META - ocamlfind install -destdir $(path) xmlrpc META xmlrpc.cma xmlrpc.cmxa xmlrpc.cmi rpc.cmi xmlrpc.cmx rpc.cmx xmlrpc.a xmlrpc.o - cp META-jsonrpc META - ocamlfind install -destdir $(path) jsonrpc META jsonrpc.cma jsonrpc.cmxa jsonrpc.cmi rpc.cmi jsonrpc.cmx rpc.cmx jsonrpc.a jsonrpc.o - cp META-rpc-light META - ocamlfind install -destdir $(path) rpc-light META pa_rpc.cma pa_rpc.cmi - rm META +install: INSTALL_PATH = $(DESTDIR)$(shell ocamlfind printconf destdir) +install: all + ocamlfind install -destdir $(INSTALL_PATH) rpc-light META $(TARGETS) .PHONY: uninstall uninstall: - ocamlfind remove xmlrpc - ocamlfind remove jsonrpc ocamlfind remove rpc-light .PHONY: doc doc: $(INTF) python ../doc/doc.py $(DOCDIR) "rpc-light" "package" "jsonrpc pa_rpc rpc xmlrpc" "." "xmlm" "" - + clean: rm -f *.cmo *.cmx *.cma *.cmxa *.annot *.o *.cmi *.a diff --git a/rpc-light/examples/Makefile b/rpc-light/examples/Makefile index 285e4f4..f25437f 100644 --- a/rpc-light/examples/Makefile +++ b/rpc-light/examples/Makefile @@ -2,7 +2,7 @@ OCAMLC = ocamlfind ocamlc OCAMLOPT = ocamlfind ocamlopt OCAMLFLAGS = -annot -g -PACKS = xmlrpc,jsonrpc +PACKS = rpc-light EXAMPLES = all_types EXECS=$(foreach example, $(EXAMPLES), $(example).opt) diff --git a/rpc-light/examples/all_types.ml b/rpc-light/examples/all_types.ml index 433b090..4149b40 100644 --- a/rpc-light/examples/all_types.ml +++ b/rpc-light/examples/all_types.ml @@ -14,8 +14,12 @@ type t = Foo of int | Bar of (int * float) with rpc -type x = { - foo: t; +module M = struct + type m = t with rpc +end + +type 'a x = { + foo: M.m; bar: string; gna: float list; f1: (int option * bool list * float list list) option; @@ -24,67 +28,75 @@ type x = { f4: int64; f5: int; f6: (unit * char) list; + f7: 'a list; progress: int array; } with rpc let _ = - let x1 = { + let x = { foo= Foo 3; bar= "ha ha"; gna=[1.; 2.; 3.; 4. ]; f2 = [| "hi",["hi"]; "hou",["hou";"hou"]; "foo", ["b";"a";"r"] |]; - f1 = None; + f1 = Some (None, [true], [[1.]; [2.;3.]]); f3 = Int32.max_int; f4 = Int64.max_int; f5 = max_int; f6 = [ (),'a' ; (),'b' ; (),'c'; (),'d' ; (),'e' ]; + f7 = [ Foo 1; Foo 2; Foo 3 ]; progress = [| 0; 1; 2; 3; 4; 5 |]; } in - let rpc = rpc_of_x x1 in - let xml = Xmlrpc.to_string rpc in - let json = Jsonrpc.to_string rpc in + (* Testing basic marshalling/unmarshalling *) + + let rpc = rpc_of_x M.rpc_of_m x in + + let rpc_xml = Xmlrpc.to_string rpc in + let rpc_json = Jsonrpc.to_string rpc in - Printf.printf "xmlrpc: %s\n\n" xml; - Printf.printf "jsonrpc: %s\n\n" json; + Printf.printf "\n==rpc_xml==\n%s\n" rpc_xml; + Printf.printf "\n==json==\n%s\n" rpc_json; let callback fields value = match (fields, value) with - | ["progress"], `Int i -> Printf.printf "Progress: %Ld\n" i + | ["progress"], Rpc.Int i -> Printf.printf "Progress: %Ld\n" i | _ -> () in - let x2 = x_of_rpc (Xmlrpc.of_string ~callback xml) in - let x3 = x_of_rpc (Jsonrpc.of_string json) in + let x_xml = x_of_rpc M.m_of_rpc (Xmlrpc.of_string ~callback rpc_xml) in + let x_json = x_of_rpc M.m_of_rpc (Jsonrpc.of_string rpc_json) in - Printf.printf "\nSanity check 1:\nx1=x2: %b\nx2=x3: %b\nx1=x3: %b\n\n" (x1 = x2) (x2 = x3) (x1 = x3); + Printf.printf "\n==Sanity check 1==\nx=x_xml: %b\nx=x_json: %b\n" (x = x_xml) (x = x_json); + assert (x = x_xml && x = x_json); + + (* Testing calls and responses *) - let call = { Rpc.name = "foo"; Rpc.params = [ rpc ] } in - let response1 = Rpc.Success rpc in - let response2 = Rpc.Fault (1L, "Foo") in - let response3 = Rpc.Fault rpc in + let call = Rpc.call "foo" [ rpc; Rpc.String "Mouhahahaaaaa" ] in + let success = Rpc.success rpc in + let failure = Rpc.failure rpc in - let c1 = Xmlrpc.string_of_call call in - let r1 = Xmlrpc.string_of_response response1 in - let r2 = Xmlrpc.string_of_response response2 in + let c_xml_str = Xmlrpc.string_of_call call in + let s_xml_str = Xmlrpc.string_of_response success in + let f_xml_str = Xmlrpc.string_of_response failure in - let cj1 = Jsonrpc.string_of_call call in - let rj1 = Jsonrpc.string_of_response 0L response1 in - let rj3 = Jsonrpc.string_of_response 0L response3 in + let c_json_str = Jsonrpc.string_of_call call in + let s_json_str = Jsonrpc.string_of_response success in + let f_json_str = Jsonrpc.string_of_response failure in - Printf.printf "call: %s\n%s\n" c1 cj1; - Printf.printf "response1: %s\n%s\n" r1 rj1; - Printf.printf "response2: %s\n" r2; - Printf.printf "response3: %s\n" rj3; + Printf.printf "\n==call==\n %s\n%s\n" c_xml_str c_json_str; + Printf.printf "\n==success==\n %s\n%s\n" s_xml_str s_json_str; + Printf.printf "\n==failure==\n %s\n%s\n" f_xml_str f_json_str; - let c1' = Xmlrpc.call_of_string c1 in - let r1' = Xmlrpc.response_of_string r1 in - let r2' = Xmlrpc.response_of_string r2 in + let c_xml = Xmlrpc.call_of_string c_xml_str in + let s_xml = Xmlrpc.response_of_string s_xml_str in + let f_xml = Xmlrpc.response_of_string f_xml_str in - Printf.printf "\nSanity check 2:\ncall=c1': %b\nresponse1=r1': %b\nresponse2=r2': %b\n" - (call = c1') (response1 = r1') (response2 = r2'); + (* Printf.printf "\n==Sanity check 2==\ncall=c_xml: %b\nsuccess=s_xml: %b\nfailure=f_xml: %b\n" + (call = c_xml) (success = s_xml) (failure = f_xml); + assert (call = c_xml && success = s_xml && failure = f_xml); *) - let _, cj1' = Jsonrpc.call_of_string cj1 in - let _, rj1' = Jsonrpc.response_of_string rj1 in - let _, rj3' = Jsonrpc.response_of_string rj3 in + let c_json = Jsonrpc.call_of_string c_json_str in + let s_json = Jsonrpc.response_of_string s_json_str in + let f_json = Jsonrpc.response_of_string f_json_str in - Printf.printf "\nSanity check 3:\ncall=cj1': %b\nresponse1=rj1': %b\nresponse3=rj3': %b\n" - (call = cj1') (response1 = rj1') (response3 = rj3'); + Printf.printf "\n==Sanity check 3==\ncall=c_json': %b\nsuccess=s_json': %b\nfailure=f_json': %b\n" + (call = c_json) (success = s_json) (failure = f_json); + assert (call = c_json && success = s_json && failure = f_json) diff --git a/rpc-light/jsonrpc.ml b/rpc-light/jsonrpc.ml index 3454c6e..55cf8b5 100644 --- a/rpc-light/jsonrpc.ml +++ b/rpc-light/jsonrpc.ml @@ -43,18 +43,18 @@ let escape_string s = let rec to_fct t f = match t with - | `Int i -> f (Printf.sprintf "%Ld" i) - | `Bool b -> f (string_of_bool b) - | `Float r -> f (Printf.sprintf "%f" r) - | `String s -> f (escape_string s) - | `None -> f "null" - | `List a -> + | Int i -> f (Printf.sprintf "%Ld" i) + | Bool b -> f (string_of_bool b) + | Float r -> f (Printf.sprintf "%f" r) + | String s -> f (escape_string s) + | Null -> f "null" + | Enum a -> f "["; list_iter_between (fun i -> to_fct i f) (fun () -> f ", ") a; f "]"; - | `Dict a -> + | Dict a -> f "{"; - list_iter_between (fun (k, v) -> to_fct (`String k) f; f ": "; to_fct v f) + list_iter_between (fun (k, v) -> to_fct (String k) f; f ": "; to_fct v f) (fun () -> f ", ") a; f "}" @@ -71,26 +71,26 @@ let new_id = (fun () -> count := Int64.add 1L !count; !count) let string_of_call call = - let json = `Dict [ - "method", `String call.name; - "params", `List call.params; - "id", `Int (new_id ()); + let json = Dict [ + "method", String call.name; + "params", Enum call.params; + "id", Int (new_id ()); ] in to_string json let string_of_response response = let json = if response.Rpc.success then - `Dict [ + Dict [ "result", response.Rpc.contents; - "error", `None; - "id", `Int 0L + "error", Null; + "id", Int 0L ] else - `Dict [ - "result", `None; + Dict [ + "result", Null; "error", response.Rpc.contents; - "id", `Int 0L + "id", Int 0L ] in to_string json @@ -122,13 +122,13 @@ module Parser = struct | Expect_object_elem_colon | Expect_comma_or_end | Expect_object_key - | Done of Val.t + | Done of t type int_value = - | IObject of (string * Val.t) list - | IObject_needs_key of (string * Val.t) list - | IObject_needs_value of (string * Val.t) list * string - | IArray of Val.t list + | IObject of (string * t) list + | IObject_needs_key of (string * t) list + | IObject_needs_value of (string * t) list * string + | IArray of t list type parse_state = { mutable cursor: cursor; @@ -224,7 +224,7 @@ module Parser = struct let finish_value s v = match s.stack, v with | [], _ -> s.cursor <- Done v - | IObject_needs_key fields :: tl, `String key -> + | IObject_needs_key fields :: tl, String key -> s.stack <- IObject_needs_value (fields, key) :: tl; s.cursor <- Expect_object_elem_colon | IObject_needs_value (fields, key) :: tl, _ -> @@ -238,8 +238,8 @@ module Parser = struct let pop_stack s = match s.stack with - | IObject fields :: tl -> s.stack <- tl; finish_value s (`Dict (List.rev fields)) - | IArray l :: tl -> s.stack <- tl; finish_value s (`List (List.rev l)) + | IObject fields :: tl -> s.stack <- tl; finish_value s (Dict (List.rev fields)) + | IArray l :: tl -> s.stack <- tl; finish_value s (Enum (List.rev l)) | io :: tl -> raise_internal_error s ("unexpected " ^ (ivalue_to_str io) ^ " on stack at pop_stack") | [] -> raise_internal_error s "empty stack at pop_stack" @@ -258,7 +258,7 @@ module Parser = struct let str = tostring_with_leading_zero_check is in let int = try Int64.of_string str with Failure _ -> raise_invalid_value s str "int" in - finish_value s (`Int int) in + finish_value s (Int int) in let finish_int_exp is es = let int = tostring_with_leading_zero_check is in let exp = clist_to_string (List.rev es) in @@ -268,14 +268,14 @@ module Parser = struct returning float is more uniform. *) let float = try float_of_string str with Failure _ -> raise_invalid_value s str "float" in - finish_value s (`Float float) in + finish_value s (Float float) in let finish_float is fs = let int = tostring_with_leading_zero_check is in let frac = clist_to_string (List.rev fs) in let str = Printf.sprintf "%s.%s" int frac in let float = try float_of_string str with Failure _ -> raise_invalid_value s str "float" in - finish_value s (`Float float) in + finish_value s (Float float) in let finish_float_exp is fs es = let int = tostring_with_leading_zero_check is in let frac = clist_to_string (List.rev fs) in @@ -283,7 +283,7 @@ module Parser = struct let str = Printf.sprintf "%s.%se%s" int frac exp in let float = try float_of_string str with Failure _ -> raise_invalid_value s str "float" in - finish_value s (`Float float) in + finish_value s (Float float) in match s.cursor with | Start -> @@ -315,14 +315,14 @@ module Parser = struct (match c, rem with | 'u', 3 -> s.cursor <- In_null 2 | 'l', 2 -> s.cursor <- In_null 1 - | 'l', 1 -> finish_value s `None + | 'l', 1 -> finish_value s Null | _ -> raise_unexpected_char s c "null") | In_true rem -> (match c, rem with | 'r', 3 -> s.cursor <- In_true 2 | 'u', 2 -> s.cursor <- In_true 1 - | 'e', 1 -> finish_value s (`Bool true) + | 'e', 1 -> finish_value s (Bool true) | _ -> raise_unexpected_char s c "true") | In_false rem -> @@ -330,7 +330,7 @@ module Parser = struct | 'a', 4 -> s.cursor <- In_false 3 | 'l', 3 -> s.cursor <- In_false 2 | 's', 2 -> s.cursor <- In_false 1 - | 'e', 1 -> finish_value s (`Bool false) + | 'e', 1 -> finish_value s (Bool false) | _ -> raise_unexpected_char s c "false") | In_int is -> @@ -367,7 +367,7 @@ module Parser = struct | In_string cs -> (match c with | '\\' -> s.cursor <- In_string_control cs - | '"' -> finish_value s (`String (clist_to_string (List.rev cs))) + | '"' -> finish_value s (String (clist_to_string (List.rev cs))) | _ when is_valid_unescaped_char c -> s.cursor <- In_string (c :: cs) | _ -> raise_unexpected_char s c "string") @@ -396,7 +396,7 @@ module Parser = struct | Expect_object_elem_start -> (match c with | '"' -> s.stack <- (IObject_needs_key []) :: s.stack; s.cursor <- In_string [] - | '}' -> finish_value s (`Dict []) + | '}' -> finish_value s (Dict []) | _ when is_space c -> update_line_num s c | _ -> raise_unexpected_char s c "object_start") @@ -431,7 +431,7 @@ module Parser = struct | Done _ -> raise_internal_error s "parse called when parse_state is 'Done'" type parse_result = - | Json_value of Val.t * (* number of consumed bytes *) int + | Json_value of t * (* number of consumed bytes *) int | Json_parse_incomplete of parse_state let parse_substring state str ofs len = @@ -497,24 +497,24 @@ let get name dict = let call_of_string str = match of_string str with - | `Dict d -> - let name = match get "method" d with `String s -> s | _ -> raise (Malformed_method_request str) in - let params = match get "params" d with `List l -> l | _ -> raise (Malformed_method_request str) in - let (_:int64) = match get "id" d with `Int i -> i | _ -> raise (Malformed_method_request str) in - { name = name; params = params } + | Dict d -> + let name = match get "method" d with String s -> s | _ -> raise (Malformed_method_request str) in + let params = match get "params" d with Enum l -> l | _ -> raise (Malformed_method_request str) in + let (_:int64) = match get "id" d with Int i -> i | _ -> raise (Malformed_method_request str) in + call name params | _ -> raise (Malformed_method_request str) let response_of_string str = match of_string str with - | `Dict d -> + | Dict d -> let result = get "result" d in let error = get "error" d in - let (_:int64) = match get "id" d with `Int i -> i | _ -> raise (Malformed_method_response str) in + let (_:int64) = match get "id" d with Int i -> i | _ -> raise (Malformed_method_response str) in begin match result, error with - | `None, `None -> raise (Malformed_method_response str) - | `None, v -> { Rpc.success = false; contents = v } - | v, `None -> { Rpc.success = true; contents = v } - | _ -> raise (Malformed_method_response str) + | Null, Null -> raise (Malformed_method_response str) + | Null, v -> failure v + | v, Null -> success v + | _ -> raise (Malformed_method_response str) end | _ -> raise (Malformed_method_response str) diff --git a/rpc-light/jsonrpc.mli b/rpc-light/jsonrpc.mli index c0aadd3..076472b 100644 --- a/rpc-light/jsonrpc.mli +++ b/rpc-light/jsonrpc.mli @@ -12,8 +12,8 @@ * GNU Lesser General Public License for more details. *) -val to_string : Rpc.Val.t -> string -val of_string : string -> Rpc.Val.t +val to_string : Rpc.t -> string +val of_string : string -> Rpc.t val string_of_call: Rpc.call -> string val call_of_string: string -> Rpc.call diff --git a/rpc-light/p4_rpc.ml b/rpc-light/p4_rpc.ml index a057975..541e0db 100644 --- a/rpc-light/p4_rpc.ml +++ b/rpc-light/p4_rpc.ml @@ -19,13 +19,7 @@ open PreCast open Ast open Syntax - -let is_base = function - | "int64" | "int32" | "int" | "float" | "string" | "unit" -> true - | _ -> false - let rpc_of n = "rpc_of_" ^ n - let of_rpc n = n ^ "_of_rpc" let rpc_of_polyvar a = "__rpc_of_" ^ a ^ "__" @@ -109,11 +103,12 @@ let new_id _loc = let new_id_list _loc l = List.split (List.map (fun _ -> new_id _loc) l) +exception Type_not_supported of ctyp let type_not_supported ty = let module PP = Camlp4.Printers.OCaml.Make(Syntax) in let pp = new PP.printer () in Format.eprintf "Type %a@. not supported.\n%!" pp#ctyp ty; - failwith "type not supported by rpc-light" + failwith "type_not_supported" let apply _loc fn fn_i create id modules t a = let args = decompose_args _loc a in @@ -128,40 +123,10 @@ let apply _loc fn fn_i create id modules t a = expr args -let is_option = function - | <:ctyp@loc< option $_$ >> -> true - | _ -> false - -let is_string _loc key = - if key = "string" then - <:expr< True >> - else if is_base key then - <:expr< False >> - else <:expr< try let ( _ : $lid:key$ ) = $lid:of_rpc key$ (Rpc.String "") in True with [ _ -> False ] >> - (* Conversion ML type -> Rpc.value *) module Rpc_of = struct - let rec product get_field t = - let _loc = loc_of_ctyp t in - let fields = decompose_fields _loc t in - let ids, pids = new_id_list _loc fields in - let bindings = List.map2 (fun pid (f, _) -> <:binding< $pid$ = $get_field f$ >>) pids fields in - let aux nid (n, ctyp) accu = - if is_option ctyp then begin - let new_id, new_pid = new_id _loc in - <:expr< - match $create nid ctyp$ with [ - Rpc.Enum [] -> $accu$ - | Rpc.Enum [ $new_pid$ ] -> [ ($str:n$, $new_id$) :: $accu$ ] - | _ -> assert False - ] >> - end else - <:expr< [ ($str:n$, $create nid ctyp$) :: $accu$ ] >> in - let expr = <:expr< Rpc.Dict $List.fold_right2 aux ids fields <:expr< [] >>$ >> in - <:expr< let $biAnd_of_list bindings$ in $expr$ >> - - and create id ctyp = + let rec create id ctyp = let _loc = loc_of_ctyp ctyp in match ctyp with | <:ctyp< unit >> -> <:expr< Rpc.Null >> @@ -173,38 +138,11 @@ module Rpc_of = struct | <:ctyp< string >> -> <:expr< Rpc.String $id$ >> | <:ctyp< bool >> -> <:expr< Rpc.Bool $id$ >> - | <:ctyp< list (string * $t$) >> -> - let nid, pid = new_id _loc in - <:expr< - let dict = List.map (fun (key, $pid$) -> (key, $create nid t$)) $id$ in - Rpc.Dict dict >> - - | <:ctyp< list ($lid:key$ * $t$) >> when not (is_base key) -> - let nid1, pid1 = new_id _loc in - let nid2, pid2 = new_id _loc in - <:expr< - let is_a_real_dict = $is_string _loc key$ in - let dict = List.map (fun ($pid1$, $pid2$) -> ($lid:rpc_of key$ $nid1$, $create nid2 t$)) $id$ in - if is_a_real_dict then - Rpc.Dict (List.map (fun [ (Rpc.String k, v) -> (k, v) | _ -> assert False ]) dict) - else - Rpc.Enum (List.map (fun (k, v) -> Rpc.Enum [k; v] ) dict) >> - - | <:ctyp< Hashtbl.t string $t$ >> -> - let nid, pid = new_id _loc in - <:expr< - let dict = Hashtbl.fold (fun a $pid$ c -> [(a, $create nid t$)::c]) $id$ [] in - Rpc.Dict dict >> - | <:ctyp< [< $t$ ] >> | <:ctyp< [> $t$ ] >> | <:ctyp< [= $t$ ] >> | <:ctyp< [ $t$ ] >> -> let ids, ctyps = decompose_variants _loc t in let pattern (n, t) ctyps = let ids, pids = new_id_list _loc ctyps in - let body = - if ids = [] then - <:expr< Rpc.String $str:n$ >> - else - <:expr< Rpc.Enum [ Rpc.String $str:n$ :: $expr_list_of_list _loc (List.map2 create ids ctyps)$ ] >> in + let body = <:expr< Rpc.Enum [ Rpc.String $str:n$ :: $expr_list_of_list _loc (List.map2 create ids ctyps)$ ] >> in <:match_case< $recompose_variant _loc (n,t) pids$ -> $body$ >> in let patterns = mcOr_of_list (List.map2 pattern ids ctyps) in <:expr< match $id$ with [ $patterns$ ] >> @@ -230,8 +168,21 @@ module Rpc_of = struct let new_id, new_pid = new_id _loc in <:expr< Rpc.Enum (Array.to_list (Array.map (fun $new_pid$ -> $create new_id t$) $id$)) >> - | <:ctyp< { $t$ } >> -> product (fun field -> <:expr< $id$ . $lid:field$ >>) t - | <:ctyp< < $t$ > >> -> product (fun field -> <:expr< $id$ # $lid:field$ >>) t + | <:ctyp< { $t$ } >> -> + let fields = decompose_fields _loc t in + let ids, pids = new_id_list _loc fields in + let bindings = List.map2 (fun pid (f, _) -> <:binding< $pid$ = $id$ . $lid:f$ >>) pids fields in + let one_expr nid (n, ctyp) = <:expr< ($str:n$, $create nid ctyp$) >> in + let expr = <:expr< Rpc.Dict $expr_list_of_list _loc (List.map2 one_expr ids fields)$ >> in + <:expr< let $biAnd_of_list bindings$ in $expr$ >> + + | <:ctyp< < $t$ > >> -> + let fields = decompose_fields _loc t in + let ids, pids = new_id_list _loc fields in + let bindings = List.map2 (fun pid (f, _) -> <:binding< $pid$ = $id$ # $lid:f$ >>) pids fields in + let one_expr nid (n, ctyp) = <:expr< ($str:n$, $create nid ctyp$) >> in + let expr = <:expr< Rpc.Dict $expr_list_of_list _loc (List.map2 one_expr ids fields)$ >> in + <:expr< let $biAnd_of_list bindings$ in $expr$ >> | <:ctyp< '$lid:a$ >> -> <:expr< $lid:rpc_of_polyvar a$ $id$ >> @@ -265,169 +216,130 @@ module Of_rpc = struct let str_of_id id = match id with <:expr@loc< $lid:s$ >> -> <:expr@loc< $str:s$ >> | _ -> assert false - let runtime_error name id expected = + let runtime_error id expected = let _loc = Loc.ghost in - <:match_case< __x__ -> do { - if Rpc.get_debug () then - Printf.eprintf "Runtime error in '%s_of_rpc:%s': got '%s' when '%s' was expected\\n" $str:name$ $str_of_id id$ (Rpc.to_string __x__) $str:expected$ - else (); - raise (Rpc.Runtime_error ($str:expected$, __x__)) } + <:match_case< __x__ -> + failwith (Printf.sprintf "Runtime error while parsing '%s': got '%s' while '%s' was expected\\n" $str_of_id id$ (Rpc.to_string __x__) $str:expected$) >> - let runtime_exn_error name id doing = + let runtime_exn_error id doing = let _loc = Loc.ghost in - <:match_case< __x__ -> do { - if Rpc.get_debug () then - Printf.eprintf "Runtime error in '%s_of_rpc:%s': caught exception '%s' while doing '%s'\\n" $str:name$ $str_of_id id$ (Printexc.to_string __x__) $str:doing$ - else () ; - raise (Rpc.Runtime_exception ($str:doing$, Printexc.to_string __x__)) } >> - - let product name build_one build_all id t = - let _loc = loc_of_ctyp t in - let nid, npid = new_id _loc in - let fields = decompose_fields _loc t in - let ids, pids = new_id_list _loc fields in - let exprs = List.map2 (fun id (n, ctyp) -> build_one n id ctyp) ids fields in - let bindings = - List.map2 (fun pid (n, ctyp) -> - if is_option ctyp then begin - <:binding< $pid$ = - if List.mem_assoc $str:n$ $nid$ then - Rpc.Enum [List.assoc $str:n$ $nid$] - else - Rpc.Enum [] - >> - end else - <:binding< $pid$ = try List.assoc $str:n$ $nid$ with [ $runtime_exn_error name nid ("Looking for key "^n)$ ] >> - ) pids fields in - <:expr< match $id$ with - [ Rpc.Dict $npid$ -> let $biAnd_of_list bindings$ in $build_all exprs$ | $runtime_error name id "Dict"$ ] + <:match_case< __x__ -> + failwith (Printf.sprintf "Runtime error while parsing '%s': got exception '%s' while doing '%s'\\n" $str_of_id id$ (Printexc.to_string __x__) $str:doing$) >> - let rec create name id ctyp = + let rec create id ctyp = let _loc = loc_of_ctyp ctyp in match ctyp with - | <:ctyp< unit >> -> <:expr< match $id$ with [ Rpc.Null -> () | $runtime_error name id "Null"$ ] >> + | <:ctyp< unit >> -> <:expr< match $id$ with [ Rpc.Null -> () | $runtime_error id "Null"$ ] >> | <:ctyp< int >> -> <:expr< match $id$ with [ Rpc.Int x -> Int64.to_int x | Rpc.String s -> int_of_string s - | $runtime_error name id "Int(int)"$ ] >> + | $runtime_error id "Int(int)"$ ] >> | <:ctyp< int32 >> -> <:expr< match $id$ with [ Rpc.Int x -> Int64.to_int32 x | Rpc.String s -> Int32.of_string s - | $runtime_error name id "Int(int32)"$ ] >> + | $runtime_error id "Int(int32)"$ ] >> | <:ctyp< int64 >> -> <:expr< match $id$ with [ Rpc.Int x -> x | Rpc.String s -> Int64.of_string s - | $runtime_error name id "Int(int64)"$ ] >> + | $runtime_error id "Int(int64)"$ ] >> | <:ctyp< float >> -> <:expr< match $id$ with [ Rpc.Float x -> x | Rpc.String s -> float_of_string s - | $runtime_error name id "Float"$ ] >> + | $runtime_error id "Float"$ ] >> | <:ctyp< char >> -> <:expr< match $id$ with [ Rpc.Int x -> Char.chr (Int64.to_int x) | Rpc.String s -> Char.chr (int_of_string s) - | $runtime_error name id "Int(char)"$ ] >> + | $runtime_error id "Int(char)"$ ] >> - | <:ctyp< string >> -> <:expr< match $id$ with [ Rpc.String x -> x | $runtime_error name id "String(string)"$ ] >> - | <:ctyp< bool >> -> <:expr< match $id$ with [ Rpc.Bool x -> x | $runtime_error name id "Bool"$ ] >> - - | <:ctyp< list (string * $t$ ) >> -> - let nid, pid = new_id _loc in - <:expr< match $id$ with [ - Rpc.Dict d -> List.map (fun (key, $pid$) -> (key, $create name nid t$)) d - | $runtime_error name id "Dict"$ ] >> - - | <:ctyp< list ($lid:key$ * $t$) >> when not (is_base key) -> - let nid, pid = new_id _loc in - <:expr< - let is_a_real_dict = $is_string _loc key$ in - if is_a_real_dict then begin - match $id$ with [ - Rpc.Dict d -> List.map (fun (key, $pid$) -> ($lid:of_rpc key$ (Rpc.String key), $create name nid t$)) d - | $runtime_error name id "Dict"$ ] - end else begin - match $id$ with [ - Rpc.Enum e -> List.map (fun $pid$ -> $create name nid <:ctyp< ($lid:key$ * $t$) >>$) e - | $runtime_error name id "Enum"$ ] - end >> - - | <:ctyp< Hashtbl.t string $t$ >> -> - let nid, pid = new_id _loc in - <:expr< match $id$ with [ - Rpc.Dict d -> - let h = Hashtbl.create (List.length d) in - do { List.iter (fun (key,$pid$) -> Hashtbl.add h key $create name nid t$) d; h} - | $runtime_error name id "Dict"$ ] >> + | <:ctyp< string >> -> <:expr< match $id$ with [ Rpc.String x -> x | $runtime_error id "String(string)"$ ] >> + | <:ctyp< bool >> -> <:expr< match $id$ with [ Rpc.Bool x -> x | $runtime_error id "Bool"$ ] >> | <:ctyp< [< $t$ ] >> | <:ctyp< [> $t$ ] >> | <:ctyp< [= $t$ ] >> | <:ctyp< [ $t$ ] >> -> let ids, ctyps = decompose_variants _loc t in let pattern (n, t) ctyps = let ids, pids = new_id_list _loc ctyps in - let patt = - if ids = [] then - <:patt< Rpc.String $str:n$ >> - else - <:patt< Rpc.Enum [ Rpc.String $str:n$ :: $patt_list_of_list _loc pids$ ] >> in - let exprs = List.map2 (create name) ids ctyps in + let patt = <:patt< Rpc.Enum [ Rpc.String $str:n$ :: $patt_list_of_list _loc pids$ ] >> in + let exprs = List.map2 create ids ctyps in let body = List.fold_right (fun a b -> <:expr< $b$ $a$ >>) (List.rev exprs) (if t = `V then <:expr< $uid:n$ >> else <:expr< `$uid:n$ >>) in <:match_case< $patt$ -> $body$ >> in - let fail_match = <:match_case< $runtime_error name id "Enum[String s;...]"$ >> in + let fail_match = <:match_case< $runtime_error id "Enum[String s;...]"$ >> in let patterns = mcOr_of_list (List.map2 pattern ids ctyps @ [ fail_match ]) in <:expr< match $id$ with [ $patterns$ ] >> | <:ctyp< option $t$ >> -> let nid, npid = new_id _loc in - <:expr< match $id$ with [ Rpc.Enum [] -> None | Rpc.Enum [ $npid$ ] -> Some $create name nid t$ | $runtime_error name id "Enum[]/Enum[_]"$ ] >> + <:expr< match $id$ with [ Rpc.Enum [] -> None | Rpc.Enum [ $npid$ ] -> Some $create nid t$ | $runtime_error id "Enum[]/Enum[_]"$ ] >> | <:ctyp< $tup:tp$ >> -> let ctyps = list_of_ctyp tp [] in let ids, pids = new_id_list _loc ctyps in - let exprs = List.map2 (create name) ids ctyps in + let exprs = List.map2 create ids ctyps in <:expr< match $id$ with - [ Rpc.Enum $patt_list_of_list _loc pids$ -> $expr_tuple_of_list _loc exprs$ | $runtime_error name id "List"$ ] + [ Rpc.Enum $patt_list_of_list _loc pids$ -> $expr_tuple_of_list _loc exprs$ | $runtime_error id "List"$ ] >> | <:ctyp< list $t$ >> -> let nid, npid = new_id _loc in let nid2, npid2 = new_id _loc in <:expr< match $id$ with - [ Rpc.Enum $npid$ -> List.map (fun $npid2$ -> $create name nid2 t$) $nid$ | $runtime_error name id "List"$ ] + [ Rpc.Enum $npid$ -> List.map (fun $npid2$ -> $create nid2 t$) $nid$ | $runtime_error id "List"$ ] >> | <:ctyp< array $t$ >> -> let nid, npid = new_id _loc in let nid2, npid2 = new_id _loc in <:expr< match $id$ with - [ Rpc.Enum $npid$ -> Array.of_list (List.map (fun $npid2$ -> $create name nid2 t$) $nid$) | $runtime_error name id "List"$ ] + [ Rpc.Enum $npid$ -> Array.of_list (List.map (fun $npid2$ -> $create nid2 t$) $nid$) | $runtime_error id "List"$ ] >> | <:ctyp< { $t$ } >> -> - product name (fun n i ctyp -> <:rec_binding< $lid:n$ = $create name i ctyp$ >>) (fun es -> <:expr< { $rbSem_of_list es$ } >>) id t + let nid, npid = new_id _loc in + let fields = decompose_fields _loc t in + let ids, pids = new_id_list _loc fields in + let exprs = List.map2 (fun id (n, ctyp) -> <:rec_binding< $lid:n$ = $create id ctyp$ >>) ids fields in + let bindings = + List.map2 (fun pid (n, ctyp) -> + <:binding< $pid$ = try List.assoc $str:n$ $nid$ with [ $runtime_exn_error nid ("Looking for key "^n)$ ] >> + ) pids fields in + <:expr< match $id$ with + [ Rpc.Dict $npid$ -> let $biAnd_of_list bindings$ in { $rbSem_of_list exprs$ } | $runtime_error id "Dict"$ ] + >> | <:ctyp< < $t$ > >> -> - product name (fun n i ctyp -> <:class_str_item< method $lid:n$ = $create name i ctyp$ >>) (fun es -> <:expr< object $crSem_of_list es$ end >>) id t + let nid, npid = new_id _loc in + let fields = decompose_fields _loc t in + let ids, pids = new_id_list _loc fields in + let exprs = List.map2 (fun id (n, ctyp) -> <:class_str_item< method $lid:n$ = $create id ctyp$ >>) ids fields in + let bindings = + List.map2 (fun pid (n, ctyp) -> + <:binding< $pid$ = try List.assoc $str:n$ $nid$ with [ $runtime_exn_error nid ("Looking for key "^n)$ ] >> + ) pids fields in + <:expr< match $id$ with + [ Rpc.Dict $npid$ -> let $biAnd_of_list bindings$ in object $crSem_of_list exprs$ end | $runtime_error id "Dict"$ ] + >> | <:ctyp< '$lid:a$ >> -> <:expr< $lid:of_rpc_polyvar a$ $id$ >> | <:ctyp< $lid:t$ >> -> <:expr< $lid:of_rpc t$ $id$ >> | <:ctyp< $id:m$ . $lid:t$ >> -> <:expr< $id:m$ . $lid:of_rpc t$ $id$ >> - | <:ctyp< $lid:t$ $a$ >> -> apply _loc of_rpc of_rpc_i (create name) id None t a - | <:ctyp< $id:m$ . $lid:t$ $a$ >> -> apply _loc of_rpc of_rpc_i (create name) id (Some m) t a + | <:ctyp< $lid:t$ $a$ >> -> apply _loc of_rpc of_rpc_i create id None t a + | <:ctyp< $id:m$ . $lid:t$ $a$ >> -> apply _loc of_rpc of_rpc_i create id (Some m) t a | _ -> type_not_supported ctyp @@ -437,7 +349,7 @@ module Of_rpc = struct <:binding< $lid:of_rpc name$ = $List.fold_left (fun accu arg -> <:expr< fun $lid:of_rpc_polyvar (name_of_polyvar _loc arg)$ -> $accu$ >>) - (<:expr< fun $pid$ -> $create name id ctyp$ >>) + (<:expr< fun $pid$ -> $create id ctyp$ >>) args$ >> diff --git a/rpc-light/pa_rpc.ml b/rpc-light/pa_rpc.ml index 6cb8c89..88016ae 100644 --- a/rpc-light/pa_rpc.ml +++ b/rpc-light/pa_rpc.ml @@ -11,295 +11,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. *) -(* -pp camlp4orf *) open Camlp4 open PreCast open Ast -open Syntax -(* utils *) +open Pa_type_conv -let biList_to_expr _loc bindings final = - List.fold_right - (fun b a -> <:expr< let $b$ in $a$ >>) - bindings final - -let function_with_label_args _loc ~fun_name ~final_ident ~function_body ~return_type opt_args = - let opt_args = opt_args @ [ <:patt< $lid:final_ident$ >> ] in - <:binding< $lid:fun_name$ = - $List.fold_right (fun b a -> - <:expr $a$ >> - ) opt_args <:expr< ( $function_body$ : $return_type$ ) >> - $ >> - -let rec list_of_fields _loc fields = - match fields with - | <:ctyp< $t1$; $t2$ >> -> - list_of_fields _loc t1 @ list_of_fields _loc t2 - | <:ctyp< $lid:field_name$: mutable $t$ >> | <:ctyp< $lid:field_name$: $t$ >> -> - [ field_name, t ] - | _ -> failwith "unexpected type while processing fields" - -let record_of_fields _loc fields = - let rec_bindings = List.map (fun (n,e) -> Ast.RbEq(_loc, <:ident< $lid:n$ >>, e)) fields in - <:expr< { $rbSem_of_list rec_bindings$ } >> - -let list_of_expr _loc exprs = - match List.rev exprs with - | [] -> <:expr< [ ] >> - | h::t -> List.fold_left (fun accu x -> <:expr< [ $x$ :: $accu$ ] >>) <:expr< [ $h$ ] >> t - -let patt_list_of_expr _loc patts = - match List.rev patts with - | [] -> assert false - | h::t -> List.fold_left (fun accu x -> <:patt< [ $x$ :: $accu$ ] >>) <:patt< [ $h$ ] >> t - -let tuple_of_expr _loc exprs = - match List.rev exprs with - | [] -> assert false - | h::t -> Ast.ExTup ( _loc, List.fold_left (fun accu x -> <:expr< $x$,$accu$ >>) h t) -(* BUG? <:expr< ( $exCom_of_list exprs$ ) doesn't work >> *) - -let patt_tuple_of_expr _loc patts = - Ast.PaTup (_loc, paCom_of_list patts) -(* BUG? <:patt< ( $paCom_of_list patts$ ) doesn't work >> *) - -let decompose_variants _loc variant = - let rec fn accu = function - | <:ctyp< $t$ | $u$ >> -> fn (fn accu t) u - | <:ctyp< $uid:id$ of $t$ >> -> (id, Some t) :: accu - | <:ctyp< $uid:id$ >> -> (id, None) :: accu - | _ -> failwith "decompose_variant" - in fn [] variant - -let count = ref 0 -let new_id _loc = - incr count; - let new_id = Printf.sprintf "__x%i__" !count in - <:expr< $lid:new_id$ >>, <:patt< $lid:new_id$ >> - -(* conversion ML type -> Rpc.Val.t *) -module Rpc_of_ML = struct - - let rec value_of_ctyp _loc id = function - | <:ctyp< unit >> -> <:expr< `None >> - | <:ctyp< int >> -> <:expr< `Int (Int64.of_int $id$) >> - | <:ctyp< int32 >> -> <:expr< `Int (Int64.of_int32 $id$) >> - | <:ctyp< int64 >> -> <:expr< `Int $id$ >> - | <:ctyp< float >> -> <:expr< `Float $id$ >> - | <:ctyp< char >> -> <:expr< `String (Printf.sprintf "%c" $id$) >> - | <:ctyp< string >> -> <:expr< `String $id$ >> - | <:ctyp< bool >> -> <:expr< `Bool $id$ >> - - | <:ctyp< [< $t$ ] >> | <:ctyp< [> $t$ ] >> | <:ctyp< [= $t$ ] >> | <:ctyp< [ $t$ ] >> -> - let decomp = decompose_variants _loc t in - let patterns = - List.map (fun (n, t) -> - let new_id, new_pid = new_id _loc in - match t with - | None -> - <:match_case< $uid:n$ -> `List [ `String $str:n$ ] >> - | Some t -> - <:match_case< $uid:n$ $new_pid$ -> `List [ `String $str:n$; $value_of_ctyp _loc new_id t$ ] >> - ) decomp in - let pattern = mcOr_of_list patterns in - <:expr< match $id$ with [ $pattern$ ] >> - - | <:ctyp< option $t$ >> -> - let new_id, new_pid = new_id _loc in - <:expr< match $id$ with [ - Some $new_pid$ -> `List [ $value_of_ctyp _loc new_id t$ ] - | None -> `List [] - ] >> - - | <:ctyp< $tup:tp$ >> -> - let tys = list_of_ctyp tp [] in - let new_ids = List.map (fun t -> let new_id, new_pid = new_id _loc in (t,new_id, new_pid)) tys in - let exprs = List.map (fun (t,new_id,_) -> value_of_ctyp _loc new_id t) new_ids in - let new_ids_patt = List.map (fun (_,_,new_pid) -> new_pid) new_ids in - <:expr< - let $patt_tuple_of_expr _loc new_ids_patt$ = $id$ in - `List $list_of_expr _loc exprs$ - >> - - | <:ctyp< list $t$ >> -> - let new_id, new_pid = new_id _loc in - <:expr< `List (List.map (fun $new_pid$ -> $value_of_ctyp _loc new_id t$) $id$) >> - - | <:ctyp< array $t$ >> -> - let new_id, new_pid = new_id _loc in - <:expr< - `List (Array.to_list (Array.map (fun $new_pid$ -> $value_of_ctyp _loc new_id t$) $id$)) - >> - - | <:ctyp< { $t$ } >> -> - let get_name_value (n,ctyp) = <:expr< ($str:n$, $value_of_ctyp _loc <:expr< $lid:n$ >> ctyp$) >> in - - let fields = list_of_fields _loc t in - let bindings = List.map (fun (f,_) -> <:binding< $lid:f$ = $id$ . $lid:f$ >>) fields in - let final_expr = <:expr< `Dict $list_of_expr _loc (List.map get_name_value fields)$ >> in - biList_to_expr _loc bindings final_expr - - | <:ctyp< $lid:t$ >> -> <:expr< $lid:"rpc_of_"^t$ $id$ >> - - | _ -> failwith "Rpc_of_ML.value_of_ctyp: type not supported" - - let rpc_of _loc id ctyp = - let id = <:expr< $lid:id$ >> in - value_of_ctyp _loc id ctyp - - let process _loc id ctyp = - function_with_label_args _loc - ~fun_name:("rpc_of_"^id) - ~final_ident:id - ~function_body:(rpc_of _loc id ctyp) - ~return_type:<:ctyp< Rpc.Val.t >> - [] - -end - -(* conversion Rpc.Val.t -> ML type *) -module ML_of_rpc = struct - - let arg = let _loc = Loc.ghost in <:expr< $lid:"__x__"$ >> - let parg = let _loc = Loc.ghost in <:patt< $lid:"__x__"$ >> - - let parse_error expected got = - let _loc = Loc.ghost in - <:expr< do { - Printf.eprintf "Parse error: got '%s' while '%s' was expected.\n" (Rpc.Val.to_string $got$) $str:expected$; - raise (Parse_error($str:expected$, $got$)) } - >> - - let rec value_of_ctyp _loc id = function - | <:ctyp< unit >> -> - <:expr< match $id$ with [ `None -> () | $parg$ -> $parse_error "None" arg$ ] >> - - | <:ctyp< int >> -> - <:expr< match $id$ with [ `Int x -> Int64.to_int x | $parg$ -> $parse_error "Int(int)" arg$ ] >> - - | <:ctyp< int32 >> -> - <:expr< match $id$ with [ `Int x -> Int64.to_int32 x | $parg$ -> $parse_error "Int(int32)" arg$ ] >> - - | <:ctyp< int64 >> -> - <:expr< match $id$ with [ `Int x -> x | $parg$ -> $parse_error "Int(int64)" arg$ ] >> - - | <:ctyp< float >> -> - <:expr< match $id$ with [ `Float x -> x | $parg$ -> $parse_error "Float" arg$ ] >> - - | <:ctyp< char >> -> - <:expr< match $id$ with [ `String x -> x.[0] | $parg$ -> $parse_error "String(char)" arg$ ] >> - - | <:ctyp< string >> -> - <:expr< match $id$ with [ `String x -> x | $parg$ -> $parse_error "String(string)" arg$ ] >> - - | <:ctyp< bool >> -> - <:expr< match $id$ with [ `Bool x -> x | $parg$ -> $parse_error "Bool" arg$ ] >> - - | <:ctyp< [< $t$ ] >> | <:ctyp< [> $t$ ] >> | <:ctyp< [= $t$ ] >> | <:ctyp< [ $t$ ] >> -> - let decomp = decompose_variants _loc t in - let patterns = - List.map (fun (n,t) -> - let new_id, new_pid = new_id _loc in - match t with - | None -> - <:match_case< `List [ `String $str:n$ ] -> $uid:n$ >> - | Some t -> - <:match_case< `List [ `String $str:n$; $new_pid$ ] -> $uid:n$ $value_of_ctyp _loc new_id t$ >> - ) decomp - @ [ <:match_case< $parg$ -> $parse_error "List[String;_]" arg$ >> ] in - let pattern = mcOr_of_list patterns in - <:expr< match $id$ with [ $pattern$ ] >> - - | <:ctyp< option $t$ >> -> - let new_id, new_pid = new_id _loc in - <:expr< match $id$ with [ - `List [] -> None - | `List [$new_pid$] -> Some $value_of_ctyp _loc new_id t$ - | $parg$ -> $parse_error "List[_]" arg$ - ] >> - - | <:ctyp< $tup:tp$ >> -> - let tys = list_of_ctyp tp [] in - let new_ids = List.map (fun t -> let new_id, new_pid = new_id _loc in (t,new_id,new_pid)) tys in - let exprs = List.map (fun (t,new_id,mew_pid) -> value_of_ctyp _loc new_id t) new_ids in - let new_ids_patt = List.map (fun (_,_,new_pid) -> new_pid) new_ids in - let new_id, new_pid = new_id _loc in - <:expr< match $id$ with [ - `List $new_pid$ -> - match $new_id$ with [ - $patt_list_of_expr _loc new_ids_patt$ -> $tuple_of_expr _loc exprs$ - | $parg$ -> $parse_error (Printf.sprintf "list of size %i" (List.length tys)) <:expr< `List $arg$ >>$ ] - | $parg$ -> $parse_error "List[_]" arg$ - ] >> - - | <:ctyp< list $t$ >> -> - let new_id, new_pid = new_id _loc in - <:expr< match $id$ with [ - `List $new_pid$ -> - let __fn__ $parg$ = $value_of_ctyp _loc arg t$ in - List.map __fn__ $new_id$ - | $parg$ -> $parse_error "List[_]" arg$ - ] >> - - | <:ctyp< array $t$ >> -> - let new_id, new_pid = new_id _loc in - <:expr< match $id$ with [ - `List $new_pid$ -> - let __fn__ $parg$ = $value_of_ctyp _loc arg t$ in - Array.of_list (List.map __fn__ $new_id$) - | $parg$ -> $parse_error "List[_]" arg$ - ] >> - - | <:ctyp< { $t$ } >> -> - let new_id, new_pid = new_id _loc in - let fields = list_of_fields _loc t in - let bindings = - List.map (fun (n,ctyp) -> - <:binding< $lid:n$ = - let __f__ $parg$ = $value_of_ctyp _loc arg ctyp$ in - __f__ (try List.assoc $str:n$ $new_id$ with [ Not_found -> $parse_error ("key "^n) id$ ]) - >>) - fields in - let record_bindings = List.map (fun (n,_) -> (n,<:expr< $lid:n$ >>)) fields in - let final_expr = record_of_fields _loc record_bindings in - <:expr< match $id$ with [ - `Dict $new_pid$ -> $biList_to_expr _loc bindings final_expr$ - | $parg$ -> $parse_error "Dict(_)" arg$ - ] >> - - | <:ctyp< $lid:t$ >> -> <:expr< $lid:t^"_of_rpc"$ $id$ >> - - | _ -> failwith "ML_of_rpc.scalar_of_ctyp: unsuported type" - - let of_rpc _loc id ctyp = - let id = <:expr< $lid:id$ >> in - value_of_ctyp _loc id ctyp - - let process _loc id ctyp = - function_with_label_args _loc - ~fun_name:(id^"_of_rpc") - ~final_ident:id - ~function_body:(of_rpc _loc id ctyp) - ~return_type:<:ctyp< $lid:id$ >> - [] - -end - -let process_type_declaration _loc process ctyp = - let rec fn ty accu = match ty with - | Ast.TyAnd (_loc, tyl, tyr) -> fn tyl (fn tyr accu) - | Ast.TyDcl (_loc, id, _, ty, []) -> process _loc id ty :: accu - | _ -> accu in - biAnd_of_list (fn ctyp []) - -let () = - Pa_type_conv.add_generator "rpc" - (fun ctyp -> - let _loc = loc_of_ctyp ctyp in - <:str_item< - exception Parse_error of (string * Rpc.Val.t); - value rec $process_type_declaration _loc Rpc_of_ML.process ctyp$; - value rec $process_type_declaration _loc ML_of_rpc.process ctyp$ - >>) +let _ = + add_generator "rpc" (fun tds -> + let _loc = loc_of_ctyp tds in + <:str_item< $P4_rpc.gen tds$ >>) diff --git a/rpc-light/rpc.ml b/rpc-light/rpc.ml index 0e2dfea..05ffa22 100644 --- a/rpc-light/rpc.ml +++ b/rpc-light/rpc.ml @@ -12,44 +12,52 @@ * GNU Lesser General Public License for more details. *) -module Sig = struct - type t = - [ `Int | `Bool | `Float | `String - | `Product of t list - | `Named_product of (string * t) list - | `Named_sum of (string * t) list - | `Option of t ] -end - -module Val = struct - type t = - [ `Int of int64 - | `Bool of bool - | `Float of float - | `String of string - | `List of t list - | `Dict of (string * t) list - | `None ] - - let rec to_string (x:t) = match x with - | `Int i -> Printf.sprintf "Int(%Lu)" i - | `Bool b -> Printf.sprintf "Bool(%b)" b - | `Float f -> Printf.sprintf "Float(%f)" f - | `String s -> Printf.sprintf "String(%s)" s - | `List l -> "List [ " ^ String.concat ", " (List.map to_string l) ^ " ]" - | `Dict d -> "Dict {" ^ String.concat ", " (List.map (fun (s,t) -> Printf.sprintf "%s: %s" s (to_string t)) d) ^ " }" - | `None -> "None" -end - -(* The first argument is the list of record field names we already went trough *) -type callback = string list -> Val.t -> unit +type t = + | Int of int64 + | Bool of bool + | Float of float + | String of string + | Enum of t list + | Dict of (string * t) list + | Null + +open Printf +let map_strings sep fn l = String.concat sep (List.map fn l) +let rec to_string t = match t with + | Int i -> sprintf "I(%Li)" i + | Bool b -> sprintf "B(%b)" b + | Float f -> sprintf "F(%g)" f + | String s -> sprintf "S(%s)" s + | Enum ts -> sprintf "[%s]" (map_strings ";" to_string ts) + | Dict ts -> sprintf "{%s}" (map_strings ";" (fun (s,t) -> sprintf "%s:%s" s (to_string t)) ts) + | Null -> "N" + + +let rpc_of_t x = x +let rpc_of_int64 i = Int i +let rpc_of_bool b = Bool b +let rpc_of_float f = Float f +let rpc_of_string s = String s + +let t_of_rpc x = x +let int64_of_rpc = function Int i -> i | _ -> failwith "int64_of_rpc" +let bool_of_rpc = function Bool b -> b | _ -> failwith "bool_of_rpc" +let float_of_rpc = function Float f -> f | _ -> failwith "float_of_rpc" +let string_of_rpc = function String s -> s | _ -> failwith "string_of_rpc" + +type callback = string list -> t -> unit type call = { name: string; - params: Val.t list + params: t list; } +let call name params = { name = name; params = params } + type response = { success: bool; - contents: Val.t + contents: t; } + +let success v = { success = true; contents = v } +let failure v = { success = false; contents = v } diff --git a/rpc-light/rpc.mli b/rpc-light/rpc.mli index cdeff15..d737ac7 100644 --- a/rpc-light/rpc.mli +++ b/rpc-light/rpc.mli @@ -30,12 +30,6 @@ val to_string : t -> string val int64_of_rpc : t -> int64 val rpc_of_int64 : int64 -> t -val int32_of_rpc : t -> int32 -val rpc_of_int32 : int32 -> t - -val int_of_rpc : t -> int -val rpc_of_int : int -> t - val bool_of_rpc : t -> bool val rpc_of_bool : bool -> t @@ -48,9 +42,6 @@ val rpc_of_string : string -> t val t_of_rpc : t -> t val rpc_of_t : t -> t -val unit_of_rpc : t -> unit -val rpc_of_unit : unit -> t - (** {2 Calls} *) type callback = string list -> t -> unit @@ -59,22 +50,9 @@ type call = { name : string; params : t list } val call : string -> t list -> call -val string_of_call : call -> string - (** {2 Responses} *) type response = { success : bool; contents : t } -val string_of_response : response -> string - val success : t -> response val failure : t -> response - -(** {2 Run-time errors} *) - -exception Runtime_error of string * t -exception Runtime_exception of string * string - -(** {2 Debug options} *) -val set_debug : bool -> unit -val get_debug : unit -> bool diff --git a/rpc-light/xmlrpc.ml b/rpc-light/xmlrpc.ml index cb79bf0..566281c 100644 --- a/rpc-light/xmlrpc.ml +++ b/rpc-light/xmlrpc.ml @@ -13,6 +13,7 @@ *) open Printf +open Rpc let debug = ref false let debug (fmt: ('a, unit, string, unit) format4) : 'a = @@ -31,32 +32,35 @@ let check s = s let rec add_value f = function - | `Int i -> - f ""; + | Null -> + f "" + + | Int i -> + f ""; f (Int64.to_string i); - f "" + f "" - | `Bool b -> - f ""; - f (string_of_bool b); - f "" + | Bool b -> + f ""; + f (if b then "1" else "0"); + f "" - | `Float d -> + | Float d -> f ""; - f (string_of_float d); + f (Printf.sprintf "%g" d); f "" - | `String s -> - f ""; + | String s -> + f ""; f (check s); - f "" + f "" - | `List a -> + | Enum l -> f ""; - List.iter (add_value f) a; + List.iter (add_value f) l; f "" - | `Dict s -> + | Dict d -> let add_member (name, value) = f ""; f name; @@ -65,12 +69,9 @@ let rec add_value f = function f "" in f ""; - List.iter add_member s; + List.iter add_member d; f "" - | `None -> - f "nil" - let to_string x = let buf = Buffer.create 128 in add_value (Buffer.add_string buf) x; @@ -82,13 +83,13 @@ let string_of_call call = let add = B.add_string buf in add ""; add ""; - add (check call.Rpc.name); + add (check call.name); add ""; List.iter (fun p -> add ""; add (to_string p); add "" - ) call.Rpc.params; + ) call.params; add ""; B.contents buf @@ -96,7 +97,7 @@ let string_of_response response = let module B = Buffer in let buf = B.create 256 in let add = B.add_string buf in - let v = `Dict [ (if response.Rpc.success then "success" else "failure"), response.Rpc.contents ] in + let v = if response.success then response.contents else Dict [ "failure", response.contents ] in add ""; add (to_string v); add ""; @@ -123,7 +124,7 @@ let debug_input input = | `El_end -> begin match tags with | [] -> - Buffer.add_string buf ""; + Buffer.add_string buf ""; aux tags | h :: t -> Buffer.add_string buf " d @@ -192,44 +193,20 @@ module Parser = struct List.rev !r - (* Basic constructors *) - let make_int ?callback accu data : Rpc.Val.t = - let r = `Int (Int64.of_string data) in - match callback with - | Some f -> f (List.rev accu) r; r - | None -> r - - let make_bool ?callback accu data : Rpc.Val.t = - let r = `Bool (bool_of_string data) in + (* Constructors *) + let make fn ?callback accu data = + let r = fn data in match callback with | Some f -> f (List.rev accu) r; r | None -> r - let make_double ?callback accu data : Rpc.Val.t = - let r = `Float (float_of_string data) in - match callback with - | Some f -> f (List.rev accu) r; r - | None -> r - - let make_string ?callback accu data : Rpc.Val.t = - let r = match data with - | "nil" -> `None - | s -> `String s in - match callback with - | Some f -> f (List.rev accu) r; r - | None -> r - - let make_array ?callback accu data : Rpc.Val.t = - let r = `List data in - match callback with - | Some f -> f (List.rev accu) r; r - | None -> r - - let make_struct ?callback accu data : Rpc.Val.t = - let r = `Dict data in - match callback with - | Some f -> f (List.rev accu) r; r - | None -> r + let make_null = make (fun () -> Null) + let make_int = make (fun data -> Int (Int64.of_string data)) + let make_bool = make (fun data -> Bool (if data = "1" then true else false)) + let make_float = make (fun data -> Float (float_of_string data)) + let make_string = make (fun data -> String data) + let make_enum = make (fun data -> Enum data) + let make_dict = make (fun data -> Dict data) (* General parser functions *) let rec of_xml ?callback accu input = @@ -240,13 +217,15 @@ module Parser = struct | e -> Printf.eprintf "%s\n%!" (Printexc.to_string e); exit (-1) and basic_types ?callback accu input = function - | "int" | "i4" -> make_int ?callback accu (get_data input) - | "bool" -> make_bool ?callback accu (get_data input) - | "double" -> make_double ?callback accu (get_data input) - | "string" -> make_string ?callback accu (get_data input) - | "array" -> make_array ?callback accu (data (of_xmls ?callback accu) input) - | "struct" -> make_struct ?callback accu (members (fun name -> of_xml ?callback (name::accu)) input) - | e -> make_string ?callback accu e + | "int" + | "i4" -> make_int ?callback accu (get_data input) + | "boolean" -> make_bool ?callback accu (get_data input) + | "double" -> make_float ?callback accu (get_data input) + | "string" -> make_string ?callback accu (get_data input) + | "array" -> make_enum ?callback accu (data (of_xmls ?callback accu) input) + | "struct" -> make_dict ?callback accu (members (fun name -> of_xml ?callback (name::accu)) input) + | "nil" -> make_null ?callback accu () + | tag -> parse_error tag (Xmlm.peek input) input and of_xmls ?callback accu input = let r = ref [] in @@ -278,7 +257,7 @@ let call_of_string ?callback str = done; ) input ) input; - { Rpc.name = !name; Rpc.params = !params } + call !name (List.rev !params) let response_of_string ?callback str = let input = Xmlm.make_input (`String (0, str)) in @@ -288,11 +267,9 @@ let response_of_string ?callback str = Parser.map_tag "methodResponse" (fun input -> Parser.map_tag "params" (fun input -> Parser.map_tag "param" (fun input -> - let signal = Xmlm.peek input in match Parser.of_xml ?callback [] input with - | `Dict [ "success", v ] -> { Rpc.success = true; Rpc.contents = v } - | `Dict [ "failure", v ] -> { Rpc.success = false; Rpc.contents = v } - | v -> parse_error "response" signal input + | Dict [ "failure", v ] -> failure v + | v -> success v ) input ) input ) input diff --git a/rpc-light/xmlrpc.mli b/rpc-light/xmlrpc.mli index 4643ec2..f0ae723 100644 --- a/rpc-light/xmlrpc.mli +++ b/rpc-light/xmlrpc.mli @@ -12,8 +12,8 @@ * GNU Lesser General Public License for more details. *) -val to_string : Rpc.Val.t -> string -val of_string : ?callback:Rpc.callback -> string -> Rpc.Val.t +val to_string : Rpc.t -> string +val of_string : ?callback:Rpc.callback -> string -> Rpc.t val string_of_call: Rpc.call -> string val call_of_string: ?callback:Rpc.callback -> string -> Rpc.call diff --git a/stdext/META.in b/stdext/META.in index 409c726..67b7e0d 100644 --- a/stdext/META.in +++ b/stdext/META.in @@ -1,5 +1,5 @@ version = "@VERSION@" description = "Stdext - Common stdlib extensions" -requires = "unix,uuid,bigarray,rpc-light,jsonrpc" +requires = "unix,uuid,bigarray,rpc-light.json" archive(byte) = "stdext.cma" archive(native) = "stdext.cmxa"