diff options
Diffstat (limited to '')
-rw-r--r-- | src/python/named_expressions.cpp | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/src/python/named_expressions.cpp b/src/python/named_expressions.cpp new file mode 100644 index 0000000..6faffee --- /dev/null +++ b/src/python/named_expressions.cpp @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "named_expressions.hpp" +#include "named_expression.hpp" +#include "global.hpp" +#include "orcus/spreadsheet/document.hpp" + +#include <ixion/formula.hpp> +#include <ixion/model_context.hpp> +#include <ixion/named_expressions_iterator.hpp> +#include <ixion/formula_name_resolver.hpp> +#include <structmember.h> + +namespace ss = orcus::spreadsheet; + +namespace orcus { namespace python { + +namespace { + +/** non-python part. */ +struct named_exps_data +{ + ss::sheet_t origin_sheet = -1; // -1 for global, >=0 for sheet local. + const ss::document* doc = nullptr; + ixion::named_expressions_iterator src; // original iterator to copy from. + ixion::named_expressions_iterator iter; +}; + +/** python object. */ +struct pyobj_named_exps +{ + PyObject_HEAD + + named_exps_data* data; +}; + +inline pyobj_named_exps* t(PyObject* self) +{ + return reinterpret_cast<pyobj_named_exps*>(self); +} + +PyObject* named_exps_names(PyObject* self, PyObject* /*args*/, PyObject* /*kwargs*/) +{ + named_exps_data& data = *t(self)->data; + PyObject* s = PySet_New(nullptr); + + for (auto iter = data.src; iter.has(); iter.next()) + { + const std::string* name = iter.get().name; + PySet_Add(s, PyUnicode_FromStringAndSize(name->data(), name->size())); + } + + return s; +} + +void tp_dealloc(pyobj_named_exps* self) +{ + delete self->data; + Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); +} + +int tp_init(pyobj_named_exps* /*self*/, PyObject* /*args*/, PyObject* /*kwargs*/) +{ + return 0; +} + +PyObject* tp_new(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwargs*/) +{ + pyobj_named_exps* self = t(type->tp_alloc(type, 0)); + self->data = new named_exps_data; + return reinterpret_cast<PyObject*>(self); +} + +PyObject* tp_iter(PyObject* self) +{ + named_exps_data& data = *t(self)->data; + data.iter = data.src; + + Py_INCREF(self); + return self; +} + +PyObject* tp_iternext(PyObject* self) +{ + named_exps_data& data = *t(self)->data; + auto& iter = data.iter; + + if (!iter.has()) + { + PyErr_SetNone(PyExc_StopIteration); + return nullptr; + } + + ixion::named_expressions_iterator::named_expression item = iter.get(); + iter.next(); + + PyObject* name = PyUnicode_FromStringAndSize(item.name->data(), item.name->size()); + if (!name) + return nullptr; + + PyObject* ne = create_named_exp_object(*data.doc, item.expression); + if (!ne) + return nullptr; + + PyObject* tup = PyTuple_New(2); + PyTuple_SET_ITEM(tup, 0, name); + PyTuple_SET_ITEM(tup, 1, ne); + + return tup; +} + +Py_ssize_t sq_length(PyObject* self) +{ + named_exps_data& data = *t(self)->data; + return data.src.size(); +} + +PySequenceMethods tp_as_sequence = +{ + sq_length, // lenfunc sq_length + 0, // binaryfunc sq_concat + 0, // ssizeargfunc sq_repeat + 0, // ssizeargfunc sq_item + 0, // void *was_sq_slice + 0, // ssizeobjargproc sq_ass_item + 0, // void *was_sq_ass_slice + 0, // objobjproc sq_contains + 0, // binaryfunc sq_inplace_concat + 0, // ssizeargfunc sq_inplace_repeat +}; + +PyMethodDef tp_methods[] = +{ + { "names", (PyCFunction)named_exps_names, METH_NOARGS, "Get names for all named expressions stored." }, + { nullptr } +}; + +PyMemberDef tp_members[] = +{ + { nullptr } +}; + +PyTypeObject named_exps_type = +{ + PyVarObject_HEAD_INIT(nullptr, 0) + "orcus.NamedExpressions", // tp_name + sizeof(pyobj_named_exps), // tp_basicsize + 0, // tp_itemsize + (destructor)tp_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + &tp_as_sequence, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags + "orcus spreadsheet formula tokens", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + tp_iter, // tp_iter + tp_iternext, // tp_iternext + tp_methods, // tp_methods + tp_members, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)tp_init, // tp_init + 0, // tp_alloc + tp_new, // tp_new +}; + +} // anonymous namespace + +PyObject* create_named_expressions_object( + spreadsheet::sheet_t origin_sheet, const spreadsheet::document& doc, ixion::named_expressions_iterator iter) +{ + PyTypeObject* type = get_named_exps_type(); + + PyObject* obj = create_object_from_type(type); + if (!obj) + return nullptr; + + type->tp_init(obj, nullptr, nullptr); + + named_exps_data& data = *t(obj)->data; + data.src = iter; + data.origin_sheet = origin_sheet; + data.doc = &doc; + + return obj; +} + +PyTypeObject* get_named_exps_type() +{ + return &named_exps_type; +} + +}} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |