417 lines
9.6 KiB
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;
|
|
}
|
|
|