debian/control: Add Build-Depends for `dh-python'.
[mLib-python] / atom-base.c
1 /* -*-c-*-
2 *
3 * Atom stuff
4 *
5 * (c) 2005 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the Python interface to mLib.
11 *
12 * mLib/Python is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * mLib/Python is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with mLib/Python; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include <Python.h>
30
31 #include <mLib/atom.h>
32 #include <mLib/assoc.h>
33 #include <mLib/dstr.h>
34
35 #include "atom.h"
36 #include "grim.h"
37
38 /*----- Data structures ---------------------------------------------------*/
39
40 typedef struct entry {
41 assoc_base _b;
42 PyObject *a;
43 } entry;
44
45 /*----- Static variables --------------------------------------------------*/
46
47 static assoc_table obarray;
48
49 /*----- Main code ---------------------------------------------------------*/
50
51 PyObject *atom_pywrap(atom *a)
52 {
53 entry *e;
54 unsigned f = 0;
55
56 e = assoc_find(&obarray, a, sizeof(entry), &f);
57 if (!f) {
58 atom_pyobj *ao = PyObject_NEW(atom_pyobj, &atom_pytype);
59 ao->a = a;
60 e->a = (PyObject *)ao;
61 }
62 RETURN_OBJ(e->a);
63 }
64
65 PyObject *atom_pyintern(PyObject *x)
66 {
67 atom *a;
68 const void *p;
69 Py_ssize_t n;
70
71 if (ATOM_PYCHECK(x))
72 RETURN_OBJ(x);
73 if (x == Py_None)
74 a = atom_gensym(ATOM_GLOBAL);
75 else {
76 if (PyObject_AsReadBuffer(x, &p, &n)) return (0);
77 a = atom_nintern(ATOM_GLOBAL, p, n);
78 }
79 return (atom_pywrap(a));
80 }
81
82 static void atom_pydealloc(PyObject *me)
83 { fprintf(stderr, "ouch! freeing atom\n"); abort(); }
84
85 static PyObject *atom_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
86 {
87 PyObject *name;
88 static char *kwlist[] = { "name", 0 };
89
90 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &name))
91 return (0);
92 return (atom_pyintern(name));
93 }
94
95 static PyObject *aget_name(PyObject *me, void *hunoz)
96 {
97 return (PyString_FromStringAndSize(ATOM_NAME(ATOM_A(me)),
98 ATOM_LEN(ATOM_A(me))));
99 }
100
101 static PyObject *aget_internedp(PyObject *me, void *hunoz)
102 {
103 PyObject *rc = (ATOM_A(me)->f & ATOMF_GENSYM) ? Py_False : Py_True;
104 RETURN_OBJ(rc);
105 }
106
107 static PyGetSetDef atom_pygetset[] = {
108 #define GETSETNAME(op, name) a##op##_##name
109 GET (name, "A.name -> NAME")
110 GET (internedp, "A.internedp -> BOOL")
111 #undef GETSETNAME
112 { 0 }
113 };
114
115 static PyObject *atom_pyrichcompare(PyObject *x, PyObject *y, int op)
116 {
117 PyObject *rc = 0;
118
119 switch (op) {
120 case Py_EQ: rc = (x == y) ? Py_True : Py_False; break;
121 case Py_NE: rc = (x != y) ? Py_True : Py_False; break;
122 default:
123 PyErr_SetString(PyExc_TypeError, "atoms are unordered");
124 return (0);
125 }
126 RETURN_OBJ(rc);
127 }
128
129 static PyObject *atom_pyrepr(PyObject *me)
130 {
131 PyObject *s, *sr = 0;
132 PyObject *rc = 0;
133 char *p;
134 Py_ssize_t n;
135 dstr d = DSTR_INIT;
136
137 if ((s = aget_name(me, 0)) == 0 ||
138 (sr = PyObject_Repr(s)) == 0 ||
139 PyString_AsStringAndSize(sr, &p, &n))
140 goto done;
141 dstr_puts(&d, "Atom(");
142 dstr_putm(&d, p, n);
143 dstr_puts(&d, ")");
144 rc = PyString_FromStringAndSize(d.buf, d.len);
145 done:
146 Py_XDECREF(s);
147 Py_XDECREF(sr);
148 dstr_destroy(&d);
149 return (rc);
150 }
151
152 static long atom_pyhash(PyObject *me)
153 { long h = ATOM_HASH(ATOM_A(me)); if (h == -1) h = -2; return (h); }
154
155 PyTypeObject atom_pytype = {
156 PyObject_HEAD_INIT(0) 0, /* Header */
157 "mLib.Atom", /* @tp_name@ */
158 sizeof(atom_pyobj), /* @tp_basicsize@ */
159 0, /* @tp_itemsize@ */
160
161 atom_pydealloc, /* @tp_dealloc@ */
162 0, /* @tp_print@ */
163 0, /* @tp_getattr@ */
164 0, /* @tp_setattr@ */
165 0, /* @tp_compare@ */
166 atom_pyrepr, /* @tp_repr@ */
167 0, /* @tp_as_number@ */
168 0, /* @tp_as_sequence@ */
169 0, /* @tp_as_mapping@ */
170 atom_pyhash, /* @tp_hash@ */
171 0, /* @tp_call@ */
172 atom_pyrepr, /* @tp_str@ */
173 0, /* @tp_getattro@ */
174 0, /* @tp_setattro@ */
175 0, /* @tp_as_buffer@ */
176 Py_TPFLAGS_DEFAULT, /* @tp_flags@ */
177
178 /* @tp_doc@ */
179 "Atom.",
180
181 0, /* @tp_traverse@ */
182 0, /* @tp_clear@ */
183 atom_pyrichcompare, /* @tp_richcompare@ */
184 0, /* @tp_weaklistoffset@ */
185 0, /* @tp_iter@ */
186 0, /* @tp_iternexr@ */
187 0, /* @tp_methods@ */
188 0, /* @tp_members@ */
189 atom_pygetset, /* @tp_getset@ */
190 0, /* @tp_base@ */
191 0, /* @tp_dict@ */
192 0, /* @tp_descr_get@ */
193 0, /* @tp_descr_set@ */
194 0, /* @tp_dictoffset@ */
195 0, /* @tp_init@ */
196 PyType_GenericAlloc, /* @tp_alloc@ */
197 atom_pynew, /* @tp_new@ */
198 0, /* @tp_free@ */
199 0 /* @tp_is_gc@ */
200 };
201
202 void atom_pysetup(void)
203 { assoc_create(&obarray); PyType_Ready(&atom_pytype); }
204
205 /*----- That's all, folks -------------------------------------------------*/