[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v7 5/9] libxl IDL: generate code to parse libxl__json_object to libxl_FOO struct



libxl_FOO_parse_json functions are generated.

Note that these functions are used to parse libxl__json_object to
libxl__FOO struct. They don't consume JSON string.

The new function definitions are generated to new header files called
__libxl_types_*_json_internal.h so that they don't contaiminate public
header.

Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
---
Change since last version: output parser function definitions to
dedicated header file.
---
 tools/libxl/Makefile                 |    4 +-
 tools/libxl/gentypes.py              |  158 +++++++++++++++++++++++++++++++++-
 tools/libxl/idl.py                   |   15 ++++
 tools/libxl/idl.txt                  |    7 +-
 tools/libxl/libxl.h                  |   14 +++
 tools/libxl/libxl_internal.h         |    3 +
 tools/libxl/libxl_types.idl          |   27 +++---
 tools/libxl/libxl_types_internal.idl |    4 +-
 8 files changed, 214 insertions(+), 18 deletions(-)

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 4cfa275..bac6287 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -180,9 +180,11 @@ $(LIBXL_OBJS) $(LIBXL_TEST_OBJS) $(LIBXLU_OBJS) \
 $(LIBXL_OBJS) $(LIBXL_TEST_OBJS): libxl_internal.h
 
 _libxl_type%.h _libxl_type%_json.h _libxl_type%.c: libxl_type%.idl gentypes.py 
idl.py
-       $(PYTHON) gentypes.py libxl_type$*.idl __libxl_type$*.h 
__libxl_type$*_json.h __libxl_type$*.c
+       $(PYTHON) gentypes.py libxl_type$*.idl __libxl_type$*.h 
__libxl_type$*_json.h \
+               __libxl_type$*_json_internal.h __libxl_type$*.c
        $(call move-if-changed,__libxl_type$*.h,_libxl_type$*.h)
        $(call move-if-changed,__libxl_type$*_json.h,_libxl_type$*_json.h)
+       $(call 
move-if-changed,__libxl_type$*_json_internal.h,_libxl_type$*_json_internal.h)
        $(call move-if-changed,__libxl_type$*.c,_libxl_type$*.c)
 
 libxenlight.so: libxenlight.so.$(MAJOR)
diff --git a/tools/libxl/gentypes.py b/tools/libxl/gentypes.py
index f06afd9..605e26e 100644
--- a/tools/libxl/gentypes.py
+++ b/tools/libxl/gentypes.py
@@ -312,6 +312,116 @@ def libxl_C_type_to_json(ty, v, indent = "    "):
         s = indent + s
     return s.replace("\n", "\n%s" % indent).rstrip(indent)
 
+def libxl_C_type_parse_json(ty, w, v, indent = "    ", parent = None, 
discriminator = None):
+    s = ""
+    if parent is None:
+        s += "int rc = 0;\n"
+        s += "const libxl__json_object *x = o;\n"
+
+    if isinstance(ty, idl.Array):
+        if parent is None:
+            raise Exception("Array type must have a parent")
+        if discriminator is not None:
+            raise Exception("Only KeyedUnion can have discriminator")
+        lenvar = parent + ty.lenvar.name
+        s += "{\n"
+        s += "    libxl__json_object *t;\n"
+        s += "    int i;\n"
+        s += "    if (!libxl__json_object_is_array(x)) {\n"
+        s += "        rc = -1;\n"
+        s += "        goto out;\n"
+        s += "    }\n"
+        s += "    %s = x->u.array->count;\n" % lenvar
+        s += "    %s = libxl__calloc(NOGC, %s, sizeof(*%s));\n" % (v, lenvar, 
v)
+        s += "    if (!%s && %s != 0) {\n" % (v, lenvar)
+        s += "        rc = -1;\n"
+        s += "        goto out;\n"
+        s += "    }\n"
+        s += "    for (i=0; (t=libxl__json_array_get(x,i)); i++) {\n"
+        s += libxl_C_type_parse_json(ty.elem_type, "t", v+"[i]",
+                                     indent + "    ", parent)
+        s += "    }\n"
+        s += "    if (i != %s) {\n" % lenvar
+        s += "        rc = -1;\n"
+        s += "        goto out;\n"
+        s += "    }\n"
+        s += "}\n"
+    elif isinstance(ty, idl.Enumeration):
+        if discriminator is not None:
+            raise Exception("Only KeyedUnion can have discriminator")
+        s += "{\n"
+        s += "    const char *enum_str;\n"
+        s += "    if (!libxl__json_object_is_string(x)) {\n"
+        s += "        rc = -1;\n"
+        s += "        goto out;\n"
+        s += "    }\n"
+        s += "    enum_str = libxl__json_object_get_string(x);\n"
+        s += "    rc = %s_from_string(enum_str, %s);\n" % (ty.typename, 
ty.pass_arg(v, parent is None, idl.PASS_BY_REFERENCE))
+        s += "    if (rc)\n"
+        s += "        goto out;\n"
+        s += "}\n"
+    elif isinstance(ty, idl.KeyedUnion):
+        if parent is None:
+            raise Exception("KeyedUnion type must have a parent")
+        if discriminator is None:
+            raise Excpetion("KeyedUnion type must have a discriminator")
+        for f in ty.fields:
+            if f.enumname != discriminator:
+                continue
+            (nparent,fexpr) = ty.member(v, f, parent is None)
+            if f.type is not None:
+                s += libxl_C_type_parse_json(f.type, w, fexpr, indent + "    
", nparent)
+    elif isinstance(ty, idl.Struct) and (parent is None or ty.json_parse_fn is 
None):
+        if discriminator is not None:
+            raise Exception("Only KeyedUnion can have discriminator")
+        for f in [f for f in ty.fields if not f.const and not f.type.private]:
+            saved_var_name = "saved_%s" % f.name
+            s += "{\n"
+            s += "    const libxl__json_object *%s = NULL;\n" % saved_var_name
+            s += "    %s = x;\n" % saved_var_name
+            if isinstance(f.type, idl.KeyedUnion):
+                for x in f.type.fields:
+                    s += "    x = libxl__json_map_get(\"%s\", %s, 
JSON_MAP);\n" % \
+                         (f.type.keyvar.name + "." + x.name, w)
+                    s += "    if (x) {\n"
+                    (nparent, fexpr) = ty.member(v, f.type.keyvar, parent is 
None)
+                    s += "        %s_init_type(%s, %s);\n" % (ty.typename, v, 
x.enumname)
+                    (nparent,fexpr) = ty.member(v, f, parent is None)
+                    s += libxl_C_type_parse_json(f.type, "x", fexpr, "  ", 
nparent, x.enumname)
+                    s += "    }\n"
+            else:
+                s += "    x = libxl__json_map_get(\"%s\", %s, %s);\n" % 
(f.name, w, f.type.json_parse_type)
+                s += "    if (x) {\n"
+                (nparent,fexpr) = ty.member(v, f, parent is None)
+                s += libxl_C_type_parse_json(f.type, "x", fexpr, "        ", 
nparent)
+                s += "    }\n"
+            s += "    x = %s;\n" % saved_var_name
+            s += "}\n"
+    else:
+        if discriminator is not None:
+            raise Exception("Only KeyedUnion can have discriminator")
+        if ty.json_parse_fn is not None:
+            s += "rc = %s(gc, %s, &%s);\n" % (ty.json_parse_fn, w, v)
+            s += "if (rc)\n"
+            s += "    goto out;\n"
+
+    if parent is None:
+        s += "out:\n"
+        s += "return rc;\n"
+
+    if s != "":
+        s = indent +s
+    return s.replace("\n", "\n%s" % indent).rstrip(indent)
+
+def libxl_C_type_from_json(ty, v, w, indent = "    "):
+    s = ""
+    parse = "(libxl__json_parse_callback)&%s_parse_json" % ty.typename
+    s += "return libxl__object_from_json(ctx, \"%s\", %s, %s, %s);\n" % 
(ty.typename, parse, v, w)
+
+    if s != "":
+        s = indent + s
+    return s.replace("\n", "\n%s" % indent).rstrip(indent)
+
 def libxl_C_enum_to_string(ty, e, indent = "    "):
     s = ""
     s += "switch(%s) {\n" % e
@@ -350,11 +460,11 @@ def libxl_C_enum_from_string(ty, str, e, indent = "    "):
 
 
 if __name__ == '__main__':
-    if len(sys.argv) != 5:
-        print >>sys.stderr, "Usage: gentypes.py <idl> <header> <header-json> 
<implementation>"
+    if len(sys.argv) != 6:
+        print >>sys.stderr, "Usage: gentypes.py <idl> <header> <header-json> 
<header-json-internal> <implementation>"
         sys.exit(1)
 
-    (_, idlname, header, header_json, impl) = sys.argv
+    (_, idlname, header, header_json, header_json_internal, impl) = sys.argv
 
     (builtins,types) = idl.parse(idlname)
 
@@ -390,6 +500,8 @@ if __name__ == '__main__':
                                                
ku.keyvar.type.make_arg(ku.keyvar.name)))
         if ty.json_gen_fn is not None:
             f.write("%schar *%s_to_json(libxl_ctx *ctx, %s);\n" % 
(ty.hidden(), ty.typename, ty.make_arg("p")))
+        if ty.json_parse_fn is not None:
+            f.write("%sint %s_from_json(libxl_ctx *ctx, %s, const char *s);\n" 
% (ty.hidden(), ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
         if isinstance(ty, idl.Enumeration):
             f.write("%sconst char *%s_to_string(%s);\n" % (ty.hidden(), 
ty.typename, ty.make_arg("p")))
             f.write("%sint %s_from_string(const char *s, %s);\n" % 
(ty.hidden(), ty.typename, ty.make_arg("e", passby=idl.PASS_BY_REFERENCE)))
@@ -423,6 +535,31 @@ if __name__ == '__main__':
     f.write("""#endif /* %s */\n""" % header_json_define)
     f.close()
 
+    print "outputting libxl JSON internal definitions to %s" % 
header_json_internal
+
+    f = open(header_json_internal, "w")
+
+    header_json_internal_define = header_json_internal.upper().replace('.','_')
+    f.write("""#ifndef %s
+#define %s
+
+/*
+ * DO NOT EDIT.
+ *
+ * This file is autogenerated by
+ * "%s"
+ */
+
+""" % (header_json_internal_define, header_json_internal_define, " 
".join(sys.argv)))
+
+    for ty in [ty for ty in types if ty.json_parse_fn is not None]:
+        f.write("%sint %s_parse_json(libxl__gc *gc, const libxl__json_object 
*o, %s);\n" % \
+                (ty.hidden(), ty.typename, ty.make_arg("p", 
passby=idl.PASS_BY_REFERENCE)))
+
+    f.write("\n")
+    f.write("""#endif /* %s */\n""" % header_json_define)
+    f.close()
+
     print "outputting libxl type implementations to %s" % impl
 
     f = open(impl, "w")
@@ -486,4 +623,19 @@ if __name__ == '__main__':
         f.write("}\n")
         f.write("\n")
 
+    for ty in [t for t in types if t.json_parse_fn is not None]:
+        f.write("int %s_parse_json(libxl__gc *gc, const libxl__json_object 
*%s, %s)\n" % (ty.typename,"o",ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
+        f.write("{\n")
+        f.write(libxl_C_type_parse_json(ty, "o", "p"))
+        f.write("}\n")
+        f.write("\n")
+
+        f.write("int %s_from_json(libxl_ctx *ctx, %s, const char *s)\n" % 
(ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)))
+        f.write("{\n")
+        if not isinstance(ty, idl.Enumeration):
+            f.write("    %s_init(p);\n" % ty.typename)
+        f.write(libxl_C_type_from_json(ty, "p", "s"))
+        f.write("}\n")
+        f.write("\n")
+
     f.close()
diff --git a/tools/libxl/idl.py b/tools/libxl/idl.py
index ada801a..381f11b 100644
--- a/tools/libxl/idl.py
+++ b/tools/libxl/idl.py
@@ -68,8 +68,12 @@ class Type(object):
 
         if self.typename is not None and not self.private:
             self.json_gen_fn = kwargs.setdefault('json_gen_fn', self.typename 
+ "_gen_json")
+            self.json_parse_type = kwargs.setdefault('json_parse_type', 
"JSON_ANY")
+            self.json_parse_fn = kwargs.setdefault('json_parse_fn', 
self.typename + "_parse_json")
         else:
             self.json_gen_fn = kwargs.setdefault('json_gen_fn', None)
+            self.json_parse_type = kwargs.setdefault('json_parse_type', None)
+            self.json_parse_fn = kwargs.setdefault('json_parse_fn', None)
 
         self.autogenerate_json = kwargs.setdefault('autogenerate_json', True)
 
@@ -121,6 +125,9 @@ class Number(Builtin):
         kwargs.setdefault('dispose_fn', None)
         kwargs.setdefault('signed', False)
         kwargs.setdefault('json_gen_fn', "yajl_gen_integer")
+        kwargs.setdefault('json_parse_type', "JSON_INTEGER")
+        # json_parse_fn might be overriden on specific type
+        kwargs.setdefault('json_parse_fn', "libxl__int_parse_json")
         self.signed = kwargs['signed']
         Builtin.__init__(self, ctype, **kwargs)
 
@@ -128,6 +135,7 @@ class UInt(Number):
     def __init__(self, w, **kwargs):
         kwargs.setdefault('namespace', None)
         kwargs.setdefault('dispose_fn', None)
+        kwargs.setdefault('json_parse_fn', "libxl__uint%d_parse_json" % w)
         Number.__init__(self, "uint%d_t" % w, **kwargs)
 
         self.width = w
@@ -144,6 +152,7 @@ class EnumerationValue(object):
 class Enumeration(Type):
     def __init__(self, typename, values, **kwargs):
         kwargs.setdefault('dispose_fn', None)
+        kwargs.setdefault('json_parse_type', "JSON_STRING")
         Type.__init__(self, typename, **kwargs)
 
         self.value_namespace = kwargs.setdefault('value_namespace',
@@ -173,6 +182,7 @@ class Field(object):
 class Aggregate(Type):
     """A type containing a collection of other types"""
     def __init__(self, kind, typename, fields, **kwargs):
+        kwargs.setdefault('json_parse_type', "JSON_MAP")
         Type.__init__(self, typename, **kwargs)
 
         if self.typename is not None:
@@ -259,6 +269,8 @@ class KeyedUnion(Aggregate):
 void = Builtin("void *", namespace = None)
 bool = Builtin("bool", namespace = None,
                json_gen_fn = "yajl_gen_bool",
+               json_parse_type = "JSON_BOOL",
+               json_parse_fn = "libxl__bool_parse_json",
                autogenerate_json = False)
 
 size_t = Number("size_t", namespace = None)
@@ -272,12 +284,15 @@ uint64 = UInt(64, json_gen_fn = "libxl__uint64_gen_json")
 
 string = Builtin("char *", namespace = None, dispose_fn = "free",
                  json_gen_fn = "libxl__string_gen_json",
+                 json_parse_type = "JSON_STRING | JSON_NULL",
+                 json_parse_fn = "libxl__string_parse_json",
                  autogenerate_json = False)
 
 class Array(Type):
     """An array of the same type"""
     def __init__(self, elem_type, lenvar_name, **kwargs):
         kwargs.setdefault('dispose_fn', 'free')
+        kwargs.setdefault('json_parse_type', 'JSON_ARRAY')
         Type.__init__(self, namespace=elem_type.namespace, 
typename=elem_type.rawname + " *", **kwargs)
 
         lv_kwargs = dict([(x.lstrip('lenvar_'),y) for (x,y) in kwargs.items() 
if x.startswith('lenvar_')])
diff --git a/tools/libxl/idl.txt b/tools/libxl/idl.txt
index d47eba8..87c4952 100644
--- a/tools/libxl/idl.txt
+++ b/tools/libxl/idl.txt
@@ -65,9 +65,14 @@ Type.json_gen_fn: (default: typename + "_gen_json" or None 
if type == None)
  The name of the C function which will generate a YAJL data structure
  representing this type.
 
+Type.json_parse_fn: (default: typename + "_parse_json" or None if type == None)
+
+ The name of the C function which will parse a libxl JSON structure
+ representing this type to C type.
+
 Type.autogenerate_json: (default: True)
 
- Indicates if the above named Type.json_gen_fn should be autogenerated.
+ Indicates if the above named Type.json_*_fn should be autogenerated.
 
 Type.check_default_fn:
 
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 69ceac8..e52a43f 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -305,6 +305,20 @@
  *
  *    Generates a JSON object from "p" in the form of a NULL terminated
  *    string.
+ *
+ * <type *> libxl_<type>_from_json(const char *json)
+ * int      libxl_<type>_from_json(const char *json)
+ *
+ *    Parses "json" and returns:
+ *
+ *    an int value, if <type> is enumeration type. The value is the enum value
+ *    representing the respective string in "json".
+ *
+ *    an instance of <type>, if <type> is aggregate type. The returned
+ *    instance has its fields filled in by the parser according to "json".
+ *
+ *    If the parsing fails, caller cannot rely on the value / instance
+ *    returned.
  */
 #ifndef LIBXL_H
 #define LIBXL_H
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 2a8f552..37fd77f 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -3186,6 +3186,9 @@ int libxl__uint64_parse_json(libxl__gc *gc, const 
libxl__json_object *o,
 int libxl__string_parse_json(libxl__gc *gc, const libxl__json_object *o,
                              char **p);
 
+#include "_libxl_types_json_internal.h"
+#include "_libxl_types_internal_json_internal.h"
+
 /* This always return false, there's no "default value" for hw cap */
 static inline int libxl__hwcap_is_default(libxl_hwcap *hwcap)
 {
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 7234519..2cb856c 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -5,22 +5,25 @@
 
 namespace("libxl_")
 
-libxl_defbool = Builtin("defbool", passby=PASS_BY_REFERENCE, 
check_default_fn="libxl__defbool_is_default")
-
-libxl_domid = Builtin("domid", json_gen_fn = "yajl_gen_integer", 
autogenerate_json = False)
-libxl_devid = Builtin("devid", json_gen_fn = "yajl_gen_integer", 
autogenerate_json = False, signed = True, init_val="-1")
-libxl_uuid = Builtin("uuid", passby=PASS_BY_REFERENCE, 
check_default_fn="libxl_uuid_is_nil")
-libxl_mac = Builtin("mac", passby=PASS_BY_REFERENCE, 
check_default_fn="libxl__mac_is_default")
-libxl_bitmap = Builtin("bitmap", dispose_fn="libxl_bitmap_dispose", 
passby=PASS_BY_REFERENCE,
+libxl_defbool = Builtin("defbool", json_parse_type="JSON_STRING", 
passby=PASS_BY_REFERENCE,
+                        check_default_fn="libxl__defbool_is_default")
+
+libxl_domid = Builtin("domid", json_gen_fn = "yajl_gen_integer", json_parse_fn 
= "libxl__uint32_parse_json",
+                      json_parse_type = "JSON_INTEGER", autogenerate_json = 
False)
+libxl_devid = Builtin("devid", json_gen_fn = "yajl_gen_integer", json_parse_fn 
= "libxl__int_parse_json",
+                      json_parse_type = "JSON_INTEGER", autogenerate_json = 
False, signed = True, init_val="-1")
+libxl_uuid = Builtin("uuid", json_parse_type="JSON_STRING", 
passby=PASS_BY_REFERENCE, check_default_fn="libxl_uuid_is_nil")
+libxl_mac = Builtin("mac", json_parse_type="JSON_STRING", 
passby=PASS_BY_REFERENCE, check_default_fn="libxl__mac_is_default")
+libxl_bitmap = Builtin("bitmap", json_parse_type="JSON_ARRAY", 
dispose_fn="libxl_bitmap_dispose", passby=PASS_BY_REFERENCE,
                        check_default_fn="libxl_bitmap_is_empty")
 libxl_cpuid_policy_list = Builtin("cpuid_policy_list", 
dispose_fn="libxl_cpuid_dispose", passby=PASS_BY_REFERENCE,
-                                  
check_default_fn="libxl__cpuid_policy_is_empty")
+                                  json_parse_type="JSON_ARRAY", 
check_default_fn="libxl__cpuid_policy_is_empty")
 
 libxl_string_list = Builtin("string_list", 
dispose_fn="libxl_string_list_dispose", passby=PASS_BY_REFERENCE,
-                            check_default_fn="libxl__string_list_is_empty")
+                            json_parse_type="JSON_ARRAY", 
check_default_fn="libxl__string_list_is_empty")
 libxl_key_value_list = Builtin("key_value_list", 
dispose_fn="libxl_key_value_list_dispose", passby=PASS_BY_REFERENCE,
-                               
check_default_fn="libxl__key_value_list_is_empty")
-libxl_hwcap = Builtin("hwcap", passby=PASS_BY_REFERENCE,
+                               json_parse_type="JSON_MAP", 
check_default_fn="libxl__key_value_list_is_empty")
+libxl_hwcap = Builtin("hwcap", passby=PASS_BY_REFERENCE, 
json_parse_type="JSON_ARRAY",
                       check_default_fn="libxl__hwcap_is_default")
 
 #
@@ -586,7 +589,7 @@ libxl_event_type = Enumeration("event_type", [
 
 libxl_ev_user = UInt(64)
 
-libxl_ev_link = Builtin("ev_link", passby=PASS_BY_REFERENCE, private=True)
+libxl_ev_link = Builtin("ev_link", json_parse_type="JSON_STRING", 
passby=PASS_BY_REFERENCE, private=True)
 
 libxl_event = Struct("event",[
     ("link",     libxl_ev_link),
diff --git a/tools/libxl/libxl_types_internal.idl 
b/tools/libxl/libxl_types_internal.idl
index a964851..17533f1 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -1,7 +1,9 @@
 namespace("libxl__")
 hidden(True)
 
-libxl_domid = Builtin("domid", namespace="libxl_", json_gen_fn = 
"yajl_gen_integer")
+libxl_domid = Builtin("domid", namespace="libxl_", json_gen_fn = 
"yajl_gen_integer",
+                     json_parse_fn = "libxl__uint32_parse_json", 
json_parse_type = "JSON_INTEGER",
+                     autogenerate_json = False)
 
 libxl__qmp_message_type = Enumeration("qmp_message_type", [
     (1, "QMP"),
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.