From: Rob Hoes <rob.hoes@citrix.com>
To: xen-devel@lists.xen.org
Cc: ian.jackson@eu.citrix.com, ian.campbell@citrix.com,
Rob Hoes <rob.hoes@citrix.com>
Subject: [PATCH v3-RESEND 04/28] libxl: ocaml: support for KeyedUnion in the bindings generator.
Date: Mon, 21 Oct 2013 14:32:21 +0100 [thread overview]
Message-ID: <1382362365-6645-5-git-send-email-rob.hoes@citrix.com> (raw)
In-Reply-To: <1382362365-6645-1-git-send-email-rob.hoes@citrix.com>
A KeyedUnion consists of two fields in the containing struct. First an
enum field ("e") used as a descriminator and second a union ("u")
containing potentially anonymous structs associated with each enum
value.
We map the anonymous structs to structs named after the descriminator
field ("e") and the specific enum values. We then declare an ocaml
variant type name e__union mapping each enum value to its associated
struct.
So given IDL:
foo = Enumeration("foo", [
(0, "BAR"),
(1, "BAZ"),
])
s = Struct("s", [
("u", KeyedUnion(none, foo, "blargle", [
("bar", Struct(...xxx...)),
("baz", Struct(...yyy...)),
])),
])
We generate C:
enum foo { BAR, BAZ };
struct s {
enum foo blargle;
union {
struct { ...xxx... } bar;
struct { ...yyy... } baz;
} u;
}
and map this to ocaml
type foo = BAR | BAZ;
module S = struct
type blargle_bar = ...xxx...;
type blargle_baz = ...yyy...;
type blargle__union = Bar of blargle_bar | Baz of blargle_baz;
type t =
{
blargle : blargle__union;
}
end
These type names are OK because they are already within the namespace
associated with the struct "s".
If the struct associated with bar is empty then we don't bother with
blargle_bar of "of blargle_bar".
No actually change in the generated code since we don't generate any
KeyedUnions yet.
The actual implementation was inspired by
http://www.linux-nantes.org/~fmonnier/ocaml/ocaml-wrapping-c.php#ref_constvrnt
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Rob Hoes <rob.hoes@citrix.com>
---
tools/libxl/idl.py | 3 +
tools/ocaml/libs/xl/genwrap.py | 162 +++++++++++++++++++++++++++++++++++-----
2 files changed, 147 insertions(+), 18 deletions(-)
diff --git a/tools/libxl/idl.py b/tools/libxl/idl.py
index 7d95e3f..f4908dd 100644
--- a/tools/libxl/idl.py
+++ b/tools/libxl/idl.py
@@ -216,6 +216,9 @@ class Struct(Aggregate):
kwargs.setdefault('passby', PASS_BY_REFERENCE)
Aggregate.__init__(self, "struct", name, fields, **kwargs)
+ def has_fields(self):
+ return len(self.fields) != 0
+
class Union(Aggregate):
def __init__(self, name, fields, **kwargs):
# Generally speaking some intelligence is required to free a
diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py
index a14fcfe..ad14cad 100644
--- a/tools/ocaml/libs/xl/genwrap.py
+++ b/tools/ocaml/libs/xl/genwrap.py
@@ -65,6 +65,8 @@ def ocaml_type_of(ty):
if not typename:
raise NotImplementedError("No typename for Builtin %s (%s)" % (ty.typename, type(ty)))
return typename
+ elif isinstance(ty,idl.KeyedUnion):
+ return ty.union_name
elif isinstance(ty,idl.Aggregate):
return ty.rawname.capitalize() + ".t"
else:
@@ -73,8 +75,67 @@ def ocaml_type_of(ty):
def munge_name(name):
return "xl_" + name
-def ocaml_instance_of(type, name):
- return "%s : %s" % (munge_name(name), ocaml_type_of(type))
+def ocaml_instance_of_field(f):
+ if isinstance(f.type, idl.KeyedUnion):
+ name = f.type.keyvar.name
+ else:
+ name = f.name
+ return "%s : %s" % (munge_name(name), ocaml_type_of(f.type))
+
+def gen_struct(ty):
+ s = ""
+ for f in ty.fields:
+ if f.type.private:
+ continue
+ x = ocaml_instance_of_field(f)
+ x = x.replace("\n", "\n\t\t")
+ s += "\t\t" + x + ";\n"
+ return s
+
+def gen_ocaml_keyedunions(ty, interface, indent, parent = None):
+ s = ""
+
+ if ty.rawname is not None:
+ # Non-anonymous types need no special handling
+ pass
+ elif isinstance(ty, idl.KeyedUnion):
+ if parent is None:
+ nparent = ty.keyvar.name
+ else:
+ nparent = parent + "_" + ty.keyvar.name
+
+ for f in ty.fields:
+ if f.type is None: continue
+ if f.type.rawname is not None: continue
+ if isinstance(f.type, idl.Struct) and not f.type.has_fields(): continue
+ s += "\ntype %s_%s =\n" % (nparent,f.name)
+ s += "{\n"
+ s += gen_struct(f.type)
+ s += "}\n"
+
+ name = "%s__union" % ty.keyvar.name
+ s += "\n"
+ s += "type %s = " % name
+ u = []
+ for f in ty.fields:
+ if f.type is None:
+ u.append("%s" % (f.name.capitalize()))
+ elif isinstance(f.type, idl.Struct):
+ if f.type.rawname is not None:
+ u.append("%s of %s" % (f.name.capitalize(), f.type.rawname.capitalize()))
+ elif f.type.has_fields():
+ u.append("%s of %s_%s" % (f.name.capitalize(), nparent, f.name))
+ else:
+ u.append("%s" % (f.name.capitalize()))
+ else:
+ raise NotImplementedError("Cannot handle KeyedUnion fields which are not Structs")
+
+ s += " | ".join(u) + "\n"
+ ty.union_name = name
+
+ if s == "":
+ return None
+ return s.replace("\n", "\n%s" % indent)
def gen_ocaml_ml(ty, interface, indent=""):
@@ -100,16 +161,17 @@ def gen_ocaml_ml(ty, interface, indent=""):
s += "module %s : sig\n" % module_name
else:
s += "module %s = struct\n" % module_name
- s += "\ttype t =\n"
- s += "\t{\n"
-
+
+ # Handle KeyedUnions...
for f in ty.fields:
- if f.type.private:
- continue
- x = ocaml_instance_of(f.type, f.name)
- x = x.replace("\n", "\n\t\t")
- s += "\t\t" + x + ";\n"
-
+ ku = gen_ocaml_keyedunions(f.type, interface, "\t")
+ if ku is not None:
+ s += ku
+ s += "\n"
+
+ s += "\ttype t =\n"
+ s += "\t{\n"
+ s += gen_struct(ty)
s += "\t}\n"
if functions.has_key(ty.rawname):
@@ -162,12 +224,43 @@ def c_val(ty, c, o, indent="", parent = None):
n += 1
s += " default: failwith_xl(\"cannot convert value to %s\", lg); break;\n" % ty.typename
s += "}"
- elif isinstance(ty, idl.Aggregate) and (parent is None):
+ elif isinstance(ty, idl.KeyedUnion):
+ s += "{\n"
+ s += "\tif(Is_long(%s)) {\n" % o
+ n = 0
+ s += "\t\tswitch(Int_val(%s)) {\n" % o
+ for f in ty.fields:
+ if f.type is None or not f.type.has_fields():
+ s += "\t\t case %d: %s = %s; break;\n" % (n,
+ parent + ty.keyvar.name,
+ f.enumname)
+ n += 1
+ s += "\t\t default: failwith_xl(\"variant handling bug %s%s (long)\", lg); break;\n" % (parent, ty.keyvar.name)
+ s += "\t\t}\n"
+ s += "\t} else {\n"
+ s += "\t\t/* Is block... */\n"
+ s += "\t\tswitch(Tag_val(%s)) {\n" % o
+ n = 0
+ for f in ty.fields:
+ if f.type is not None and f.type.has_fields():
+ if f.type.private:
+ continue
+ s += "\t\t case %d:\n" % (n)
+ s += "\t\t %s = %s;\n" % (parent + ty.keyvar.name, f.enumname)
+ (nparent,fexpr) = ty.member(c, f, False)
+ s += "%s" % c_val(f.type, fexpr, "Field(%s, 0)" % o, indent=indent+"\t\t ")
+ s += "break;\n"
+ n += 1
+ s += "\t\t default: failwith_xl(\"variant handling bug %s%s (block)\", lg); break;\n" % (parent, ty.keyvar.name)
+ s += "\t\t}\n"
+ s += "\t}\n"
+ s += "}"
+ elif isinstance(ty, idl.Aggregate) and (parent is None or ty.rawname is None):
n = 0
for f in ty.fields:
if f.type.private:
continue
- (nparent,fexpr) = ty.member(c, f, parent is None)
+ (nparent,fexpr) = ty.member(c, f, ty.rawname is not None)
s += "%s\n" % c_val(f.type, fexpr, "Field(%s, %d)" % (o,n), parent=nparent)
n = n + 1
else:
@@ -189,7 +282,7 @@ def gen_c_val(ty, indent=""):
s += "}\n"
return s.replace("\n", "\n%s" % indent)
-
+
def ocaml_Val(ty, o, c, indent="", parent = None):
s = indent
if isinstance(ty,idl.UInt):
@@ -229,9 +322,42 @@ def ocaml_Val(ty, o, c, indent="", parent = None):
n += 1
s += " default: failwith_xl(\"cannot convert value from %s\", lg); break;\n" % ty.typename
s += "}"
- elif isinstance(ty,idl.Aggregate) and (parent is None):
+ elif isinstance(ty, idl.KeyedUnion):
+ n = 0
+ m = 0
+ s += "switch(%s) {\n" % (parent + ty.keyvar.name)
+ for f in ty.fields:
+ s += "\t case %s:\n" % f.enumname
+ if f.type is None:
+ s += "\t /* %d: None */\n" % n
+ s += "\t %s = Val_long(%d);\n" % (o,n)
+ n += 1
+ elif not f.type.has_fields():
+ s += "\t /* %d: Long */\n" % n
+ s += "\t %s = Val_long(%d);\n" % (o,n)
+ n += 1
+ else:
+ s += "\t /* %d: Block */\n" % m
+ (nparent,fexpr) = ty.member(c, f, parent is None)
+ s += "\t {\n"
+ s += "\t\t CAMLlocal1(tmp);\n"
+ s += "\t\t %s = caml_alloc(%d,%d);\n" % (o, 1, m)
+ s += ocaml_Val(f.type, 'tmp', fexpr, indent="\t\t ", parent=nparent)
+ s += "\n"
+ s += "\t\t Store_field(%s, 0, tmp);\n" % o
+ s += "\t }\n"
+ m += 1
+ #s += "\t %s = caml_alloc(%d,%d);\n" % (o,len(f.type.fields),n)
+ s += "\t break;\n"
+ s += "\t default: failwith_xl(\"cannot convert value from %s\", lg); break;\n" % ty.typename
+ s += "\t}"
+ elif isinstance(ty,idl.Aggregate) and (parent is None or ty.rawname is None):
s += "{\n"
- s += "\tvalue %s_field;\n" % ty.rawname
+ if ty.rawname is None:
+ fn = "anon_field"
+ else:
+ fn = "%s_field" % ty.rawname
+ s += "\tvalue %s;\n" % fn
s += "\n"
s += "\t%s = caml_alloc_tuple(%d);\n" % (o, len(ty.fields))
@@ -243,8 +369,8 @@ def ocaml_Val(ty, o, c, indent="", parent = None):
(nparent,fexpr) = ty.member(c, f, parent is None)
s += "\n"
- s += "\t%s\n" % ocaml_Val(f.type, "%s_field" % ty.rawname, ty.pass_arg(fexpr, c), parent=nparent)
- s += "\tStore_field(%s, %d, %s);\n" % (o, n, "%s_field" % ty.rawname)
+ s += "\t%s\n" % ocaml_Val(f.type, fn, ty.pass_arg(fexpr, c), parent=nparent)
+ s += "\tStore_field(%s, %d, %s);\n" % (o, n, fn)
n = n + 1
s += "}"
else:
--
1.7.10.4
next prev parent reply other threads:[~2013-10-21 13:32 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-10-21 13:32 libxl: ocaml: improve the bindings Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 01/28] libxl: idl: allow KeyedUnion members to be empty Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 02/28] libxl: ocaml: support for Arrays in bindings generator Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 03/28] libxl: ocaml: avoid reserved words in type and field names Rob Hoes
2013-10-24 22:04 ` Ian Campbell
2013-10-24 22:11 ` Rob Hoes
2013-10-25 6:56 ` Ian Campbell
2013-10-25 8:44 ` Rob Hoes
2013-10-28 15:24 ` Ian Jackson
2013-10-31 13:43 ` Ian Campbell
2013-10-31 14:27 ` Ian Jackson
2013-10-31 17:20 ` Ian Campbell
2013-11-04 14:59 ` Rob Hoes
2013-10-21 13:32 ` Rob Hoes [this message]
2013-10-21 13:32 ` [PATCH v3-RESEND 05/28] libxl: ocaml: add some more builtin types Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 06/28] libxc: ocaml: add simple binding for xentoollog (output only) Rob Hoes
2013-11-13 13:45 ` Ian Campbell
2013-11-14 14:11 ` Rob Hoes
2013-11-15 11:48 ` Andrew Cooper
2013-10-21 13:32 ` [PATCH v3-RESEND 07/28] libxl: ocaml: allocate a long lived libxl context Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 08/28] libxl: ocaml: switch all functions over to take a context Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 09/28] libxl: make the libxl error type an IDL enum Rob Hoes
2013-10-31 18:07 ` Ian Campbell
2013-11-04 14:48 ` Rob Hoes
2013-11-04 15:05 ` Ian Campbell
2013-10-21 13:32 ` [PATCH v3-RESEND 10/28] libxl: ocaml: generate string_of_* functions for enums Rob Hoes
2013-10-31 18:13 ` Ian Campbell
2013-11-06 10:30 ` Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 11/28] libxl: ocaml: propagate the libxl return error code in exceptions Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 12/28] libxl: ocaml: make Val_defbool GC-proof Rob Hoes
2013-10-31 18:15 ` Ian Campbell
2013-10-31 18:55 ` Ian Jackson
2013-10-31 18:57 ` Ian Jackson
2013-10-31 19:10 ` Ian Campbell
2013-10-31 19:42 ` Dave Scott
2013-10-31 19:19 ` Ian Jackson
2013-10-21 13:32 ` [PATCH v3-RESEND 13/28] libxl: ocaml: add domain_build/create_info/config and events to the bindings Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 14/28] libxl: ocaml: add META to list of generated files in Makefile Rob Hoes
2013-10-31 18:47 ` Ian Campbell
2013-10-21 13:32 ` [PATCH v3-RESEND 15/28] libxl: ocaml: fix the handling of enums in the bindings generator Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 16/28] libxl: ocaml: use the "string option" type for IDL strings Rob Hoes
2013-10-31 18:18 ` Ian Campbell
2013-10-31 18:48 ` Ian Campbell
2013-10-21 13:32 ` [PATCH v3-RESEND 17/28] libxl: ocaml: add dominfo_list and dominfo_get Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 18/28] libxl: ocaml: implement some simple tests Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 19/28] libxl: ocaml: event management Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 20/28] libxl: ocaml: allow device operations to be called asynchronously Rob Hoes
2013-10-31 18:21 ` Ian Campbell
2013-11-06 11:46 ` Rob Hoes
2013-11-06 12:02 ` Ian Campbell
2013-10-21 13:32 ` [PATCH v3-RESEND 21/28] libxl: ocaml: add NIC helper functions Rob Hoes
2013-10-31 18:23 ` Ian Campbell
2013-11-06 11:55 ` Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 22/28] libxl: ocaml: add PCI device " Rob Hoes
2013-10-31 18:24 ` Ian Campbell
2013-10-21 13:32 ` [PATCH v3-RESEND 23/28] libxl: ocaml: add disk and cdrom " Rob Hoes
2013-10-31 18:25 ` Ian Campbell
2013-10-21 13:32 ` [PATCH v3-RESEND 24/28] libxl: ocaml: add VM lifecycle operations Rob Hoes
2013-10-31 18:36 ` Ian Campbell
2013-11-06 12:20 ` Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 25/28] libxl: ocaml: in send_debug_keys, clean up before raising exception Rob Hoes
2013-10-31 18:38 ` Ian Campbell
2013-11-06 13:56 ` Rob Hoes
2013-10-21 13:32 ` [PATCH v3-RESEND 26/28] libxl: ocaml: provide defaults for libxl types Rob Hoes
2013-10-31 18:43 ` Ian Campbell
2013-10-21 13:32 ` [PATCH v3-RESEND 27/28] libxl: ocaml: use CAMLlocal1 macro rather than value-type in auto-generated C-code Rob Hoes
2013-10-31 18:48 ` Ian Campbell
2013-10-21 13:32 ` [PATCH v3-RESEND 28/28] libxl: ocaml: add console reader functions Rob Hoes
2013-10-31 18:45 ` Ian Campbell
2013-10-23 11:33 ` libxl: ocaml: improve the bindings David Scott
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=1382362365-6645-5-git-send-email-rob.hoes@citrix.com \
--to=rob.hoes@citrix.com \
--cc=ian.campbell@citrix.com \
--cc=ian.jackson@eu.citrix.com \
--cc=xen-devel@lists.xen.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).