~free.ekanayaka/storm/any-expr

142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
1
/*
2
#
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
3
# Copyright (c) 2006-2008 Canonical
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
4
#
5
# Written by Gustavo Niemeyer <gustavo@niemeyer.net>
6
#
7
# This file is part of Storm Object Relational Mapper.
8
#
9
# Storm is free software; you can redistribute it and/or modify
10
# it under the terms of the GNU Lesser General Public License as
11
# published by the Free Software Foundation; either version 2.1 of
12
# the License, or (at your option) any later version.
13
#
14
# Storm is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
# GNU Lesser General Public License for more details.
18
#
19
# You should have received a copy of the GNU Lesser General Public License
20
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
#
22
*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
23
#include <Python.h>
305.2.2 by James Henstridge
Clean up build patch a bit:
24
#include <structmember.h>
25
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
26
235.2.16 by Gustavo Niemeyer
Use the compatibility Py_ssize_t of the PEP, as suggested by James.
27
#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
28
typedef int Py_ssize_t;
29
#define PY_SSIZE_T_MAX INT_MAX
30
#define PY_SSIZE_T_MIN INT_MIN
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
31
#endif
32
235.2.16 by Gustavo Niemeyer
Use the compatibility Py_ssize_t of the PEP, as suggested by James.
33
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
34
#define CATCH(error_value, expression) \
35
        do { \
36
            if ((expression) == error_value) {\
37
                /*printf("GOT AN ERROR AT LINE %d!\n", __LINE__);*/ \
38
                goto error; \
39
            } \
40
        } while (0)
41
235.2.17 by Gustavo Niemeyer
Fixed a couple of GC-unsafe variable swaps spotted by James.
42
#define REPLACE(variable, new_value) \
43
        do { \
44
            PyObject *tmp = variable; \
45
            variable = new_value; \
46
            Py_DECREF(tmp); \
47
        } while(0)
48
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
49
235.4.1 by James Henstridge
* Provide a minimal PySet_* API implementation if we're compiling for
50
/* Python 2.4 does not include the PySet_* API, so provide a minimal
51
   implementation for the calls we care about. */
52
#if PY_VERSION_HEX < 0x02050000 && !defined(PySet_GET_SIZE)
53
#  define PySet_GET_SIZE(so) \
54
     ((PyDictObject *)((PySetObject *)so)->data)->ma_used
55
static PyObject *
56
PySet_New(PyObject *p)
57
{
58
    return PyObject_CallObject((PyObject *)&PySet_Type, NULL);
59
}
60
61
static int
62
PySet_Add(PyObject *set, PyObject *key)
63
{
64
    PyObject *dict;
65
66
    if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) {
67
        PyErr_BadInternalCall();
68
        return -1;
69
    }
70
    dict = ((PySetObject *)set)->data;
71
    return PyDict_SetItem(dict, key, Py_True);
72
}
73
74
static int
75
PySet_Discard(PyObject *set, PyObject *key)
76
{
77
    PyObject *dict;
78
    int result;
79
80
    if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) {
81
        PyErr_BadInternalCall();
82
        return -1;
83
    }
84
    dict = ((PySetObject *)set)->data;
85
    result = PyDict_DelItem(dict, key);
86
    if (result == 0) {
87
        /* key found and removed */
88
        result = 1;
89
    } else {
90
        if (PyErr_ExceptionMatches(PyExc_KeyError)) {
91
            /* key not found */
92
            PyErr_Clear();
93
            result = 0;
94
        }
95
    }
96
    return result;
97
}
98
#endif
99
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
100
static PyObject *Undef = NULL;
101
static PyObject *LazyValue = NULL;
102
static PyObject *raise_none_error = NULL;
103
static PyObject *get_cls_info = NULL;
104
static PyObject *EventSystem = NULL;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
105
static PyObject *SQLRaw = NULL;
106
static PyObject *SQLToken = NULL;
107
static PyObject *State = NULL;
108
static PyObject *CompileError = NULL;
109
static PyObject *parenthesis_format = NULL;
235.2.15 by Gustavo Niemeyer
Use a unicode default join string in the cextensions Compile, and
110
static PyObject *default_compile_join = NULL;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
111
112
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
113
typedef struct {
114
    PyObject_HEAD
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
115
    PyObject *_owner_ref;
116
    PyObject *_hooks;
117
} EventSystemObject;
118
119
typedef struct {
120
    PyObject_HEAD
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
121
    PyObject *_value;
122
    PyObject *_lazy_value;
123
    PyObject *_checkpoint_state;
124
    PyObject *_allow_none;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
125
    PyObject *_validator;
126
    PyObject *_validator_object_factory;
127
    PyObject *_validator_attribute;
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
128
    PyObject *column;
129
    PyObject *event;
130
} VariableObject;
131
132
typedef struct {
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
133
    PyObject_HEAD
134
    PyObject *__weakreflist;
135
    PyObject *_local_dispatch_table;
136
    PyObject *_local_precedence;
137
    PyObject *_local_reserved_words;
138
    PyObject *_dispatch_table;
139
    PyObject *_precedence;
140
    PyObject *_reserved_words;
141
    PyObject *_children;
142
    PyObject *_parents;
143
} CompileObject;
144
145
typedef struct {
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
146
    PyDictObject super;
147
    PyObject *__weakreflist;
148
    PyObject *__obj_ref;
149
    PyObject *__obj_ref_callback;
150
    PyObject *cls_info;
151
    PyObject *event;
152
    PyObject *variables;
153
    PyObject *primary_vars;
154
} ObjectInfoObject;
155
156
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
157
static int
158
initialize_globals(void)
159
{
160
    static int initialized = 0;
161
    PyObject *module;
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
162
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
163
    if (initialized)
164
        return 1;
165
166
    initialized = 1;
167
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
168
    /* Import objects from storm module */
169
    module = PyImport_ImportModule("storm");
170
    if (!module)
171
        return 0;
172
173
    Undef = PyObject_GetAttrString(module, "Undef");
174
    if (!Undef)
175
        return 0;
176
177
    Py_DECREF(module);
178
179
    /* Import objects from storm.variables module */
180
    module = PyImport_ImportModule("storm.variables");
181
    if (!module)
182
        return 0;
183
184
    raise_none_error = PyObject_GetAttrString(module, "raise_none_error");
185
    if (!raise_none_error)
186
        return 0;
187
188
    LazyValue = PyObject_GetAttrString(module, "LazyValue");
189
    if (!LazyValue)
190
        return 0;
191
192
    Py_DECREF(module);
193
194
    /* Import objects from storm.info module */
195
    module = PyImport_ImportModule("storm.info");
196
    if (!module)
197
        return 0;
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
198
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
199
    get_cls_info = PyObject_GetAttrString(module, "get_cls_info");
200
    if (!get_cls_info)
201
        return 0;
202
203
    Py_DECREF(module);
204
205
    /* Import objects from storm.event module */
206
    module = PyImport_ImportModule("storm.event");
207
    if (!module)
208
        return 0;
209
210
    EventSystem = PyObject_GetAttrString(module, "EventSystem");
211
    if (!EventSystem)
212
        return 0;
213
214
    Py_DECREF(module);
215
216
    /* Import objects from storm.expr module */
217
    module = PyImport_ImportModule("storm.expr");
218
    if (!module)
219
        return 0;
220
221
    SQLRaw = PyObject_GetAttrString(module, "SQLRaw");
222
    if (!SQLRaw)
223
        return 0;
224
225
    SQLToken = PyObject_GetAttrString(module, "SQLToken");
226
    if (!SQLToken)
227
        return 0;
228
229
    State = PyObject_GetAttrString(module, "State");
230
    if (!State)
231
        return 0;
232
233
    CompileError = PyObject_GetAttrString(module, "CompileError");
234
    if (!CompileError)
235
        return 0;
236
237
    Py_DECREF(module);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
238
235.2.15 by Gustavo Niemeyer
Use a unicode default join string in the cextensions Compile, and
239
    /* A few frequently used objects which are part of the fast path. */
240
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
241
    parenthesis_format = PyUnicode_DecodeASCII("(%s)", 4, "strict");
235.2.15 by Gustavo Niemeyer
Use a unicode default join string in the cextensions Compile, and
242
    default_compile_join = PyUnicode_DecodeASCII(", ", 2, "strict");
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
243
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
244
    return 1;
245
}
246
247
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
248
static int
249
EventSystem_init(EventSystemObject *self, PyObject *args, PyObject *kwargs)
250
{
251
    static char *kwlist[] = {"owner", NULL};
252
    PyObject *owner;
235.5.2 by James Henstridge
Fix a few more C99-isms.
253
    int result = -1;
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
254
255
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &owner))
256
        return -1;
257
258
    /* self._owner_ref = weakref.ref(owner) */
259
    self->_owner_ref = PyWeakref_NewRef(owner, NULL);
260
    if (self->_owner_ref) {
261
        /* self._hooks = {} */
262
        self->_hooks = PyDict_New();
263
        if (self->_hooks) {
264
            result = 0;
265
        }
266
    }
267
268
    return result;
269
}
270
271
static int
272
EventSystem_traverse(EventSystemObject *self, visitproc visit, void *arg)
273
{
274
    Py_VISIT(self->_owner_ref);
275
    Py_VISIT(self->_hooks);
276
    return 0;
277
}
278
279
static int
280
EventSystem_clear(EventSystemObject *self)
281
{
282
    Py_CLEAR(self->_owner_ref);
283
    Py_CLEAR(self->_hooks);
284
    return 0;
285
}
286
287
static void
288
EventSystem_dealloc(EventSystemObject *self)
289
{
290
    EventSystem_clear(self);
291
    self->ob_type->tp_free((PyObject *)self);
292
}
293
294
static PyObject *
295
EventSystem_hook(EventSystemObject *self, PyObject *args)
296
{
297
    PyObject *result = NULL;
235.5.2 by James Henstridge
Fix a few more C99-isms.
298
    PyObject *name, *callback, *data;
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
299
300
    if (PyTuple_GET_SIZE(args) < 2) {
301
        PyErr_SetString(PyExc_TypeError, "Invalid number of arguments");
302
        return NULL;
303
    }
304
235.5.2 by James Henstridge
Fix a few more C99-isms.
305
    name = PyTuple_GET_ITEM(args, 0);
306
    callback = PyTuple_GET_ITEM(args, 1);
307
    data = PyTuple_GetSlice(args, 2, PyTuple_GET_SIZE(args));
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
308
    if (data) {
235.5.2 by James Henstridge
Fix a few more C99-isms.
309
        /*
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
310
           callbacks = self._hooks.get(name)
311
           if callbacks is None:
312
               self._hooks.setdefault(name, set()).add((callback, data))
313
           else:
314
               callbacks.add((callback, data))
315
        */
316
        PyObject *callbacks = PyDict_GetItem(self->_hooks, name);
317
        if (!PyErr_Occurred()) {
318
            if (callbacks == NULL) {
319
                callbacks = PySet_New(NULL);
320
                if (callbacks &&
321
                    PyDict_SetItem(self->_hooks, name, callbacks) == -1) {
322
                    Py_DECREF(callbacks);
323
                    callbacks = NULL;
324
                }
325
            } else {
326
                Py_INCREF(callbacks);
327
            }
328
            if (callbacks) {
329
                PyObject *tuple = PyTuple_New(2);
330
                if (tuple) {
331
                    Py_INCREF(callback);
332
                    PyTuple_SET_ITEM(tuple, 0, callback);
333
                    Py_INCREF(data);
334
                    PyTuple_SET_ITEM(tuple, 1, data);
335
                    if (PySet_Add(callbacks, tuple) != -1) {
336
                        Py_INCREF(Py_None);
337
                        result = Py_None;
338
                    }
339
                    Py_DECREF(tuple);
340
                }
341
                Py_DECREF(callbacks);
342
            }
343
        }
344
        Py_DECREF(data);
345
    }
346
347
    return result;
348
}
349
350
static PyObject *
351
EventSystem_unhook(EventSystemObject *self, PyObject *args)
352
{
353
    PyObject *result = NULL;
235.5.2 by James Henstridge
Fix a few more C99-isms.
354
    PyObject *name, *callback, *data;
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
355
356
    if (PyTuple_GET_SIZE(args) < 2) {
357
        PyErr_SetString(PyExc_TypeError, "Invalid number of arguments");
358
        return NULL;
359
    }
360
235.5.2 by James Henstridge
Fix a few more C99-isms.
361
    name = PyTuple_GET_ITEM(args, 0);
362
    callback = PyTuple_GET_ITEM(args, 1);
363
    data = PyTuple_GetSlice(args, 2, PyTuple_GET_SIZE(args));
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
364
    if (data) {
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
365
        /*
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
366
           callbacks = self._hooks.get(name)
367
           if callbacks is not None:
368
               callbacks.discard((callback, data))
369
        */
370
        PyObject *callbacks = PyDict_GetItem(self->_hooks, name);
371
        if (callbacks) {
372
            PyObject *tuple = PyTuple_New(2);
373
            if (tuple) {
374
                Py_INCREF(callback);
375
                PyTuple_SET_ITEM(tuple, 0, callback);
376
                Py_INCREF(data);
377
                PyTuple_SET_ITEM(tuple, 1, data);
378
                if (PySet_Discard(callbacks, tuple) != -1) {
379
                    Py_INCREF(Py_None);
380
                    result = Py_None;
381
                }
382
                Py_DECREF(tuple);
383
            }
384
        } else if (!PyErr_Occurred()) {
385
            Py_INCREF(Py_None);
386
            result = Py_None;
387
        }
388
        Py_DECREF(data);
389
    }
390
391
    return result;
392
}
393
394
static PyObject *
395
EventSystem__do_emit_call(PyObject *callback, PyObject *owner,
396
                          PyObject *args, PyObject *data)
397
{
398
    /* return callback(owner, *(args+data)) */
399
    PyObject *result = NULL;
400
    PyObject *tuple = PyTuple_New(PyTuple_GET_SIZE(args) +
401
                                  PyTuple_GET_SIZE(data) + 1);
402
    if (tuple) {
235.5.2 by James Henstridge
Fix a few more C99-isms.
403
        Py_ssize_t i, tuple_i;
404
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
405
        Py_INCREF(owner);
406
        PyTuple_SET_ITEM(tuple, 0, owner);
407
        tuple_i = 1;
408
        for (i = 0; i != PyTuple_GET_SIZE(args); i++) {
409
            PyObject *item = PyTuple_GET_ITEM(args, i);
410
            Py_INCREF(item);
411
            PyTuple_SET_ITEM(tuple, tuple_i++, item);
412
        }
413
        for (i = 0; i != PyTuple_GET_SIZE(data); i++) {
414
            PyObject *item = PyTuple_GET_ITEM(data, i);
415
            Py_INCREF(item);
416
            PyTuple_SET_ITEM(tuple, tuple_i++, item);
417
        }
418
        result = PyObject_Call(callback, tuple, NULL);
419
        Py_DECREF(tuple);
420
    }
421
    return result;
422
}
423
424
static PyObject *
425
EventSystem_emit(EventSystemObject *self, PyObject *all_args)
426
{
427
    PyObject *result = NULL;
235.5.2 by James Henstridge
Fix a few more C99-isms.
428
    PyObject *name, *args;
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
429
430
    if (PyTuple_GET_SIZE(all_args) == 0) {
431
        PyErr_SetString(PyExc_TypeError, "Invalid number of arguments");
432
        return NULL;
433
    }
434
435
    /* XXX In the following code we trust on the format inserted by
436
     *     the hook() method.  If it's hacked somehow, it may blow up. */
437
235.5.2 by James Henstridge
Fix a few more C99-isms.
438
    name = PyTuple_GET_ITEM(all_args, 0);
439
    args = PyTuple_GetSlice(all_args, 1, PyTuple_GET_SIZE(all_args));
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
440
    if (args) {
441
        /* owner = self._owner_ref() */
442
        PyObject *owner = PyWeakref_GET_OBJECT(self->_owner_ref);
443
        /* if owner is not None: */
444
        if (owner != Py_None) {
445
            /* callbacks = self._hooks.get(name) */
446
            PyObject *callbacks = PyDict_GetItem(self->_hooks, name);
235.5.2 by James Henstridge
Fix a few more C99-isms.
447
            Py_INCREF(owner);
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
448
            /* if callbacks: */
449
            if (callbacks && PySet_GET_SIZE(callbacks) != 0) {
450
                /* for callback, data in tuple(callbacks): */
451
                PyObject *sequence = \
452
                    PySequence_Fast(callbacks, "callbacks object isn't a set");
453
                if (sequence) {
454
                    int failed = 0;
455
                    Py_ssize_t i;
456
                    for (i = 0; i != PySequence_Fast_GET_SIZE(sequence); i++) {
457
                        PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
458
                        PyObject *callback = PyTuple_GET_ITEM(item, 0);
459
                        PyObject *data = PyTuple_GET_ITEM(item, 1);
460
                        PyObject *res;
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
461
                        /*
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
462
                           if callback(owner, *(args+data)) is False:
463
                               callbacks.discard((callback, data))
464
                        */
465
                        res = EventSystem__do_emit_call(callback, owner,
466
                                                        args, data);
467
                        Py_XDECREF(res);
468
                        if (res == NULL ||
469
                            (res == Py_False &&
470
                             PySet_Discard(callbacks, item) == -1)) {
471
                            failed = 1;
472
                            break;
473
                        }
474
                    }
475
                    if (!failed) {
476
                        Py_INCREF(Py_None);
477
                        result = Py_None;
478
                    }
479
                    Py_DECREF(sequence);
480
                }
481
            } else if (!PyErr_Occurred()) {
482
                Py_INCREF(Py_None);
483
                result = Py_None;
484
            }
485
            Py_DECREF(owner);
486
        } else {
487
            Py_INCREF(Py_None);
488
            result = Py_None;
489
        }
490
        Py_DECREF(args);
491
    }
492
493
    return result;
494
}
495
496
497
static PyMethodDef EventSystem_methods[] = {
498
    {"hook", (PyCFunction)EventSystem_hook, METH_VARARGS, NULL},
499
    {"unhook", (PyCFunction)EventSystem_unhook, METH_VARARGS, NULL},
500
    {"emit", (PyCFunction)EventSystem_emit, METH_VARARGS, NULL},
501
    {NULL, NULL}
502
};
503
504
#define OFFSETOF(x) offsetof(EventSystemObject, x)
505
static PyMemberDef EventSystem_members[] = {
506
    {"_object_ref", T_OBJECT, OFFSETOF(_owner_ref), READONLY, 0},
507
    {"_hooks", T_OBJECT, OFFSETOF(_hooks), READONLY, 0},
508
    {NULL}
509
};
510
#undef OFFSETOF
511
512
statichere PyTypeObject EventSystem_Type = {
513
    PyObject_HEAD_INIT(NULL)
514
    0,            /*ob_size*/
515
    "storm.variables.EventSystem",    /*tp_name*/
516
    sizeof(EventSystemObject), /*tp_basicsize*/
517
    0,            /*tp_itemsize*/
518
    (destructor)EventSystem_dealloc, /*tp_dealloc*/
519
    0,            /*tp_print*/
520
    0,            /*tp_getattr*/
521
    0,            /*tp_setattr*/
522
    0,            /*tp_compare*/
523
    0,          /*tp_repr*/
524
    0,            /*tp_as_number*/
525
    0,            /*tp_as_sequence*/
526
    0,            /*tp_as_mapping*/
527
    0,                      /*tp_hash*/
528
    0,                      /*tp_call*/
529
    0,                      /*tp_str*/
305.2.2 by James Henstridge
Clean up build patch a bit:
530
    0,                      /*tp_getattro*/
531
    0,                      /*tp_setattro*/
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
532
    0,                      /*tp_as_buffer*/
533
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
534
    0,                      /*tp_doc*/
535
    (traverseproc)EventSystem_traverse,  /*tp_traverse*/
536
    (inquiry)EventSystem_clear,          /*tp_clear*/
537
    0,                      /*tp_richcompare*/
538
    0,                      /*tp_weaklistoffset*/
539
    0,                      /*tp_iter*/
540
    0,                      /*tp_iternext*/
541
    EventSystem_methods,        /*tp_methods*/
542
    EventSystem_members,        /*tp_members*/
543
    0,                      /*tp_getset*/
544
    0,                      /*tp_base*/
545
    0,                      /*tp_dict*/
546
    0,                      /*tp_descr_get*/
547
    0,                      /*tp_descr_set*/
548
    0,                      /*tp_dictoffset*/
549
    (initproc)EventSystem_init, /*tp_init*/
305.2.2 by James Henstridge
Clean up build patch a bit:
550
    0,                      /*tp_alloc*/
551
    0,                      /*tp_new*/
552
    0,                      /*tp_free*/
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
553
    0,                      /*tp_is_gc*/
554
};
555
556
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
557
static PyObject *
558
Variable_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
559
{
560
    VariableObject *self = (VariableObject *)type->tp_alloc(type, 0);
561
562
    if (!initialize_globals())
563
        return NULL;
564
565
    /* The following are defined as class properties, so we must initialize
566
       them here for methods to work with the same logic. */
567
    Py_INCREF(Undef);
568
    self->_value = Undef;
569
    Py_INCREF(Undef);
570
    self->_lazy_value = Undef;
571
    Py_INCREF(Undef);
572
    self->_checkpoint_state = Undef;
573
    Py_INCREF(Py_True);
574
    self->_allow_none = Py_True;
575
    Py_INCREF(Py_None);
576
    self->event = Py_None;
577
    Py_INCREF(Py_None);
578
    self->column = Py_None;
579
580
    return (PyObject *)self;
581
}
582
583
static int
584
Variable_init(VariableObject *self, PyObject *args, PyObject *kwargs)
585
{
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
586
    static char *kwlist[] = {"value", "value_factory", "from_db",
587
                             "allow_none", "column", "event", "validator",
588
                             "validator_object_factory", "validator_attribute",
589
                             NULL};
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
590
591
    PyObject *value = Undef;
592
    PyObject *value_factory = Undef;
593
    PyObject *from_db = Py_False;
594
    PyObject *allow_none = Py_True;
595
    PyObject *column = Py_None;
596
    PyObject *event = Py_None;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
597
    PyObject *validator = Py_None;
598
    PyObject *validator_object_factory = Py_None;
599
    PyObject *validator_attribute = Py_None;
600
    PyObject *tmp;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
601
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
602
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOOOOOOO", kwlist, &value,
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
603
                                     &value_factory, &from_db, &allow_none,
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
604
                                     &column, &event, &validator,
605
                                     &validator_object_factory,
606
                                     &validator_attribute))
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
607
        return -1;
608
609
    /* if not allow_none: */
610
    if (allow_none != Py_True &&
611
        (allow_none == Py_False || !PyObject_IsTrue(allow_none))) {
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
612
        /* self._allow_none = False */
613
        Py_INCREF(Py_False);
235.2.17 by Gustavo Niemeyer
Fixed a couple of GC-unsafe variable swaps spotted by James.
614
        REPLACE(self->_allow_none, Py_False);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
615
    }
616
617
    /* if value is not Undef: */
618
    if (value != Undef) {
619
        /* self.set(value, from_db) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
620
        CATCH(NULL, tmp = PyObject_CallMethod((PyObject *)self,
621
                                              "set", "OO", value, from_db));
622
        Py_DECREF(tmp);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
623
    }
624
    /* elif value_factory is not Undef: */
625
    else if (value_factory != Undef) {
626
        /* self.set(value_factory(), from_db) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
627
        CATCH(NULL, value = PyObject_CallFunctionObjArgs(value_factory, NULL));
628
        tmp = PyObject_CallMethod((PyObject *)self,
629
                                  "set", "OO", value, from_db);
630
        Py_DECREF(value);
631
        CATCH(NULL, tmp);
632
        Py_DECREF(tmp);
633
    }
634
635
    /* if validator is not None: */
636
    if (validator != Py_None) {
637
        /* self._validator = validator */
638
        Py_INCREF(validator);
639
        self->_validator = validator;
640
        /* self._validator_object_factory = validator_object_factory */
641
        Py_INCREF(validator_object_factory);
642
        self->_validator_object_factory = validator_object_factory;
643
        /* self._validator_attribute = validator_attribute */
644
        Py_INCREF(validator_attribute);
645
        self->_validator_attribute = validator_attribute;
646
    }
647
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
648
    /* self.column = column */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
649
    Py_DECREF(self->column);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
650
    Py_INCREF(column);
651
    self->column = column;
652
653
    /* self.event = event */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
654
    Py_DECREF(self->event);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
655
    Py_INCREF(event);
656
    self->event = event;
657
658
    return 0;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
659
660
error:
661
    return -1;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
662
}
663
664
static int
665
Variable_traverse(VariableObject *self, visitproc visit, void *arg)
666
{
667
    Py_VISIT(self->_value);
668
    Py_VISIT(self->_lazy_value);
669
    Py_VISIT(self->_checkpoint_state);
670
    /* Py_VISIT(self->_allow_none); */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
671
    Py_VISIT(self->_validator);
672
    Py_VISIT(self->_validator_object_factory);
673
    Py_VISIT(self->_validator_attribute);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
674
    Py_VISIT(self->column);
675
    Py_VISIT(self->event);
676
    return 0;
677
}
678
679
static int
680
Variable_clear(VariableObject *self)
681
{
682
    Py_CLEAR(self->_value);
683
    Py_CLEAR(self->_lazy_value);
684
    Py_CLEAR(self->_checkpoint_state);
685
    Py_CLEAR(self->_allow_none);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
686
    Py_CLEAR(self->_validator);
687
    Py_CLEAR(self->_validator_object_factory);
688
    Py_CLEAR(self->_validator_attribute);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
689
    Py_CLEAR(self->column);
690
    Py_CLEAR(self->event);
691
    return 0;
692
}
693
694
static void
695
Variable_dealloc(VariableObject *self)
696
{
697
    Variable_clear(self);
698
    self->ob_type->tp_free((PyObject *)self);
699
}
700
701
static PyObject *
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
702
Variable_parse_get(VariableObject *self, PyObject *args)
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
703
{
704
    /* return value */
705
    PyObject *value, *to_db;
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
706
    if (!PyArg_ParseTuple(args, "OO:parse_get", &value, &to_db))
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
707
        return NULL;
708
    Py_INCREF(value);
709
    return value;
710
}
711
712
static PyObject *
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
713
Variable_parse_set(VariableObject *self, PyObject *args)
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
714
{
715
    /* return value */
716
    PyObject *value, *from_db;
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
717
    if (!PyArg_ParseTuple(args, "OO:parse_set", &value, &from_db))
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
718
        return NULL;
719
    Py_INCREF(value);
720
    return value;
721
}
722
723
static PyObject *
724
Variable_get_lazy(VariableObject *self, PyObject *args, PyObject *kwargs)
725
{
726
    static char *kwlist[] = {"default", NULL};
727
    PyObject *default_ = Py_None;
728
    PyObject *result;
729
730
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:get_lazy", kwlist,
731
                                     &default_))
732
        return NULL;
733
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
734
    /*
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
735
       if self._lazy_value is Undef:
736
           return default
737
       return self._lazy_value
738
    */
739
    if (self->_lazy_value == Undef) {
740
        result = default_;
741
    } else {
742
        result = self->_lazy_value;
743
    }
744
    Py_INCREF(result);
745
    return result;
746
}
747
748
static PyObject *
749
Variable_get(VariableObject *self, PyObject *args, PyObject *kwargs)
750
{
751
    static char *kwlist[] = {"default", "to_db", NULL};
752
    PyObject *default_ = Py_None;
753
    PyObject *to_db = Py_False;
754
755
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:get", kwlist,
756
                                     &default_, &to_db))
757
        return NULL;
758
759
    /* if self._lazy_value is not Undef and self.event is not None: */
760
    if (self->_lazy_value != Undef && self->event != Py_None) {
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
761
        PyObject *tmp;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
762
        /* self.event.emit("resolve-lazy-value", self, self._lazy_value) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
763
        CATCH(NULL, tmp = PyObject_CallMethod(self->event, "emit", "sOO",
764
                                              "resolve-lazy-value", self,
765
                                              self->_lazy_value));
766
        Py_DECREF(tmp);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
767
    }
768
769
    /* value = self->_value */
770
    /* if value is Undef: */
771
    if (self->_value == Undef) {
772
        /* return default */
773
        Py_INCREF(default_);
774
        return default_;
775
    }
776
777
    /* if value is None: */
778
    if (self->_value == Py_None) {
779
        /* return None */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
780
        Py_RETURN_NONE;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
781
    }
782
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
783
    /* return self.parse_get(value, to_db) */
784
    return PyObject_CallMethod((PyObject *)self, "parse_get",
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
785
                               "OO", self->_value, to_db);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
786
787
error:
788
    return NULL;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
789
}
790
791
static PyObject *
792
Variable_set(VariableObject *self, PyObject *args, PyObject *kwargs)
793
{
794
    static char *kwlist[] = {"value", "from_db", NULL};
795
    PyObject *value = Py_None;
796
    PyObject *from_db = Py_False;
797
    PyObject *old_value = NULL;
798
    PyObject *new_value = NULL;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
799
    PyObject *tmp;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
800
801
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:set", kwlist,
802
                                     &value, &from_db))
803
        return NULL;
804
805
    Py_INCREF(value);
806
807
    /* if isinstance(value, LazyValue): */
808
    if (PyObject_IsInstance(value, LazyValue)) {
809
        /* self._lazy_value = value */
810
        Py_INCREF(value);
235.2.17 by Gustavo Niemeyer
Fixed a couple of GC-unsafe variable swaps spotted by James.
811
        REPLACE(self->_lazy_value, value);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
812
269.2.2 by Thomas Hervé
Update C extension with the same fix as variables.py
813
        /* self._checkpoint_state = new_value = Undef */
814
        Py_INCREF(Undef);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
815
        Py_INCREF(Undef);
816
        new_value = Undef;
290 by Thomas Hervé
Fix a leak in the C implementation of Variable.set: a port from the python
817
        Py_DECREF(self->_checkpoint_state);
269.2.2 by Thomas Hervé
Update C extension with the same fix as variables.py
818
        self->_checkpoint_state = Undef;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
819
    }
820
    /* else: */
821
    else {
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
822
        /* if not from_db and self._validator is not None: */
823
        if (self->_validator && !PyObject_IsTrue(from_db)) {
824
            /* value = self._validator(self._validator_object_factory and
825
                                       self._validator_object_factory(),
826
                                       self._validator_attribute, value) */
827
            PyObject *validator_object, *tmp;
828
            if (self->_validator_object_factory == Py_None) {
829
                Py_INCREF(Py_None);
830
                validator_object = Py_None;
831
            } else {
832
                CATCH(NULL, validator_object = PyObject_CallFunctionObjArgs(
833
                                self->_validator_object_factory, NULL));
834
            }
835
            tmp = PyObject_CallFunctionObjArgs(self->_validator,
836
                                               validator_object,
837
                                               self->_validator_attribute,
838
                                               value, NULL);
839
            Py_DECREF(validator_object);
840
            CATCH(NULL, tmp);
841
842
            Py_DECREF(value);
843
            value = tmp;
844
        }
845
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
846
        /* self._lazy_value = Undef */
847
        Py_INCREF(Undef);
848
        Py_DECREF(self->_lazy_value);
849
        self->_lazy_value = Undef;
850
851
        /* if value is None: */
852
        if (value == Py_None) {
853
            /* if self._allow_none is False: */
854
            if (self->_allow_none == Py_False) {
855
                /* raise_none_error(self.column) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
856
                tmp = PyObject_CallFunctionObjArgs(raise_none_error,
857
                                                   self->column, NULL);
858
                /* tmp should always be NULL here. */
859
                Py_XDECREF(tmp);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
860
                goto error;
861
            }
862
863
            /* new_value = None */
864
            Py_INCREF(Py_None);
865
            new_value = Py_None;
866
        }
867
        /* else: */
868
        else {
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
869
            /* new_value = self.parse_set(value, from_db) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
870
            CATCH(NULL,
871
                  new_value = PyObject_CallMethod((PyObject *)self, "parse_set",
872
                                                  "OO", value, from_db));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
873
874
            /* if from_db: */
875
            if (PyObject_IsTrue(from_db)) {
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
876
                /* value = self.parse_get(new_value, False) */
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
877
                Py_DECREF(value);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
878
                CATCH(NULL,
879
                      value = PyObject_CallMethod((PyObject *)self, "parse_get",
880
                                                  "OO", new_value, Py_False));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
881
            }
882
        }
883
    }
884
885
    /* old_value = self._value */
886
    old_value = self->_value;
887
    /* Keep the reference with old_value. */
888
889
    /* self._value = new_value */
890
    Py_INCREF(new_value);
891
    self->_value = new_value;
892
893
    /* if (self.event is not None and
894
           (self._lazy_value is not Undef or new_value != old_value)): */
895
    if (self->event != Py_None &&
896
        (self->_lazy_value != Undef ||
897
         PyObject_RichCompareBool(new_value, old_value, Py_NE))) {
898
899
        /* if old_value is not None and old_value is not Undef: */
900
        if (old_value != Py_None && old_value != Undef) {
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
901
            /* old_value = self.parse_get(old_value, False) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
902
            CATCH(NULL, tmp = PyObject_CallMethod((PyObject *)self, "parse_get",
903
                                                  "OO", old_value, Py_False));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
904
            Py_DECREF(old_value);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
905
            old_value = tmp;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
906
        }
907
        /* self.event.emit("changed", self, old_value, value, from_db) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
908
        CATCH(NULL, tmp = PyObject_CallMethod((PyObject *)self->event, "emit",
909
                                              "sOOOO", "changed", self,
910
                                              old_value, value, from_db));
911
        Py_DECREF(tmp);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
912
    }
913
914
    Py_DECREF(value);
915
    Py_DECREF(old_value);
916
    Py_DECREF(new_value);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
917
918
    Py_RETURN_NONE;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
919
920
error:
921
    Py_XDECREF(value);
922
    Py_XDECREF(old_value);
923
    Py_XDECREF(new_value);
924
    return NULL;
925
}
926
927
static PyObject *
928
Variable_delete(VariableObject *self, PyObject *args)
929
{
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
930
    PyObject *old_value;
931
    PyObject *tmp;
932
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
933
    /* old_value = self._value */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
934
    old_value = self->_value;
935
    Py_INCREF(old_value);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
936
937
    /* if old_value is not Undef: */
938
    if (old_value != Undef) {
939
940
        /* self._value = Undef */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
941
        Py_DECREF(self->_value);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
942
        Py_INCREF(Undef);
943
        self->_value = Undef;
944
945
        /* if self.event is not None: */
946
        if (self->event != Py_None) {
947
            /* if old_value is not None and old_value is not Undef: */
948
            if (old_value != Py_None && old_value != Undef) {
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
949
                /* old_value = self.parse_get(old_value, False) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
950
                CATCH(NULL,
951
                      tmp = PyObject_CallMethod((PyObject *)self, "parse_get",
952
                                                "OO", old_value, Py_False));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
953
                Py_DECREF(old_value);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
954
                old_value = tmp;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
955
            }
956
957
            /* self.event.emit("changed", self, old_value, Undef, False) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
958
            CATCH(NULL,
959
                  tmp = PyObject_CallMethod((PyObject *)self->event, "emit",
960
                                            "sOOOO", "changed", self, old_value,
961
                                            Undef, Py_False));
962
            Py_DECREF(tmp);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
963
        }
964
    }
965
966
    Py_DECREF(old_value);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
967
    Py_RETURN_NONE;
968
969
error:
970
    Py_XDECREF(old_value);
971
    return NULL;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
972
}
973
974
static PyObject *
975
Variable_is_defined(VariableObject *self, PyObject *args)
976
{
977
    /* return self._value is not Undef */
978
    return PyBool_FromLong(self->_value != Undef);
979
}
980
981
static PyObject *
982
Variable_has_changed(VariableObject *self, PyObject *args)
983
{
984
    /* return (self._lazy_value is not Undef or
985
               self.get_state() != self._checkpoint_state) */
986
    PyObject *result = Py_True;
987
    if (self->_lazy_value == Undef) {
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
988
        PyObject *state;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
989
        int res;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
990
        CATCH(NULL, state = PyObject_CallMethod((PyObject *)self,
991
                                                "get_state", NULL));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
992
        res = PyObject_RichCompareBool(state, self->_checkpoint_state, Py_EQ);
993
        Py_DECREF(state);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
994
        CATCH(-1, res);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
995
        if (res)
996
            result = Py_False;
997
    }
998
    Py_INCREF(result);
999
    return result;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1000
1001
error:
1002
    return NULL;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1003
}
1004
1005
static PyObject *
1006
Variable_get_state(VariableObject *self, PyObject *args)
1007
{
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1008
    /* return (self._lazy_value, self._value) */
1009
    PyObject *result;
1010
    CATCH(NULL, result = PyTuple_New(2));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1011
    Py_INCREF(self->_lazy_value);
1012
    Py_INCREF(self->_value);
1013
    PyTuple_SET_ITEM(result, 0, self->_lazy_value);
1014
    PyTuple_SET_ITEM(result, 1, self->_value);
1015
    return result;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1016
error:
1017
    return NULL;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1018
}
1019
1020
static PyObject *
1021
Variable_set_state(VariableObject *self, PyObject *args)
1022
{
1023
    /* self._lazy_value, self._value = state */
235.5.1 by James Henstridge
* Fix reference leak in Variable_set_state().
1024
    PyObject *lazy_value, *value;
1025
    if (!PyArg_ParseTuple(args, "(OO):set_state", &lazy_value, &value))
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1026
        return NULL;
235.5.1 by James Henstridge
* Fix reference leak in Variable_set_state().
1027
    Py_INCREF(lazy_value);
1028
    REPLACE(self->_lazy_value, lazy_value);
1029
    Py_INCREF(value);
1030
    REPLACE(self->_value, value);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1031
    Py_RETURN_NONE;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1032
}
1033
1034
static PyObject *
1035
Variable_checkpoint(VariableObject *self, PyObject *args)
1036
{
1037
    /* self._checkpoint_state = self.get_state() */
1038
    PyObject *state = PyObject_CallMethod((PyObject *)self, "get_state", NULL);
1039
    if (!state)
1040
        return NULL;
1041
    Py_DECREF(self->_checkpoint_state);
1042
    self->_checkpoint_state = state;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1043
    Py_RETURN_NONE;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1044
}
1045
1046
static PyObject *
1047
Variable_copy(VariableObject *self, PyObject *args)
1048
{
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1049
    PyObject *noargs = NULL;
1050
    PyObject *variable = NULL;
1051
    PyObject *state = NULL;
1052
    PyObject *tmp;
1053
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1054
    /* variable = self.__class__.__new__(self.__class__) */
1055
    noargs = PyTuple_New(0);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1056
    CATCH(NULL, variable = self->ob_type->tp_new(self->ob_type, noargs, NULL));
1057
1058
    /* variable.set_state(self.get_state()) */
1059
    CATCH(NULL,
1060
          state = PyObject_CallMethod((PyObject *)self, "get_state", NULL));
1061
1062
    CATCH(NULL, tmp = PyObject_CallMethod((PyObject *)variable,
1063
                                          "set_state", "(O)", state));
1064
    Py_DECREF(tmp);
1065
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1066
    Py_DECREF(noargs);
1067
    Py_DECREF(state);
1068
    return variable;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1069
1070
error:
1071
    Py_XDECREF(noargs);
1072
    Py_XDECREF(state);
1073
    Py_XDECREF(variable);
1074
    return NULL;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1075
}
1076
1077
static PyMethodDef Variable_methods[] = {
142.3.1 by Christopher Armstrong
drop the underscores from the _parse_set and _parse_get methods,
1078
    {"parse_get", (PyCFunction)Variable_parse_get, METH_VARARGS, NULL},
1079
    {"parse_set", (PyCFunction)Variable_parse_set, METH_VARARGS, NULL},
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1080
    {"get_lazy", (PyCFunction)Variable_get_lazy,
1081
        METH_VARARGS | METH_KEYWORDS, NULL},
1082
    {"get", (PyCFunction)Variable_get, METH_VARARGS | METH_KEYWORDS, NULL},
1083
    {"set", (PyCFunction)Variable_set, METH_VARARGS | METH_KEYWORDS, NULL},
1084
    {"delete", (PyCFunction)Variable_delete,
1085
        METH_VARARGS | METH_KEYWORDS, NULL},
1086
    {"is_defined", (PyCFunction)Variable_is_defined, METH_NOARGS, NULL},
1087
    {"has_changed", (PyCFunction)Variable_has_changed, METH_NOARGS, NULL},
1088
    {"get_state", (PyCFunction)Variable_get_state, METH_NOARGS, NULL},
1089
    {"set_state", (PyCFunction)Variable_set_state, METH_VARARGS, NULL},
1090
    {"checkpoint", (PyCFunction)Variable_checkpoint, METH_NOARGS, NULL},
1091
    {"copy", (PyCFunction)Variable_copy, METH_NOARGS, NULL},
1092
    {NULL, NULL}
1093
};
1094
1095
#define OFFSETOF(x) offsetof(VariableObject, x)
1096
static PyMemberDef Variable_members[] = {
1097
    {"_value", T_OBJECT, OFFSETOF(_value), 0, 0},
1098
    {"_lazy_value", T_OBJECT, OFFSETOF(_lazy_value), 0, 0},
1099
    {"_checkpoint_state", T_OBJECT, OFFSETOF(_checkpoint_state), 0, 0},
1100
    {"_allow_none", T_OBJECT, OFFSETOF(_allow_none), 0, 0},
1101
    {"column", T_OBJECT, OFFSETOF(column), 0, 0},
1102
    {"event", T_OBJECT, OFFSETOF(event), 0, 0},
1103
    {NULL}
1104
};
1105
#undef OFFSETOF
1106
1107
statichere PyTypeObject Variable_Type = {
142.2.4 by Gustavo Niemeyer
Oops.. we don't like tabs, even in C files.
1108
    PyObject_HEAD_INIT(NULL)
1109
    0,            /*ob_size*/
1110
    "storm.variables.Variable",    /*tp_name*/
1111
    sizeof(VariableObject), /*tp_basicsize*/
1112
    0,            /*tp_itemsize*/
1113
    (destructor)Variable_dealloc, /*tp_dealloc*/
1114
    0,            /*tp_print*/
1115
    0,            /*tp_getattr*/
1116
    0,            /*tp_setattr*/
1117
    0,            /*tp_compare*/
1118
    0,          /*tp_repr*/
1119
    0,            /*tp_as_number*/
1120
    0,            /*tp_as_sequence*/
1121
    0,            /*tp_as_mapping*/
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
1122
    0,            /*tp_hash*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1123
    0,                      /*tp_call*/
1124
    0,                      /*tp_str*/
305.2.2 by James Henstridge
Clean up build patch a bit:
1125
    0,                      /*tp_getattro*/
1126
    0,                      /*tp_setattro*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1127
    0,                      /*tp_as_buffer*/
1128
    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
1129
    0,                      /*tp_doc*/
1130
    (traverseproc)Variable_traverse,  /*tp_traverse*/
1131
    (inquiry)Variable_clear,          /*tp_clear*/
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
1132
    0,                      /*tp_richcompare*/
269.3.7 by Thomas Hervé
Revert changes about tp_weaklistoffset, and create a custom PickleVariable
1133
    0,                      /*tp_weaklistoffset*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1134
    0,                      /*tp_iter*/
1135
    0,                      /*tp_iternext*/
1136
    Variable_methods,        /*tp_methods*/
1137
    Variable_members,        /*tp_members*/
1138
    0,                      /*tp_getset*/
1139
    0,                      /*tp_base*/
1140
    0,                      /*tp_dict*/
1141
    0,                      /*tp_descr_get*/
1142
    0,                      /*tp_descr_set*/
1143
    0,                      /*tp_dictoffset*/
1144
    (initproc)Variable_init, /*tp_init*/
305.2.2 by James Henstridge
Clean up build patch a bit:
1145
    0,                       /*tp_alloc*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1146
    Variable_new,      /*tp_new*/
305.2.2 by James Henstridge
Clean up build patch a bit:
1147
    0,                      /*tp_free*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1148
    0,                      /*tp_is_gc*/
1149
};
1150
1151
1152
static PyObject *
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1153
Compile__update_cache(CompileObject *self, PyObject *args);
1154
1155
static int
1156
Compile_init(CompileObject *self, PyObject *args, PyObject *kwargs)
1157
{
1158
    static char *kwlist[] = {"parent", NULL};
1159
1160
    PyObject *parent = Py_None;
1161
1162
    PyObject *module = NULL;
1163
    PyObject *WeakKeyDictionary = NULL;
1164
1165
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &parent))
1166
        return -1;
1167
1168
    /*
1169
       self._local_dispatch_table = {}
1170
       self._local_precedence = {}
1171
       self._local_reserved_words = {}
1172
       self._dispatch_table = {}
1173
       self._precedence = {}
1174
       self._reserved_words = {}
1175
    */
1176
    CATCH(NULL, self->_local_dispatch_table = PyDict_New());
1177
    CATCH(NULL, self->_local_precedence = PyDict_New());
1178
    CATCH(NULL, self->_local_reserved_words = PyDict_New());
1179
    CATCH(NULL, self->_dispatch_table = PyDict_New());
1180
    CATCH(NULL, self->_precedence = PyDict_New());
1181
    CATCH(NULL, self->_reserved_words = PyDict_New());
1182
1183
    /* self._children = WeakKeyDictionary() */
1184
    CATCH(NULL, module = PyImport_ImportModule("weakref"));
1185
    CATCH(NULL, WeakKeyDictionary = \
1186
                    PyObject_GetAttrString(module, "WeakKeyDictionary"));
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1187
    Py_CLEAR(module);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1188
    CATCH(NULL, self->_children = \
1189
                    PyObject_CallFunctionObjArgs(WeakKeyDictionary, NULL));
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1190
    Py_CLEAR(WeakKeyDictionary);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1191
1192
    /* self._parents = [] */
1193
    CATCH(NULL, self->_parents = PyList_New(0));
1194
1195
    /* if parent: */
1196
    if (parent != Py_None) {
1197
        PyObject *tmp;
1198
1199
        /* self._parents.extend(parent._parents) */
1200
        CompileObject *parent_object = (CompileObject *)parent;
235.2.17 by Gustavo Niemeyer
Fixed a couple of GC-unsafe variable swaps spotted by James.
1201
        CATCH(-1, PyList_SetSlice(self->_parents, 0, 0,
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1202
                                  parent_object->_parents));
1203
1204
        /* self._parents.append(parent) */
1205
        CATCH(-1, PyList_Append(self->_parents, parent));
1206
1207
        /* parent._children[self] = True */
1208
        CATCH(-1, PyObject_SetItem(parent_object->_children,
1209
                                   (PyObject *)self, Py_True));
1210
1211
        /* self._update_cache() */
1212
        CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1213
        Py_DECREF(tmp);
1214
    }
1215
1216
    return 0;
1217
1218
error:
1219
    Py_XDECREF(module);
1220
    Py_XDECREF(WeakKeyDictionary);
1221
    return -1;
1222
}
1223
1224
static int
1225
Compile_traverse(CompileObject *self, visitproc visit, void *arg)
1226
{
1227
    Py_VISIT(self->_local_dispatch_table);
1228
    Py_VISIT(self->_local_precedence);
1229
    Py_VISIT(self->_local_reserved_words);
1230
    Py_VISIT(self->_dispatch_table);
1231
    Py_VISIT(self->_precedence);
1232
    Py_VISIT(self->_reserved_words);
1233
    Py_VISIT(self->_children);
1234
    Py_VISIT(self->_parents);
1235
    return 0;
1236
}
1237
1238
static int
1239
Compile_clear(CompileObject *self)
1240
{
1241
    if (self->__weakreflist)
1242
        PyObject_ClearWeakRefs((PyObject *)self);
1243
    Py_CLEAR(self->_local_dispatch_table);
1244
    Py_CLEAR(self->_local_precedence);
1245
    Py_CLEAR(self->_local_reserved_words);
1246
    Py_CLEAR(self->_dispatch_table);
1247
    Py_CLEAR(self->_precedence);
1248
    Py_CLEAR(self->_reserved_words);
1249
    Py_CLEAR(self->_children);
1250
    Py_CLEAR(self->_parents);
1251
    return 0;
1252
}
1253
1254
static void
1255
Compile_dealloc(CompileObject *self)
1256
{
1257
    Compile_clear(self);
1258
    self->ob_type->tp_free((PyObject *)self);
1259
}
1260
1261
static PyObject *
1262
Compile__update_cache(CompileObject *self, PyObject *args)
1263
{
1264
    PyObject *iter = NULL;
1265
    PyObject *child = NULL;
1266
    Py_ssize_t size;
1267
    int i;
1268
1269
    /* for parent in self._parents: */
1270
    size = PyList_GET_SIZE(self->_parents);
1271
    for (i = 0; i != size; i++) {
1272
        CompileObject *parent = \
1273
            (CompileObject *)PyList_GET_ITEM(self->_parents, i);
1274
        /* self._dispatch_table.update(parent._local_dispatch_table) */
1275
        CATCH(-1, PyDict_Update(self->_dispatch_table,
1276
                                parent->_local_dispatch_table));
1277
        /* self._precedence.update(parent._local_precedence) */
1278
        CATCH(-1, PyDict_Update(self->_precedence,
1279
                                parent->_local_precedence));
1280
        /* self._reserved_words.update(parent._local_reserved_words) */
1281
        CATCH(-1, PyDict_Update(self->_reserved_words,
1282
                                parent->_local_reserved_words));
1283
    }
1284
    /* self._dispatch_table.update(self._local_dispatch_table) */
1285
    CATCH(-1, PyDict_Update(self->_dispatch_table,
1286
                            self->_local_dispatch_table));
1287
    /* self._precedence.update(self._local_precedence) */
1288
    CATCH(-1, PyDict_Update(self->_precedence, self->_local_precedence));
1289
    /* self._reserved_words.update(self._local_reserved_words) */
1290
    CATCH(-1, PyDict_Update(self->_reserved_words,
1291
                            self->_local_reserved_words));
1292
1293
    /* for child in self._children: */
1294
    CATCH(NULL, iter = PyObject_GetIter(self->_children));
1295
    while((child = PyIter_Next(iter))) {
1296
        PyObject *tmp;
1297
1298
        /* child._update_cache() */
1299
        CATCH(NULL, tmp = Compile__update_cache((CompileObject *)child, NULL));
1300
        Py_DECREF(tmp);
1301
        Py_DECREF(child);
1302
    }
1303
    if (PyErr_Occurred())
1304
        goto error;
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1305
    Py_CLEAR(iter);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1306
1307
    Py_RETURN_NONE;
1308
1309
error:
1310
    Py_XDECREF(child);
1311
    Py_XDECREF(iter);
1312
    return NULL;
1313
}
1314
1315
static PyObject *
1316
Compile_when(CompileObject *self, PyObject *types)
1317
{
235.2.20 by Gustavo Niemeyer
Simplify the calling semantics of _when in the expr module, as
1318
    PyObject *result = NULL;
1319
    PyObject *module = PyImport_ImportModule("storm.expr");
1320
    if (module) {
1321
        PyObject *_when = PyObject_GetAttrString(module, "_when");
1322
        if (_when) {
1323
            result = PyObject_CallFunctionObjArgs(_when, self, types, NULL);
1324
            Py_DECREF(_when);
1325
        }
1326
        Py_DECREF(module);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1327
    }
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
1328
    return result;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1329
}
1330
1331
static PyObject *
1332
Compile_add_reserved_words(CompileObject *self, PyObject *words)
1333
{
1334
    PyObject *lower_word = NULL;
1335
    PyObject *iter = NULL;
1336
    PyObject *word = NULL;
1337
    PyObject *tmp;
1338
1339
    /* self._local_reserved_words.update((word.lower(), True)
1340
                                         for word in words) */
1341
    CATCH(NULL, iter = PyObject_GetIter(words));
1342
    while ((word = PyIter_Next(iter))) {
1343
        CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
1344
        CATCH(-1, PyDict_SetItem(self->_local_reserved_words,
1345
                                 lower_word, Py_True));
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1346
        Py_CLEAR(lower_word);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1347
        Py_DECREF(word);
1348
    }
1349
    if (PyErr_Occurred())
1350
        goto error;
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1351
    Py_CLEAR(iter);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1352
1353
    /* self._update_cache() */
1354
    CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1355
    Py_DECREF(tmp);
1356
1357
    Py_RETURN_NONE;
1358
1359
error:
1360
    Py_XDECREF(lower_word);
1361
    Py_XDECREF(word);
1362
    Py_XDECREF(iter);
1363
    return NULL;
1364
}
1365
1366
static PyObject *
1367
Compile_remove_reserved_words(CompileObject *self, PyObject *words)
1368
{
1369
    PyObject *lower_word = NULL;
1370
    PyObject *word = NULL;
1371
    PyObject *iter = NULL;
1372
    PyObject *tmp;
1373
1374
    /* self._local_reserved_words.update((word.lower(), None)
1375
                                         for word in words) */
1376
    CATCH(NULL, iter = PyObject_GetIter(words));
1377
    while ((word = PyIter_Next(iter))) {
1378
        CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
1379
        CATCH(-1, PyDict_SetItem(self->_local_reserved_words,
1380
                                 lower_word, Py_None));
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1381
        Py_CLEAR(lower_word);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1382
        Py_DECREF(word);
1383
    }
1384
    if (PyErr_Occurred())
1385
        goto error;
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1386
    Py_CLEAR(iter);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1387
1388
    /* self._update_cache() */
1389
    CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1390
    Py_DECREF(tmp);
1391
1392
    Py_RETURN_NONE;
1393
1394
error:
1395
    Py_XDECREF(lower_word);
1396
    Py_XDECREF(word);
1397
    Py_XDECREF(iter);
1398
    return NULL;
1399
}
1400
1401
static PyObject *
1402
Compile_is_reserved_word(CompileObject *self, PyObject *word)
1403
{
1404
    PyObject *lower_word = NULL;
1405
    PyObject *result = Py_False;
1406
    PyObject *item;
1407
1408
    /* return self._reserved_words.get(word.lower()) is not None */
1409
    CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
1410
    item = PyDict_GetItem(self->_reserved_words, lower_word);
1411
    if (item == NULL && PyErr_Occurred()) {
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
1412
        goto error;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1413
    } else if (item != NULL && item != Py_None) {
1414
        result = Py_True;
1415
    }
1416
    Py_DECREF(lower_word);
1417
    Py_INCREF(result);
1418
    return result;
1419
1420
error:
1421
    Py_XDECREF(lower_word);
1422
    return NULL;
1423
}
1424
1425
staticforward PyTypeObject Compile_Type;
1426
1427
static PyObject *
1428
Compile_create_child(CompileObject *self, PyObject *args)
1429
{
1430
    /* return self.__class__(self) */
1431
    return PyObject_CallFunctionObjArgs((PyObject *)self->ob_type, self, NULL);
1432
}
1433
1434
static PyObject *
1435
Compile_get_precedence(CompileObject *self, PyObject *type)
1436
{
1437
    /* return self._precedence.get(type, MAX_PRECEDENCE) */
1438
    PyObject *result = PyDict_GetItem(self->_precedence, type);
1439
    if (result == NULL && !PyErr_Occurred()) {
1440
        /* That should be MAX_PRECEDENCE, defined in expr.py */
1441
        return PyInt_FromLong(1000);
1442
    }
1443
    Py_INCREF(result);
1444
    return result;
1445
}
1446
1447
static PyObject *
1448
Compile_set_precedence(CompileObject *self, PyObject *args)
1449
{
1450
    Py_ssize_t size = PyTuple_GET_SIZE(args);
1451
    PyObject *precedence = NULL;
1452
    PyObject *tmp;
1453
    int i;
1454
1455
    if (size < 2) {
1456
        PyErr_SetString(PyExc_TypeError,
1457
                        "set_precedence() takes at least 2 arguments.");
1458
        return NULL;
1459
    }
1460
1461
    /* for type in types: */
1462
    precedence = PyTuple_GET_ITEM(args, 0);
1463
    for (i = 1; i != size; i++) {
1464
        PyObject *type = PyTuple_GET_ITEM(args, i);
1465
        /* self._local_precedence[type] = precedence */
1466
        CATCH(-1, PyDict_SetItem(self->_local_precedence, type, precedence));
1467
    }
1468
1469
    /* self._update_cache() */
1470
    CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1471
    Py_DECREF(tmp);
1472
1473
    Py_RETURN_NONE;
1474
error:
1475
    return NULL;
1476
}
1477
1478
PyObject *
1479
Compile_single(CompileObject *self,
1480
               PyObject *expr, PyObject *state, PyObject *outer_precedence)
1481
{
1482
    PyObject *inner_precedence = NULL;
1483
    PyObject *statement = NULL;
1484
1485
    /* cls = expr.__class__ */
1486
    PyObject *cls = (PyObject *)expr->ob_type;
1487
1488
    /*
1489
       dispatch_table = self._dispatch_table
1490
       if cls in dispatch_table:
1491
           handler = dispatch_table[cls]
1492
       else:
1493
    */
1494
    PyObject *handler = PyDict_GetItem(self->_dispatch_table, cls);
1495
    if (!handler) {
235.5.2 by James Henstridge
Fix a few more C99-isms.
1496
        PyObject *mro;
1497
        Py_ssize_t size, i;
1498
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1499
        if (PyErr_Occurred())
1500
            goto error;
1501
1502
        /* for mro_cls in cls.__mro__: */
235.5.2 by James Henstridge
Fix a few more C99-isms.
1503
        mro = expr->ob_type->tp_mro;
1504
        size = PyTuple_GET_SIZE(mro);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1505
        for (i = 0; i != size; i++) {
1506
            PyObject *mro_cls = PyTuple_GET_ITEM(mro, i);
1507
            /*
1508
               if mro_cls in dispatch_table:
1509
                   handler = dispatch_table[mro_cls]
1510
                   break
1511
            */
1512
            handler = PyDict_GetItem(self->_dispatch_table, mro_cls);
1513
            if (handler)
1514
                break;
1515
1516
            if (PyErr_Occurred())
1517
                goto error;
1518
        }
1519
        /* else: */
1520
        if (i == size) {
1521
            /*
1522
               raise CompileError("Don't know how to compile type %r of %r"
1523
                                  % (expr.__class__, expr))
1524
            */
1525
            PyObject *repr = PyObject_Repr(expr);
1526
            if (repr) {
1527
                PyErr_Format(CompileError,
1528
                             "Don't know how to compile type %s of %s",
1529
                             expr->ob_type->tp_name, PyString_AS_STRING(repr));
1530
                Py_DECREF(repr);
1531
            }
1532
            goto error;
1533
        }
1534
    }
1535
1536
    /*
1537
       inner_precedence = state.precedence = \
1538
                          self._precedence.get(cls, MAX_PRECEDENCE)
1539
    */
1540
    CATCH(NULL, inner_precedence = Compile_get_precedence(self, cls));
1541
    CATCH(-1, PyObject_SetAttrString(state, "precedence", inner_precedence));
1542
1543
    /* statement = handler(self, expr, state) */
1544
    CATCH(NULL, statement = PyObject_CallFunctionObjArgs(handler, self, expr,
1545
                                                         state, NULL));
1546
1547
    /* if inner_precedence < outer_precedence: */
1548
    if (PyObject_Compare(inner_precedence, outer_precedence) == -1) {
235.5.2 by James Henstridge
Fix a few more C99-isms.
1549
        PyObject *args, *tmp;
1550
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1551
        if (PyErr_Occurred())
1552
            goto error;
1553
1554
        /* return "(%s)" % statement */
1555
        CATCH(NULL, args = PyTuple_Pack(1, statement));
1556
        tmp = PyUnicode_Format(parenthesis_format, args);
1557
        Py_DECREF(args);
1558
        CATCH(NULL, tmp);
1559
        Py_DECREF(statement);
1560
        statement = tmp;
1561
    }
1562
1563
    Py_DECREF(inner_precedence);
1564
1565
    return statement;
1566
1567
error:
1568
    Py_XDECREF(inner_precedence);
1569
    Py_XDECREF(statement);
1570
1571
    return NULL;
1572
}
1573
1574
PyObject *
1575
Compile_one_or_many(CompileObject *self, PyObject *expr, PyObject *state,
235.2.19 by Gustavo Niemeyer
psycer is gone.
1576
                    PyObject *join, int raw, int token)
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1577
{
1578
    PyObject *outer_precedence = NULL;
1579
    PyObject *compiled = NULL;
1580
    PyObject *sequence = NULL;
1581
    PyObject *statement = NULL;
1582
    Py_ssize_t size, i;
1583
1584
    Py_INCREF(expr);
1585
1586
    /*
1587
      expr_type = type(expr)
1588
      if (expr_type is SQLRaw or
1589
          raw and (expr_type is str or expr_type is unicode)):
1590
          return expr
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
1591
    */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1592
    if ((PyObject *)expr->ob_type == SQLRaw ||
1593
        (raw && (PyString_CheckExact(expr) || PyUnicode_CheckExact(expr)))) {
1594
        /* Pass our reference on. */
1595
        return expr;
1596
    }
1597
1598
    /*
1599
       if token and (expr_type is str or expr_type is unicode):
1600
           expr = SQLToken(expr)
1601
    */
1602
    if (token && (PyString_CheckExact(expr) || PyUnicode_CheckExact(expr))) {
1603
        PyObject *tmp;
1604
        CATCH(NULL, tmp = PyObject_CallFunctionObjArgs(SQLToken, expr, NULL));
1605
        Py_DECREF(expr);
1606
        expr = tmp;
1607
    }
1608
1609
    /*
1610
       if state is None:
1611
           state = State()
1612
    */
1613
    /* That's done in Compile__call__ just once. */
1614
1615
    /* outer_precedence = state.precedence */
1616
    CATCH(NULL, outer_precedence = PyObject_GetAttrString(state, "precedence"));
1617
    /* if expr_type is tuple or expr_type is list: */
1618
    if (PyTuple_CheckExact(expr) || PyList_CheckExact(expr)) {
1619
        /* compiled = [] */
1620
        CATCH(NULL, compiled = PyList_New(0));
1621
1622
        /* for subexpr in expr: */
1623
        sequence = PySequence_Fast(expr, "This can't actually fail! ;-)");
1624
        size = PySequence_Fast_GET_SIZE(sequence);
1625
        for (i = 0; i != size; i++) {
1626
            PyObject *subexpr = PySequence_Fast_GET_ITEM(sequence, i);
1627
            /*
1628
               subexpr_type = type(subexpr)
1629
               if subexpr_type is SQLRaw or raw and (subexpr_type is str or
1630
                                                     subexpr_type is unicode):
1631
            */
1632
            if ((PyObject *)subexpr->ob_type == (PyObject *)SQLRaw ||
1633
                (raw && (PyString_CheckExact(subexpr) ||
1634
                         PyUnicode_CheckExact(subexpr)))) {
1635
                /* statement = subexpr */
1636
                Py_INCREF(subexpr);
1637
                statement = subexpr;
1638
            /* elif subexpr_type is tuple or subexpr_type is list: */
1639
            } else if (PyTuple_CheckExact(subexpr) ||
1640
                       PyList_CheckExact(subexpr)) {
1641
                /* state.precedence = outer_precedence */
1642
                CATCH(-1, PyObject_SetAttrString(state, "precedence",
1643
                                                 outer_precedence));
1644
                /* statement = self(subexpr, state, join, raw, token) */
1645
                CATCH(NULL,
1646
                      statement = Compile_one_or_many(self, subexpr, state,
1647
                                                      join, raw, token));
1648
            /* else: */
1649
            } else {
1650
                /*
1651
                   if token and (subexpr_type is unicode or
1652
                                 subexpr_type is str):
1653
                */
1654
                if (token && (PyUnicode_CheckExact(subexpr) ||
1655
                              PyString_CheckExact(subexpr))) {
1656
                    /* subexpr = SQLToken(subexpr) */
1657
                    CATCH(NULL,
1658
                          subexpr = PyObject_CallFunctionObjArgs(SQLToken,
1659
                                                                 subexpr,
1660
                                                                 NULL));
1661
                } else {
1662
                    Py_INCREF(subexpr);
1663
                }
1664
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
1665
                /*
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1666
                   statement = self._compile_single(subexpr, state,
1667
                                                    outer_precedence)
1668
                */
1669
                statement = Compile_single(self, subexpr, state,
1670
                                           outer_precedence);
1671
                Py_DECREF(subexpr);
1672
                CATCH(NULL, statement);
1673
            }
269.1.2 by Thomas Hervé
Remove tp_hash and tp_richcompare in the C implementation of Variable.
1674
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1675
            /* compiled.append(statement) */
1676
            CATCH(-1, PyList_Append(compiled, statement));
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1677
            Py_CLEAR(statement);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1678
        }
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1679
        Py_CLEAR(sequence);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1680
1681
        /* statement = join.join(compiled) */
1682
        CATCH(NULL, statement = PyUnicode_Join(join, compiled));
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1683
        Py_CLEAR(compiled);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1684
    } else {
1685
        /* statement = self._compile_single(expr, state, outer_precedence) */
1686
        CATCH(NULL, statement = Compile_single(self, expr, state,
1687
                                               outer_precedence));
1688
    }
1689
1690
    /* state.precedence = outer_precedence */
1691
    CATCH(-1, PyObject_SetAttrString(state, "precedence", outer_precedence));
235.2.18 by Gustavo Niemeyer
Replaced custom DECREF by Py_CLEAR, as suggested by James.
1692
    Py_CLEAR(outer_precedence);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1693
1694
    Py_DECREF(expr);
1695
1696
    return statement;
1697
1698
error:
1699
    Py_XDECREF(expr);
1700
    Py_XDECREF(outer_precedence);
1701
    Py_XDECREF(compiled);
1702
    Py_XDECREF(sequence);
1703
    Py_XDECREF(statement);
1704
1705
    return NULL;
1706
}
1707
1708
static PyObject *
1709
Compile__call__(CompileObject *self, PyObject *args, PyObject *kwargs)
1710
{
1711
    static char *kwlist[] = {"expr", "state", "join", "raw", "token", NULL};
1712
    PyObject *expr = NULL;
1713
    PyObject *state = Py_None;
235.5.1 by James Henstridge
* Fix reference leak in Variable_set_state().
1714
    PyObject *join;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1715
    char raw = 0;
1716
    char token = 0;
1717
235.2.22 by Gustavo Niemeyer
Fixed bug in Compile__call__ pointed out by James.
1718
    PyObject *result = NULL;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1719
235.5.1 by James Henstridge
* Fix reference leak in Variable_set_state().
1720
    if (!initialize_globals())
1721
        return NULL;
1722
1723
    join = default_compile_join;
1724
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1725
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OSbb", kwlist,
1726
                                     &expr, &state, &join, &raw, &token)) {
1727
        return NULL;
1728
    }
1729
1730
    if (state == Py_None) {
235.2.22 by Gustavo Niemeyer
Fixed bug in Compile__call__ pointed out by James.
1731
        state = PyObject_CallFunctionObjArgs(State, NULL);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1732
    } else {
1733
        Py_INCREF(state);
1734
    }
235.2.22 by Gustavo Niemeyer
Fixed bug in Compile__call__ pointed out by James.
1735
    if (state) {
1736
        result = Compile_one_or_many(self, expr, state, join, raw, token);
1737
        Py_DECREF(state);
1738
    }
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1739
    return result;
1740
}
1741
1742
1743
static PyMethodDef Compile_methods[] = {
1744
    {"_update_cache", (PyCFunction)Compile__update_cache, METH_NOARGS, NULL},
1745
    {"when", (PyCFunction)Compile_when, METH_VARARGS, NULL},
1746
    {"add_reserved_words", (PyCFunction)Compile_add_reserved_words,
1747
        METH_O, NULL},
1748
    {"remove_reserved_words", (PyCFunction)Compile_remove_reserved_words,
1749
        METH_O, NULL},
1750
    {"is_reserved_word", (PyCFunction)Compile_is_reserved_word, METH_O, NULL},
1751
    {"create_child", (PyCFunction)Compile_create_child, METH_NOARGS, NULL},
1752
    {"get_precedence", (PyCFunction)Compile_get_precedence, METH_O, NULL},
1753
    {"set_precedence", (PyCFunction)Compile_set_precedence, METH_VARARGS, NULL},
1754
    {NULL, NULL}
1755
};
1756
1757
#define OFFSETOF(x) offsetof(CompileObject, x)
1758
static PyMemberDef Compile_members[] = {
1759
    {"_local_dispatch_table", T_OBJECT, OFFSETOF(_local_dispatch_table), 0, 0},
1760
    {"_local_precedence", T_OBJECT, OFFSETOF(_local_precedence), 0, 0},
1761
    {"_local_reserved_words", T_OBJECT, OFFSETOF(_local_reserved_words), 0, 0},
1762
    {"_dispatch_table", T_OBJECT, OFFSETOF(_dispatch_table), 0, 0},
1763
    {"_precedence", T_OBJECT, OFFSETOF(_precedence), 0, 0},
1764
    {"_reserved_words", T_OBJECT, OFFSETOF(_reserved_words), 0, 0},
1765
    {"_children", T_OBJECT, OFFSETOF(_children), 0, 0},
1766
    {"_parents", T_OBJECT, OFFSETOF(_parents), 0, 0},
1767
    {NULL}
1768
};
1769
#undef OFFSETOF
1770
1771
statichere PyTypeObject Compile_Type = {
1772
    PyObject_HEAD_INIT(NULL)
1773
    0,            /*ob_size*/
1774
    "storm.variables.Compile",    /*tp_name*/
1775
    sizeof(CompileObject), /*tp_basicsize*/
1776
    0,            /*tp_itemsize*/
1777
    (destructor)Compile_dealloc, /*tp_dealloc*/
1778
    0,            /*tp_print*/
1779
    0,            /*tp_getattr*/
1780
    0,            /*tp_setattr*/
1781
    0,            /*tp_compare*/
1782
    0,          /*tp_repr*/
1783
    0,            /*tp_as_number*/
1784
    0,            /*tp_as_sequence*/
1785
    0,            /*tp_as_mapping*/
1786
    0,                      /*tp_hash*/
1787
    (ternaryfunc)Compile__call__, /*tp_call*/
1788
    0,                      /*tp_str*/
305.2.2 by James Henstridge
Clean up build patch a bit:
1789
    0,                      /*tp_getattro*/
1790
    0,                      /*tp_setattro*/
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1791
    0,                      /*tp_as_buffer*/
1792
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
1793
    0,                      /*tp_doc*/
1794
    (traverseproc)Compile_traverse,  /*tp_traverse*/
1795
    (inquiry)Compile_clear,          /*tp_clear*/
1796
    0,                      /*tp_richcompare*/
1797
    offsetof(CompileObject, __weakreflist), /*tp_weaklistoffset*/
1798
    0,                      /*tp_iter*/
1799
    0,                      /*tp_iternext*/
1800
    Compile_methods,        /*tp_methods*/
1801
    Compile_members,        /*tp_members*/
1802
    0,                      /*tp_getset*/
1803
    0,                      /*tp_base*/
1804
    0,                      /*tp_dict*/
1805
    0,                      /*tp_descr_get*/
1806
    0,                      /*tp_descr_set*/
1807
    0,                      /*tp_dictoffset*/
1808
    (initproc)Compile_init, /*tp_init*/
305.2.2 by James Henstridge
Clean up build patch a bit:
1809
    0,                      /*tp_alloc*/
1810
    0,                      /*tp_new*/
1811
    0,                      /*tp_free*/
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1812
    0,                      /*tp_is_gc*/
1813
};
1814
1815
1816
static PyObject *
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1817
ObjectInfo__emit_object_deleted(ObjectInfoObject *self, PyObject *args)
1818
{
1819
    /* self.event.emit("object-deleted") */
1820
    return PyObject_CallMethod(self->event, "emit", "s", "object-deleted");
1821
}
1822
1823
static PyMethodDef ObjectInfo_deleted_callback =
1824
    {"_emit_object_deleted", (PyCFunction)ObjectInfo__emit_object_deleted,
1825
        METH_O, NULL};
1826
1827
static int
1828
ObjectInfo_init(ObjectInfoObject *self, PyObject *args)
1829
{
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1830
    PyObject *self_get_obj = NULL;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1831
    PyObject *empty_args = NULL;
1832
    PyObject *factory_kwargs = NULL;
1833
    PyObject *columns = NULL;
1834
    PyObject *primary_key = NULL;
1835
    PyObject *obj;
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
1836
    Py_ssize_t i;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1837
1838
    empty_args = PyTuple_New(0);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1839
1840
    CATCH(-1, PyDict_Type.tp_init((PyObject *)self, empty_args, NULL));
1841
1842
    CATCH(0, initialize_globals());
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1843
1844
    if (!PyArg_ParseTuple(args, "O", &obj))
1845
        goto error;
1846
1847
    /* self.cls_info = get_cls_info(type(obj)) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1848
    CATCH(NULL, self->cls_info = PyObject_CallFunctionObjArgs(get_cls_info,
1849
                                                              obj->ob_type,
1850
                                                              NULL));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1851
1852
    /* self.set_obj(obj) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1853
    CATCH(NULL, self->__obj_ref_callback =
1854
                    PyCFunction_NewEx(&ObjectInfo_deleted_callback,
1855
                                      (PyObject *)self, NULL));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1856
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1857
    CATCH(NULL,
1858
          self->__obj_ref = PyWeakref_NewRef(obj, self->__obj_ref_callback));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1859
1860
    /* self.event = event = EventSystem(self) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1861
    CATCH(NULL,
1862
          self->event = PyObject_CallFunctionObjArgs(EventSystem, self, NULL));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1863
1864
    /* self->variables = variables = {} */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1865
    CATCH(NULL, self->variables = PyDict_New());
1866
1867
    CATCH(NULL, self_get_obj = PyObject_GetAttrString((PyObject *)self,
1868
                                                      "get_obj"));
1869
    CATCH(NULL, factory_kwargs = PyDict_New());
1870
    CATCH(-1, PyDict_SetItemString(factory_kwargs, "event", self->event));
1871
    CATCH(-1, PyDict_SetItemString(factory_kwargs, "validator_object_factory",
1872
                                   self_get_obj));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1873
1874
    /* for column in self.cls_info.columns: */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1875
    CATCH(NULL, columns = PyObject_GetAttrString(self->cls_info, "columns"));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1876
    for (i = 0; i != PyTuple_GET_SIZE(columns); i++) {
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1877
        /*
1878
           variables[column] = \
1879
               column.variable_factory(column=column,
1880
                                       event=event,
1881
                                       validator_object_factory=self.get_obj)
1882
        */
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1883
        PyObject *column = PyTuple_GET_ITEM(columns, i);
1884
        PyObject *variable, *factory;
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1885
        CATCH(-1, PyDict_SetItemString(factory_kwargs, "column", column));
1886
        CATCH(NULL, factory = PyObject_GetAttrString(column,
1887
                                                     "variable_factory"));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1888
        variable = PyObject_Call(factory, empty_args, factory_kwargs);
1889
        Py_DECREF(factory);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1890
        CATCH(NULL, variable);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1891
        if (PyDict_SetItem(self->variables, column, variable) == -1) {
1892
            Py_DECREF(variable);
1893
            goto error;
1894
        }
1895
        Py_DECREF(variable);
1896
    }
1897
1898
    /* self.primary_vars = tuple(variables[column]
1899
                                 for column in self.cls_info.primary_key) */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1900
    CATCH(NULL, primary_key = PyObject_GetAttrString((PyObject *)self->cls_info,
1901
                                                     "primary_key"));
1902
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1903
    /* XXX Check primary_key type here. */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1904
    CATCH(NULL,
1905
          self->primary_vars = PyTuple_New(PyTuple_GET_SIZE(primary_key)));
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1906
    for (i = 0; i != PyTuple_GET_SIZE(primary_key); i++) {
1907
        PyObject *column = PyTuple_GET_ITEM(primary_key, i);
1908
        PyObject *variable = PyDict_GetItem(self->variables, column);
1909
        Py_INCREF(variable);
1910
        PyTuple_SET_ITEM(self->primary_vars, i, variable);
1911
    }
1912
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1913
    Py_DECREF(self_get_obj);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1914
    Py_DECREF(empty_args);
1915
    Py_DECREF(factory_kwargs);
1916
    Py_DECREF(columns);
1917
    Py_DECREF(primary_key);
1918
    return 0;
1919
1920
error:
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1921
    Py_XDECREF(self_get_obj);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1922
    Py_XDECREF(empty_args);
1923
    Py_XDECREF(factory_kwargs);
1924
    Py_XDECREF(columns);
1925
    Py_XDECREF(primary_key);
1926
    return -1;
1927
}
1928
1929
static PyObject *
1930
ObjectInfo_get_obj(ObjectInfoObject *self, PyObject *args)
1931
{
1932
    PyObject *obj = PyWeakref_GET_OBJECT(self->__obj_ref);
1933
    Py_INCREF(obj);
1934
    return obj;
1935
}
1936
1937
static PyObject *
1938
ObjectInfo_set_obj(ObjectInfoObject *self, PyObject *args)
1939
{
1940
    PyObject *obj;
1941
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1942
    /* self._ref = ref(obj, self._emit_object_deleted) */
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1943
    if (!PyArg_ParseTuple(args, "O", &obj))
1944
        return NULL;
1945
1946
    Py_DECREF(self->__obj_ref);
1947
    self->__obj_ref = PyWeakref_NewRef(obj, self->__obj_ref_callback);
1948
    if (!self->__obj_ref)
1949
        return NULL;
1950
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1951
    Py_RETURN_NONE;
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1952
}
1953
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
1954
static PyObject *
1955
ObjectInfo_checkpoint(ObjectInfoObject *self, PyObject *args)
1956
{
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1957
    PyObject *column, *variable, *tmp;
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
1958
    Py_ssize_t i = 0;
1959
1960
    /* for variable in self.variables.itervalues(): */
1961
    while (PyDict_Next(self->variables, &i, &column, &variable)) {
1962
        /* variable.checkpoint() */
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1963
        CATCH(NULL, tmp = PyObject_CallMethod(variable, "checkpoint", NULL));
1964
        Py_DECREF(tmp);
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
1965
    }
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
1966
    Py_RETURN_NONE;
1967
error:
1968
    return NULL;
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
1969
}
1970
1971
static PyObject *
1972
ObjectInfo__storm_object_info__(PyObject *self, void *closure)
1973
{
1974
    /* __storm_object_info__ = property(lambda self:self) */
1975
    Py_INCREF(self);
1976
    return self;
1977
}
1978
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1979
static int
1980
ObjectInfo_traverse(ObjectInfoObject *self, visitproc visit, void *arg)
1981
{
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
1982
    Py_VISIT(self->__obj_ref);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
1983
    Py_VISIT(self->__obj_ref_callback);
1984
    Py_VISIT(self->cls_info);
1985
    Py_VISIT(self->event);
1986
    Py_VISIT(self->variables);
1987
    Py_VISIT(self->primary_vars);
1988
    return PyDict_Type.tp_traverse((PyObject *)self, visit, arg);
1989
}
1990
1991
static int
1992
ObjectInfo_clear(ObjectInfoObject *self)
1993
{
1994
    Py_CLEAR(self->__obj_ref);
1995
    Py_CLEAR(self->__obj_ref_callback);
1996
    Py_CLEAR(self->cls_info);
1997
    Py_CLEAR(self->event);
1998
    Py_CLEAR(self->variables);
1999
    Py_CLEAR(self->primary_vars);
2000
    return PyDict_Type.tp_clear((PyObject *)self);
2001
}
2002
305.2.2 by James Henstridge
Clean up build patch a bit:
2003
static PyObject *
2004
ObjectInfo_richcompare(PyObject *self, PyObject *other, int op)
2005
{
2006
    PyObject *res;
2007
2008
    /* Implement equality via object identity. */
2009
    switch (op) {
2010
    case Py_EQ:
2011
        res = (self == other) ? Py_True : Py_False;
2012
        break;
2013
    case Py_NE:
2014
        res = (self != other) ? Py_True : Py_False;
2015
        break;
2016
    default:
2017
        res = Py_NotImplemented;
2018
    }
2019
    Py_INCREF(res);
2020
    return res;
2021
}
2022
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2023
static void
2024
ObjectInfo_dealloc(ObjectInfoObject *self)
2025
{
142.2.4 by Gustavo Niemeyer
Oops.. we don't like tabs, even in C files.
2026
    if (self->__weakreflist)
2027
        PyObject_ClearWeakRefs((PyObject *)self);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2028
    Py_CLEAR(self->__obj_ref);
2029
    Py_CLEAR(self->__obj_ref_callback);
2030
    Py_CLEAR(self->cls_info);
2031
    Py_CLEAR(self->event);
2032
    Py_CLEAR(self->variables);
2033
    Py_CLEAR(self->primary_vars);
235.5.2 by James Henstridge
Fix a few more C99-isms.
2034
    PyDict_Type.tp_dealloc((PyObject *)self);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2035
}
2036
2037
static PyMethodDef ObjectInfo_methods[] = {
2038
    {"_emit_object_deleted", (PyCFunction)ObjectInfo__emit_object_deleted,
2039
        METH_O, NULL},
2040
    {"get_obj", (PyCFunction)ObjectInfo_get_obj, METH_NOARGS, NULL},
2041
    {"set_obj", (PyCFunction)ObjectInfo_set_obj, METH_VARARGS, NULL},
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
2042
    {"checkpoint", (PyCFunction)ObjectInfo_checkpoint, METH_VARARGS, NULL},
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2043
    {NULL, NULL}
2044
};
2045
2046
#define OFFSETOF(x) offsetof(ObjectInfoObject, x)
2047
static PyMemberDef ObjectInfo_members[] = {
2048
    {"cls_info", T_OBJECT, OFFSETOF(cls_info), 0, 0},
2049
    {"event", T_OBJECT, OFFSETOF(event), 0, 0},
2050
    {"variables", T_OBJECT, OFFSETOF(variables), 0, 0},
2051
    {"primary_vars", T_OBJECT, OFFSETOF(primary_vars), 0, 0},
2052
    {NULL}
2053
};
2054
#undef OFFSETOF
2055
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
2056
static PyGetSetDef ObjectInfo_getset[] = {
2057
    {"__storm_object_info__", (getter)ObjectInfo__storm_object_info__,
2058
        NULL, NULL},
2059
    {NULL}
2060
};
2061
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2062
statichere PyTypeObject ObjectInfo_Type = {
142.2.4 by Gustavo Niemeyer
Oops.. we don't like tabs, even in C files.
2063
    PyObject_HEAD_INIT(NULL)
2064
    0,            /*ob_size*/
2065
    "storm.info.ObjectInfo", /*tp_name*/
2066
    sizeof(ObjectInfoObject), /*tp_basicsize*/
2067
    0,            /*tp_itemsize*/
2068
    (destructor)ObjectInfo_dealloc, /*tp_dealloc*/
2069
    0,            /*tp_print*/
2070
    0,            /*tp_getattr*/
2071
    0,            /*tp_setattr*/
2072
    0,            /*tp_compare*/
2073
    0,            /*tp_repr*/
2074
    0,            /*tp_as_number*/
2075
    0,            /*tp_as_sequence*/
2076
    0,            /*tp_as_mapping*/
305.2.2 by James Henstridge
Clean up build patch a bit:
2077
    0,                      /*tp_hash*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2078
    0,                      /*tp_call*/
2079
    0,                      /*tp_str*/
305.2.2 by James Henstridge
Clean up build patch a bit:
2080
    0,                      /*tp_getattro*/
2081
    0,                      /*tp_setattro*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2082
    0,                      /*tp_as_buffer*/
2083
    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2084
    0,                      /*tp_doc*/
2085
    (traverseproc)ObjectInfo_traverse, /*tp_traverse*/
2086
    (inquiry)ObjectInfo_clear, /*tp_clear*/
305.2.2 by James Henstridge
Clean up build patch a bit:
2087
    ObjectInfo_richcompare, /*tp_richcompare*/
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
2088
    offsetof(ObjectInfoObject, __weakreflist), /*tp_weaklistoffset*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2089
    0,                      /*tp_iter*/
2090
    0,                      /*tp_iternext*/
2091
    ObjectInfo_methods,     /*tp_methods*/
2092
    ObjectInfo_members,     /*tp_members*/
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
2093
    ObjectInfo_getset,      /*tp_getset*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2094
    0,                      /*tp_base*/
2095
    0,                      /*tp_dict*/
2096
    0,                      /*tp_descr_get*/
2097
    0,                      /*tp_descr_set*/
2098
    0,                      /*tp_dictoffset*/
2099
    (initproc)ObjectInfo_init, /*tp_init*/
305.2.2 by James Henstridge
Clean up build patch a bit:
2100
    0,                      /*tp_alloc*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2101
    0,                      /*tp_new*/
305.2.2 by James Henstridge
Clean up build patch a bit:
2102
    0,                      /*tp_free*/
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2103
    0,                      /*tp_is_gc*/
2104
};
2105
2106
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
2107
static PyObject *
2108
get_obj_info(PyObject *self, PyObject *obj)
2109
{
2110
    PyObject *obj_info;
2111
2112
    if (obj->ob_type == &ObjectInfo_Type) {
2113
        /* Much better than asking the ObjectInfo to return itself. ;-) */
2114
        Py_INCREF(obj);
2115
        return obj;
2116
    }
2117
2118
    /* try:
2119
          return obj.__storm_object_info__ */
2120
    obj_info = PyObject_GetAttrString(obj, "__storm_object_info__");
2121
2122
    /* except AttributeError: */
2123
    if (obj_info == NULL) {
2124
        PyErr_Clear();
2125
2126
        /* obj_info = ObjectInfo(obj) */
2127
        obj_info = PyObject_CallFunctionObjArgs((PyObject *)&ObjectInfo_Type,
2128
                                                obj, NULL);
2129
        if (!obj_info)
2130
            return NULL;
2131
2132
        /* return obj.__dict__.setdefault("__storm_object_info__", obj_info) */
2133
        if (PyObject_SetAttrString(obj, "__storm_object_info__",
2134
                                   obj_info) == -1)
2135
            return NULL;
2136
    }
2137
2138
    return obj_info;
2139
}
2140
2141
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2142
static PyMethodDef cextensions_methods[] = {
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
2143
    {"get_obj_info", (PyCFunction)get_obj_info, METH_O, NULL},
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2144
    {NULL, NULL}
2145
};
2146
305.2.2 by James Henstridge
Clean up build patch a bit:
2147
2148
static int
2149
prepare_type(PyTypeObject *type)
2150
{
2151
    if (!type->tp_getattro && !type->tp_getattr)
2152
        type->tp_getattro = PyObject_GenericGetAttr;
2153
    if (!type->tp_setattro && !type->tp_setattr)
2154
        type->tp_setattro = PyObject_GenericSetAttr;
2155
    if (!type->tp_alloc)
2156
        type->tp_alloc = PyType_GenericAlloc;
2157
    /* Don't fill in tp_new if this class has a base class */
2158
    if (!type->tp_base && !type->tp_new)
2159
        type->tp_new = PyType_GenericNew;
2160
    if (!type->tp_free) {
305.2.3 by James Henstridge
Fix typo.
2161
        assert((type->tp_flags & Py_TPFLAGS_HAVE_GC) != 0);
305.2.2 by James Henstridge
Clean up build patch a bit:
2162
        type->tp_free = PyObject_GC_Del;
2163
    }
2164
    return PyType_Ready(type);
2165
}
142.2.3 by Gustavo Niemeyer
- Finished implementation of the C version of ObjectInfo
2166
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2167
DL_EXPORT(void)
2168
initcextensions(void)
2169
{
2170
    PyObject *module;
305.2.2 by James Henstridge
Clean up build patch a bit:
2171
2172
    prepare_type(&EventSystem_Type);
2173
    prepare_type(&Compile_Type);
2174
    ObjectInfo_Type.tp_base = &PyDict_Type;
305.2.1 by Michał Pasternak
Patch from Michał Pasternak to improve build on Windows.
2175
    ObjectInfo_Type.tp_hash = (hashfunc)_Py_HashPointer;
305.2.2 by James Henstridge
Clean up build patch a bit:
2176
    prepare_type(&ObjectInfo_Type);
2177
    prepare_type(&Variable_Type);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2178
2179
    module = Py_InitModule3("cextensions", cextensions_methods, "");
2180
    Py_INCREF(&Variable_Type);
2181
2182
#define REGISTER_TYPE(name) \
2183
    do { \
2184
        Py_INCREF(&name##_Type); \
2185
        PyModule_AddObject(module, #name, (PyObject*)&name##_Type); \
2186
    } while(0)
2187
2188
    REGISTER_TYPE(Variable);
2189
    REGISTER_TYPE(ObjectInfo);
235.2.1 by Gustavo Niemeyer
Several improvements in cextensions:
2190
    REGISTER_TYPE(Compile);
235.2.12 by Gustavo Niemeyer
Implemented EventSystem in cextensions!
2191
    REGISTER_TYPE(EventSystem);
142.2.1 by Gustavo Niemeyer
- Started to build a cextensions module, which will offer alternative
2192
}
2193
2194
/* vim:ts=4:sw=4:et
2195
*/