chiark / gitweb /
@@@ cython and python3
[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 = 0;
54   atom_pyobj *ao;
55   unsigned f = 0;
56
57   e = assoc_find(&obarray, a, sizeof(entry), &f);
58   if (!f) {
59     ao = PyObject_NEW(atom_pyobj, &atom_pytype); ao->a = a;
60     e->a = (PyObject *)ao;
61   }
62
63   /* If we just created the new `Atom' object, we get a reference, which
64    * belongs to the `obarray' table.  So when we return it to the caller, we
65    * always need to increment it.
66    */
67   RETURN_OBJ(e->a);
68 }
69
70 PyObject *atom_pyintern(PyObject *x)
71 {
72   atom *a;
73   const void *p;
74   Py_ssize_t n;
75
76   if (ATOM_PYCHECK(x))
77     RETURN_OBJ(x);
78   if (x == Py_None)
79     a = atom_gensym(ATOM_GLOBAL);
80   else if (!TEXT_CHECK(x))
81     { PyErr_SetString(PyExc_TypeError, "string wanted"); return (0); }
82   else {
83     TEXT_PTRLEN(x, &p, &n); if (!p) return (0);
84     a = atom_nintern(ATOM_GLOBAL, p, n);
85   }
86   return (atom_pywrap(a));
87 }
88
89 static void atom_pydealloc(PyObject *me)
90   { fprintf(stderr, "ouch!  freeing atom\n"); abort();  }
91
92 static PyObject *atom_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
93 {
94   PyObject *name = Py_None;
95   static const char *const kwlist[] = { "name", 0 };
96
97   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", KWLIST, &name))
98     return (0);
99   return (atom_pyintern(name));
100 }
101
102 static PyObject *aget_name(PyObject *me, void *hunoz)
103   { return (TEXT_FROMSTRLEN(ATOM_NAME(ATOM_A(me)), ATOM_LEN(ATOM_A(me)))); }
104
105 static PyObject *aget_internedp(PyObject *me, void *hunoz)
106 {
107   PyObject *rc = (ATOM_A(me)->f & ATOMF_GENSYM) ? Py_False : Py_True;
108   RETURN_OBJ(rc);
109 }
110
111 static PyGetSetDef atom_pygetset[] = {
112 #define GETSETNAME(op, name) a##op##_##name
113   GET   (name,                  "A.name -> NAME")
114   GET   (internedp,             "A.internedp -> BOOL")
115 #undef GETSETNAME
116   { 0 }
117 };
118
119 static PyObject *atom_pyrichcompare(PyObject *x, PyObject *y, int op)
120 {
121   PyObject *rc = 0;
122
123   switch (op) {
124     case Py_EQ: rc = (x == y) ? Py_True : Py_False; break;
125     case Py_NE: rc = (x != y) ? Py_True : Py_False; break;
126     default:
127       PyErr_SetString(PyExc_TypeError, "atoms are unordered");
128       return (0);
129   }
130   RETURN_OBJ(rc);
131 }
132
133 static PyObject *atom_pyrepr(PyObject *me)
134 {
135   PyObject *s, *sr = 0;
136   PyObject *rc = 0;
137   char *p;
138   Py_ssize_t n;
139   dstr d = DSTR_INIT;
140
141   if ((s = aget_name(me, 0)) == 0 ||
142       (sr = PyObject_Repr(s)) == 0)
143     goto done;
144   if (!TEXT_CHECK(sr))
145     { PyErr_SetString(PyExc_TypeError, "string wanted"); goto done; }
146   TEXT_PTRLEN(sr, &p, &n); if (!p) goto done;
147   dstr_puts(&d, "Atom(");
148   dstr_putm(&d, p, n);
149   dstr_puts(&d, ")");
150   rc = TEXT_FROMSTRLEN(d.buf, d.len);
151 done:
152   Py_XDECREF(s);
153   Py_XDECREF(sr);
154   dstr_destroy(&d);
155   return (rc);
156 }
157
158 static Py_hash_t atom_pyhash(PyObject *me)
159   { Py_hash_t h = ATOM_HASH(ATOM_A(me)); if (h == -1) h = -2; return (h); }
160
161 PyTypeObject atom_pytype = {
162   PyVarObject_HEAD_INIT(0, 0)           /* Header */
163   "mLib.Atom",                          /* @tp_name@ */
164   sizeof(atom_pyobj),                   /* @tp_basicsize@ */
165   0,                                    /* @tp_itemsize@ */
166
167   atom_pydealloc,                       /* @tp_dealloc@ */
168   0,                                    /* @tp_print@ */
169   0,                                    /* @tp_getattr@ */
170   0,                                    /* @tp_setattr@ */
171   0,                                    /* @tp_compare@ */
172   atom_pyrepr,                          /* @tp_repr@ */
173   0,                                    /* @tp_as_number@ */
174   0,                                    /* @tp_as_sequence@ */
175   0,                                    /* @tp_as_mapping@ */
176   atom_pyhash,                          /* @tp_hash@ */
177   0,                                    /* @tp_call@ */
178   atom_pyrepr,                          /* @tp_str@ */
179   0,                                    /* @tp_getattro@ */
180   0,                                    /* @tp_setattro@ */
181   0,                                    /* @tp_as_buffer@ */
182   Py_TPFLAGS_DEFAULT,                   /* @tp_flags@ */
183
184   /* @tp_doc@ */
185 "Atom.",
186
187   0,                                    /* @tp_traverse@ */
188   0,                                    /* @tp_clear@ */
189   atom_pyrichcompare,                   /* @tp_richcompare@ */
190   0,                                    /* @tp_weaklistoffset@ */
191   0,                                    /* @tp_iter@ */
192   0,                                    /* @tp_iternexr@ */
193   0,                                    /* @tp_methods@ */
194   0,                                    /* @tp_members@ */
195   atom_pygetset,                        /* @tp_getset@ */
196   0,                                    /* @tp_base@ */
197   0,                                    /* @tp_dict@ */
198   0,                                    /* @tp_descr_get@ */
199   0,                                    /* @tp_descr_set@ */
200   0,                                    /* @tp_dictoffset@ */
201   0,                                    /* @tp_init@ */
202   PyType_GenericAlloc,                  /* @tp_alloc@ */
203   atom_pynew,                           /* @tp_new@ */
204   0,                                    /* @tp_free@ */
205   0                                     /* @tp_is_gc@ */
206 };
207
208 void atom_pysetup(void)
209   { assoc_create(&obarray); PyType_Ready(&atom_pytype); }
210
211 /*----- That's all, folks -------------------------------------------------*/