From bfe575dee72a29bce70bc2fb981e87a8f8c2cda9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 Jan 2014 14:33:21 +0000 Subject: [PATCH] rxgen: Extract py wrapper type emitter Extract the code to emit python wrapper types from the main rxgen script and put into its own module. Signed-off-by: David Howells --- rxgen/emit_py_types.pm | 244 +++++++++++++++++++++++++++++++++++++++++ rxgen/rxgen.pl | 239 +--------------------------------------- 2 files changed, 246 insertions(+), 237 deletions(-) create mode 100644 rxgen/emit_py_types.pm diff --git a/rxgen/emit_py_types.pm b/rxgen/emit_py_types.pm new file mode 100644 index 0000000..73d4f65 --- /dev/null +++ b/rxgen/emit_py_types.pm @@ -0,0 +1,244 @@ +# +# Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. +# Written by David Howells (dhowells@redhat.com) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public Licence +# as published by the Free Software Foundation; either version +# 2 of the Licence, or (at your option) any later version. +# + +############################################################################### +# +# Emit python type wrappers for C structs. +# +############################################################################### +sub emit_py_type_wrapper($@) { + my ($struct, @members) = @_; + + # Dump the banner comment block + my @comments = @{shift @members}; + + print PYHDR "\n"; + print PYHDR @comments; + print PYOUT "\n"; + print PYOUT @comments; + + # Write a python wrapper struct + print PYHDR "struct py_$struct {\n"; + print PYHDR "\tPyObject_HEAD\n"; + print PYHDR "\tstruct $struct x;\n"; + print PYHDR "};\n"; + print PYHDR "\n"; + + # We want allocation and deallocation functions + print PYOUT "static PyObject *\n"; + print PYOUT "py_", $struct, "_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\n"; + print PYOUT "{\n"; + print PYOUT "\treturn (PyObject *)(struct py_$struct *)type->tp_alloc(type, 0);\n"; + print PYOUT "}\n"; + print PYOUT "\n"; + print PYOUT "static void\n"; + print PYOUT "py_", $struct, "_dealloc(struct py_$struct *self)\n"; + print PYOUT "{\n"; + print PYOUT "\tPy_TYPE(self)->tp_free((PyObject *)self);\n"; + print PYOUT "}\n"; + print PYOUT "\n"; + + # Divide into single members and array members + my @singles = (); + my @arrays = (); + foreach my $m (@members) { + my ($type, $name, $array_size, $max_size) = @{$m}; + if ($array_size == -1) { + push @singles, $m; + } else { + push @arrays, $m; + } + } + + # Any non-array elements are made directly accessible to the Python interpreter + print PYOUT "static PyMemberDef py_", $struct, "_members[] = {\n"; + if (@singles) { + foreach my $m (@singles) { + my ($type, $name, $array_size, $max_size) = @{$m}; + print PYOUT "\t{ \"$name\", "; + if ($type eq "char") { + print PYOUT "T_CHAR"; + } elsif ($type eq "int8_t") { + print PYOUT "T_BYTE"; + } elsif ($type eq "int16_t") { + print PYOUT "T_SHORT"; + } elsif ($type eq "int32_t") { + print PYOUT "T_INT"; + } elsif ($type eq "int64_t") { + print PYOUT "T_LONGLONG"; + } elsif ($type eq "uint8_t") { + print PYOUT "T_UBYTE"; + } elsif ($type eq "uint16_t") { + print PYOUT "T_USHORT"; + } elsif ($type eq "uint32_t") { + print PYOUT "T_UINT"; + } elsif ($type eq "uint64_t") { + print PYOUT "T_ULONGLONG"; + } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) { + die "Don't py-wrap structs yet"; + } else { + die "Unsupported type \"$type\""; + } + print PYOUT ", offsetof(struct py_$struct, x.$name), 0, \"\"},\n"; + } + } + print PYOUT "\t{}\n"; + print PYOUT "};\n"; + print PYOUT "\n"; + + # Array elements have to be accessed through ->tp_[sg]etattro() as + # tuples (int[]/uint[]) or strings (char[]) + if (@arrays) { + # The attribute get function + print PYOUT "static PyObject *\n"; + print PYOUT "py_", $struct, "_getattro(PyObject *_self, PyObject *name)\n"; + print PYOUT "{\n"; + print PYOUT "\tstruct py_$struct *self = (struct py_$struct *)_self;\n"; + print PYOUT "\n"; + print PYOUT "\tif (PyUnicode_Check(name)) {\n"; + + foreach my $m (@arrays) { + my ($type, $name, $array_size, $max_size) = @{$m}; + + print PYOUT "\t\tif (PyUnicode_CompareWithASCIIString(name, \"$name\") == 0)\n"; + if ($type eq "char") { + print PYOUT "\t\t\treturn py_rxgen_get_string(&self->x.$name, $array_size);\n"; + } elsif ($type eq "uint8_t") { + print PYOUT "\t\t\treturn py_rxgen_get_uint8(&self->x.$name, $array_size);\n"; + } elsif ($type eq "uint16_t") { + print PYOUT "\t\t\treturn py_rxgen_get_uint16(&self->x.$name, $array_size);\n"; + } elsif ($type eq "uint32_t") { + print PYOUT "\t\t\treturn py_rxgen_get_uint32(&self->x.$name, $array_size);\n"; + } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) { + die "Don't py-wrap struct arrays yet"; + } else { + die "Unsupported array type \"$type\""; + } + } + + print PYOUT "\t}\n"; + print PYOUT "\n"; + print PYOUT "\treturn PyObject_GenericGetAttr(_self, name);\n"; + print PYOUT "}\n"; + print PYOUT "\n"; + + # The attribute set function + print PYOUT "static int\n"; + print PYOUT "py_", $struct, "_setattro(PyObject *_self, PyObject *name, PyObject *val)\n"; + print PYOUT "{\n"; + print PYOUT "\tstruct py_$struct *self = (struct py_$struct *)_self;\n"; + print PYOUT "\n"; + print PYOUT "\tif (PyUnicode_Check(name)) {\n"; + + foreach my $m (@arrays) { + my ($type, $name, $array_size, $max_size) = @{$m}; + + print PYOUT "\t\tif (PyUnicode_CompareWithASCIIString(name, \"$name\") == 0)\n"; + if ($type eq "char") { + print PYOUT "\t\t\treturn py_rxgen_set_string(&self->x.$name, $array_size, val);\n"; + } elsif ($type eq "uint8_t") { + print PYOUT "\t\t\treturn py_rxgen_set_uint8(&self->x.$name, $array_size, val);\n"; + } elsif ($type eq "uint16_t") { + print PYOUT "\t\t\treturn py_rxgen_set_uint16(&self->x.$name, $array_size, val);\n"; + } elsif ($type eq "uint32_t") { + print PYOUT "\t\t\treturn py_rxgen_set_uint32(&self->x.$name, $array_size, val);\n"; + } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) { + die "Don't py-wrap struct arrays yet"; + } else { + die "Unsupported array type \"$type\""; + } + } + + print PYOUT "\t}\n"; + print PYOUT "\n"; + print PYOUT "\treturn PyObject_GenericSetAttr(_self, name, val);\n"; + print PYOUT "}\n"; + print PYOUT "\n"; + } + + # Emit the Python type definition + print PYOUT "static PyTypeObject py_", $struct, "Type = {\n"; + + print PYOUT "\tPyVarObject_HEAD_INIT(NULL, 0)\n"; + print PYOUT "\t\"kafs.$struct\",\t\t/*tp_name*/\n"; + print PYOUT "\tsizeof(struct py_$struct),\t/*tp_basicsize*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_itemsize*/\n"; + print PYOUT "\t(destructor)py_", $struct, "_dealloc, /*tp_dealloc*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_print*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_getattr*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_setattr*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_compare*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_repr*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_as_number*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_as_sequence*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_as_mapping*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_hash */\n"; + print PYOUT "\t0,\t\t\t\t/*tp_call*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_str*/\n"; + if (@arrays) { + print PYOUT "\tpy_", $struct, "_getattro,\n"; + print PYOUT "\tpy_", $struct, "_setattro,\n"; + } else { + print PYOUT "\t0,\t\t\t\t/*tp_getattro*/\n"; + print PYOUT "\t0,\t\t\t\t/*tp_setattro*/\n"; + } + print PYOUT "\t0,\t\t\t\t/*tp_as_buffer*/\n"; + print PYOUT "\tPy_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/\n"; + if (@comments) { + print PYOUT "\t"; + foreach my $c (@comments) { + $c =~ s/\s+$//; + $c =~ s/^\s+//; + next if ($c eq "/*" || $c eq "*/"); + $c =~ s/^[*] //; + $c =~ s/^[*]$//; + print PYOUT "\n\t\t\"", $c, "\\n\""; + } + print PYOUT ",\n"; + } else { + print PYOUT "\t\"\",\t\t\t/* tp_doc */\n"; + } + print PYOUT "\t0,\t\t\t\t/* tp_traverse */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_clear */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_richcompare */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_weaklistoffset */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_iter */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_iternext */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_methods */\n"; + if (@singles) { + print PYOUT "\tpy_", $struct, "_members,\n"; + } else { + print PYOUT "\t0,\t\t\t/* tp_members */\n"; + } + print PYOUT "\t0,\t\t\t\t/* tp_getset */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_base */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_dict */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_descr_get */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_descr_set */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_dictoffset */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_init */\n"; + print PYOUT "\t0,\t\t\t\t/* tp_alloc */\n"; + print PYOUT "\tpy_", $struct, "_new,\t/* tp_new */\n"; + print PYOUT "};\n"; + + # Emit a function to allocate such a type + print PYHDR "extern PyObject *kafs_new_py_$struct(PyObject *, PyObject *);\n"; + + print PYOUT "\n"; + print PYOUT "PyObject *\n"; + print PYOUT "kafs_new_py_$struct(PyObject *_self, PyObject *args)\n"; + print PYOUT "{\n"; + print PYOUT "\tPyObject *obj;\n"; + print PYOUT "\tobj = _PyObject_New(&py_", $struct, "Type);\n"; + print PYOUT "\treturn obj ?: PyExc_MemoryError;\n"; + print PYOUT "}\n"; +} + +1; diff --git a/rxgen/rxgen.pl b/rxgen/rxgen.pl index 59d4cc3..54f617b 100755 --- a/rxgen/rxgen.pl +++ b/rxgen/rxgen.pl @@ -18,11 +18,9 @@ use strict; use lib "rxgen"; +use emit_py_types; use emit_py_sync_funcs; -sub emit_py_struct_wrapper($@); -sub emit_py_func_simple_sync_call($$$@); - die "Need list of sources\n" if ($#ARGV < 0); our @structs = (); # Structure definitions @@ -302,7 +300,7 @@ foreach my $s (@structs) { my @members = @{$s}; my $struct = shift @members; emit_struct_encdec($struct, @members); - emit_py_struct_wrapper($struct, @members); + emit_py_type_wrapper($struct, @members); } ############################################################################### @@ -581,239 +579,6 @@ foreach $func (sort keys %funcs) { emit_py_func_simple_sync_call($func, \@request, \@reply, @params); } -############################################################################### -# -# Emit python structure wrappers -# -############################################################################### -sub emit_py_struct_wrapper($@) { - my ($struct, @members) = @_; - - # Dump the banner comment block - my @comments = @{shift @members}; - - print PYHDR "\n"; - print PYHDR @comments; - print PYOUT "\n"; - print PYOUT @comments; - - # Write a python wrapper struct - print PYHDR "struct py_$struct {\n"; - print PYHDR "\tPyObject_HEAD\n"; - print PYHDR "\tstruct $struct x;\n"; - print PYHDR "};\n"; - print PYHDR "\n"; - - # We want allocation and deallocation functions - print PYOUT "static PyObject *\n"; - print PYOUT "py_", $struct, "_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\n"; - print PYOUT "{\n"; - print PYOUT "\treturn (PyObject *)(struct py_$struct *)type->tp_alloc(type, 0);\n"; - print PYOUT "}\n"; - print PYOUT "\n"; - print PYOUT "static void\n"; - print PYOUT "py_", $struct, "_dealloc(struct py_$struct *self)\n"; - print PYOUT "{\n"; - print PYOUT "\tPy_TYPE(self)->tp_free((PyObject *)self);\n"; - print PYOUT "}\n"; - print PYOUT "\n"; - - # Divide into single members and array members - my @singles = (); - my @arrays = (); - foreach my $m (@members) { - my ($type, $name, $array_size, $max_size) = @{$m}; - if ($array_size == -1) { - push @singles, $m; - } else { - push @arrays, $m; - } - } - - # Any non-array elements are made directly accessible to the Python interpreter - print PYOUT "static PyMemberDef py_", $struct, "_members[] = {\n"; - if (@singles) { - foreach my $m (@singles) { - my ($type, $name, $array_size, $max_size) = @{$m}; - print PYOUT "\t{ \"$name\", "; - if ($type eq "char") { - print PYOUT "T_CHAR"; - } elsif ($type eq "int8_t") { - print PYOUT "T_BYTE"; - } elsif ($type eq "int16_t") { - print PYOUT "T_SHORT"; - } elsif ($type eq "int32_t") { - print PYOUT "T_INT"; - } elsif ($type eq "int64_t") { - print PYOUT "T_LONGLONG"; - } elsif ($type eq "uint8_t") { - print PYOUT "T_UBYTE"; - } elsif ($type eq "uint16_t") { - print PYOUT "T_USHORT"; - } elsif ($type eq "uint32_t") { - print PYOUT "T_UINT"; - } elsif ($type eq "uint64_t") { - print PYOUT "T_ULONGLONG"; - } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) { - die "Don't py-wrap structs yet"; - } else { - die "Unsupported type \"$type\""; - } - print PYOUT ", offsetof(struct py_$struct, x.$name), 0, \"\"},\n"; - } - } - print PYOUT "\t{}\n"; - print PYOUT "};\n"; - print PYOUT "\n"; - - # Array elements have to be accessed through ->tp_[sg]etattro() as - # tuples (int[]/uint[]) or strings (char[]) - if (@arrays) { - # The attribute get function - print PYOUT "static PyObject *\n"; - print PYOUT "py_", $struct, "_getattro(PyObject *_self, PyObject *name)\n"; - print PYOUT "{\n"; - print PYOUT "\tstruct py_$struct *self = (struct py_$struct *)_self;\n"; - print PYOUT "\n"; - print PYOUT "\tif (PyUnicode_Check(name)) {\n"; - - foreach my $m (@arrays) { - my ($type, $name, $array_size, $max_size) = @{$m}; - - print PYOUT "\t\tif (PyUnicode_CompareWithASCIIString(name, \"$name\") == 0)\n"; - if ($type eq "char") { - print PYOUT "\t\t\treturn py_rxgen_get_string(&self->x.$name, $array_size);\n"; - } elsif ($type eq "uint8_t") { - print PYOUT "\t\t\treturn py_rxgen_get_uint8(&self->x.$name, $array_size);\n"; - } elsif ($type eq "uint16_t") { - print PYOUT "\t\t\treturn py_rxgen_get_uint16(&self->x.$name, $array_size);\n"; - } elsif ($type eq "uint32_t") { - print PYOUT "\t\t\treturn py_rxgen_get_uint32(&self->x.$name, $array_size);\n"; - } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) { - die "Don't py-wrap struct arrays yet"; - } else { - die "Unsupported array type \"$type\""; - } - } - - print PYOUT "\t}\n"; - print PYOUT "\n"; - print PYOUT "\treturn PyObject_GenericGetAttr(_self, name);\n"; - print PYOUT "}\n"; - print PYOUT "\n"; - - # The attribute set function - print PYOUT "static int\n"; - print PYOUT "py_", $struct, "_setattro(PyObject *_self, PyObject *name, PyObject *val)\n"; - print PYOUT "{\n"; - print PYOUT "\tstruct py_$struct *self = (struct py_$struct *)_self;\n"; - print PYOUT "\n"; - print PYOUT "\tif (PyUnicode_Check(name)) {\n"; - - foreach my $m (@arrays) { - my ($type, $name, $array_size, $max_size) = @{$m}; - - print PYOUT "\t\tif (PyUnicode_CompareWithASCIIString(name, \"$name\") == 0)\n"; - if ($type eq "char") { - print PYOUT "\t\t\treturn py_rxgen_set_string(&self->x.$name, $array_size, val);\n"; - } elsif ($type eq "uint8_t") { - print PYOUT "\t\t\treturn py_rxgen_set_uint8(&self->x.$name, $array_size, val);\n"; - } elsif ($type eq "uint16_t") { - print PYOUT "\t\t\treturn py_rxgen_set_uint16(&self->x.$name, $array_size, val);\n"; - } elsif ($type eq "uint32_t") { - print PYOUT "\t\t\treturn py_rxgen_set_uint32(&self->x.$name, $array_size, val);\n"; - } elsif ($type =~ /struct ([a-zA-Z_][a-zA-Z0-9_]*)[*]/) { - die "Don't py-wrap struct arrays yet"; - } else { - die "Unsupported array type \"$type\""; - } - } - - print PYOUT "\t}\n"; - print PYOUT "\n"; - print PYOUT "\treturn PyObject_GenericSetAttr(_self, name, val);\n"; - print PYOUT "}\n"; - print PYOUT "\n"; - } - - # Emit the Python type definition - print PYOUT "static PyTypeObject py_", $struct, "Type = {\n"; - - print PYOUT "\tPyVarObject_HEAD_INIT(NULL, 0)\n"; - print PYOUT "\t\"kafs.$struct\",\t\t/*tp_name*/\n"; - print PYOUT "\tsizeof(struct py_$struct),\t/*tp_basicsize*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_itemsize*/\n"; - print PYOUT "\t(destructor)py_", $struct, "_dealloc, /*tp_dealloc*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_print*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_getattr*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_setattr*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_compare*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_repr*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_as_number*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_as_sequence*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_as_mapping*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_hash */\n"; - print PYOUT "\t0,\t\t\t\t/*tp_call*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_str*/\n"; - if (@arrays) { - print PYOUT "\tpy_", $struct, "_getattro,\n"; - print PYOUT "\tpy_", $struct, "_setattro,\n"; - } else { - print PYOUT "\t0,\t\t\t\t/*tp_getattro*/\n"; - print PYOUT "\t0,\t\t\t\t/*tp_setattro*/\n"; - } - print PYOUT "\t0,\t\t\t\t/*tp_as_buffer*/\n"; - print PYOUT "\tPy_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/\n"; - if (@comments) { - print PYOUT "\t"; - foreach my $c (@comments) { - $c =~ s/\s+$//; - $c =~ s/^\s+//; - next if ($c eq "/*" || $c eq "*/"); - $c =~ s/^[*] //; - $c =~ s/^[*]$//; - print PYOUT "\n\t\t\"", $c, "\\n\""; - } - print PYOUT ",\n"; - } else { - print PYOUT "\t\"\",\t\t\t/* tp_doc */\n"; - } - print PYOUT "\t0,\t\t\t\t/* tp_traverse */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_clear */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_richcompare */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_weaklistoffset */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_iter */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_iternext */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_methods */\n"; - if (@singles) { - print PYOUT "\tpy_", $struct, "_members,\n"; - } else { - print PYOUT "\t0,\t\t\t/* tp_members */\n"; - } - print PYOUT "\t0,\t\t\t\t/* tp_getset */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_base */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_dict */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_descr_get */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_descr_set */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_dictoffset */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_init */\n"; - print PYOUT "\t0,\t\t\t\t/* tp_alloc */\n"; - print PYOUT "\tpy_", $struct, "_new,\t/* tp_new */\n"; - print PYOUT "};\n"; - - # Emit a function to allocate such a type - print PYHDR "extern PyObject *kafs_new_py_$struct(PyObject *, PyObject *);\n"; - - print PYOUT "\n"; - print PYOUT "PyObject *\n"; - print PYOUT "kafs_new_py_$struct(PyObject *_self, PyObject *args)\n"; - print PYOUT "{\n"; - print PYOUT "\tPyObject *obj;\n"; - print PYOUT "\tobj = _PyObject_New(&py_", $struct, "Type);\n"; - print PYOUT "\treturn obj ?: PyExc_MemoryError;\n"; - print PYOUT "}\n"; -} - ############################################################################### # # Emit python structure wrapper static method table -- 2.49.0