let add_known_type ident = known_types := ident :: !known_types
let reset_known_types () = known_types := []
+let converters = ((ref []) : (string * string) list ref)
+let add_converter ident conv =
+ add_known_type ident;
+ converters := (ident, conv) :: !converters
+let find_converter ident =
+ try List.assoc ident !converters
+ with Not_found -> ident
+let reset_converters () = converters := []
+
let base_to_str = function
| B_string -> "Json_conv.string"
| B_int -> "Json_conv.int"
| B_int64 -> "Json_conv.int64"
| B_float -> "Json_conv.float"
| B_bool -> "Json_conv.bool"
- | B_ident s -> s
+ | B_ident s -> find_converter s
type var = { stem: string; mark: int }
module Pragma = struct
exception Missing_prefix of string * string
+ exception Unknown_pragma of string
- let is_space c = c = ' ' || c = '\t' || c = '\n'
-
- let rev_strip_leading clist =
- let do_char (l, pass) c =
- if pass then c::l, true
- else if is_space c then l, false
- else c::l, true
- in
- fst (List.fold_left do_char ([], false) clist)
+ (* NOTE: To make parsing pragmas robust, use a space at each
+ end of the Scanf format string.
+ *)
- let trim clist =
- rev_strip_leading (rev_strip_leading clist)
+ let record_prefix = ref ""
+ let try_parse_set_record_prefix p =
+ try
+ Scanf.sscanf p " set_record_prefix = %s "
+ (fun prefix ->
+ record_prefix := prefix;
+ dbg "Set record prefix to \"%s\".\n" !record_prefix
+ );
+ true
+ with _ -> false
+
+ let try_parse_clear_record_prefix p =
+ try
+ Scanf.sscanf p " %s "
+ (fun p ->
+ if p = "clear_record_prefix" then begin
+ dbg "Cleared record prefix (was \"%s\").\n" !record_prefix;
+ record_prefix := "";
+ true
+ end else false
+ )
+ with _ -> false
+
+ let try_parse_use_converter p =
+ try
+ Scanf.sscanf p " use_converter %s for %s "
+ (fun conv typ ->
+ dbg "added converter \"%s\" for \"%s\"\n." conv typ;
+ add_converter typ conv
+ );
+ true
+ with _ -> false
+
+ let try_parse_open ff p =
+ try
+ Scanf.sscanf p " open %s "
+ (fun m ->
+ dbg "inserted open for module \"%s\"\n." m;
+ fprintf ff "open %s@\n" m
+ );
+ true
+ with _ -> false
let clist_to_str clist =
let len = List.length clist in
ignore (List.fold_left (fun pos c -> s.[pos] <- c; (pos - 1)) (len-1) clist);
s
+ let process_pragma ff p =
+ let p = clist_to_str p in
+ if try_parse_set_record_prefix p then ()
+ else if try_parse_clear_record_prefix p then ()
+ else if try_parse_use_converter p then ()
+ else if try_parse_open ff p then ()
+ else raise (Unknown_pragma p)
+
let is_prefix prefix str =
let plen, slen = String.length prefix, String.length str in
(plen <= slen) && (String.sub str 0 plen = prefix)
then String.sub str plen (slen - plen)
else str
- let record_prefix = ref ""
- let process_pragma p =
- let p = clist_to_str (trim p) in
- dbg "Saw pragma %s.\n" p;
- if is_prefix "set_record_prefix=" p then begin
- record_prefix := strip_prefix "set_record_prefix=" p;
- dbg "Set record prefix to \"%s\".\n" !record_prefix
- end else if is_prefix "clear_record_prefix" p then begin
- dbg "Cleared record prefix (was \"%s\").\n" !record_prefix;
- record_prefix := ""
- end
-
let json_field_name fn =
if is_prefix !record_prefix fn
then strip_prefix !record_prefix fn
Printf.sprintf "Unknown base type \"%s\"" id
| Pragma.Missing_prefix (p, f) ->
Printf.sprintf "Prefix \"%s\" cannot be stripped from field \"%s\"" p f
+ | Pragma.Unknown_pragma p ->
+ Printf.sprintf "Unable to parse pragma \"%s\"" p
| e ->
Printf.sprintf "%s" (Printexc.to_string e)
let generate defn_list ofn ifn =
reset_known_types ();
+ reset_converters ();
(try Unix.unlink ofn with _ -> ());
let op_flags = [ Open_wronly ; Open_creat; Open_trunc; Open_text ] in
let oc = open_out_gen op_flags 0o444 ofn in
generate_header ff ifn;
List.iter (function
| Pragma p ->
- Pragma.process_pragma p
+ Pragma.process_pragma ff p
| Type_defn def ->
generate_one_defn ff def
) defn_list;
| Constr2 <type> ["Constr2", enc(<type>)]
| Constr3 (<type1>,<type2>) ["Constr3", enc(<type1>), enc(<type2>)]
+
+The input file can specify some pragmas to control the generated code.
+A pragma is specified in the form:
+
+(*** json-pragma: pragma ***)
+^^^^^^^^^^^^^^^^^^ ^^^^^
+Note that specified characters (including spaces) must appear exactly
+as shown.
+
+A "set_record_prefix=p" pragma allows a prefix p to be trimmed from all
+fields of an ocaml record type before generating the corresponding
+json object, and added back when converting back from json. The
+code-generator reports an error if a record field doesn't possess the
+specified prefix. A "clear_record_prefix" pragma unsets this pragma.
+
+A "use_converter prefix for type" pragma allows the
+specification of alternate converter functions
+prefix_{to_json,of_json} for a specified type, instead of the default
+type_{to_json,of_json}.
+
+A "open module" pragma inserts an "open module" into the generated
+code.
+
+
JSON-RPC boilerplate generator:
-------------------------------