]> xenbits.xensource.com Git - xenclient/toolstack.git/commitdiff
[json] half-done json<->ocaml conv generator
authorPrashanth Mundkur <prashanth.mundkur@citrix.com>
Mon, 6 Apr 2009 21:41:29 +0000 (14:41 -0700)
committerPrashanth Mundkur <prashanth.mundkur@citrix.com>
Mon, 6 Apr 2009 21:41:29 +0000 (14:41 -0700)
    <ocaml>_to_json should be basically done; json_to_<ocaml> remains.
    Made a minor directory reorg, and added an omakefile to ease standalone builds.

91 files changed:
libs/json/OMakefile [new file with mode: 0644]
libs/json/OMakeroot [new file with mode: 0644]
libs/json/base_conv.ml [new file with mode: 0644]
libs/json/base_conv.mli [new file with mode: 0644]
libs/json/codegen.ml [new file with mode: 0644]
libs/json/json.ml
libs/json/json.mli
libs/json/json_parse_test.ml [deleted file]
libs/json/jsonc.ml [new file with mode: 0644]
libs/json/lexer.mll [new file with mode: 0644]
libs/json/parser.mly [new file with mode: 0644]
libs/json/parser_tests/LICENSE.txt [new file with mode: 0644]
libs/json/parser_tests/README [new file with mode: 0644]
libs/json/parser_tests/fail1.json [new file with mode: 0644]
libs/json/parser_tests/fail10.json [new file with mode: 0644]
libs/json/parser_tests/fail11.json [new file with mode: 0644]
libs/json/parser_tests/fail12.json [new file with mode: 0644]
libs/json/parser_tests/fail13.json [new file with mode: 0644]
libs/json/parser_tests/fail14.json [new file with mode: 0644]
libs/json/parser_tests/fail15.json [new file with mode: 0644]
libs/json/parser_tests/fail16.json [new file with mode: 0644]
libs/json/parser_tests/fail17.json [new file with mode: 0644]
libs/json/parser_tests/fail18.json [new file with mode: 0644]
libs/json/parser_tests/fail19.json [new file with mode: 0644]
libs/json/parser_tests/fail2.json [new file with mode: 0644]
libs/json/parser_tests/fail20.json [new file with mode: 0644]
libs/json/parser_tests/fail21.json [new file with mode: 0644]
libs/json/parser_tests/fail22.json [new file with mode: 0644]
libs/json/parser_tests/fail23.json [new file with mode: 0644]
libs/json/parser_tests/fail24.json [new file with mode: 0644]
libs/json/parser_tests/fail25.json [new file with mode: 0644]
libs/json/parser_tests/fail26.json [new file with mode: 0644]
libs/json/parser_tests/fail27.json [new file with mode: 0644]
libs/json/parser_tests/fail28.json [new file with mode: 0644]
libs/json/parser_tests/fail29.json [new file with mode: 0644]
libs/json/parser_tests/fail3.json [new file with mode: 0644]
libs/json/parser_tests/fail30.json [new file with mode: 0644]
libs/json/parser_tests/fail31.json [new file with mode: 0644]
libs/json/parser_tests/fail32.json [new file with mode: 0644]
libs/json/parser_tests/fail33.json [new file with mode: 0644]
libs/json/parser_tests/fail4.json [new file with mode: 0644]
libs/json/parser_tests/fail5.json [new file with mode: 0644]
libs/json/parser_tests/fail6.json [new file with mode: 0644]
libs/json/parser_tests/fail7.json [new file with mode: 0644]
libs/json/parser_tests/fail8.json [new file with mode: 0644]
libs/json/parser_tests/fail9.json [new file with mode: 0644]
libs/json/parser_tests/pass1.json [new file with mode: 0644]
libs/json/parser_tests/pass2.json [new file with mode: 0644]
libs/json/parser_tests/pass3.json [new file with mode: 0644]
libs/json/parser_tests/run_tests.sh [new file with mode: 0755]
libs/json/syntax.ml [new file with mode: 0644]
libs/json/test_parser.ml [new file with mode: 0644]
libs/json/tests/LICENSE.txt [deleted file]
libs/json/tests/README [deleted file]
libs/json/tests/fail1.json [deleted file]
libs/json/tests/fail10.json [deleted file]
libs/json/tests/fail11.json [deleted file]
libs/json/tests/fail12.json [deleted file]
libs/json/tests/fail13.json [deleted file]
libs/json/tests/fail14.json [deleted file]
libs/json/tests/fail15.json [deleted file]
libs/json/tests/fail16.json [deleted file]
libs/json/tests/fail17.json [deleted file]
libs/json/tests/fail18.json [deleted file]
libs/json/tests/fail19.json [deleted file]
libs/json/tests/fail2.json [deleted file]
libs/json/tests/fail20.json [deleted file]
libs/json/tests/fail21.json [deleted file]
libs/json/tests/fail22.json [deleted file]
libs/json/tests/fail23.json [deleted file]
libs/json/tests/fail24.json [deleted file]
libs/json/tests/fail25.json [deleted file]
libs/json/tests/fail26.json [deleted file]
libs/json/tests/fail27.json [deleted file]
libs/json/tests/fail28.json [deleted file]
libs/json/tests/fail29.json [deleted file]
libs/json/tests/fail3.json [deleted file]
libs/json/tests/fail30.json [deleted file]
libs/json/tests/fail31.json [deleted file]
libs/json/tests/fail32.json [deleted file]
libs/json/tests/fail33.json [deleted file]
libs/json/tests/fail4.json [deleted file]
libs/json/tests/fail5.json [deleted file]
libs/json/tests/fail6.json [deleted file]
libs/json/tests/fail7.json [deleted file]
libs/json/tests/fail8.json [deleted file]
libs/json/tests/fail9.json [deleted file]
libs/json/tests/pass1.json [deleted file]
libs/json/tests/pass2.json [deleted file]
libs/json/tests/pass3.json [deleted file]
libs/json/tests/run_tests.sh [deleted file]

diff --git a/libs/json/OMakefile b/libs/json/OMakefile
new file mode 100644 (file)
index 0000000..a629b5c
--- /dev/null
@@ -0,0 +1,36 @@
+.PHONY: clean
+
+OCAMLFLAGS += -dtypes
+
+JSON_FILES[] =
+       json
+       json_parse
+       base_conv
+
+LIB = json
+JSON_LIB = $(OCamlLibrary $(LIB), $(JSON_FILES))
+
+section
+       TEST_PARSER_PROG = test_parser
+       OCAML_LIBS += json
+       TEST_PARSER = $(OCamlProgram $(TEST_PARSER_PROG), test_parser $(JSON_FILES))
+       export TEST_PARSER
+
+section
+       GEN_FILES = parser.mli parser.ml lexer.ml
+       OCamlGeneratedFiles($(GEN_FILES))
+       CONV_FILES[] =
+               lexer
+               parser
+               syntax
+               codegen
+               jsonc
+
+       JSON_CONV_PROG = jsonc
+       JSON_CONV = $(OCamlProgram $(JSON_CONV_PROG), $(CONV_FILES))
+       export JSON_CONV
+
+.DEFAULT: $(JSON_LIB) $(TEST_PARSER) $(JSON_CONV)
+
+clean:
+    rm -f $(filter-proper-targets $(ls R, .)) *.annot *.cmo
diff --git a/libs/json/OMakeroot b/libs/json/OMakeroot
new file mode 100644 (file)
index 0000000..78ebe81
--- /dev/null
@@ -0,0 +1,12 @@
+open build/OCaml
+
+#
+# The command-line variables are defined *after* the
+# standard configuration has been loaded.
+#
+DefineCommandVars()
+
+#
+# Include the OMakefile in this directory.
+#
+.SUBDIRS: .
diff --git a/libs/json/base_conv.ml b/libs/json/base_conv.ml
new file mode 100644 (file)
index 0000000..a792786
--- /dev/null
@@ -0,0 +1,120 @@
+(*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Prashanth Mundkur <firstname.lastname@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Json
+
+exception Json_conv_failure of string
+
+let string_of_json ?(permissive=false) j =
+       let strict = function
+               | Json_null _   -> raise (Json_conv_failure "null->string")
+               | Json_bool _   -> raise (Json_conv_failure "bool->string")
+               | Json_int  _   -> raise (Json_conv_failure "int->string")
+               | Json_float _  -> raise (Json_conv_failure "float->string")
+               | Json_string s -> s
+               | Json_object _ -> raise (Json_conv_failure "object->string")
+               | Json_array _  -> raise (Json_conv_failure "array->string") in
+       let lenient = function
+               | Json_null _   -> ""
+               | Json_bool _   -> raise (Json_conv_failure "bool->string")
+               | Json_int  _   -> raise (Json_conv_failure "int->string")
+               | Json_float _  -> raise (Json_conv_failure "float->string")
+               | Json_string s -> s
+               | Json_object _ -> raise (Json_conv_failure "object->string")
+               | Json_array a  ->
+                       if Array.length a = 0 then
+                               raise (Json_conv_failure "array->string")
+                       else
+                               strict a.(0) in
+       if not permissive then strict j else lenient j
+let string_to_json s = Json_string s
+
+
+let int_of_json ?(permissive=false) j =
+       let strict = function
+               | Json_null _   -> raise (Json_conv_failure "null->int")
+               | Json_bool _   -> raise (Json_conv_failure "bool->int")
+               | Json_int i    -> Int64.to_int i
+               | Json_float _  -> raise (Json_conv_failure "float->int")
+               | Json_string _ -> raise (Json_conv_failure "float->int")
+               | Json_object _ -> raise (Json_conv_failure "object->int")
+               | Json_array _  -> raise (Json_conv_failure "array->int") in
+       let lenient = function
+               | Json_null _   -> 0
+               | Json_bool b   -> if b then 1 else 0
+               | Json_int i    -> Int64.to_int i
+               | Json_float _  -> raise (Json_conv_failure "float->int")
+               | Json_string _ -> raise (Json_conv_failure "string->int")
+               | Json_object _ -> raise (Json_conv_failure "object->int")
+               | Json_array a  ->
+                       if Array.length a = 0 then
+                               raise (Json_conv_failure "array->int")
+                       else
+                               strict a.(0) in
+       if not permissive then strict j else lenient j
+
+let int_to_json i = Json_int (Int64.of_int i)
+
+
+let int64_of_json ?(permissive=false) j =
+       let strict = function
+               | Json_null _   -> raise (Json_conv_failure "null->int64")
+               | Json_bool _   -> raise (Json_conv_failure "bool->int64")
+               | Json_int i    -> i
+               | Json_float _  -> raise (Json_conv_failure "float->int64")
+               | Json_string _ -> raise (Json_conv_failure "float->int64")
+               | Json_object _ -> raise (Json_conv_failure "object->int64")
+               | Json_array _  -> raise (Json_conv_failure "array->int64") in
+       let lenient = function
+               | Json_null _   -> 0L
+               | Json_bool b   -> if b then 1L else 0L
+               | Json_int i    -> i
+               | Json_float _  -> raise (Json_conv_failure "float->int64")
+               | Json_string _ -> raise (Json_conv_failure "string->int64")
+               | Json_object _ -> raise (Json_conv_failure "object->int64")
+               | Json_array a  ->
+                       if Array.length a = 0 then
+                               raise (Json_conv_failure "array->int64")
+                       else
+                               strict a.(0) in
+       if not permissive then strict j else lenient j
+
+let int64_to_json i = Json_int i
+
+let bool_of_json  ?(permissive=false) j =
+       let strict = function
+               | Json_null _   -> raise (Json_conv_failure "null->bool")
+               | Json_bool b   -> b
+               | Json_int i    -> raise (Json_conv_failure "int->bool")
+               | Json_float _  -> raise (Json_conv_failure "float->bool")
+               | Json_string _ -> raise (Json_conv_failure "float->bool")
+               | Json_object _ -> raise (Json_conv_failure "object->bool")
+               | Json_array _  -> raise (Json_conv_failure "array->bool") in
+       let lenient = function
+               | Json_null _   -> false
+               | Json_bool b   -> b
+               | Json_int i    -> i <> 0L
+               | Json_float _  -> raise (Json_conv_failure "float->bool")
+               | Json_string _ -> raise (Json_conv_failure "string->bool")
+               | Json_object _ -> raise (Json_conv_failure "object->bool")
+               | Json_array a  ->
+                       if Array.length a = 0 then
+                               raise (Json_conv_failure "array->bool")
+                       else
+                               strict a.(0) in
+       if not permissive then strict j else lenient j
+
+let bool_to_json b = Json_bool b
diff --git a/libs/json/base_conv.mli b/libs/json/base_conv.mli
new file mode 100644 (file)
index 0000000..62ef6f5
--- /dev/null
@@ -0,0 +1,31 @@
+(*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Prashanth Mundkur <firstname.lastname@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+exception Json_conv_failure of string
+
+val string_of_json: ?permissive:bool -> Json.t -> string
+val string_to_json: string -> Json.t
+
+val int_of_json: ?permissive:bool -> Json.t -> int
+val int_to_json: int -> Json.t
+
+val int64_of_json: ?permissive:bool -> Json.t -> int64
+val int64_to_json: int64 -> Json.t
+
+val bool_of_json: ?permissive:bool -> Json.t -> bool
+val bool_to_json: bool -> Json.t
+
+
+
diff --git a/libs/json/codegen.ml b/libs/json/codegen.ml
new file mode 100644 (file)
index 0000000..26a3dc6
--- /dev/null
@@ -0,0 +1,216 @@
+(*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Prashanth Mundkur <firstname.lastname@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Syntax
+open Format
+
+let base_to_str = function
+       | B_string -> "string"  | B_int -> "int"        | B_int64 -> "int64"
+       | B_bool -> "bool"      | B_ident s -> s
+
+type var = { stem: string; mark: int }
+
+let name_of_var v =
+       match v.mark with
+       | 0 -> Printf.sprintf "%s" v.stem
+       | d -> Printf.sprintf "%s_%d" v.stem d
+
+module type VAR_ENV = sig
+       type t
+       val new_env: t
+       val new_ident_from_name: t -> ?prefix:string -> ?suffix:string -> string -> var * t
+       val new_ident_from_type: t -> complex_type -> var * t
+       val new_idents_from_types: t -> complex_type list -> var list * t
+       val new_idents_from_vars: t -> ?prefix:string -> ?suffix:string -> var list -> var list * t
+end
+
+module Var_env : VAR_ENV = struct
+       module StringMap = Map.Make (struct type t = string let compare = compare end)
+
+       type name_entry = { cur_mark: int; entries: var list; }
+
+       let new_name_entry = { cur_mark = 0; entries = [] }
+
+       let make_new_var name_entry name =
+               let var = { stem = name; mark = name_entry.cur_mark} in
+               var, { cur_mark = var.mark + 1; entries = var :: name_entry.entries }
+
+       type t = name_entry StringMap.t
+       let new_env = StringMap.empty
+
+       let new_var env full_name =
+               let var, new_entry = make_new_var (try StringMap.find full_name env
+                                                  with Not_found -> new_name_entry) full_name in
+               var, (StringMap.add full_name new_entry env)
+
+       let new_ident_from_name env ?(prefix="") ?(suffix="") stem =
+               new_var env (prefix ^ stem ^ suffix)
+
+       let base_to_stem = function
+       | B_string -> "str"     | B_int -> "int"        | B_int64 -> "int64"
+       | B_bool -> "bool"      | B_ident s -> s
+
+       let complex_type_to_stem = function
+       | C_base b -> base_to_stem b    | C_option _ -> "opt"   | C_list _ -> "lst"
+       | C_array _ -> "arr"            | C_tuple _ -> "tup"    | C_record _ -> "rec"
+       | C_variant _ -> "var"
+
+       let new_ident_from_type env ct =
+               new_ident_from_name env (complex_type_to_stem ct)
+
+       let new_idents_from_types env cts =
+               let vlist, env =
+                       List.fold_left (fun (vlist, env) ct ->
+                                               let v, env' = new_ident_from_type env ct in
+                                               (v :: vlist), env'
+                                      ) ([], env) cts in
+               (List.rev vlist), env
+
+       let new_ident_from_var env ?(prefix="") ?(suffix="") var =
+               new_ident_from_name env ~prefix ~suffix var.stem
+
+       let new_idents_from_vars env ?(prefix="") ?(suffix="") vlist =
+               let vlist, env =
+                       List.fold_left (fun (vlist, env) v ->
+                                               let v, env' = new_ident_from_var env ~prefix ~suffix v in
+                                               (v :: vlist), env'
+                                      ) ([], env) vlist in
+               (List.rev vlist), env
+end
+
+module To = struct
+       let prod_vars_to_str vlist =
+               let elems = List.map name_of_var vlist in
+               String.concat ", " elems
+       let to_array_str ?(constr="") vlist =
+               let elems = List.map name_of_var vlist in
+               let constr = if constr = "" then "" else "(string_to_json \"" ^ constr ^ "\"); " in
+               "[| " ^ constr ^ (String.concat "; " elems) ^ " |]"
+       let to_object_str fn_list fv_list =
+               let elems = List.map2 (fun f v ->
+                                       Printf.sprintf "(\"%s\", %s)" f (name_of_var v)
+                                     ) fn_list fv_list in
+               "[| " ^ (String.concat "; " elems) ^ " |]"
+       let to_record_str fnlist fvlist =
+               let fields = List.map2 (fun fn fv ->
+                                         Printf.sprintf "%s = %s" fn (name_of_var fv)
+                                      ) fnlist fvlist in
+               "{ " ^ (String.concat "; " fields) ^ " }"
+       let rec to_json ff venv inv typ =
+               let v = name_of_var inv in
+               match typ with
+               | C_base bt ->
+                       fprintf ff "%s_to_json %s" (base_to_str bt) v
+               | C_option optt ->
+                       let optv, venv' = Var_env.new_ident_from_type venv optt in
+                       fprintf ff "(match %s with@," v;
+                       fprintf ff "| None -> Json_null@,";
+                       fprintf ff "@[<v 8>| Some %s ->@," (name_of_var optv);
+                       to_json ff venv' optv optt;
+                       fprintf ff "@]@,)"
+               | C_list elemt ->
+                       let elemv, venv' = Var_env.new_ident_from_type venv elemt in
+                       let jlistv, venv' = Var_env.new_ident_from_name venv' v ~suffix:"_jlist" in
+                       let jlistvn = name_of_var jlistv in
+                       fprintf ff "@[<v 8>let %s = List.map@," jlistvn;
+                       fprintf ff "@[<v 8>(fun %s ->@," (name_of_var elemv);
+                       to_json ff venv' elemv elemt;
+                       fprintf ff "@]@,) %s in@]@," v;
+                       fprintf ff "Json_array (Array.of_list %s)" jlistvn
+               | C_array elemt ->
+                       let elemv, venv' = Var_env.new_ident_from_type venv elemt in
+                       let jarrayv, venv' = Var_env.new_ident_from_name venv' v ~suffix:"_jarray" in
+                       let jarrayvn = name_of_var jarrayv in
+                       fprintf ff "@[<v 8>let %s = Array.map@," jarrayvn;
+                       fprintf ff "@[<v 8>(fun %s ->@," (name_of_var elemv);
+                       to_json ff venv' elemv elemt;
+                       fprintf ff "@]@,) %s in@]@," v;
+                       fprintf ff "Json_array %s" jarrayvn
+               | C_tuple ctlist ->
+                       let cvlist, venv' = Var_env.new_idents_from_types venv ctlist in
+                       let letvlist, venv' = Var_env.new_idents_from_vars venv' ~prefix:"j_" cvlist in
+                       let cvtlist = List.combine cvlist ctlist in
+                       fprintf ff "(match %s with@," v;
+                       fprintf ff "@[<v 8>| %s ->@," (prod_vars_to_str cvlist);
+                       List.iter2 (fun letv (cv, ct) ->
+                                       let_bind ff venv' letv cv ct
+                                 ) letvlist cvtlist;
+                       fprintf ff "Json_array %s@]@,)" (to_array_str letvlist)
+               | C_record cls ->
+                       let fnlist, ftlist = List.split cls in
+                       let fvlist, venv' = Var_env.new_idents_from_types venv ftlist in
+                       let letvlist, venv' = Var_env.new_idents_from_vars venv' ~prefix:"j_" fvlist in
+                       fprintf ff "(match %s with@," v;
+                       fprintf ff "@[<v 8>| %s ->@," (to_record_str fnlist fvlist);
+                       List.iter2 (fun letv (fv, ft) ->
+                                       let_bind ff venv' letv fv ft
+                                  ) letvlist (List.combine fvlist ftlist);
+                       fprintf ff "Json_object %s@]@,)" (to_object_str fnlist letvlist)
+               | C_variant cdlist ->
+                       fprintf ff "(match %s with@," v;
+                       List.iter (fun cd -> variant ff venv cd) cdlist;
+                       fprintf ff ")"
+       and variant ff venv (CD_tuple (vname, vtlist)) =
+               let vlist, venv' = Var_env.new_idents_from_types venv vtlist in
+               let letvlist, venv' = Var_env.new_idents_from_vars venv' ~prefix:"j_" vlist in
+               if List.length vlist = 0 then
+                       fprintf ff "@[<v 8>| %s ->@," vname
+               else
+                       fprintf ff "@[<v 8>| %s (%s) ->@," vname (prod_vars_to_str vlist);
+               List.iter2 (fun letv (v, vt) ->
+                               let_bind ff venv' letv v vt
+                          ) letvlist (List.combine vlist vtlist);
+               fprintf ff "Json_array %s@]@," (to_array_str ~constr:vname letvlist)
+       and let_bind ff venv letv inv typ =
+               fprintf ff "@[<v 8>let %s =@," (name_of_var letv);
+               to_json ff venv inv typ;
+               fprintf ff " in@]@,"
+       let def ff venv fn_name typ is_and =
+               let fnv, venv' = Var_env.new_ident_from_name venv fn_name in
+               let inv, venv' = Var_env.new_ident_from_name venv' "o" in
+               fprintf ff "@[<v 8>%s %s %s =@," (if is_and then "and" else "let rec") fn_name (name_of_var inv);
+               to_json ff venv' inv typ;
+               fprintf ff "@]@,@\n"
+end
+
+let generate_to_def ff is_and (tname, trep) =
+       let fn = tname ^ "_to_json" in
+       To.def ff Var_env.new_env fn trep is_and
+
+let generate_from_def ff is_and (tname, trep) =
+       let fn = tname ^ "_from_json" in
+       Printf.printf "Generating %s\n" fn
+       (* From.def ff Var_env.new_env Type_env.new_env fn trep *)
+
+let generate_header ff ifn =
+       let md = Filename.basename (Filename.chop_extension ifn) in
+       fprintf ff "open Json@\n";
+       fprintf ff "open Base_conv@\n";
+       fprintf ff "open %s@\n" (String.capitalize md);
+       fprintf ff "@\n"
+
+let generate_one_defn ff td =
+       match td with
+       | [] -> ()
+       | h :: t ->
+               generate_to_def ff false h;
+               List.iter (generate_to_def ff true) t;
+               generate_from_def ff false h;
+               List.iter (generate_from_def ff true) t
+
+let generate defn_list ofn ifn =
+       let ff = formatter_of_out_channel (open_out ofn) in
+       generate_header ff ifn;
+       List.iter (generate_one_defn ff) defn_list
index 1f272bd863fd13e8e0841c51f88d77ec14927cb5..7ee7b6bec681e8bbcbece1331ad16de8cee078ec 100644 (file)
@@ -46,7 +46,7 @@ let rec to_fct t f =
 let to_buffer t buf =
        to_fct t (fun s -> Buffer.add_string buf s)
 
-let to_string t =
+let json_to_string t =
        let buf = Buffer.create 2048 in
        to_buffer t buf;
        Buffer.contents buf
index cddfdd66f5104a94ea100052689c81592d26de90..75f8b3c5a0af5a34e43739e6bcbc10b0d040fb1a 100644 (file)
@@ -22,4 +22,4 @@ type t =
   | Json_object of (string * t) array
   | Json_array of t array
 
-val to_string: t -> string
+val json_to_string: t -> string
diff --git a/libs/json/json_parse_test.ml b/libs/json/json_parse_test.ml
deleted file mode 100644 (file)
index a8c8095..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-(*
- * Copyright (C) 2009      Citrix Ltd.
- * Author Prashanth Mundkur <firstname.lastname@citrix.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; version 2.1 only. with the special
- * exception on linking described in file LICENSE.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Lesser General Public License for more details.
- *)
-
-let options = [ ]
-
-let parse_args () =
-       let file = ref None in
-       let usage = Printf.sprintf "Usage: %s file" Sys.argv.(0) in
-       Arg.parse (Arg.align options) (fun f -> file := Some f) usage;
-       match !file with
-       | Some f -> f
-       | None -> Printf.eprintf "%s\n" usage; exit 1
-
-let read_whole_file ic =
-       let buf = Buffer.create 512 in
-       let rec do_read () =
-               try
-                       let line = input_line ic in
-                       Buffer.add_string buf line;
-                       do_read ()
-               with End_of_file ->
-                       Buffer.contents buf
-       in do_read ()
-
-let parse_file f =
-       let ic = open_in f in
-       let input = ref (read_whole_file ic) in
-       let state = ref (Json_parse.init_parse_state ()) in
-       while String.length !input > 0 do
-               match Json_parse.parse !state !input with
-               | Json_parse.Json_value (v, rem) ->
-                       Printf.printf "%s\n" (Json.to_string v);
-                       input := rem;
-                       state := Json_parse.init_parse_state ()
-               | Json_parse.Json_parse_incomplete st ->
-                       input := "";
-                       state := st
-       done;
-       match Json_parse.finish_parse !state with
-       | Some v -> Printf.printf "%s\n" (Json.to_string v)
-       | None -> ()
-
-let print_exception e =
-       match e with
-       | Json_parse.Unexpected_char (c, state) ->
-               Printf.eprintf "Unexpected char %C (x%X) encountered in state %s\n"
-                 c (Char.code c) state
-       | Json_parse.Invalid_value (v, t) ->
-               Printf.eprintf "'%s' is an invalid %s\n" v t
-       | Json_parse.Invalid_leading_zero s ->
-               Printf.eprintf "'%s' should not have leading zeros\n" s
-       | Json_parse.Unterminated_value s ->
-               Printf.eprintf "unterminated %s\n" s
-       | Json_parse.Internal_error m ->
-               Printf.eprintf "Internal error: %s\n" m
-       | Sys_error s ->
-               Printf.eprintf "%s\n" s
-       | e ->
-               Printf.eprintf "%s\n" (Printexc.to_string e)
-
-let is_internal_error = function
-       | Json_parse.Internal_error _ -> true
-       | _ -> false
-
-let _ =
-       let input_file = parse_args () in
-       try
-               parse_file input_file;
-               exit 0
-       with e ->
-               print_exception e;
-               if is_internal_error e then exit 255 else exit 1
-
diff --git a/libs/json/jsonc.ml b/libs/json/jsonc.ml
new file mode 100644 (file)
index 0000000..f536e86
--- /dev/null
@@ -0,0 +1,79 @@
+(*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Prashanth Mundkur <firstname.lastname@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Syntax
+open Parser
+open Lexing
+
+let show_syntax_error e l =
+       let loc = Printf.sprintf "%s at line %d, char %d"
+                       l.pos_fname l.pos_lnum (l.pos_cnum - l.pos_bol) in
+       let msg =
+               match e with
+               | Illegal_character c -> Printf.sprintf "Illegal character %c" c
+               | Invalid_ident s -> Printf.sprintf "Invalid/unsupported identifier %s" s
+               | Unmatched_comment -> Printf.sprintf "Unmatched comment"
+               | Unterminated_comment -> Printf.sprintf "Unterminated comment"
+       in
+       Printf.printf "%s: %s\n" loc msg;
+       exit 1
+
+let show_parse_error lexbuf =
+       let lxm = lexeme lexbuf in
+       let loc = Printf.sprintf "%s at line %d, char %d"
+                       lexbuf.lex_curr_p.pos_fname lexbuf.lex_curr_p.pos_lnum
+                       (lexbuf.lex_curr_p.pos_cnum - lexbuf.lex_curr_p.pos_bol) in
+       (match lxm with
+       | "" -> Printf.printf "%s: parsing error\n" loc
+       | _  -> Printf.printf "%s: parsing error at \"%s\"\n" loc lxm);
+       exit 1
+
+let parse_file file =
+       let f = open_in file in
+       let lexbuf = Lexing.from_channel f in
+       try
+               Lexer.init lexbuf file;
+               Parser.defn_list Lexer.main lexbuf
+       with
+       | Syntax_error (e, l) ->
+               show_syntax_error e l
+       | Parsing.Parse_error ->
+               show_parse_error lexbuf
+
+let default_output_filename f =
+       let dir, base = Filename.dirname f, Filename.basename f in
+       let stem = Filename.chop_extension base in
+       Filename.concat dir (stem ^ "_json_conv.ml")
+
+let gen_code defn_list f =
+       Codegen.generate defn_list f
+
+let () =
+       let input = ref "" in
+       let output = ref "" in
+
+       (* parse argv *)
+       let larg = [
+               ("-i", Arg.Set_string input, "input file");
+               ("-o", Arg.Set_string output, "output file");
+       ] in
+       let usage_msg = Printf.sprintf "%s -i <file> [-o <file>]" Sys.argv.(0) in
+       Arg.parse larg (fun s -> ()) usage_msg;
+
+       if !output = "" then output := default_output_filename !input;
+
+       match !input with
+       | "" -> Printf.printf "%s\n" usage_msg
+       | file -> gen_code (parse_file file) !output !input
diff --git a/libs/json/lexer.mll b/libs/json/lexer.mll
new file mode 100644 (file)
index 0000000..a2985e2
--- /dev/null
@@ -0,0 +1,122 @@
+(*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Prashanth Mundkur <firstname.lastname@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+{
+
+open Lexing
+open Syntax
+open Parser
+
+let comment_depth = ref 0
+let comment_start = ref dummy_pos
+
+let line_num = ref 0
+
+let init lexbuf fname =
+       lexbuf.lex_curr_p <- { pos_fname = fname;
+                              pos_lnum = 1;
+                              pos_bol = 0;
+                              pos_cnum = 0 }
+
+let raise_syntax_error e loc =
+       raise (Syntax_error (e, loc))
+
+}
+
+let letter = ['A'-'Z' 'a'-'z']
+
+(* The handling of '.' is a bit of a hack for now; not sure if it's
+   really needed. *)
+let ident_first = letter | '_'
+let ident_others  = letter | ['0'-'9'] | '_' | '\'' | '.'
+let ident = ident_first ident_others*
+
+rule main = parse
+| [' ' '\009' '\012' '\r']+
+       { main lexbuf }
+| ['\n']
+       { new_line lexbuf;
+         main lexbuf
+       }
+| "*/"
+       { raise_syntax_error Unmatched_comment (lexeme_start_p lexbuf) }
+| "/*"
+       { comment_depth := 1;
+         comment_start := lexeme_start_p lexbuf;
+         comment lexbuf;
+         main lexbuf
+       }
+
+| eof  { EOF }
+| "="  { EQUAL }
+| "*"  { STAR }
+| ";"  { SEMI }
+| ";;" { SEMISEMI }
+| ":"  { COLON }
+| "|"  { BAR }
+
+| "{"  { LBRACE }
+| "}"  { RBRACE }
+| "("  { LPAREN }
+| ")"  { RPAREN }
+| "["  { LBRACK }
+| "]"  { RBRACK }
+
+| "type"       { TYPE }
+| "and"                { AND }
+| "mutable"    { MUTABLE }
+| "of"         { OF }
+
+(* hardcoded type constructors; this could be handled more
+   intelligently later. *)
+
+| "option"     { OPTION }
+| "list"       { LIST }
+| "array"      { ARRAY }
+
+| "string"     { STRING }
+| "int"                { INT }
+| "int64"      { INT64 }
+| "bool"       { BOOL }
+
+(* general identifiers.  we could handle the '.' here. *)
+| ident
+       { let str = lexeme lexbuf in
+         match String.get str 0 with
+         | 'A' .. 'Z' -> UIDENT str
+         | 'a' .. 'z' -> LIDENT str
+         | _ ->          raise_syntax_error (Invalid_ident str) (lexeme_start_p lexbuf)
+       }
+| _
+       { raise_syntax_error (Illegal_character (lexeme_char lexbuf 0)) (lexeme_start_p lexbuf) }
+
+
+and comment = parse
+| "/*"
+       { incr comment_depth;
+         comment lexbuf
+       }
+| "*/"
+       { decr comment_depth;
+         if !comment_depth > 0 then comment lexbuf
+       }
+| ['\n']
+       { new_line lexbuf;
+         comment lexbuf
+       }
+| eof
+       { raise_syntax_error Unterminated_comment !comment_start }
+| _
+       { comment lexbuf }
diff --git a/libs/json/parser.mly b/libs/json/parser.mly
new file mode 100644 (file)
index 0000000..534d527
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Prashanth Mundkur <firstname.lastname@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+
+%{
+
+open Syntax
+
+let raise_syntax_error e pos =
+       raise (Syntax_error (e, pos))
+
+%}
+
+/* keywords */
+%token TYPE AND MUTABLE OF
+%token OPTION LIST ARRAY STRING INT INT64 BOOL
+
+%token LBRACE RBRACE LPAREN RPAREN LBRACK RBRACK
+%token EQUAL STAR SEMI SEMISEMI COLON BAR
+%token EOF
+
+%token <string> UIDENT LIDENT
+
+%start defn_list
+
+%type <Syntax.type_defn list> defn_list
+
+%%
+
+defn_list:
+| defns EOF
+       { List.rev $1 }
+;
+
+defns:
+| defns top_defn_term
+       { $2 :: $1 }
+| /* epsilon */
+       { [] }
+;
+
+top_defn_term:
+| defn semi
+       { $1 }
+
+defn:
+| TYPE eqn
+       { [ $2 ] }
+
+| TYPE eqn AND defn_parts
+       { $2 :: (List.rev $4) }
+
+defn_parts:
+| defn_parts AND eqn
+       { $3 :: $1 }
+| eqn
+       { [ $1 ] }
+
+eqn:
+| LIDENT EQUAL repn
+       { ($1, $3) }
+;
+
+semi:
+| SEMISEMI
+       {}
+| /* epsilon */
+       {}
+
+repn:
+| expr
+       { $1 }
+| expr STAR tuple
+       { C_tuple ($1 :: (List.rev $3)) }
+| record
+       { C_record (List.rev $1) }
+| variant
+       { C_variant (List.rev $1) }
+
+expr:
+| LPAREN expr RPAREN
+       { $2 }
+| LPAREN expr STAR tuple RPAREN
+       { C_tuple ($2 :: (List.rev $4)) }
+| expr OPTION
+       { C_option $1 }
+| expr LIST
+       { C_list $1 }
+| expr ARRAY
+       { C_array $1 }
+| base
+       { C_base $1 }
+
+tuple:
+| tuple STAR expr
+       { $3 :: $1 }
+| expr
+       { [ $1 ] }
+
+base:
+| STRING       { B_string }
+| INT          { B_int }
+| INT64                { B_int64 }
+| BOOL         { B_bool }
+| LIDENT       { B_ident $1 }
+/* TODO:
+| UIDENT       { raise_syntax_error (Invalid_ident $1) }
+*/
+
+record:
+| LBRACE field_decls RBRACE
+       { $2 }
+
+field_decls:
+| field_decls SEMI field_decl
+       { $3 :: $1 }
+| field_decl
+       { [ $1 ] }
+
+field_decl:
+| LIDENT COLON expr
+       { ($1, $3) }
+| MUTABLE LIDENT COLON expr
+       { ($2, $4) }
+
+variant:
+| variant BAR constr
+       { $3 :: $1 }
+| constr
+       { [ $1 ] }
+| /* epsilon */
+       { [] }
+
+constr:
+| UIDENT
+       { CD_tuple ($1, []) }
+| UIDENT OF expr
+       { CD_tuple ($1, [ $3 ]) }
+
+| UIDENT OF expr STAR tuple
+       { CD_tuple ($1, ($3 :: (List.rev $5))) }
+
diff --git a/libs/json/parser_tests/LICENSE.txt b/libs/json/parser_tests/LICENSE.txt
new file mode 100644 (file)
index 0000000..7d41935
--- /dev/null
@@ -0,0 +1,23 @@
+/*                                                                                               
+Copyright (c) 2005 JSON.org                                                                      
+                                                                                                 
+Permission is hereby granted, free of charge, to any person obtaining a copy                     
+of this software and associated documentation files (the "Software"), to deal                    
+in the Software without restriction, including without limitation the rights                     
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell                        
+copies of the Software, and to permit persons to whom the Software is                            
+furnished to do so, subject to the following conditions:                                         
+                                                                                                 
+The above copyright notice and this permission notice shall be included in all                   
+copies or substantial portions of the Software.                                                  
+                                                                                                 
+The Software shall be used for Good, not Evil.                                                   
+                                                                                                 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR                       
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,                         
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE                      
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER                           
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,                    
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE                    
+SOFTWARE.                                                                                        
+*/
diff --git a/libs/json/parser_tests/README b/libs/json/parser_tests/README
new file mode 100644 (file)
index 0000000..a4892e1
--- /dev/null
@@ -0,0 +1,4 @@
+The .json files in this directory are taken from the JSON_checker
+project [1], and are covered by the license in LICENSE.txt.
+
+[1] http://www.json.org/JSON_checker/
diff --git a/libs/json/parser_tests/fail1.json b/libs/json/parser_tests/fail1.json
new file mode 100644 (file)
index 0000000..6216b86
--- /dev/null
@@ -0,0 +1 @@
+"A JSON payload should be an object or array, not a string."
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail10.json b/libs/json/parser_tests/fail10.json
new file mode 100644 (file)
index 0000000..5d8c004
--- /dev/null
@@ -0,0 +1 @@
+{"Extra value after close": true} "misplaced quoted value"
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail11.json b/libs/json/parser_tests/fail11.json
new file mode 100644 (file)
index 0000000..76eb95b
--- /dev/null
@@ -0,0 +1 @@
+{"Illegal expression": 1 + 2}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail12.json b/libs/json/parser_tests/fail12.json
new file mode 100644 (file)
index 0000000..77580a4
--- /dev/null
@@ -0,0 +1 @@
+{"Illegal invocation": alert()}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail13.json b/libs/json/parser_tests/fail13.json
new file mode 100644 (file)
index 0000000..379406b
--- /dev/null
@@ -0,0 +1 @@
+{"Numbers cannot have leading zeroes": 013}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail14.json b/libs/json/parser_tests/fail14.json
new file mode 100644 (file)
index 0000000..0ed366b
--- /dev/null
@@ -0,0 +1 @@
+{"Numbers cannot be hex": 0x14}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail15.json b/libs/json/parser_tests/fail15.json
new file mode 100644 (file)
index 0000000..fc8376b
--- /dev/null
@@ -0,0 +1 @@
+["Illegal backslash escape: \x15"]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail16.json b/libs/json/parser_tests/fail16.json
new file mode 100644 (file)
index 0000000..3fe21d4
--- /dev/null
@@ -0,0 +1 @@
+[\naked]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail17.json b/libs/json/parser_tests/fail17.json
new file mode 100644 (file)
index 0000000..62b9214
--- /dev/null
@@ -0,0 +1 @@
+["Illegal backslash escape: \017"]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail18.json b/libs/json/parser_tests/fail18.json
new file mode 100644 (file)
index 0000000..edac927
--- /dev/null
@@ -0,0 +1 @@
+[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail19.json b/libs/json/parser_tests/fail19.json
new file mode 100644 (file)
index 0000000..3b9c46f
--- /dev/null
@@ -0,0 +1 @@
+{"Missing colon" null}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail2.json b/libs/json/parser_tests/fail2.json
new file mode 100644 (file)
index 0000000..6b7c11e
--- /dev/null
@@ -0,0 +1 @@
+["Unclosed array"
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail20.json b/libs/json/parser_tests/fail20.json
new file mode 100644 (file)
index 0000000..27c1af3
--- /dev/null
@@ -0,0 +1 @@
+{"Double colon":: null}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail21.json b/libs/json/parser_tests/fail21.json
new file mode 100644 (file)
index 0000000..6247457
--- /dev/null
@@ -0,0 +1 @@
+{"Comma instead of colon", null}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail22.json b/libs/json/parser_tests/fail22.json
new file mode 100644 (file)
index 0000000..a775258
--- /dev/null
@@ -0,0 +1 @@
+["Colon instead of comma": false]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail23.json b/libs/json/parser_tests/fail23.json
new file mode 100644 (file)
index 0000000..494add1
--- /dev/null
@@ -0,0 +1 @@
+["Bad value", truth]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail24.json b/libs/json/parser_tests/fail24.json
new file mode 100644 (file)
index 0000000..caff239
--- /dev/null
@@ -0,0 +1 @@
+['single quote']
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail25.json b/libs/json/parser_tests/fail25.json
new file mode 100644 (file)
index 0000000..8b7ad23
--- /dev/null
@@ -0,0 +1 @@
+["     tab     character       in      string  "]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail26.json b/libs/json/parser_tests/fail26.json
new file mode 100644 (file)
index 0000000..845d26a
--- /dev/null
@@ -0,0 +1 @@
+["tab\   character\   in\  string\  "]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail27.json b/libs/json/parser_tests/fail27.json
new file mode 100644 (file)
index 0000000..6b01a2c
--- /dev/null
@@ -0,0 +1,2 @@
+["line
+break"]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail28.json b/libs/json/parser_tests/fail28.json
new file mode 100644 (file)
index 0000000..621a010
--- /dev/null
@@ -0,0 +1,2 @@
+["line\
+break"]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail29.json b/libs/json/parser_tests/fail29.json
new file mode 100644 (file)
index 0000000..47ec421
--- /dev/null
@@ -0,0 +1 @@
+[0e]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail3.json b/libs/json/parser_tests/fail3.json
new file mode 100644 (file)
index 0000000..168c81e
--- /dev/null
@@ -0,0 +1 @@
+{unquoted_key: "keys must be quoted"}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail30.json b/libs/json/parser_tests/fail30.json
new file mode 100644 (file)
index 0000000..8ab0bc4
--- /dev/null
@@ -0,0 +1 @@
+[0e+]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail31.json b/libs/json/parser_tests/fail31.json
new file mode 100644 (file)
index 0000000..1cce602
--- /dev/null
@@ -0,0 +1 @@
+[0e+-1]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail32.json b/libs/json/parser_tests/fail32.json
new file mode 100644 (file)
index 0000000..45cba73
--- /dev/null
@@ -0,0 +1 @@
+{"Comma instead if closing brace": true,
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail33.json b/libs/json/parser_tests/fail33.json
new file mode 100644 (file)
index 0000000..ca5eb19
--- /dev/null
@@ -0,0 +1 @@
+["mismatch"}
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail4.json b/libs/json/parser_tests/fail4.json
new file mode 100644 (file)
index 0000000..9de168b
--- /dev/null
@@ -0,0 +1 @@
+["extra comma",]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail5.json b/libs/json/parser_tests/fail5.json
new file mode 100644 (file)
index 0000000..ddf3ce3
--- /dev/null
@@ -0,0 +1 @@
+["double extra comma",,]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail6.json b/libs/json/parser_tests/fail6.json
new file mode 100644 (file)
index 0000000..ed91580
--- /dev/null
@@ -0,0 +1 @@
+[   , "<-- missing value"]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail7.json b/libs/json/parser_tests/fail7.json
new file mode 100644 (file)
index 0000000..8a96af3
--- /dev/null
@@ -0,0 +1 @@
+["Comma after the close"],
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail8.json b/libs/json/parser_tests/fail8.json
new file mode 100644 (file)
index 0000000..b28479c
--- /dev/null
@@ -0,0 +1 @@
+["Extra close"]]
\ No newline at end of file
diff --git a/libs/json/parser_tests/fail9.json b/libs/json/parser_tests/fail9.json
new file mode 100644 (file)
index 0000000..5815574
--- /dev/null
@@ -0,0 +1 @@
+{"Extra comma": true,}
\ No newline at end of file
diff --git a/libs/json/parser_tests/pass1.json b/libs/json/parser_tests/pass1.json
new file mode 100644 (file)
index 0000000..70e2685
--- /dev/null
@@ -0,0 +1,58 @@
+[
+    "JSON Test Pattern pass1",
+    {"object with 1 member":["array with 1 element"]},
+    {},
+    [],
+    -42,
+    true,
+    false,
+    null,
+    {
+        "integer": 1234567890,
+        "real": -9876.543210,
+        "e": 0.123456789e-12,
+        "E": 1.234567890E+34,
+        "":  23456789012E66,
+        "zero": 0,
+        "one": 1,
+        "space": " ",
+        "quote": "\"",
+        "backslash": "\\",
+        "controls": "\b\f\n\r\t",
+        "slash": "/ & \/",
+        "alpha": "abcdefghijklmnopqrstuvwyz",
+        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
+        "digit": "0123456789",
+        "0123456789": "digit",
+        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
+        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+        "true": true,
+        "false": false,
+        "null": null,
+        "array":[  ],
+        "object":{  },
+        "address": "50 St. James Street",
+        "url": "http://www.JSON.org/",
+        "comment": "// /* <!-- --",
+        "# -- --> */": " ",
+        " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5        ,          6           ,7        ],"compact":[1,2,3,4,5,6,7],
+        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+        "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
+: "A key can be any string"
+    },
+    0.5 ,98.6
+,
+99.44
+,
+
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,2e+00,2e-00
+,"rosebud"]
\ No newline at end of file
diff --git a/libs/json/parser_tests/pass2.json b/libs/json/parser_tests/pass2.json
new file mode 100644 (file)
index 0000000..d3c63c7
--- /dev/null
@@ -0,0 +1 @@
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
diff --git a/libs/json/parser_tests/pass3.json b/libs/json/parser_tests/pass3.json
new file mode 100644 (file)
index 0000000..4528d51
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "JSON Test Pattern pass3": {
+        "The outermost value": "must be an object or array.",
+        "In this test": "It is an object."
+    }
+}
diff --git a/libs/json/parser_tests/run_tests.sh b/libs/json/parser_tests/run_tests.sh
new file mode 100755 (executable)
index 0000000..2e86a1e
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+PROG=../test_parser
+
+for f in `ls *pass*.json`; do
+       $PROG $f > /dev/null 2>&1
+       ec=$?
+       if [ $ec -eq 1 ] ; then
+               echo "Test case $f should pass, but failed."
+       elif [ $ec -eq 255 ] ; then
+               echo "Test case $f triggered an internal error!"
+       fi
+done
+for f in `ls *fail*.json`; do
+       $PROG $f > /dev/null 2>&1
+       ec=$?
+       if [ $ec -eq 0 ] ; then
+               echo "Test case $f should fail, but passed."
+       elif [ $ec -eq 255 ] ; then
+               echo "Test case $f triggered an internal error!"
+       fi
+done
diff --git a/libs/json/syntax.ml b/libs/json/syntax.ml
new file mode 100644 (file)
index 0000000..d74b3bf
--- /dev/null
@@ -0,0 +1,44 @@
+(*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Prashanth Mundkur <firstname.lastname@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+type syntax_error =
+       | Illegal_character of char
+       | Invalid_ident of string
+       | Unmatched_comment
+       | Unterminated_comment
+
+exception Syntax_error of syntax_error * Lexing.position
+
+type base_type =
+       | B_string
+       | B_int
+       | B_int64
+       | B_bool
+       | B_ident of string
+
+type complex_type =
+       | C_base of base_type
+       | C_option of complex_type
+       | C_list of complex_type
+       | C_array of complex_type
+       | C_tuple of complex_type list
+       | C_record of (string * complex_type) list
+       | C_variant of constr_decl list
+
+and constr_decl =
+       | CD_tuple of string * complex_type list
+
+type type_defn = (string * complex_type) list
+
diff --git a/libs/json/test_parser.ml b/libs/json/test_parser.ml
new file mode 100644 (file)
index 0000000..dd61d31
--- /dev/null
@@ -0,0 +1,85 @@
+(*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Prashanth Mundkur <firstname.lastname@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+let options = [ ]
+
+let parse_args () =
+       let file = ref None in
+       let usage = Printf.sprintf "Usage: %s file" Sys.argv.(0) in
+       Arg.parse (Arg.align options) (fun f -> file := Some f) usage;
+       match !file with
+       | Some f -> f
+       | None -> Printf.eprintf "%s\n" usage; exit 1
+
+let read_whole_file ic =
+       let buf = Buffer.create 512 in
+       let rec do_read () =
+               try
+                       let line = input_line ic in
+                       Buffer.add_string buf line;
+                       do_read ()
+               with End_of_file ->
+                       Buffer.contents buf
+       in do_read ()
+
+let parse_file f =
+       let ic = open_in f in
+       let input = ref (read_whole_file ic) in
+       let state = ref (Json_parse.init_parse_state ()) in
+       while String.length !input > 0 do
+               match Json_parse.parse !state !input with
+               | Json_parse.Json_value (v, rem) ->
+                       Printf.printf "%s\n" (Json.json_to_string v);
+                       input := rem;
+                       state := Json_parse.init_parse_state ()
+               | Json_parse.Json_parse_incomplete st ->
+                       input := "";
+                       state := st
+       done;
+       match Json_parse.finish_parse !state with
+       | Some v -> Printf.printf "%s\n" (Json.json_to_string v)
+       | None -> ()
+
+let print_exception e =
+       match e with
+       | Json_parse.Unexpected_char (c, state) ->
+               Printf.eprintf "Unexpected char %C (x%X) encountered in state %s\n"
+                 c (Char.code c) state
+       | Json_parse.Invalid_value (v, t) ->
+               Printf.eprintf "'%s' is an invalid %s\n" v t
+       | Json_parse.Invalid_leading_zero s ->
+               Printf.eprintf "'%s' should not have leading zeros\n" s
+       | Json_parse.Unterminated_value s ->
+               Printf.eprintf "unterminated %s\n" s
+       | Json_parse.Internal_error m ->
+               Printf.eprintf "Internal error: %s\n" m
+       | Sys_error s ->
+               Printf.eprintf "%s\n" s
+       | e ->
+               Printf.eprintf "%s\n" (Printexc.to_string e)
+
+let is_internal_error = function
+       | Json_parse.Internal_error _ -> true
+       | _ -> false
+
+let _ =
+       let input_file = parse_args () in
+       try
+               parse_file input_file;
+               exit 0
+       with e ->
+               print_exception e;
+               if is_internal_error e then exit 255 else exit 1
+
diff --git a/libs/json/tests/LICENSE.txt b/libs/json/tests/LICENSE.txt
deleted file mode 100644 (file)
index 7d41935..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*                                                                                               
-Copyright (c) 2005 JSON.org                                                                      
-                                                                                                 
-Permission is hereby granted, free of charge, to any person obtaining a copy                     
-of this software and associated documentation files (the "Software"), to deal                    
-in the Software without restriction, including without limitation the rights                     
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell                        
-copies of the Software, and to permit persons to whom the Software is                            
-furnished to do so, subject to the following conditions:                                         
-                                                                                                 
-The above copyright notice and this permission notice shall be included in all                   
-copies or substantial portions of the Software.                                                  
-                                                                                                 
-The Software shall be used for Good, not Evil.                                                   
-                                                                                                 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR                       
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,                         
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE                      
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER                           
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,                    
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE                    
-SOFTWARE.                                                                                        
-*/
diff --git a/libs/json/tests/README b/libs/json/tests/README
deleted file mode 100644 (file)
index a4892e1..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-The .json files in this directory are taken from the JSON_checker
-project [1], and are covered by the license in LICENSE.txt.
-
-[1] http://www.json.org/JSON_checker/
diff --git a/libs/json/tests/fail1.json b/libs/json/tests/fail1.json
deleted file mode 100644 (file)
index 6216b86..0000000
+++ /dev/null
@@ -1 +0,0 @@
-"A JSON payload should be an object or array, not a string."
\ No newline at end of file
diff --git a/libs/json/tests/fail10.json b/libs/json/tests/fail10.json
deleted file mode 100644 (file)
index 5d8c004..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Extra value after close": true} "misplaced quoted value"
\ No newline at end of file
diff --git a/libs/json/tests/fail11.json b/libs/json/tests/fail11.json
deleted file mode 100644 (file)
index 76eb95b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Illegal expression": 1 + 2}
\ No newline at end of file
diff --git a/libs/json/tests/fail12.json b/libs/json/tests/fail12.json
deleted file mode 100644 (file)
index 77580a4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Illegal invocation": alert()}
\ No newline at end of file
diff --git a/libs/json/tests/fail13.json b/libs/json/tests/fail13.json
deleted file mode 100644 (file)
index 379406b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Numbers cannot have leading zeroes": 013}
\ No newline at end of file
diff --git a/libs/json/tests/fail14.json b/libs/json/tests/fail14.json
deleted file mode 100644 (file)
index 0ed366b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Numbers cannot be hex": 0x14}
\ No newline at end of file
diff --git a/libs/json/tests/fail15.json b/libs/json/tests/fail15.json
deleted file mode 100644 (file)
index fc8376b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["Illegal backslash escape: \x15"]
\ No newline at end of file
diff --git a/libs/json/tests/fail16.json b/libs/json/tests/fail16.json
deleted file mode 100644 (file)
index 3fe21d4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[\naked]
\ No newline at end of file
diff --git a/libs/json/tests/fail17.json b/libs/json/tests/fail17.json
deleted file mode 100644 (file)
index 62b9214..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["Illegal backslash escape: \017"]
\ No newline at end of file
diff --git a/libs/json/tests/fail18.json b/libs/json/tests/fail18.json
deleted file mode 100644 (file)
index edac927..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
diff --git a/libs/json/tests/fail19.json b/libs/json/tests/fail19.json
deleted file mode 100644 (file)
index 3b9c46f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Missing colon" null}
\ No newline at end of file
diff --git a/libs/json/tests/fail2.json b/libs/json/tests/fail2.json
deleted file mode 100644 (file)
index 6b7c11e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["Unclosed array"
\ No newline at end of file
diff --git a/libs/json/tests/fail20.json b/libs/json/tests/fail20.json
deleted file mode 100644 (file)
index 27c1af3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Double colon":: null}
\ No newline at end of file
diff --git a/libs/json/tests/fail21.json b/libs/json/tests/fail21.json
deleted file mode 100644 (file)
index 6247457..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Comma instead of colon", null}
\ No newline at end of file
diff --git a/libs/json/tests/fail22.json b/libs/json/tests/fail22.json
deleted file mode 100644 (file)
index a775258..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["Colon instead of comma": false]
\ No newline at end of file
diff --git a/libs/json/tests/fail23.json b/libs/json/tests/fail23.json
deleted file mode 100644 (file)
index 494add1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["Bad value", truth]
\ No newline at end of file
diff --git a/libs/json/tests/fail24.json b/libs/json/tests/fail24.json
deleted file mode 100644 (file)
index caff239..0000000
+++ /dev/null
@@ -1 +0,0 @@
-['single quote']
\ No newline at end of file
diff --git a/libs/json/tests/fail25.json b/libs/json/tests/fail25.json
deleted file mode 100644 (file)
index 8b7ad23..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["     tab     character       in      string  "]
\ No newline at end of file
diff --git a/libs/json/tests/fail26.json b/libs/json/tests/fail26.json
deleted file mode 100644 (file)
index 845d26a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["tab\   character\   in\  string\  "]
\ No newline at end of file
diff --git a/libs/json/tests/fail27.json b/libs/json/tests/fail27.json
deleted file mode 100644 (file)
index 6b01a2c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-["line
-break"]
\ No newline at end of file
diff --git a/libs/json/tests/fail28.json b/libs/json/tests/fail28.json
deleted file mode 100644 (file)
index 621a010..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-["line\
-break"]
\ No newline at end of file
diff --git a/libs/json/tests/fail29.json b/libs/json/tests/fail29.json
deleted file mode 100644 (file)
index 47ec421..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[0e]
\ No newline at end of file
diff --git a/libs/json/tests/fail3.json b/libs/json/tests/fail3.json
deleted file mode 100644 (file)
index 168c81e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{unquoted_key: "keys must be quoted"}
\ No newline at end of file
diff --git a/libs/json/tests/fail30.json b/libs/json/tests/fail30.json
deleted file mode 100644 (file)
index 8ab0bc4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[0e+]
\ No newline at end of file
diff --git a/libs/json/tests/fail31.json b/libs/json/tests/fail31.json
deleted file mode 100644 (file)
index 1cce602..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[0e+-1]
\ No newline at end of file
diff --git a/libs/json/tests/fail32.json b/libs/json/tests/fail32.json
deleted file mode 100644 (file)
index 45cba73..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Comma instead if closing brace": true,
\ No newline at end of file
diff --git a/libs/json/tests/fail33.json b/libs/json/tests/fail33.json
deleted file mode 100644 (file)
index ca5eb19..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["mismatch"}
\ No newline at end of file
diff --git a/libs/json/tests/fail4.json b/libs/json/tests/fail4.json
deleted file mode 100644 (file)
index 9de168b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["extra comma",]
\ No newline at end of file
diff --git a/libs/json/tests/fail5.json b/libs/json/tests/fail5.json
deleted file mode 100644 (file)
index ddf3ce3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["double extra comma",,]
\ No newline at end of file
diff --git a/libs/json/tests/fail6.json b/libs/json/tests/fail6.json
deleted file mode 100644 (file)
index ed91580..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[   , "<-- missing value"]
\ No newline at end of file
diff --git a/libs/json/tests/fail7.json b/libs/json/tests/fail7.json
deleted file mode 100644 (file)
index 8a96af3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["Comma after the close"],
\ No newline at end of file
diff --git a/libs/json/tests/fail8.json b/libs/json/tests/fail8.json
deleted file mode 100644 (file)
index b28479c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-["Extra close"]]
\ No newline at end of file
diff --git a/libs/json/tests/fail9.json b/libs/json/tests/fail9.json
deleted file mode 100644 (file)
index 5815574..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"Extra comma": true,}
\ No newline at end of file
diff --git a/libs/json/tests/pass1.json b/libs/json/tests/pass1.json
deleted file mode 100644 (file)
index 70e2685..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-[
-    "JSON Test Pattern pass1",
-    {"object with 1 member":["array with 1 element"]},
-    {},
-    [],
-    -42,
-    true,
-    false,
-    null,
-    {
-        "integer": 1234567890,
-        "real": -9876.543210,
-        "e": 0.123456789e-12,
-        "E": 1.234567890E+34,
-        "":  23456789012E66,
-        "zero": 0,
-        "one": 1,
-        "space": " ",
-        "quote": "\"",
-        "backslash": "\\",
-        "controls": "\b\f\n\r\t",
-        "slash": "/ & \/",
-        "alpha": "abcdefghijklmnopqrstuvwyz",
-        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
-        "digit": "0123456789",
-        "0123456789": "digit",
-        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
-        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
-        "true": true,
-        "false": false,
-        "null": null,
-        "array":[  ],
-        "object":{  },
-        "address": "50 St. James Street",
-        "url": "http://www.JSON.org/",
-        "comment": "// /* <!-- --",
-        "# -- --> */": " ",
-        " s p a c e d " :[1,2 , 3
-
-,
-
-4 , 5        ,          6           ,7        ],"compact":[1,2,3,4,5,6,7],
-        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
-        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
-        "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
-: "A key can be any string"
-    },
-    0.5 ,98.6
-,
-99.44
-,
-
-1066,
-1e1,
-0.1e1,
-1e-1,
-1e00,2e+00,2e-00
-,"rosebud"]
\ No newline at end of file
diff --git a/libs/json/tests/pass2.json b/libs/json/tests/pass2.json
deleted file mode 100644 (file)
index d3c63c7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
diff --git a/libs/json/tests/pass3.json b/libs/json/tests/pass3.json
deleted file mode 100644 (file)
index 4528d51..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-    "JSON Test Pattern pass3": {
-        "The outermost value": "must be an object or array.",
-        "In this test": "It is an object."
-    }
-}
diff --git a/libs/json/tests/run_tests.sh b/libs/json/tests/run_tests.sh
deleted file mode 100755 (executable)
index 1cf7460..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-
-PROG=../json_test
-
-for f in `ls *pass*.json`; do
-       $PROG $f > /dev/null 2>&1
-       ec=$?
-       if [ $ec -eq 1 ] ; then
-               echo "Test case $f should pass, but failed."
-       elif [ $ec -eq 255 ] ; then
-               echo "Test case $f triggered an internal error!"
-       fi
-done
-for f in `ls *fail*.json`; do
-       $PROG $f > /dev/null 2>&1
-       ec=$?
-       if [ $ec -eq 0 ] ; then
-               echo "Test case $f should fail, but passed."
-       elif [ $ec -eq 255 ] ; then
-               echo "Test case $f triggered an internal error!"
-       fi
-done