1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6  */
7 
8 #include "formula_tokens.hpp"
9 #include "formula_token.hpp"
10 #include "orcus/spreadsheet/document.hpp"
11 
12 #include <ixion/formula_tokens.hpp>
13 #include <structmember.h>
14 
15 namespace ss = orcus::spreadsheet;
16 
17 namespace orcus { namespace python {
18 
19 namespace {
20 
21 /** non-python part. */
22 struct formula_tokens_data
23 {
24     const ss::document* doc;
25     ixion::abs_address_t origin;
26     const ixion::formula_tokens_t* tokens = nullptr;
27     ixion::formula_tokens_t::const_iterator pos;
28     ixion::formula_tokens_t::const_iterator end;
29 };
30 
31 /** python object */
32 struct pyobj_formula_tokens
33 {
34     PyObject_HEAD
35 
36     formula_tokens_data* data = nullptr;
37 };
38 
t(PyObject * self)39 inline pyobj_formula_tokens* t(PyObject* self)
40 {
41     return reinterpret_cast<pyobj_formula_tokens*>(self);
42 }
43 
init_members(pyobj_formula_tokens * self,const ss::document & doc,const ixion::abs_address_t & origin,const ixion::formula_tokens_t & tokens)44 void init_members(
45     pyobj_formula_tokens* self, const ss::document& doc, const ixion::abs_address_t& origin, const ixion::formula_tokens_t& tokens)
46 {
47     assert(self->data);
48     self->data->doc = &doc;
49     self->data->origin = origin;
50     self->data->tokens = &tokens;
51 }
52 
tp_dealloc(pyobj_formula_tokens * self)53 void tp_dealloc(pyobj_formula_tokens* self)
54 {
55     delete self->data;
56     Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
57 }
58 
tp_init(pyobj_formula_tokens * self,PyObject *,PyObject *)59 int tp_init(pyobj_formula_tokens* self, PyObject* /*args*/, PyObject* /*kwargs*/)
60 {
61     return 0;
62 }
63 
tp_new(PyTypeObject * type,PyObject *,PyObject *)64 PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/)
65 {
66     pyobj_formula_tokens* self = t(type->tp_alloc(type, 0));
67     self->data = new formula_tokens_data;
68     return reinterpret_cast<PyObject*>(self);
69 }
70 
tp_iter(PyObject * self)71 PyObject* tp_iter(PyObject* self)
72 {
73     formula_tokens_data& data = *t(self)->data;
74     data.pos = data.tokens->cbegin();
75     data.end = data.tokens->cend();
76 
77     Py_INCREF(self);
78     return self;
79 }
80 
tp_iternext(PyObject * self)81 PyObject* tp_iternext(PyObject* self)
82 {
83     formula_tokens_data& data = *t(self)->data;
84 
85     if (data.pos == data.end)
86     {
87         // No more elements.  Stop the iteration.
88         PyErr_SetNone(PyExc_StopIteration);
89         return nullptr;
90     }
91 
92     PyObject* ft_obj = create_formula_token_object(*data.doc, data.origin, **data.pos);
93     ++data.pos;
94     return ft_obj;
95 }
96 
sq_length(PyObject * self)97 Py_ssize_t sq_length(PyObject* self)
98 {
99     formula_tokens_data& data = *t(self)->data;
100     return data.tokens->size();
101 }
102 
103 PySequenceMethods tp_as_sequence =
104 {
105     sq_length, // lenfunc sq_length
106     0,         // binaryfunc sq_concat
107     0,         // ssizeargfunc sq_repeat
108     0,         // ssizeargfunc sq_item
109     0,         // void *was_sq_slice
110     0,         // ssizeobjargproc sq_ass_item
111     0,         // void *was_sq_ass_slice
112     0,         // objobjproc sq_contains
113     0,         // binaryfunc sq_inplace_concat
114     0,         // ssizeargfunc sq_inplace_repeat
115 };
116 
117 PyMethodDef tp_methods[] =
118 {
119     { nullptr }
120 };
121 
122 PyMemberDef tp_members[] =
123 {
124     { nullptr }
125 };
126 
127 PyTypeObject formula_tokens_type =
128 {
129     PyVarObject_HEAD_INIT(nullptr, 0)
130     "orcus.FormulaTokens",                    // tp_name
131     sizeof(pyobj_formula_tokens),             // tp_basicsize
132     0,                                        // tp_itemsize
133     (destructor)tp_dealloc,                   // tp_dealloc
134     0,                                        // tp_print
135     0,                                        // tp_getattr
136     0,                                        // tp_setattr
137     0,                                        // tp_compare
138     0,                                        // tp_repr
139     0,                                        // tp_as_number
140     &tp_as_sequence,                          // tp_as_sequence
141     0,                                        // tp_as_mapping
142     0,                                        // tp_hash
143     0,                                        // tp_call
144     0,                                        // tp_str
145     0,                                        // tp_getattro
146     0,                                        // tp_setattro
147     0,                                        // tp_as_buffer
148     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
149     "orcus spreadsheet formula tokens",       // tp_doc
150     0,		                                  // tp_traverse
151     0,		                                  // tp_clear
152     0,		                                  // tp_richcompare
153     0,		                                  // tp_weaklistoffset
154     tp_iter,		                          // tp_iter
155     tp_iternext,                              // tp_iternext
156     tp_methods,                               // tp_methods
157     tp_members,                               // tp_members
158     0,                                        // tp_getset
159     0,                                        // tp_base
160     0,                                        // tp_dict
161     0,                                        // tp_descr_get
162     0,                                        // tp_descr_set
163     0,                                        // tp_dictoffset
164     (initproc)tp_init,                        // tp_init
165     0,                                        // tp_alloc
166     tp_new,                                   // tp_new
167 };
168 
169 } // anonymous namespace
170 
create_formula_tokens_iterator_object(const ss::document & doc,const ixion::abs_address_t & origin,const ixion::formula_tokens_t & tokens)171 PyObject* create_formula_tokens_iterator_object(
172     const ss::document& doc, const ixion::abs_address_t& origin, const ixion::formula_tokens_t& tokens)
173 {
174     PyTypeObject* ft_type = get_formula_tokens_type();
175     if (!ft_type)
176     {
177         PyErr_SetString(PyExc_RuntimeError, "Failed to get the formula tokens type object.");
178         return nullptr;
179     }
180 
181     PyObject* obj = ft_type->tp_new(ft_type, nullptr, nullptr);
182     if (!obj)
183     {
184         PyErr_SetString(PyExc_RuntimeError, "Failed to instantiate a formula tokens object.");
185         return nullptr;
186     }
187 
188     init_members(t(obj), doc, origin, tokens);
189 
190     return obj;
191 }
192 
get_formula_tokens_type()193 PyTypeObject* get_formula_tokens_type()
194 {
195     return &formula_tokens_type;
196 }
197 
198 }}
199 
200 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
201