diff mbox

[v3,12/21] qapi: add qapi-types.py code generator

Message ID 1308018686-8235-13-git-send-email-mdroth@linux.vnet.ibm.com
State New
Headers show

Commit Message

Michael Roth June 14, 2011, 2:31 a.m. UTC
This is the code generator for qapi types. It will generation the
following files:

  $(prefix)qapi-types.h - C types corresponding to types defined in
                          the schema you pass in
  $(prefix)qapi-types.c - Cleanup functions for the above C types

The $(prefix) is used to as a namespace to keep the generated code from
one schema/code-generation separated from others so code and be
generated from multiple schemas with clobbering previously created code.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qapi-types.py |  230 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 230 insertions(+), 0 deletions(-)
 create mode 100644 scripts/qapi-types.py

Comments

Luiz Capitulino June 15, 2011, 7:11 p.m. UTC | #1
On Mon, 13 Jun 2011 21:31:17 -0500
Michael Roth <mdroth@linux.vnet.ibm.com> wrote:

> This is the code generator for qapi types. It will generation the
> following files:
> 
>   $(prefix)qapi-types.h - C types corresponding to types defined in
>                           the schema you pass in
>   $(prefix)qapi-types.c - Cleanup functions for the above C types
> 
> The $(prefix) is used to as a namespace to keep the generated code from
> one schema/code-generation separated from others so code and be
> generated from multiple schemas with clobbering previously created code.
> 
> Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
> ---
>  scripts/qapi-types.py |  230 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 230 insertions(+), 0 deletions(-)
>  create mode 100644 scripts/qapi-types.py
> 
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> new file mode 100644
> index 0000000..c8d6b2f
> --- /dev/null
> +++ b/scripts/qapi-types.py
> @@ -0,0 +1,230 @@
> +#
> +# QAPI types generator
> +#
> +# Copyright IBM, Corp. 2011
> +#
> +# Authors:
> +#  Anthony Liguori <aliguori@us.ibm.com>
> +#
> +# This work is licensed under the terms of the GNU GPLv2.
> +# See the COPYING.LIB file in the top-level directory.
> +
> +from ordereddict import OrderedDict
> +from qapi import *
> +import sys
> +import os
> +import getopt
> +
> +def generate_fwd_struct(name, members):
> +    return mcgen('''
> +typedef struct %(name)s %(name)s;
> +
> +typedef struct %(name)sList
> +{
> +    %(name)s *value;
> +    struct %(name)sList *next;
> +} %(name)sList;
> +''',
> +                 name=name)
> +
> +def generate_struct(structname, fieldname, members):
> +    ret = mcgen('''
> +struct %(name)s
> +{
> +''',
> +          name=structname)
> +
> +    for argname, argentry, optional, structured in parse_args(members):
> +        if optional:
> +            ret += mcgen('''
> +    bool has_%(c_name)s;
> +''',
> +                         c_name=c_var(argname))
> +        if structured:
> +            push_indent()
> +            ret += generate_struct("", argname, argentry)
> +            pop_indent()
> +        else:
> +            ret += mcgen('''
> +    %(c_type)s %(c_name)s;
> +''',
> +                     c_type=c_type(argentry), c_name=c_var(argname))
> +
> +    if len(fieldname):
> +        fieldname = " " + fieldname
> +    ret += mcgen('''
> +}%(field)s;
> +''',
> +            field=fieldname)
> +
> +    return ret
> +
> +def generate_handle(name, typeinfo):
> +    return mcgen('''
> +typedef struct %(name)s
> +{
> +    %(c_type)s handle;
> +} %(name)s;
> +
> +typedef struct %(name)sList
> +{
> +    %(name)s *value;
> +    struct %(name)sList *next;
> +} %(name)sList;
> +''',
> +                 name=name, c_type=c_type(typeinfo))
> +
> +def generate_enum(name, values):
> +    ret = mcgen('''
> +typedef enum %(name)s
> +{
> +''',
> +                name=name)
> +
> +    i = 1
> +    for value in values:
> +        ret += mcgen('''
> +    %(abbrev)s_%(value)s = %(i)d,
> +''',
> +                     abbrev=de_camel_case(name).upper(),
> +                     value=c_var(value).upper(),
> +                     i=i)
> +        i += 1
> +
> +    ret += mcgen('''
> +} %(name)s;
> +''',
> +                 name=name)
> +
> +    return ret
> +
> +def generate_union(name, typeinfo):
> +    ret = mcgen('''
> +struct %(name)s
> +{
> +    %(name)sKind kind;
> +    union {
> +''',
> +                name=name)
> +
> +    for key in typeinfo:
> +        ret += mcgen('''
> +        %(c_type)s %(c_name)s;
> +''',
> +                     c_type=c_type(typeinfo[key]),
> +                     c_name=c_var(key))
> +
> +    ret += mcgen('''
> +    };
> +};
> +''')
> +
> +    return ret
> +
> +def generate_type_cleanup_decl(name):
> +    ret = mcgen('''
> +void qapi_free_%(type)s(%(c_type)s obj);
> +''',
> +                c_type=c_type(name),type=name)
> +    return ret
> +
> +def generate_type_cleanup(name):
> +    ret = mcgen('''
> +void qapi_free_%(type)s(%(c_type)s obj)
> +{
> +    QapiDeallocVisitor *md;
> +    Visitor *v;
> +
> +    if (!obj) {
> +        return;
> +    }
> +
> +    md = qapi_dealloc_visitor_new();
> +    v = qapi_dealloc_get_visitor(md);
> +    visit_type_%(type)s(v, &obj, NULL, NULL);
> +    qapi_dealloc_visitor_cleanup(md);
> +}
> +''',
> +                c_type=c_type(name),type=name)
> +    return ret
> +
> +
> +try:
> +    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
> +except getopt.GetoptError, err:
> +    print str(err)
> +    sys.exit(1)
> +
> +output_dir = ""
> +prefix = ""
> +c_file = 'qapi-types.c'
> +h_file = 'qapi-types.h'
> +
> +for o, a in opts:
> +    if o in ("-p", "--prefix"):
> +        prefix = a
> +    elif o in ("-o", "--output-dir"):
> +        output_dir = a + "/"
> +
> +c_file = output_dir + prefix + c_file
> +h_file = output_dir + prefix + h_file
> +
> +if os.path.isdir(output_dir) == False:
> +    os.makedirs(output_dir)
> +
> +fdef = open(c_file, 'w')
> +fdecl = open(h_file, 'w')
> +
> +fdef.write(mcgen('''
> +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */

No license, I think all the code generators forget this.

> +
> +#include "qapi/qapi-dealloc-visitor.h"
> +#include "%(prefix)sqapi-types.h"
> +#include "%(prefix)sqapi-visit.h"
> +
> +''',             prefix=prefix))
> +
> +fdecl.write(mcgen('''
> +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
> +#ifndef %(guard)s
> +#define %(guard)s
> +
> +#include "qapi/qapi-types-core.h"
> +''',
> +                  guard=guardname(h_file)))
> +
> +exprs = parse_schema(sys.stdin)
> +
> +for expr in exprs:
> +    ret = "\n"
> +    if expr.has_key('type'):
> +        ret += generate_fwd_struct(expr['type'], expr['data'])
> +    elif expr.has_key('enum'):
> +        ret += generate_enum(expr['enum'], expr['data'])
> +    elif expr.has_key('union'):
> +        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
> +        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
> +    else:
> +        continue
> +    fdecl.write(ret)
> +
> +for expr in exprs:
> +    ret = "\n"
> +    if expr.has_key('type'):
> +        ret += generate_struct(expr['type'], "", expr['data']) + "\n"
> +        ret += generate_type_cleanup_decl(expr['type'])
> +        fdef.write(generate_type_cleanup(expr['type']) + "\n")
> +    elif expr.has_key('handle'):
> +        ret += generate_handle(expr['handle'], expr['data'])
> +    elif expr.has_key('union'):
> +        ret += generate_union(expr['union'], expr['data'])
> +    else:
> +        continue
> +    fdecl.write(ret)
> +
> +fdecl.write('''
> +#endif
> +''')
> +
> +fdecl.flush()
> +fdecl.close()
diff mbox

Patch

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
new file mode 100644
index 0000000..c8d6b2f
--- /dev/null
+++ b/scripts/qapi-types.py
@@ -0,0 +1,230 @@ 
+#
+# QAPI types generator
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+
+def generate_fwd_struct(name, members):
+    return mcgen('''
+typedef struct %(name)s %(name)s;
+
+typedef struct %(name)sList
+{
+    %(name)s *value;
+    struct %(name)sList *next;
+} %(name)sList;
+''',
+                 name=name)
+
+def generate_struct(structname, fieldname, members):
+    ret = mcgen('''
+struct %(name)s
+{
+''',
+          name=structname)
+
+    for argname, argentry, optional, structured in parse_args(members):
+        if optional:
+            ret += mcgen('''
+    bool has_%(c_name)s;
+''',
+                         c_name=c_var(argname))
+        if structured:
+            push_indent()
+            ret += generate_struct("", argname, argentry)
+            pop_indent()
+        else:
+            ret += mcgen('''
+    %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(argentry), c_name=c_var(argname))
+
+    if len(fieldname):
+        fieldname = " " + fieldname
+    ret += mcgen('''
+}%(field)s;
+''',
+            field=fieldname)
+
+    return ret
+
+def generate_handle(name, typeinfo):
+    return mcgen('''
+typedef struct %(name)s
+{
+    %(c_type)s handle;
+} %(name)s;
+
+typedef struct %(name)sList
+{
+    %(name)s *value;
+    struct %(name)sList *next;
+} %(name)sList;
+''',
+                 name=name, c_type=c_type(typeinfo))
+
+def generate_enum(name, values):
+    ret = mcgen('''
+typedef enum %(name)s
+{
+''',
+                name=name)
+
+    i = 1
+    for value in values:
+        ret += mcgen('''
+    %(abbrev)s_%(value)s = %(i)d,
+''',
+                     abbrev=de_camel_case(name).upper(),
+                     value=c_var(value).upper(),
+                     i=i)
+        i += 1
+
+    ret += mcgen('''
+} %(name)s;
+''',
+                 name=name)
+
+    return ret
+
+def generate_union(name, typeinfo):
+    ret = mcgen('''
+struct %(name)s
+{
+    %(name)sKind kind;
+    union {
+''',
+                name=name)
+
+    for key in typeinfo:
+        ret += mcgen('''
+        %(c_type)s %(c_name)s;
+''',
+                     c_type=c_type(typeinfo[key]),
+                     c_name=c_var(key))
+
+    ret += mcgen('''
+    };
+};
+''')
+
+    return ret
+
+def generate_type_cleanup_decl(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj);
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+def generate_type_cleanup(name):
+    ret = mcgen('''
+void qapi_free_%(type)s(%(c_type)s obj)
+{
+    QapiDeallocVisitor *md;
+    Visitor *v;
+
+    if (!obj) {
+        return;
+    }
+
+    md = qapi_dealloc_visitor_new();
+    v = qapi_dealloc_get_visitor(md);
+    visit_type_%(type)s(v, &obj, NULL, NULL);
+    qapi_dealloc_visitor_cleanup(md);
+}
+''',
+                c_type=c_type(name),type=name)
+    return ret
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+c_file = 'qapi-types.c'
+h_file = 'qapi-types.h'
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+
+c_file = output_dir + prefix + c_file
+h_file = output_dir + prefix + h_file
+
+if os.path.isdir(output_dir) == False:
+    os.makedirs(output_dir)
+
+fdef = open(c_file, 'w')
+fdecl = open(h_file, 'w')
+
+fdef.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+#include "qapi/qapi-dealloc-visitor.h"
+#include "%(prefix)sqapi-types.h"
+#include "%(prefix)sqapi-visit.h"
+
+''',             prefix=prefix))
+
+fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+#ifndef %(guard)s
+#define %(guard)s
+
+#include "qapi/qapi-types-core.h"
+''',
+                  guard=guardname(h_file)))
+
+exprs = parse_schema(sys.stdin)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_fwd_struct(expr['type'], expr['data'])
+    elif expr.has_key('enum'):
+        ret += generate_enum(expr['enum'], expr['data'])
+    elif expr.has_key('union'):
+        ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
+        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
+    else:
+        continue
+    fdecl.write(ret)
+
+for expr in exprs:
+    ret = "\n"
+    if expr.has_key('type'):
+        ret += generate_struct(expr['type'], "", expr['data']) + "\n"
+        ret += generate_type_cleanup_decl(expr['type'])
+        fdef.write(generate_type_cleanup(expr['type']) + "\n")
+    elif expr.has_key('handle'):
+        ret += generate_handle(expr['handle'], expr['data'])
+    elif expr.has_key('union'):
+        ret += generate_union(expr['union'], expr['data'])
+    else:
+        continue
+    fdecl.write(ret)
+
+fdecl.write('''
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()