rpnifs/python_rpntoken.c

417 lines
9.6 KiB
C

#include "python_rpntoken.h"
static PyMethodDef RPNToken_methods[] = {
{"from_str", (PyCFunction)rpntoken_from_str, METH_CLASS | METH_O,
"Return a new RPNToken subclass instance from string"},
{NULL} //
};
PyTypeObject RPNTokenType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "pyrpn.tokens.Token",
.tp_doc = "Abstract class for RPN expression tokens",
.tp_basicsize = sizeof(RPNToken_t),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_init = rpntoken_init,
.tp_new = PyType_GenericNew,
.tp_str = rpntoken_str,
.tp_repr = rpntoken_repr,
.tp_methods = RPNToken_methods,
};
static PyMethodDef RPNTokenOp_methods[] = {
{"opcode_max", (PyCFunction)rpntokenop_opcode_max,
METH_STATIC | METH_NOARGS,
"Return the maximum valid value for an opcode"},
{"chr", (PyCFunction)rpntokenop_opchr, METH_NOARGS,
"Return the single char representation of the operand"},
{"str", (PyCFunction)rpntokenop_opstr, METH_NOARGS,
"Return the string (multi-char) representation of the operand"},
{NULL} //
};
static PyMemberDef RPNTokenOp_members[] = {
{"opcode", T_BYTE, offsetof(RPNTokenOp_t, super.value.op_n), READONLY,
"The number representing the operand"},
/*
{"chr", T_CHAR, offsetof(RPNTokenOp_t, super.value.op->chr), READONLY,
"The single char representation of the operand"},
{"str", T_STRING, offsetof(RPNTokenOp_t, super.value.op->str), READONLY,
"The str representation of the operand"},
*/
{NULL} //
};
PyTypeObject RPNTokenOpType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_base = &RPNTokenType,
.tp_name = "pyrpn.tokens.Operand",
.tp_doc = "RPN expression operand token",
.tp_basicsize = sizeof(RPNTokenOp_t),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_init = rpntokenop_init,
.tp_members = RPNTokenOp_members,
.tp_methods = RPNTokenOp_methods,
};
static PyMemberDef RPNTokenArg_members[] = {
{"argno", T_ULONG, offsetof(RPNTokenOp_t, super.value.arg_n), READONLY,
"The argument number"},
{NULL} //
};
PyTypeObject RPNTokenArgType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_base = &RPNTokenType,
.tp_name = "pyrpn.tokens.Argument",
.tp_doc = "RPN expression argument token",
.tp_basicsize = sizeof(RPNTokenArg_t),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_init = rpntokenarg_init,
.tp_members = RPNTokenArg_members,
};
static PyMemberDef RPNTokenVal_members[] = {
{"value", T_ULONG, offsetof(RPNTokenOp_t, super.value.value), READONLY,
"The immediate value"},
{NULL} //
};
PyTypeObject RPNTokenValType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_base = &RPNTokenType,
.tp_name = "pyrpn.tokens.Value",
.tp_doc = "RPN expression value token",
.tp_basicsize = sizeof(RPNTokenVal_t),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_init = rpntokenval_init,
.tp_members = RPNTokenVal_members,
};
PyModuleDef rpntokens_module = {
PyModuleDef_HEAD_INIT,
.m_name = "pyrpn.tokens",
.m_doc = "RPN expression tokens classes",
.m_size = -1,
.m_methods = NULL,
.m_clear = NULL,
};
PyObject* rpntokens_module_init(void)
{
PyObject *mod;
mod = PyModule_Create(&rpntokens_module);
if(!mod) { return NULL; }
if(PyType_Ready(&RPNTokenType) < 0
|| PyType_Ready(&RPNTokenOpType) < 0 \
|| PyType_Ready(&RPNTokenValType) < 0 \
|| PyType_Ready(&RPNTokenArgType) < 0)
{
return NULL;
}
Py_INCREF(&RPNTokenType);
Py_INCREF(&RPNTokenOpType);
Py_INCREF(&RPNTokenValType);
Py_INCREF(&RPNTokenArgType);
if( PyModule_AddObject(mod, "Token",
(PyObject*)&RPNTokenType) < 0 \
|| PyModule_AddObject(mod, "Operand",
(PyObject*)&RPNTokenOpType) < 0 \
|| PyModule_AddObject(mod, "Value",
(PyObject*)&RPNTokenValType) < 0 \
|| PyModule_AddObject(mod, "Argument",
(PyObject*)&RPNTokenArgType) < 0)
{
Py_DECREF(&RPNTokenType);
Py_DECREF(&RPNTokenOpType);
Py_DECREF(&RPNTokenValType);
Py_DECREF(&RPNTokenArgType);
return NULL;
}
return mod;
}
PyObject* rpntoken_from_str(PyObject *cls, PyObject *arg)
{
if(!PyUnicode_Check(arg))
{
PyErr_SetString(PyExc_TypeError, "Expected argument to be a str");
return NULL;
}
PyObject *bytes_str = PyUnicode_AsASCIIString(arg);
if(PyErr_Occurred())
{
return NULL;
}
const char *str = PyBytes_AS_STRING(bytes_str);
rpn_token_t token;
char err_str[64];
if(rpn_tokenize(str, &token, err_str) < 0)
{
Py_DECREF(bytes_str);
PyObject *ascii = PyObject_ASCII(arg);
PyErr_Format(PyExc_ValueError, "Unable to parse %s", ascii);
Py_DECREF(ascii);
return NULL;
}
Py_DECREF(bytes_str);
return rpntoken_from_token(&token);
}
PyObject* rpntoken_from_token(const rpn_token_t *token)
{
PyTypeObject *type;
switch(token->type)
{
case RPN_op:
type = &RPNTokenOpType;
break;
case RPN_val:
type = &RPNTokenValType;
break;
case RPN_arg:
type = &RPNTokenArgType;
break;
default:
PyErr_SetString(PyExc_RuntimeError,
"Unrecognized parsed token");
return NULL;
}
PyObject *ret = PyObject_CallMethod((PyObject*)type, "__new__", "O", type);
if(PyErr_Occurred())
{
return NULL;
}
// Any child type should work here since struct begins with super
RPNToken_t *_ret = (RPNToken_t*)ret;
memcpy(&_ret->value, token, sizeof(*token));
return ret;
}
int rpntoken_init(PyObject *_self, PyObject *args, PyObject *kwds)
{
PyErr_SetString(PyExc_NotImplementedError, "Abstract class");
return -1;
}
PyObject* rpntoken_repr(PyObject *_self)
{
RPNToken_t *self = (RPNToken_t*)_self;
int needed_sz = rpn_token_snprintf(&self->value, NULL, 0);
if(needed_sz < 0)
{
PyErr_Format(PyExc_RuntimeError, "Error : %s", strerror(errno));
return NULL;
}
char str[needed_sz+1];
rpn_token_snprintf(&self->value, str, needed_sz+1);
PyTypeObject *tp = Py_TYPE(_self);
PyObject *tp_name = PyType_GetName(tp);
PyObject *bytes_str = PyUnicode_AsASCIIString(tp_name);
Py_DECREF(tp_name);
const char *typename = PyBytes_AS_STRING(bytes_str);
needed_sz = snprintf(NULL, 0, "<%s '%s'>", typename, str);
char res_str[needed_sz+1];
needed_sz = snprintf(res_str, needed_sz+1, "<%s '%s'>", typename, str);
Py_DECREF(bytes_str);
return PyUnicode_FromString(res_str);
}
PyObject* rpntoken_str(PyObject *_self)
{
RPNToken_t *self = (RPNToken_t*)_self;
int needed_sz = rpn_token_snprintf(&self->value, NULL, 0);
if(needed_sz < 0)
{
PyErr_Format(PyExc_RuntimeError, "Error : %s", strerror(errno));
return NULL;
}
char str[needed_sz+1];
rpn_token_snprintf(&self->value, str, needed_sz+1);
return PyUnicode_FromString(str);
}
int rpntokenop_init(PyObject *_self, PyObject *args, PyObject *kwds)
{
RPNTokenOp_t *self = (RPNTokenOp_t*)_self;
PyObject *pyop = NULL;
char *names[] = {"op", NULL};
if(!PyArg_ParseTupleAndKeywords(args, kwds, "O:RPNTokenOP.__init__",
names,
&pyop))
{
return -1;
}
Py_INCREF(pyop);
if(PyLong_Check(pyop))
{
//opcode given ?
long opcode = PyLong_AsLong(pyop);
if(PyErr_Occurred()) { return -1; }
if(opcode < 0)
{
PyErr_SetString(PyExc_ValueError, "Opcode cannot be negative");
return -1;
}
else if (opcode >= rpn_op_sz())
{
PyErr_Format(PyExc_ValueError,
"Maximum opcode is %ld but %ld given",
rpn_op_sz()-1, opcode);
return -1;
}
self->super.value.op_n = opcode;
self->super.value.op = rpn_op_from_opcode(opcode);
}
else if(PyUnicode_Check(pyop))
{
PyObject *bytes_str = PyUnicode_AsASCIIString(pyop);
if(PyErr_Occurred())
{
return -1;
}
const char *token_str = PyBytes_AS_STRING(bytes_str);
char err_str[64];
if(rpn_tokenize(token_str, &(self->super.value), err_str) < 0)
{
Py_DECREF(bytes_str);
PyObject *ascii = PyObject_ASCII(pyop);
PyErr_Format(PyExc_ValueError, "Unrecognized token '%s' : %s",
ascii, err_str);
Py_DECREF(ascii);
goto err;
}
Py_DECREF(bytes_str);
if(self->super.value.type != RPN_op)
{
PyErr_SetString(PyExc_TypeError, "Decoded token is not an operand");
goto err;
}
}
else
{
PyErr_SetString(PyExc_TypeError, "Given argument is neither str neither int");
goto err;
}
Py_DECREF(pyop);
return 0;
err:
if(pyop)
{
Py_DECREF(pyop);
}
return -1;
}
PyObject *rpntokenop_opcode_max(PyObject* Py_UNUSED(_static))
{
return PyLong_FromSize_t(rpn_op_sz()-1);
}
PyObject *rpntokenop_opchr(PyObject *_self, PyObject* Py_UNUSED(_null))
{
RPNTokenOp_t *self = (RPNTokenOp_t*)_self;
if(self->super.value.op->chr == '\0')
{
Py_RETURN_NONE;
}
char buf[2];
buf[1] = '\0';
buf[0] = self->super.value.op->chr;
return PyUnicode_FromString(buf);
}
PyObject *rpntokenop_opstr(PyObject *_self, PyObject* Py_UNUSED(_null))
{
RPNTokenOp_t *self = (RPNTokenOp_t*)_self;
if(!self->super.value.op->str)
{
Py_RETURN_NONE;
}
Py_RETURN_NONE;
return PyUnicode_FromString(self->super.value.op->str);
}
int rpntokenval_init(PyObject *_self, PyObject *args, PyObject *kwds)
{
RPNTokenOp_t *self = (RPNTokenOp_t*)_self;
char *names[] = {"value", NULL};
PyObject *arg = NULL;
if(!PyArg_ParseTupleAndKeywords(args, kwds, "O:RPNTokenVal.__init__",
names, &arg))
{
return -1;
}
if(!PyLong_Check(arg))
{
PyErr_SetString(PyExc_TypeError, "Expected integer as argument");
return -1;
}
self->super.value.value = PyLong_AsUnsignedLong(arg);
if(PyErr_Occurred())
{
return -1;
}
self->super.value.type = RPN_val;
return 0;
}
int rpntokenarg_init(PyObject *_self, PyObject *args, PyObject *kwds)
{
RPNTokenOp_t *self = (RPNTokenOp_t*)_self;
char *names[] = {"argno", NULL};
PyObject *arg = NULL;
if(!PyArg_ParseTupleAndKeywords(args, kwds, "O:RPNTokenArg.__init__",
names, &arg))
{
return -1;
}
if(!PyLong_Check(arg))
{
PyErr_SetString(PyExc_TypeError, "Expected integer as argument");
return -1;
}
self->super.value.arg_n = PyLong_AsUnsignedLong(arg);
if(PyErr_Occurred())
{
return -1;
}
self->super.value.type = RPN_arg;
return 0;
}