mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 01:33:06 +00:00
libdrgn/python: add proper type for enumerators
Currently, type members, enumerators, and parameters are all represented by tuples in the Python bindings. This is awkward to document and implement. Instead, let's replace these tuples with proper types, starting with the easiest one, TypeEnumerator. This one still makes sense to treat as a sequence so that it can be unpacked as (name, value).
This commit is contained in:
parent
bda1426ae9
commit
7c70a1a384
@ -1136,9 +1136,7 @@ Types
|
||||
List of enumeration constants of this type, or ``None`` if this is an
|
||||
incomplete type. This is only present for enumerated types.
|
||||
|
||||
Each enumeration constant is a (name, value) tuple.
|
||||
|
||||
:vartype: list[tuple(str, int)] or None
|
||||
:vartype: list[TypeEnumerator] or None
|
||||
|
||||
.. attribute:: parameters
|
||||
|
||||
@ -1189,6 +1187,29 @@ Types
|
||||
|
||||
:rtype: Type
|
||||
|
||||
.. class:: TypeEnumerator(name, value)
|
||||
|
||||
A ``TypeEnumerator`` represents a constant in an enumerated type.
|
||||
|
||||
Its name and value may be accessed as attributes or unpacked:
|
||||
|
||||
>>> prog.type('enum pid_type').enumerators[0].name
|
||||
'PIDTYPE_PID'
|
||||
>>> name, value = prog.type('enum pid_type').enumerators[0]
|
||||
>>> value
|
||||
0
|
||||
|
||||
:param str name: Enumerator name.
|
||||
:param int value: Enumerator value.
|
||||
|
||||
.. attribute:: name
|
||||
|
||||
:vartype: str
|
||||
|
||||
.. attribute:: value
|
||||
|
||||
:vartype: int
|
||||
|
||||
.. class:: TypeKind
|
||||
|
||||
``TypeKind`` is an :class:`enum.Enum` of the different kinds of types.
|
||||
@ -1401,7 +1422,7 @@ can be used just like types obtained from :meth:`Program.type()`.
|
||||
:param type: The compatible integer type (:attr:`Type.type`)
|
||||
:type type: Type or None
|
||||
:param enumerators: :attr:`Type.enumerators`
|
||||
:type enumerators: list[tuple] or None
|
||||
:type enumerators: list[TypeEnumerator] or None
|
||||
:param qualifiers: :attr:`Type.qualifiers`
|
||||
:type qualifiers: Qualifiers or None
|
||||
:rtype: Type
|
||||
|
@ -64,6 +64,7 @@ from _drgn import (
|
||||
StackTrace,
|
||||
Symbol,
|
||||
Type,
|
||||
TypeEnumerator,
|
||||
TypeKind,
|
||||
_with_libkdumpfile,
|
||||
array_type,
|
||||
@ -110,6 +111,7 @@ __all__ = (
|
||||
"StackTrace",
|
||||
"Symbol",
|
||||
"Type",
|
||||
"TypeEnumerator",
|
||||
"TypeKind",
|
||||
"array_type",
|
||||
"bool_type",
|
||||
|
@ -101,6 +101,12 @@ typedef struct {
|
||||
struct drgn_symbol *sym;
|
||||
} Symbol;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *name;
|
||||
PyObject *value;
|
||||
} TypeEnumerator;
|
||||
|
||||
extern PyObject *Architecture_class;
|
||||
extern PyObject *FindObjectFlags_class;
|
||||
extern PyObject *PlatformFlags_class;
|
||||
@ -119,6 +125,7 @@ extern PyTypeObject Register_type;
|
||||
extern PyTypeObject StackFrame_type;
|
||||
extern PyTypeObject StackTrace_type;
|
||||
extern PyTypeObject Symbol_type;
|
||||
extern PyTypeObject TypeEnumerator_type;
|
||||
extern PyObject *MissingDebugInfoError;
|
||||
extern PyObject *OutOfBoundsError;
|
||||
|
||||
|
@ -216,6 +216,12 @@ DRGNPY_PUBLIC PyMODINIT_FUNC PyInit__drgn(void)
|
||||
Py_INCREF(&DrgnType_type);
|
||||
PyModule_AddObject(m, "Type", (PyObject *)&DrgnType_type);
|
||||
|
||||
if (PyType_Ready(&TypeEnumerator_type) < 0)
|
||||
goto err;
|
||||
Py_INCREF(&TypeEnumerator_type);
|
||||
PyModule_AddObject(m, "TypeEnumerator",
|
||||
(PyObject *)&TypeEnumerator_type);
|
||||
|
||||
host_platform_obj = Platform_wrap(&drgn_host_platform);
|
||||
if (!host_platform_obj)
|
||||
goto err;
|
||||
|
@ -336,11 +336,13 @@ static PyObject *DrgnType_get_enumerators(DrgnType *self)
|
||||
PyObject *item;
|
||||
|
||||
if (is_signed) {
|
||||
item = Py_BuildValue("(sL)", enumerators[i].name,
|
||||
(long long)enumerators[i].svalue);
|
||||
item = PyObject_CallFunction((PyObject *)&TypeEnumerator_type,
|
||||
"sL", enumerators[i].name,
|
||||
(long long)enumerators[i].svalue);
|
||||
} else {
|
||||
item = Py_BuildValue("(sK)", enumerators[i].name,
|
||||
(unsigned long long)enumerators[i].uvalue);
|
||||
item = PyObject_CallFunction((PyObject *)&TypeEnumerator_type,
|
||||
"sK", enumerators[i].name,
|
||||
(unsigned long long)enumerators[i].uvalue);
|
||||
}
|
||||
if (!item) {
|
||||
Py_DECREF(enumerators_obj);
|
||||
@ -957,6 +959,107 @@ PyTypeObject DrgnType_type = {
|
||||
.tp_getset = DrgnType_getset,
|
||||
};
|
||||
|
||||
static TypeEnumerator *TypeEnumerator_new(PyTypeObject *subtype, PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static char *keywords[] = {"name", "value", NULL};
|
||||
PyObject *name, *value;
|
||||
TypeEnumerator *enumerator;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!:TypeEnumerator",
|
||||
keywords, &PyUnicode_Type, &name,
|
||||
&PyLong_Type, &value))
|
||||
return NULL;
|
||||
|
||||
enumerator = (TypeEnumerator *)subtype->tp_alloc(subtype, 0);
|
||||
if (enumerator) {
|
||||
Py_INCREF(name);
|
||||
enumerator->name = name;
|
||||
Py_INCREF(value);
|
||||
enumerator->value = value;
|
||||
}
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
static void TypeEnumerator_dealloc(TypeEnumerator *self)
|
||||
{
|
||||
Py_XDECREF(self->value);
|
||||
Py_XDECREF(self->name);
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *TypeEnumerator_repr(TypeEnumerator *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("TypeEnumerator(%R, %R)", self->name,
|
||||
self->value);
|
||||
}
|
||||
|
||||
Py_ssize_t TypeEnumerator_length(PyObject *self)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
PyObject *TypeEnumerator_item(TypeEnumerator *self, Py_ssize_t i)
|
||||
{
|
||||
switch (i) {
|
||||
case 0:
|
||||
Py_INCREF(self->name);
|
||||
return self->name;
|
||||
case 1:
|
||||
Py_INCREF(self->value);
|
||||
return self->value;
|
||||
default:
|
||||
PyErr_SetString(PyExc_IndexError,
|
||||
"TypeEnumerator index out of range");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *TypeEnumerator_richcompare(TypeEnumerator *self,
|
||||
TypeEnumerator *other,
|
||||
int op)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((op != Py_EQ && op != Py_NE) ||
|
||||
!PyObject_TypeCheck((PyObject *)other, &TypeEnumerator_type))
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
|
||||
ret = PyUnicode_Compare(self->name, other->name);
|
||||
if (ret == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if (ret != 0)
|
||||
Py_RETURN_RICHCOMPARE(ret, 0, op);
|
||||
return PyObject_RichCompare(self->value, other->value, op);
|
||||
}
|
||||
|
||||
static PySequenceMethods TypeEnumerator_as_sequence = {
|
||||
.sq_length = TypeEnumerator_length,
|
||||
.sq_item = (ssizeargfunc)TypeEnumerator_item,
|
||||
};
|
||||
|
||||
static PyMemberDef TypeEnumerator_members[] = {
|
||||
{"name", T_OBJECT, offsetof(TypeEnumerator, name), READONLY,
|
||||
drgn_TypeEnumerator_name_DOC},
|
||||
{"value", T_OBJECT, offsetof(TypeEnumerator, value), READONLY,
|
||||
drgn_TypeEnumerator_value_DOC},
|
||||
{},
|
||||
};
|
||||
|
||||
PyTypeObject TypeEnumerator_type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "_drgn.TypeEnumerator",
|
||||
.tp_basicsize = sizeof(TypeEnumerator),
|
||||
.tp_dealloc = (destructor)TypeEnumerator_dealloc,
|
||||
.tp_repr = (reprfunc)TypeEnumerator_repr,
|
||||
.tp_as_sequence = &TypeEnumerator_as_sequence,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = drgn_TypeEnumerator_DOC,
|
||||
.tp_richcompare = (richcmpfunc)TypeEnumerator_richcompare,
|
||||
.tp_members = TypeEnumerator_members,
|
||||
.tp_new = (newfunc)TypeEnumerator_new,
|
||||
};
|
||||
|
||||
DrgnType *void_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *keywords[] = { "qualifiers", NULL, };
|
||||
@ -1429,67 +1532,41 @@ DrgnType *class_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
DRGN_TYPE_CLASS);
|
||||
}
|
||||
|
||||
static int unpack_enumerator(DrgnType *type_obj, PyObject *enumerators_seq,
|
||||
PyObject *cached_enumerators_obj, size_t i,
|
||||
bool is_signed)
|
||||
static int unpack_enumerator(DrgnType *type_obj, PyObject *cached_enumerators_obj,
|
||||
size_t i, bool is_signed)
|
||||
{
|
||||
static const char *msg = "enumerator must be (name, value) sequence";
|
||||
PyObject *seq, *tuple, *name_obj, *value_obj;
|
||||
TypeEnumerator *item;
|
||||
const char *name;
|
||||
int ret = -1;
|
||||
|
||||
seq = PySequence_Fast(PySequence_Fast_GET_ITEM(enumerators_seq, i),
|
||||
msg);
|
||||
if (!seq)
|
||||
item = (TypeEnumerator *)PyTuple_GET_ITEM(cached_enumerators_obj, i);
|
||||
if (!PyObject_TypeCheck((PyObject *)item, &TypeEnumerator_type)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"enumerator must be TypeEnumerator");
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = PyUnicode_AsUTF8(item->name);
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
if (PySequence_Fast_GET_SIZE(seq) != 2) {
|
||||
PyErr_SetString(PyExc_ValueError, msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
name_obj = PySequence_Fast_GET_ITEM(seq, 0);
|
||||
if (!PyUnicode_Check(name_obj)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"enumerator name must be string");
|
||||
goto out;
|
||||
}
|
||||
name = PyUnicode_AsUTF8(name_obj);
|
||||
if (!name)
|
||||
goto out;
|
||||
|
||||
value_obj = PySequence_Fast_GET_ITEM(seq, 1);
|
||||
if (!PyLong_Check(value_obj)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"enumerator value must be integer");
|
||||
goto out;
|
||||
}
|
||||
if (is_signed) {
|
||||
long long svalue;
|
||||
|
||||
svalue = PyLong_AsLongLong(value_obj);
|
||||
svalue = PyLong_AsLongLong(item->value);
|
||||
if (svalue == -1 && PyErr_Occurred())
|
||||
goto out;
|
||||
return -1;
|
||||
drgn_type_enumerator_init_signed(type_obj->type, i, name,
|
||||
svalue);
|
||||
} else {
|
||||
unsigned long long uvalue;
|
||||
|
||||
uvalue = PyLong_AsUnsignedLongLong(value_obj);
|
||||
uvalue = PyLong_AsUnsignedLongLong(item->value);
|
||||
if (uvalue == (unsigned long long)-1 && PyErr_Occurred())
|
||||
goto out;
|
||||
return -1;
|
||||
drgn_type_enumerator_init_unsigned(type_obj->type, i, name,
|
||||
uvalue);
|
||||
}
|
||||
|
||||
tuple = PySequence_Tuple(seq);
|
||||
if (!tuple)
|
||||
goto out;
|
||||
PyTuple_SET_ITEM(cached_enumerators_obj, i, tuple);
|
||||
ret = 0;
|
||||
out:
|
||||
Py_DECREF(seq);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DrgnType *enum_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
@ -1502,7 +1579,6 @@ DrgnType *enum_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
struct drgn_type *compatible_type;
|
||||
PyObject *enumerators_obj = Py_None;
|
||||
unsigned char qualifiers = 0;
|
||||
PyObject *enumerators_seq = NULL;
|
||||
PyObject *cached_enumerators_obj = NULL;
|
||||
size_t num_enumerators;
|
||||
|
||||
@ -1567,14 +1643,15 @@ DrgnType *enum_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
"enum type must have compatible type");
|
||||
return NULL;
|
||||
}
|
||||
enumerators_seq = PySequence_Fast(enumerators_obj,
|
||||
"enumerators must be sequence or None");
|
||||
if (!enumerators_seq)
|
||||
if (!PySequence_Check(enumerators_obj)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"enumerators must be sequence or None");
|
||||
return NULL;
|
||||
num_enumerators = PySequence_Fast_GET_SIZE(enumerators_seq);
|
||||
cached_enumerators_obj = PyTuple_New(num_enumerators);
|
||||
}
|
||||
cached_enumerators_obj = PySequence_Tuple(enumerators_obj);
|
||||
if (!cached_enumerators_obj)
|
||||
goto err;
|
||||
return NULL;
|
||||
num_enumerators = PyTuple_GET_SIZE(cached_enumerators_obj);
|
||||
is_signed = drgn_type_is_signed(compatible_type);
|
||||
|
||||
type_obj = DrgnType_new(qualifiers, num_enumerators,
|
||||
@ -1582,12 +1659,10 @@ DrgnType *enum_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
if (!type_obj)
|
||||
goto err;
|
||||
for (i = 0; i < num_enumerators; i++) {
|
||||
if (unpack_enumerator(type_obj, enumerators_seq,
|
||||
cached_enumerators_obj, i,
|
||||
is_signed) == -1)
|
||||
if (unpack_enumerator(type_obj, cached_enumerators_obj,
|
||||
i, is_signed) == -1)
|
||||
goto err;
|
||||
}
|
||||
Py_CLEAR(enumerators_seq);
|
||||
|
||||
if (_PyDict_SetItemId(type_obj->attr_cache,
|
||||
&DrgnType_attr_enumerators.id,
|
||||
@ -1614,7 +1689,6 @@ DrgnType *enum_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
err:
|
||||
Py_XDECREF(type_obj);
|
||||
Py_XDECREF(cached_enumerators_obj);
|
||||
Py_XDECREF(enumerators_seq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ from drgn import (
|
||||
PlatformFlags,
|
||||
Program,
|
||||
Type,
|
||||
TypeEnumerator,
|
||||
TypeKind,
|
||||
class_type,
|
||||
enum_type,
|
||||
@ -42,7 +43,9 @@ option_type = union_type(
|
||||
"option", 4, ((int_type("int", 4, True), "i"), (float_type("float", 4), "f"),)
|
||||
)
|
||||
color_type = enum_type(
|
||||
"color", int_type("unsigned int", 4, False), (("RED", 0), ("GREEN", 1), ("BLUE", 2))
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(TypeEnumerator("RED", 0), TypeEnumerator("GREEN", 1), TypeEnumerator("BLUE", 2)),
|
||||
)
|
||||
pid_type = typedef_type("pid_t", int_type("int", 4, True))
|
||||
|
||||
|
@ -7,6 +7,7 @@ from drgn import (
|
||||
Object,
|
||||
Program,
|
||||
Qualifiers,
|
||||
TypeEnumerator,
|
||||
array_type,
|
||||
class_type,
|
||||
complex_type,
|
||||
@ -1022,7 +1023,11 @@ class TestTypes(unittest.TestCase):
|
||||
enum_type(
|
||||
"color",
|
||||
int_type("<unknown>", 4, True),
|
||||
[("RED", 0), ("GREEN", -1), ("BLUE", -2)],
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", -1),
|
||||
TypeEnumerator("BLUE", -2),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@ -1874,7 +1879,13 @@ class TestObjects(ObjectTestCase):
|
||||
]
|
||||
|
||||
type_ = enum_type(
|
||||
"color", int_type("int", 4, True), [("RED", 0), ("GREEN", 1), ("BLUE", 2)]
|
||||
"color",
|
||||
int_type("int", 4, True),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
)
|
||||
prog = dwarf_program(dies)
|
||||
self.assertEqual(prog["BLUE"], Object(prog, type_, value=2))
|
||||
@ -1883,7 +1894,11 @@ class TestObjects(ObjectTestCase):
|
||||
type_ = enum_type(
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
[("RED", 0), ("GREEN", 1), ("BLUE", 2)],
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
)
|
||||
prog = dwarf_program(dies)
|
||||
self.assertEqual(prog["GREEN"], Object(prog, type_, value=1))
|
||||
@ -1892,7 +1907,11 @@ class TestObjects(ObjectTestCase):
|
||||
type_ = enum_type(
|
||||
None,
|
||||
int_type("unsigned int", 4, False),
|
||||
[("RED", 0), ("GREEN", 1), ("BLUE", 2)],
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
)
|
||||
prog = dwarf_program(dies)
|
||||
self.assertEqual(
|
||||
|
@ -4,6 +4,7 @@ import unittest
|
||||
|
||||
from drgn import (
|
||||
Qualifiers,
|
||||
TypeEnumerator,
|
||||
array_type,
|
||||
bool_type,
|
||||
class_type,
|
||||
@ -407,7 +408,11 @@ class coord {
|
||||
t = enum_type(
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(("RED", 0), ("GREEN", 1), ("BLUE", 2),),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
)
|
||||
self.assertPrettyPrint(
|
||||
t,
|
||||
@ -422,7 +427,11 @@ enum color {
|
||||
t = enum_type(
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(("RED", 0), ("GREEN", 1), ("BLUE", 2),),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
Qualifiers.CONST,
|
||||
)
|
||||
self.assertPrettyPrint(
|
||||
@ -436,7 +445,13 @@ const enum color {
|
||||
)
|
||||
|
||||
t = enum_type(
|
||||
None, int_type("int", 4, True), (("RED", 0), ("GREEN", -1), ("BLUE", -2),)
|
||||
None,
|
||||
int_type("int", 4, True),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", -1),
|
||||
TypeEnumerator("BLUE", -2),
|
||||
),
|
||||
)
|
||||
self.assertPrettyPrint(
|
||||
t,
|
||||
|
@ -8,6 +8,7 @@ from drgn import (
|
||||
OutOfBoundsError,
|
||||
Qualifiers,
|
||||
Type,
|
||||
TypeEnumerator,
|
||||
array_type,
|
||||
cast,
|
||||
container_of,
|
||||
@ -996,7 +997,11 @@ class TestCIntegerPromotion(ObjectTestCase):
|
||||
type_ = enum_type(
|
||||
"color",
|
||||
self.prog.type("unsigned long long"),
|
||||
(("RED", 0), ("GREEN", 1), ("BLUE", 2)),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
+Object(self.prog, type_, value=1),
|
||||
@ -1004,7 +1009,13 @@ class TestCIntegerPromotion(ObjectTestCase):
|
||||
)
|
||||
|
||||
type_ = enum_type(
|
||||
"color", self.prog.type("char"), (("RED", 0), ("GREEN", 1), ("BLUE", 2))
|
||||
"color",
|
||||
self.prog.type("char"),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
+Object(self.prog, type_, value=1), Object(self.prog, "int", value=1)
|
||||
|
@ -3,6 +3,7 @@ import unittest
|
||||
from drgn import (
|
||||
PrimitiveType,
|
||||
Qualifiers,
|
||||
TypeEnumerator,
|
||||
TypeKind,
|
||||
array_type,
|
||||
bool_type,
|
||||
@ -790,13 +791,24 @@ class TestType(unittest.TestCase):
|
||||
t = enum_type(
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(("RED", 0), ("GREEN", 1), ("BLUE", 2)),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
)
|
||||
self.assertEqual(t.kind, TypeKind.ENUM)
|
||||
self.assertIsNone(t.primitive)
|
||||
self.assertEqual(t.tag, "color")
|
||||
self.assertEqual(t.type, int_type("unsigned int", 4, False))
|
||||
self.assertEqual(t.enumerators, (("RED", 0), ("GREEN", 1), ("BLUE", 2)))
|
||||
self.assertEqual(
|
||||
t.enumerators,
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
)
|
||||
self.assertTrue(t.is_complete())
|
||||
|
||||
self.assertEqual(
|
||||
@ -804,7 +816,11 @@ class TestType(unittest.TestCase):
|
||||
enum_type(
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(("RED", 0), ("GREEN", 1), ("BLUE", 2)),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
),
|
||||
)
|
||||
# Different tag.
|
||||
@ -813,7 +829,11 @@ class TestType(unittest.TestCase):
|
||||
enum_type(
|
||||
"COLOR",
|
||||
int_type("unsigned int", 4, False),
|
||||
(("RED", 0), ("GREEN", 1), ("BLUE", 2)),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
),
|
||||
)
|
||||
# One is anonymous.
|
||||
@ -822,7 +842,11 @@ class TestType(unittest.TestCase):
|
||||
enum_type(
|
||||
None,
|
||||
int_type("unsigned int", 4, False),
|
||||
(("RED", 0), ("GREEN", 1), ("BLUE", 2)),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
),
|
||||
)
|
||||
# Different compatible type.
|
||||
@ -831,7 +855,11 @@ class TestType(unittest.TestCase):
|
||||
enum_type(
|
||||
"color",
|
||||
int_type("int", 4, True),
|
||||
(("RED", 0), ("GREEN", 1), ("BLUE", 2)),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("GREEN", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
),
|
||||
)
|
||||
# Different enumerators.
|
||||
@ -840,14 +868,20 @@ class TestType(unittest.TestCase):
|
||||
enum_type(
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(("RED", 0), ("YELLOW", 1), ("BLUE", 2)),
|
||||
(
|
||||
TypeEnumerator("RED", 0),
|
||||
TypeEnumerator("YELLOW", 1),
|
||||
TypeEnumerator("BLUE", 2),
|
||||
),
|
||||
),
|
||||
)
|
||||
# Different number of enumerators.
|
||||
self.assertNotEqual(
|
||||
t,
|
||||
enum_type(
|
||||
"color", int_type("unsigned int", 4, False), (("RED", 0), ("GREEN", 1))
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(TypeEnumerator("RED", 0), TypeEnumerator("GREEN", 1)),
|
||||
),
|
||||
)
|
||||
# One is incomplete.
|
||||
@ -855,7 +889,7 @@ class TestType(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
repr(t),
|
||||
"enum_type(tag='color', type=int_type(name='unsigned int', size=4, is_signed=False), enumerators=(('RED', 0), ('GREEN', 1), ('BLUE', 2)))",
|
||||
"enum_type(tag='color', type=int_type(name='unsigned int', size=4, is_signed=False), enumerators=(TypeEnumerator('RED', 0), TypeEnumerator('GREEN', 1), TypeEnumerator('BLUE', 2)))",
|
||||
)
|
||||
self.assertEqual(sizeof(t), 4)
|
||||
|
||||
@ -916,36 +950,12 @@ class TestType(unittest.TestCase):
|
||||
)
|
||||
self.assertRaisesRegex(
|
||||
TypeError,
|
||||
"must be.*sequence",
|
||||
"must be TypeEnumerator",
|
||||
enum_type,
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(4,),
|
||||
)
|
||||
self.assertRaisesRegex(
|
||||
ValueError,
|
||||
"must be.*sequence",
|
||||
enum_type,
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
((),),
|
||||
)
|
||||
self.assertRaisesRegex(
|
||||
TypeError,
|
||||
"must be string",
|
||||
enum_type,
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
((None, 0),),
|
||||
)
|
||||
self.assertRaisesRegex(
|
||||
TypeError,
|
||||
"must be integer",
|
||||
enum_type,
|
||||
"color",
|
||||
int_type("unsigned int", 4, False),
|
||||
(("RED", None),),
|
||||
)
|
||||
|
||||
def test_typedef(self):
|
||||
t = typedef_type("INT", int_type("int", 4, True))
|
||||
@ -1201,3 +1211,29 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(void_type(), int_type("int", 4, True))
|
||||
self.assertNotEqual(void_type(), 1)
|
||||
self.assertNotEqual(1, void_type())
|
||||
|
||||
|
||||
class TestTypeEnumerator(unittest.TestCase):
|
||||
def test_init(self):
|
||||
e = TypeEnumerator("a", 1)
|
||||
self.assertEqual(e.name, "a")
|
||||
self.assertEqual(e.value, 1)
|
||||
|
||||
self.assertRaises(TypeError, TypeEnumerator, "a", None)
|
||||
self.assertRaises(TypeError, TypeEnumerator, None, 1)
|
||||
|
||||
def test_repr(self):
|
||||
e = TypeEnumerator("a", 1)
|
||||
self.assertEqual(repr(e), "TypeEnumerator('a', 1)")
|
||||
|
||||
def test_sequence(self):
|
||||
e = TypeEnumerator("a", 1)
|
||||
name, value = e
|
||||
self.assertEqual(name, "a")
|
||||
self.assertEqual(value, 1)
|
||||
self.assertEqual(list(e), ["a", 1])
|
||||
|
||||
def test_cmp(self):
|
||||
self.assertEqual(TypeEnumerator("a", 1), TypeEnumerator(name="a", value=1))
|
||||
self.assertNotEqual(TypeEnumerator("a", 1), TypeEnumerator("a", 2))
|
||||
self.assertNotEqual(TypeEnumerator("b", 1), TypeEnumerator("a", 1))
|
||||
|
Loading…
Reference in New Issue
Block a user