cyphesis/rules/python/CyPy_Element.cpp

590 lines
17 KiB
C++
Raw Normal View History

#include <utility>
#include <utility>
/*
Copyright (C) 2018 Erik Ogenvik
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <common/compose.hpp>
#include <common/debug.h>
#include "CyPy_Element.h"
#include "CyPy_Operation.h"
#include "CyPy_Oplist.h"
#include "CyPy_Location.h"
#include "CyPy_RootEntity.h"
2018-12-17 14:15:30 +01:00
#include "CyPy_Root.h"
using Atlas::Message::Element;
using Atlas::Message::MapType;
using Atlas::Message::ListType;
/**
* Used when iterating over a List element.
*/
struct CyPy_ListElementIterator : Py::PythonClass<CyPy_ListElementIterator>
{
//The owning element. Reference count is incremented at construction and decremented at destruction.
CyPy_ElementList* m_element;
Atlas::Message::ListType::const_iterator iter;
CyPy_ListElementIterator(Py::PythonClassInstance* self, Py::Tuple& args, Py::Dict& kwds)
: PythonClass(self, args, kwds), m_element(nullptr)
{
throw Py::RuntimeError("Can not instantiate directly.");
}
CyPy_ListElementIterator(Py::PythonClassInstance* self, CyPy_ElementList* value)
: PythonClass(self),
m_element(value),
iter(m_element->m_value.begin())
{
m_element->self().increment_reference_count();
}
~CyPy_ListElementIterator() override
{
m_element->self().decrement_reference_count();
}
PyObject* iternext()
{
if (iter != m_element->m_value.end()) {
auto wrapper = CyPy_Element::wrap(*iter);
wrapper.increment_reference_count();
*(iter)++;
return wrapper.ptr();
} else {
return nullptr;
}
}
static void init_type()
{
behaviors().name("Element list iterator");
behaviors().doc("");
behaviors().supportIter(Py::PythonType::support_iter_iternext);
behaviors().readyType();
}
static Py::PythonClassObject<CyPy_ListElementIterator> wrap(CyPy_ElementList* value)
{
auto obj = extension_object_new(type_object(), nullptr, nullptr);
reinterpret_cast<Py::PythonClassInstance*>(obj)->m_pycxx_object = new CyPy_ListElementIterator(reinterpret_cast<Py::PythonClassInstance*>(obj), value);
return Py::PythonClassObject<CyPy_ListElementIterator>(obj);
}
};
CyPy_ElementList::CyPy_ElementList(Py::PythonClassInstance* self, Py::Tuple& args, Py::Dict& kwds) :
WrapperBase(self, args, kwds)
{
for (auto entry : args) {
m_value.push_back(CyPy_Element::asElement(entry));
}
}
CyPy_ElementList::CyPy_ElementList(Py::PythonClassInstance* self, Atlas::Message::ListType element)
: WrapperBase(self, std::move(element))
{
}
void CyPy_ElementList::init_type()
{
behaviors().name("Element List");
behaviors().doc("");
behaviors().supportRepr();
behaviors().supportRichCompare();
behaviors().supportIter(Py::PythonType::support_iter_iter);
2018-10-15 17:40:08 +02:00
behaviors().supportSequenceType(Py::PythonType::support_sequence_length
| Py::PythonType::support_sequence_contains
| Py::PythonType::support_sequence_item
| Py::PythonType::support_sequence_ass_item
| Py::PythonType::support_sequence_repeat
| Py::PythonType::support_sequence_slice
| Py::PythonType::support_sequence_inplace_concat
| Py::PythonType::support_sequence_inplace_repeat);
2018-07-29 23:20:42 +02:00
behaviors().readyType();
CyPy_ListElementIterator::init_type();
}
Py::Object CyPy_ElementList::repr()
{
return Py::String(String::compose("<%1 object at %2>(%3)", type_object()->tp_name, this, debug_tostring(m_value)));
}
Py::Object CyPy_ElementList::rich_compare(const Py::Object& other, int op)
{
if ((op != Py_EQ) && (op != Py_NE)) {
throw Py::NotImplementedError("Element List object can only be check for == or !=.");
}
bool equal = false;
if (CyPy_ElementList::check(other)) {
equal = m_value == CyPy_ElementList::value(other);
}
if ((equal && op == Py_EQ) || (!equal && op == Py_NE)) {
return Py::True();
}
return Py::False();
}
Py::Object CyPy_ElementList::iter()
{
return CyPy_ListElementIterator::wrap(this);
}
PyCxx_ssize_t CyPy_ElementList::sequence_length()
{
return m_value.size();
}
Py::Object CyPy_ElementList::sequence_repeat(Py_ssize_t count)
{
Py::List list;
for (Py_ssize_t i = 0; i < count; ++count) {
for (auto& entry : m_value) {
list.append(CyPy_Element::asPyObject(entry, false));
}
}
return list;
}
int CyPy_ElementList::sequence_contains(const Py::Object& object)
{
auto element = CyPy_Element::asElement(object);
for (auto& entity : m_value) {
if (entity == element) {
return 1;
}
}
return 0;
}
Py::Object CyPy_ElementList::sequence_inplace_repeat(Py_ssize_t)
{
//TODO: implement
return self();
}
Py::Object CyPy_ElementList::sequence_inplace_concat(const Py::Object&)
{
//TODO: implement
return self();
}
int CyPy_ElementList::sequence_ass_item(Py_ssize_t index, const Py::Object& object)
{
if (index < static_cast<Py_ssize_t>(m_value.size())) {
m_value[index] = CyPy_Element::asElement(object);
return 1;
}
return -1;
}
Py::Object CyPy_ElementList::sequence_item(Py_ssize_t index)
{
if (index < static_cast<Py_ssize_t>(m_value.size())) {
return CyPy_Element::asPyObject(m_value.at(static_cast<unsigned long>(index)), false);
}
return Py::None();
}
Py::Object CyPy_ElementList::sequence_concat(const Py::Object& otherValue)
{
auto element = CyPy_Element::asElement(otherValue);
auto list = m_value;
list.push_back(element);
return wrap(list);
}
CyPy_ElementMap::CyPy_ElementMap(Py::PythonClassInstance* self, Py::Tuple& args, Py::Dict& kwds)
: WrapperBase(self, args, kwds)
{
for (auto entry : kwds) {
m_value.emplace(entry.first.as_string(), CyPy_Element::asElement(entry.second));
}
}
CyPy_ElementMap::CyPy_ElementMap(Py::PythonClassInstance* self, Atlas::Message::MapType element)
: WrapperBase(self, std::move(element))
{
}
void CyPy_ElementMap::init_type()
{
behaviors().name("Element Map");
behaviors().doc("");
behaviors().supportRepr();
behaviors().supportRichCompare();
behaviors().supportMappingType(Py::PythonType::support_mapping_ass_subscript
| Py::PythonType::support_mapping_subscript);
behaviors().readyType();
}
Py::Object CyPy_ElementMap::repr()
{
return Py::String(String::compose("<%1 object at %2>(%3)", type_object()->tp_name, this, debug_tostring(m_value)));
}
Py::Object CyPy_ElementMap::rich_compare(const Py::Object& other, int op)
{
if ((op != Py_EQ) && (op != Py_NE)) {
throw Py::NotImplementedError("Element Map object can only be check for == or !=.");
}
bool equal = false;
if (CyPy_ElementMap::check(other)) {
equal = m_value == CyPy_ElementMap::value(other);
}
if ((equal && op == Py_EQ) || (!equal && op == Py_NE)) {
return Py::True();
}
return Py::False();
}
Py::Object CyPy_ElementMap::getattro(const Py::String& name)
{
auto I = m_value.find(name);
if (I != m_value.end()) {
return CyPy_Element::asPyObject(I->second, false);
}
return PythonExtensionBase::getattro(name);
}
int CyPy_ElementMap::setattro(const Py::String& name, const Py::Object& attr)
{
m_value.emplace(name.as_string(), CyPy_Element::asElement(attr));
return 0;
}
Py::Object CyPy_ElementMap::mapping_subscript(const Py::Object& key)
{
auto I = m_value.find(verifyString(key));
if (I != m_value.end()) {
return CyPy_Element::asPyObject(I->second, false);
}
return Py::None();
}
int CyPy_ElementMap::mapping_ass_subscript(const Py::Object& key, const Py::Object& value)
{
m_value[verifyString(key)] = CyPy_Element::asElement(value);
return 0;
}
//
//CyPy_Element::CyPy_Element(Py::PythonClassInstance* self, Py::Tuple& args, Py::Dict& kwds) :
// WrapperBase(self, args, kwds)
//{
// if (args.size() > 1) {
// throw Py::TypeError("Must take max one argument.");
// }
// if (args.size()) {
// m_value = asElement(args.front());
// }
//}
//
//CyPy_Element::CyPy_Element(Py::PythonClassInstance* self, Atlas::Message::Element element)
// : WrapperBase(self, std::move(element))
//{
//}
//
//void CyPy_Element::init_type()
//{
// behaviors().name("Element");
// behaviors().doc("");
//
// behaviors().supportRepr();
// behaviors().supportRichCompare();
//
// behaviors().supportMappingType(Py::PythonType::support_mapping_ass_subscript
// | Py::PythonType::support_mapping_subscript);
// behaviors().supportIter(Py::PythonType::support_iter_iter);
// behaviors().supportSequenceType(Py::PythonType::support_sequence_length
// | Py::PythonType::support_sequence_contains
// | Py::PythonType::support_sequence_item
// | Py::PythonType::support_sequence_ass_item
// | Py::PythonType::support_sequence_repeat
// | Py::PythonType::support_sequence_slice
// | Py::PythonType::support_sequence_inplace_concat
// | Py::PythonType::support_sequence_inplace_repeat);
//
// PYCXX_ADD_NOARGS_METHOD(get_name, get_name, "");
// PYCXX_ADD_NOARGS_METHOD(pythonize, pythonize, "");
//
// behaviors().readyType();
//
// CyPy_ListElementIterator::init_type();
//}
//
//Py::Object CyPy_Element::get_name()
//{
// return Py::String("obj");
//}
//
//Py::Object CyPy_Element::pythonize()
//{
// return asPyObject(m_value, true);
//}
2018-10-15 17:40:08 +02:00
Py::Object CyPy_Element::mapAsPyObject(const MapType& map, bool useNativePythonType)
{
Py::Dict dict;
for (auto& entry : map) {
2018-10-15 17:40:08 +02:00
if (useNativePythonType) {
dict.setItem(entry.first, CyPy_Element::asPyObject(entry.second, useNativePythonType));
} else {
dict.setItem(entry.first, CyPy_Element::wrap(entry.second));
}
}
return dict;
}
2018-10-15 17:40:08 +02:00
Py::Object CyPy_Element::listAsPyObject(const ListType& list, bool useNativePythonType)
{
Py::List pyList;
for (auto& entry : list) {
2018-10-15 17:40:08 +02:00
if (useNativePythonType) {
pyList.append(CyPy_Element::asPyObject(entry, useNativePythonType));
} else {
pyList.append(CyPy_Element::wrap(entry));
}
}
return pyList;
}
2018-10-15 17:40:08 +02:00
Py::Object CyPy_Element::asPyObject(const Atlas::Message::Element& obj, bool useNativePythonType)
{
switch (obj.getType()) {
case Element::TYPE_INT:
return Py::Long(obj.Int());
case Element::TYPE_FLOAT:
return Py::Float(obj.Float());
case Element::TYPE_STRING:
return Py::String(obj.String());
case Element::TYPE_MAP:
2018-10-15 17:40:08 +02:00
return mapAsPyObject(obj.Map(), useNativePythonType);
case Element::TYPE_LIST:
2018-10-15 17:40:08 +02:00
return listAsPyObject(obj.List(), useNativePythonType);
default:
break;
}
return Py::None();
}
//Py::Object CyPy_Element::repr()
//{
// if (m_value.isString()) {
// return Py::String(m_value.String());
// }
// return Py::String(String::compose("<%1 object at %2>(%3)", type_object()->tp_name, this, debug_tostring(m_value)));
//}
//
//Py::Object CyPy_Element::rich_compare(const Py::Object& other, int op)
//{
// if (m_value.isFloat()) {
// if (op == Py_GT && other.isNumeric()) {
// return Py::Boolean(m_value.Float() > Py::Float(other));
// } else if (op == Py_GE && other.isNumeric()) {
// return Py::Boolean(m_value.Float() >= Py::Float(other));
// } else if (op == Py_LT && other.isNumeric()) {
// return Py::Boolean(m_value.Float() < Py::Float(other));
// } else if (op == Py_LE && other.isNumeric()) {
// return Py::Boolean(m_value.Float() <= Py::Float(other));
// }
// } else if (m_value.isInt()) {
// if (op == Py_GT && other.isNumeric()) {
// return Py::Boolean(m_value.Int() > Py::Long(other));
// } else if (op == Py_GE && other.isNumeric()) {
// return Py::Boolean(m_value.Int() >= Py::Long(other));
// } else if (op == Py_LT && other.isNumeric()) {
// return Py::Boolean(m_value.Int() < Py::Long(other));
// } else if (op == Py_LE && other.isNumeric()) {
// return Py::Boolean(m_value.Int() <= Py::Long(other));
// }
// }
//
//
// bool equal = false;
// if ((op != Py_EQ) && (op != Py_NE)) {
// throw Py::NotImplementedError("MessageElement object can only be check for == or !=, or <, <=, > and >= for ints and floats.");
// }
// if (m_value.isString()) {
// if (other.isString() &&
// m_value.asString() == Py::String(other).as_string()) {
// equal = true;
// }
// } else if (m_value.isInt()) {
// if (other.isLong() &&
// m_value.asInt() == Py::Long(other).as_long()) {
// equal = true;
// }
// } else if (m_value.isFloat()) {
// if (other.isFloat()
// && m_value.asFloat() == Py::Float(other).as_double()) {
// equal = true;
// }
// }
//
// if ((equal && op == Py_EQ) || (!equal && op == Py_NE)) {
// return Py::True();
// }
// return Py::False();
//}
ListType CyPy_Element::listAsElement(const Py::List& list)
{
ListType res;
for (auto& entry : list) {
res.push_back(asElement(entry));
}
return res;
}
2018-12-17 14:15:30 +01:00
ListType CyPy_Element::sequenceAsElement(const Py::Sequence& sequence)
{
ListType res;
for (auto& entry : sequence) {
res.push_back(asElement(entry));
}
return res;
}
MapType CyPy_Element::dictAsElement(const Py::Dict& dict)
{
MapType map;
for (auto key : dict.keys()) {
map.emplace(key.str(), asElement(dict.getItem(key)));
}
return map;
}
Element CyPy_Element::asElement(const Py::Object& o)
{
if (o.isLong()) {
return Py::Long(o).as_long();
}
if (o.isFloat()) {
return Py::Float(o).as_double();
}
if (o.isString()) {
return o.as_string();
}
2018-12-17 14:15:30 +01:00
if (CyPy_ElementList::check(o)) {
return CyPy_ElementList::value(o);
}
if (CyPy_ElementMap::check(o)) {
return CyPy_ElementMap::value(o);
}
if (CyPy_Operation::check(o)) {
return CyPy_Operation::value(o)->asMessage();
}
if (CyPy_RootEntity::check(o)) {
return CyPy_RootEntity::value(o)->asMessage();
}
2018-12-17 14:15:30 +01:00
if (CyPy_Root::check(o)) {
return CyPy_Root::value(o)->asMessage();
}
if (CyPy_Oplist::check(o)) {
auto& oplist = CyPy_Oplist::value(o);
ListType list;
for (auto& entry : oplist) {
list.push_back(entry->asMessage());
}
return list;
}
if (CyPy_Location::check(o)) {
MapType map;
CyPy_Location::value(o).addToMessage(map);
return map;
}
if (o.isList()) {
return listAsElement(Py::List(o));
}
if (o.isDict()) {
return dictAsElement(Py::Dict(o));
}
if (o.isSequence()) {
2018-12-17 14:15:30 +01:00
return sequenceAsElement(Py::Sequence(o));
}
if (o.isNone()) {
return Element();
}
throw Py::TypeError(String::compose("Contained object (of type %1) could not be converted to an Element.", o.type().as_string()));
}
2018-07-23 16:43:39 +02:00
Py::Object CyPy_Element::wrap(Atlas::Message::Element value)
{
if (value.isNone()) {
return Py::None();
2018-07-28 13:49:40 +02:00
} else if (value.isString()) {
return Py::String(value.String());
} else if (value.isInt()) {
return Py::Long(value.Int());
} else if (value.isFloat()) {
return Py::Float(value.Float());
} else if (value.isList()) {
return CyPy_ElementList::wrap(value.List());
2018-07-23 16:43:39 +02:00
} else {
return CyPy_ElementMap::wrap(value.Map());
2018-07-23 16:43:39 +02:00
}
}
2018-07-29 23:20:42 +02:00
2018-10-15 17:40:08 +02:00
//
//void CyPy_Element::checkIsList()
//{
// if (!m_value.isList()) {
// throw Py::RuntimeError("Element is not of List type.");
// }
//
//}