All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Marc-André Lureau" <marcandre.lureau@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>,
	"Dr. David Alan Gilbert" <dgilbert@redhat.com>,
	"Michael Roth" <mdroth@linux.vnet.ibm.com>
Subject: [Qemu-devel] [PATCH 04/26] qapi: generate a literal qobject for introspection
Date: Thu, 27 Jul 2017 17:41:04 +0200	[thread overview]
Message-ID: <20170727154126.11339-5-marcandre.lureau@redhat.com> (raw)
In-Reply-To: <20170727154126.11339-1-marcandre.lureau@redhat.com>

Replace the generated json string with a literal qobject. The later is
easier to deal with, at run time, as well as compile time: #if blocks
can be more easily added than in a json string.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-introspect.py         | 83 +++++++++++++++++++++-----------------
 monitor.c                          |  2 +-
 tests/test-qobject-input-visitor.c | 10 +++--
 docs/devel/qapi-code-gen.txt       | 29 ++++++++-----
 4 files changed, 72 insertions(+), 52 deletions(-)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 032bcea491..fc72cdb66d 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -12,72 +12,74 @@
 from qapi import *
 
 
-# Caveman's json.dumps() replacement (we're stuck at Python 2.4)
-# TODO try to use json.dumps() once we get unstuck
-def to_json(obj, level=0):
+def to_qlit(obj, level=0, first_indent=True):
+    def indent(level):
+        return level * 4 * ' '
+    ret = ''
+    if first_indent:
+        ret += indent(level)
     if obj is None:
-        ret = 'null'
+        ret += 'QLIT_QNULL'
     elif isinstance(obj, str):
-        ret = '"' + obj.replace('"', r'\"') + '"'
+        ret += 'QLIT_QSTR(' + '"' + obj.replace('"', r'\"') + '"' + ')'
     elif isinstance(obj, list):
-        elts = [to_json(elt, level + 1)
+        elts = [to_qlit(elt, level + 1)
                 for elt in obj]
-        ret = '[' + ', '.join(elts) + ']'
+        elts.append(indent(level + 1) + "{ }")
+        ret += 'QLIT_QLIST(((QLitObject[]) {\n'
+        ret += ',\n'.join(elts) + '\n'
+        ret += indent(level) + '}))'
     elif isinstance(obj, dict):
-        elts = ['"%s": %s' % (key.replace('"', r'\"'),
-                              to_json(obj[key], level + 1))
-                for key in sorted(obj.keys())]
-        ret = '{' + ', '.join(elts) + '}'
+        elts = [ indent(level + 1) + '{ "%s", %s }' %
+                 (key.replace('"', r'\"'), to_qlit(obj[key], level + 1, False))
+                 for key in sorted(obj.keys())]
+        elts.append(indent(level + 1) + '{ }')
+        ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n'
+        ret += ',\n'.join(elts) + '\n'
+        ret += indent(level) + '}))'
     else:
         assert False                # not implemented
-    if level == 1:
-        ret = '\n' + ret
     return ret
 
 
-def to_c_string(string):
-    return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"'
-
-
 class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
     def __init__(self, unmask):
         self._unmask = unmask
         self.defn = None
         self.decl = None
         self._schema = None
-        self._jsons = None
+        self._qlits = None
         self._used_types = None
         self._name_map = None
 
     def visit_begin(self, schema):
         self._schema = schema
-        self._jsons = []
+        self._qlits = []
         self._used_types = []
         self._name_map = {}
 
     def visit_end(self):
         # visit the types that are actually used
-        jsons = self._jsons
-        self._jsons = []
+        qlits = self._qlits
+        self._qlits = []
         for typ in self._used_types:
             typ.visit(self)
         # generate C
         # TODO can generate awfully long lines
-        jsons.extend(self._jsons)
-        name = c_name(prefix, protect=False) + 'qmp_schema_json'
+        qlits.extend(self._qlits)
+        name = c_name(prefix, protect=False) + 'qmp_schema_qlit'
         self.decl = mcgen('''
-extern const char %(c_name)s[];
+extern const QLitObject %(c_name)s;
 ''',
                           c_name=c_name(name))
-        lines = to_json(jsons).split('\n')
-        c_string = '\n    '.join([to_c_string(line) for line in lines])
+        c_string = to_qlit(qlits)
         self.defn = mcgen('''
-const char %(c_name)s[] = %(c_string)s;
+const QLitObject %(c_name)s = %(c_string)s;
 ''',
                           c_name=c_name(name),
                           c_string=c_string)
         self._schema = None
-        self._jsons = None
+        self._qlits = None
         self._used_types = None
         self._name_map = None
 
@@ -111,12 +113,12 @@ const char %(c_name)s[] = %(c_string)s;
             return '[' + self._use_type(typ.element_type) + ']'
         return self._name(typ.name)
 
-    def _gen_json(self, name, mtype, obj):
+    def _gen_qlit(self, name, mtype, obj):
         if mtype not in ('command', 'event', 'builtin', 'array'):
             name = self._name(name)
         obj['name'] = name
         obj['meta-type'] = mtype
-        self._jsons.append(obj)
+        self._qlits.append(obj)
 
     def _gen_member(self, member):
         ret = {'name': member.name, 'type': self._use_type(member.type)}
@@ -132,24 +134,24 @@ const char %(c_name)s[] = %(c_string)s;
         return {'case': variant.name, 'type': self._use_type(variant.type)}
 
     def visit_builtin_type(self, name, info, json_type):
-        self._gen_json(name, 'builtin', {'json-type': json_type})
+        self._gen_qlit(name, 'builtin', {'json-type': json_type})
 
     def visit_enum_type(self, name, info, values, prefix):
-        self._gen_json(name, 'enum', {'values': values})
+        self._gen_qlit(name, 'enum', {'values': values})
 
     def visit_array_type(self, name, info, element_type):
         element = self._use_type(element_type)
-        self._gen_json('[' + element + ']', 'array', {'element-type': element})
+        self._gen_qlit('[' + element + ']', 'array', {'element-type': element})
 
     def visit_object_type_flat(self, name, info, members, variants):
         obj = {'members': [self._gen_member(m) for m in members]}
         if variants:
             obj.update(self._gen_variants(variants.tag_member.name,
                                           variants.variants))
-        self._gen_json(name, 'object', obj)
+        self._gen_qlit(name, 'object', obj)
 
     def visit_alternate_type(self, name, info, variants):
-        self._gen_json(name, 'alternate',
+        self._gen_qlit(name, 'alternate',
                        {'members': [{'type': self._use_type(m.type)}
                                     for m in variants.variants]})
 
@@ -157,13 +159,13 @@ const char %(c_name)s[] = %(c_string)s;
                       gen, success_response, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
-        self._gen_json(name, 'command',
+        self._gen_qlit(name, 'command',
                        {'arg-type': self._use_type(arg_type),
                         'ret-type': self._use_type(ret_type)})
 
     def visit_event(self, name, info, arg_type, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
-        self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
+        self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)})
 
 # Debugging aid: unmask QAPI schema's type names
 # We normally mask them, because they're not QMP wire ABI
@@ -205,11 +207,18 @@ h_comment = '''
 
 fdef.write(mcgen('''
 #include "qemu/osdep.h"
+#include "qapi/qmp/qlit.h"
 #include "%(prefix)sqmp-introspect.h"
 
 ''',
                  prefix=prefix))
 
+fdecl.write(mcgen('''
+#include "qemu/osdep.h"
+#include "qapi/qmp/qlit.h"
+
+'''))
+
 schema = QAPISchema(input_file)
 gen = QAPISchemaGenIntrospectVisitor(opt_unmask)
 schema.visit(gen)
diff --git a/monitor.c b/monitor.c
index 6d040e620f..a1773d5bc7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -953,7 +953,7 @@ EventInfoList *qmp_query_events(Error **errp)
 static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
                                  Error **errp)
 {
-    *ret_data = qobject_from_json(qmp_schema_json, &error_abort);
+    *ret_data = qobject_from_qlit(&qmp_schema_qlit);
 }
 
 /*
diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c
index bcf02617dc..1969733971 100644
--- a/tests/test-qobject-input-visitor.c
+++ b/tests/test-qobject-input-visitor.c
@@ -1247,24 +1247,26 @@ static void test_visitor_in_fail_alternate(TestInputVisitorData *data,
 }
 
 static void do_test_visitor_in_qmp_introspect(TestInputVisitorData *data,
-                                              const char *schema_json)
+                                              const QLitObject *qlit)
 {
     SchemaInfoList *schema = NULL;
+    QObject *obj = qobject_from_qlit(qlit);
     Visitor *v;
 
-    v = visitor_input_test_init_raw(data, schema_json);
+    v = qobject_input_visitor_new(obj);
 
     visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
     g_assert(schema);
 
     qapi_free_SchemaInfoList(schema);
+    qobject_decref(obj);
 }
 
 static void test_visitor_in_qmp_introspect(TestInputVisitorData *data,
                                            const void *unused)
 {
-    do_test_visitor_in_qmp_introspect(data, test_qmp_schema_json);
-    do_test_visitor_in_qmp_introspect(data, qmp_schema_json);
+    do_test_visitor_in_qmp_introspect(data, &test_qmp_schema_qlit);
+    do_test_visitor_in_qmp_introspect(data, &qmp_schema_qlit);
 }
 
 int main(int argc, char **argv)
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 9903ac4c19..885c61b52f 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -1295,18 +1295,27 @@ Example:
     #ifndef EXAMPLE_QMP_INTROSPECT_H
     #define EXAMPLE_QMP_INTROSPECT_H
 
-    extern const char example_qmp_schema_json[];
+    extern const QLitObject qmp_schema_qlit;
 
     #endif
     $ cat qapi-generated/example-qmp-introspect.c
 [Uninteresting stuff omitted...]
 
-    const char example_qmp_schema_json[] = "["
-        "{\"arg-type\": \"0\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
-        "{\"arg-type\": \"1\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"2\"}, "
-        "{\"members\": [], \"meta-type\": \"object\", \"name\": \"0\"}, "
-        "{\"members\": [{\"name\": \"arg1\", \"type\": \"[2]\"}], \"meta-type\": \"object\", \"name\": \"1\"}, "
-        "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"default\": null, \"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, "
-        "{\"element-type\": \"2\", \"meta-type\": \"array\", \"name\": \"[2]\"}, "
-        "{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, "
-        "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]";
+    const QLitObject example_qmp_schema_qlit = QLIT_QLIST(((QLitObject[]) {
+        QLIT_QDICT(((QLitDictEntry[]) {
+            { "arg-type", QLIT_QSTR("0") },
+            { "meta-type", QLIT_QSTR("event") },
+            { "name", QLIT_QSTR("Event") },
+            { }
+        })),
+        QLIT_QDICT(((QLitDictEntry[]) {
+            { "members", QLIT_QLIST(((QLitObject[]) {
+                { }
+            })) },
+            { "meta-type", QLIT_QSTR("object") },
+            { "name", QLIT_QSTR("0") },
+            { }
+        })),
+        ....
+        { }
+    }));
-- 
2.14.0.rc0.1.g40ca67566

  parent reply	other threads:[~2017-07-27 15:47 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-27 15:41 [Qemu-devel] [PATCH 00/26] qapi: add #if pre-processor conditions to generated code Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 01/26] qapi: fix type_seen key error Marc-André Lureau
2017-08-15 14:40   ` Markus Armbruster
2017-08-17 23:17     ` Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 02/26] qobject: replace dump_qobject() by qobject_to_string() Marc-André Lureau
2017-08-16  9:02   ` Markus Armbruster
2017-07-27 15:41 ` [Qemu-devel] [PATCH 03/26] qboject: add literal qobject type Marc-André Lureau
2017-08-16  8:59   ` Markus Armbruster
2017-08-22 11:16     ` Marc-André Lureau
2017-07-27 15:41 ` Marc-André Lureau [this message]
2017-08-16 10:21   ` [Qemu-devel] [PATCH 04/26] qapi: generate a literal qobject for introspection Markus Armbruster
2017-08-22 11:17     ` Marc-André Lureau
2017-08-17 11:48   ` Markus Armbruster
2017-07-27 15:41 ` [Qemu-devel] [PATCH 05/26] visitor: pass size of strings array to enum visitor Marc-André Lureau
2017-08-16 12:54   ` Markus Armbruster
2017-08-22 11:17     ` Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 06/26] qapi2texi: minor python code simplification Marc-André Lureau
2017-08-16 12:55   ` Markus Armbruster
2017-07-27 15:41 ` [Qemu-devel] [PATCH 07/26] qapi: add 'if' condition on top-level schema elements Marc-André Lureau
2017-08-16 15:43   ` Markus Armbruster
2017-08-17  5:50     ` Markus Armbruster
2017-08-22 11:17     ` Marc-André Lureau
2017-08-22 16:52       ` Markus Armbruster
2017-08-23 12:45         ` Eduardo Habkost
2017-08-17 11:51   ` Markus Armbruster
2017-07-27 15:41 ` [Qemu-devel] [PATCH 08/26] qapi: add 'if' condition on enum member values Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 09/26] qapi: add 'if' condition on struct member Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 10/26] qapi: add 'if' condition on union variant Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 11/26] qapi: add 'if' condition on alternate variant Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 12/26] qapi2texi: add 'If:' section to generated documentation Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 13/26] qapi2texi: add 'If:' condition to enum values Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 14/26] qapi2texi: add 'If:' condition to struct members Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 15/26] qapi2texi: add condition to variants Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 16/26] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
2017-07-28 19:00   ` Dr. David Alan Gilbert
2017-08-17  6:32     ` Markus Armbruster
2017-08-17  9:33       ` Dr. David Alan Gilbert
2017-08-17  7:04   ` Markus Armbruster
2017-08-17  8:56     ` Markus Armbruster
2017-08-23 15:07       ` Gerd Hoffmann
2017-08-23 17:35         ` Eduardo Habkost
2017-08-23 15:09     ` Gerd Hoffmann
2017-08-29 10:42     ` Daniel P. Berrange
2017-08-29 10:46       ` Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 17/26] qapi: add conditions to SPICE " Marc-André Lureau
2017-08-17  8:10   ` Markus Armbruster
2017-08-17  8:43     ` Markus Armbruster
2017-07-27 15:41 ` [Qemu-devel] [PATCH 18/26] qapi: add conditions to REPLICATION type/commands " Marc-André Lureau
2017-08-17  9:16   ` Markus Armbruster
2017-08-22 11:18     ` Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 19/26] build-sys: move qapi variables in qapi.mak Marc-André Lureau
2017-08-17  9:19   ` Markus Armbruster
2017-07-27 15:41 ` [Qemu-devel] [PATCH 20/26] tests/qmp-test: add query-qmp-schema test Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 21/26] build-sys: make qemu qapi objects per-target Marc-André Lureau
2017-08-17 11:44   ` Markus Armbruster
2017-08-22 11:18     ` Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 22/26] qapi: make rtc-reset-reinjection depend on TARGET_I386 Marc-André Lureau
2017-08-17 11:57   ` Markus Armbruster
2017-08-22 11:18     ` Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 23/26] qapi: make s390 commands depend on TARGET_S390X Marc-André Lureau
2017-08-17 12:13   ` Markus Armbruster
2017-07-27 15:41 ` [Qemu-devel] [PATCH 24/26] qapi: make query-gic-capabilities depend on TARGET_ARM Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 25/26] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
2017-07-27 15:41 ` [Qemu-devel] [PATCH 26/26] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
2017-08-17 12:30   ` Markus Armbruster
2017-08-17 12:43     ` Marc-André Lureau
2017-08-17 13:55 ` [Qemu-devel] [PATCH 00/26] qapi: add #if pre-processor conditions to generated code Markus Armbruster
2017-08-22 11:22   ` Marc-André Lureau
2017-08-22 16:58     ` Markus Armbruster

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170727154126.11339-5-marcandre.lureau@redhat.com \
    --to=marcandre.lureau@redhat.com \
    --cc=armbru@redhat.com \
    --cc=dgilbert@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.