Changeset 4 for trunk/ext/_syckmodule.c


Ignore:
Timestamp:
07/16/05 15:14:11 (9 years ago)
Author:
xi
Message:

Add the module _syck and test suite.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ext/_syckmodule.c

    r3 r4  
    33#include <syck.h> 
    44 
    5 static PyMethodDef _syck_methods[] = { 
     5/* Global objects. */ 
     6 
     7static PyObject *_syck_Error; 
     8 
     9static PyObject *_syck_ScalarKind; 
     10static PyObject *_syck_SeqKind; 
     11static PyObject *_syck_MapKind; 
     12 
     13/* Node type. */ 
     14 
     15typedef struct { 
     16    PyObject_HEAD 
     17    PyObject *kind; 
     18    PyObject *type_id; 
     19    PyObject *value; 
     20} _syck_Node; 
     21 
     22static void 
     23_syck_Node_dealloc(_syck_Node *self) 
     24{ 
     25    Py_XDECREF(self->kind); 
     26    Py_XDECREF(self->type_id); 
     27    Py_XDECREF(self->value); 
     28    PyObject_Del(self); 
     29} 
     30 
     31static PyObject * 
     32_syck_Node_getattr(_syck_Node *self, char *name) 
     33{ 
     34    PyObject *value; 
     35 
     36    if (strcmp(name, "kind") == 0) 
     37        value = self->kind; 
     38    else if (strcmp(name, "type_id") == 0) 
     39        value = self->type_id; 
     40    else if (strcmp(name, "value") == 0) 
     41        value = self->value; 
     42    else { 
     43        PyErr_SetString(PyExc_AttributeError, name); 
     44        return NULL; 
     45    } 
     46 
     47    Py_INCREF(value); 
     48    return value; 
     49} 
     50 
     51static char _syck_Node_doc[] = 
     52    "Node object\n" 
     53    "\n" 
     54    "Attributes of the Node object:\n\n" 
     55    "kind -- 'scalar', 'seq', or 'map'.\n" 
     56    "type_id -- the tag of the node.\n" 
     57    "value -- the value of the node, a string, list or dict object.\n"; 
     58 
     59static PyTypeObject _syck_NodeType = { 
     60    PyObject_HEAD_INIT(NULL) 
     61    0,                                  /* ob_size */ 
     62    "_syck.Node",                       /* tp_name */ 
     63    sizeof(_syck_Node),                 /* tp_basicsize */ 
     64    0,                                  /* tp_itemsize */ 
     65    (destructor)_syck_Node_dealloc,     /* tp_dealloc */ 
     66    0,                                  /* tp_print */ 
     67    (getattrfunc)_syck_Node_getattr,    /* tp_getattr */ 
     68    0,                                  /* tp_setattr */ 
     69    0,                                  /* tp_compare */ 
     70    0,                                  /* tp_repr */ 
     71    0,                                  /* tp_as_number */ 
     72    0,                                  /* tp_as_sequence */ 
     73    0,                                  /* tp_as_mapping */ 
     74    0,                                  /* tp_hash */ 
     75    0,                                  /* tp_call */ 
     76    0,                                  /* tp_str */ 
     77    0,                                  /* tp_getattro */ 
     78    0,                                  /* tp_setattro */ 
     79    0,                                  /* tp_as_buffer */ 
     80    Py_TPFLAGS_DEFAULT,                 /* tp_flags */ 
     81    _syck_Node_doc,                     /* tp_doc */ 
     82}; 
     83 
     84static PyObject * 
     85_syck_NewNode(PyObject *self, PyObject *args) 
     86{ 
     87    if (!PyArg_ParseTuple(args, ":_syck.Node")) 
     88        return NULL; 
     89 
     90    PyErr_SetString(PyExc_TypeError, "Node object cannot be created explicitly. Use _syck.Parser.parse() instead."); 
     91    return NULL; 
     92} 
     93 
     94static char _syck_NewNode_doc[] = 
     95    "Node object cannot be created explicitly. Use _syck.Parser.parse() instead."; 
     96 
     97static PyObject * 
     98_syck_NewNode_FromValue(char *type_id, PyObject *value) /* Note: steals the reference to the value. */ 
     99{ 
     100    _syck_Node *self; 
     101    PyObject *kind; 
     102 
     103    self = PyObject_NEW(_syck_Node, &_syck_NodeType); 
     104    if (!self) { 
     105        Py_XDECREF(value); 
     106        return NULL; 
     107    } 
     108 
     109    self->value = value; 
     110 
     111    if (PyList_Check(value)) 
     112        kind = _syck_SeqKind; 
     113    else if (PyDict_Check(value)) 
     114        kind = _syck_MapKind; 
     115    else 
     116        kind = _syck_ScalarKind; 
     117    Py_INCREF(kind); 
     118    self->kind = kind; 
     119 
     120    if (type_id) { 
     121        self->type_id = PyString_FromString(type_id); 
     122        if (!self->type_id) { 
     123            Py_DECREF(self); 
     124            return NULL; 
     125        } 
     126    } 
     127    else { 
     128        Py_INCREF(Py_None); 
     129        self->type_id = Py_None; 
     130    } 
     131 
     132    return (PyObject *)self; 
     133} 
     134 
     135/* Parser type. */ 
     136 
     137typedef struct { 
     138    PyObject_HEAD 
     139    PyObject *source; 
     140    PyObject *resolver; 
     141    PyObject *symbols; 
     142    int error_state; 
     143    int mark; 
     144    SyckParser *parser; 
     145} _syck_Parser; 
     146 
     147static PyObject * 
     148_syck_Parser_parse(_syck_Parser *self, PyObject *args) 
     149{ 
     150    SYMID index; 
     151    PyObject *value; 
     152 
     153    if (!PyArg_ParseTuple(args, ":parse")) 
     154        return NULL; 
     155 
     156    if (!self->parser) { 
     157        PyErr_SetString(PyExc_TypeError, "Parser object is closed"); 
     158        return NULL; 
     159    } 
     160 
     161    self->symbols = PyList_New(0); 
     162    if (!self->symbols) { 
     163        return NULL; 
     164    } 
     165 
     166    index = syck_parse(self->parser); 
     167    if (!self->error_state && !self->parser->eof) { 
     168        value = PyList_GetItem(self->symbols, index-1); 
     169    } 
     170 
     171    Py_DECREF(self->symbols); 
     172 
     173    if (self->error_state) { 
     174        self->error_state = 0; 
     175        return NULL; 
     176    } 
     177 
     178    if (self->parser->eof) { 
     179        Py_INCREF(Py_None); 
     180        return Py_None; 
     181    } 
     182     
     183    return value; 
     184} 
     185 
     186static char _syck_Parser_parse_doc[] = 
     187    "Parses the next document in the YAML stream, return the root Node object or None on EOF."; 
     188 
     189static PyObject * 
     190_syck_Parser_parse_documents(_syck_Parser *self, PyObject *args) 
     191{ 
     192    SYMID index; 
     193    PyObject *value = NULL; 
     194    PyObject *result = NULL; 
     195 
     196    if (!PyArg_ParseTuple(args, ":parse_document")) 
     197        return NULL; 
     198 
     199    if (!self->parser) { 
     200        PyErr_SetString(PyExc_TypeError, "Parser object is closed"); 
     201        return NULL; 
     202    } 
     203 
     204    result = PyList_New(0); 
     205    if (!result) return NULL; 
     206 
     207    while (1) { 
     208 
     209        self->symbols = PyList_New(0); 
     210        if (!self->symbols) { 
     211            Py_DECREF(result); 
     212            return NULL; 
     213        }; 
     214 
     215        index = syck_parse(self->parser); 
     216 
     217        if (!self->error_state && !self->parser->eof) { 
     218            value = PyList_GetItem(self->symbols, index-1); 
     219            if (!value) { 
     220                Py_DECREF(self->symbols); 
     221                Py_DECREF(result); 
     222                return NULL; 
     223            } 
     224            if (PyList_Append(result, value) < 0) { 
     225                Py_DECREF(self->symbols); 
     226                Py_DECREF(value); 
     227                Py_DECREF(result); 
     228                return NULL; 
     229            } 
     230            Py_DECREF(value); 
     231        } 
     232 
     233        Py_DECREF(self->symbols); 
     234 
     235        if (self->error_state) { 
     236            self->error_state = 0; 
     237            Py_DECREF(result); 
     238            return NULL; 
     239        } 
     240 
     241        if (self->parser->eof) break; 
     242    } 
     243 
     244    return result; 
     245} 
     246 
     247static char _syck_Parser_parse_documents_doc[] = 
     248    "Parses the entire YAML stream and returns list of documents."; 
     249 
     250static PyObject * 
     251_syck_Parser_close(_syck_Parser *self, PyObject *args) 
     252{ 
     253    if (!PyArg_ParseTuple(args, ":close")) 
     254        return NULL; 
     255 
     256    Py_XDECREF(self->source); 
     257    self->source = NULL; 
     258 
     259    if (self->parser) { 
     260        syck_free_parser(self->parser); 
     261    } 
     262    self->parser = NULL; 
     263 
     264    Py_INCREF(Py_None); 
     265    return Py_None; 
     266} 
     267 
     268static char _syck_Parser_close_doc[] = 
     269    "Closes the parser and frees memory"; 
     270 
     271static PyMethodDef _syck_Parser_methods[] = { 
     272    {"parse",  (PyCFunction)_syck_Parser_parse, METH_VARARGS, _syck_Parser_parse_doc}, 
     273    {"parse_documents",  (PyCFunction)_syck_Parser_parse_documents, METH_VARARGS, _syck_Parser_parse_documents_doc}, 
     274    {"close",  (PyCFunction)_syck_Parser_close, METH_VARARGS, _syck_Parser_close_doc}, 
    6275    {NULL}  /* Sentinel */ 
    7276}; 
    8277 
     278static void 
     279_syck_Parser_dealloc(_syck_Parser *self) 
     280{ 
     281    Py_XDECREF(self->source); 
     282    if (self->parser) { 
     283        syck_free_parser(self->parser); 
     284    } 
     285    PyObject_Del(self); 
     286} 
     287 
     288static PyObject * 
     289_syck_Parser_getattr(_syck_Parser *self, char *name) 
     290{ 
     291    return Py_FindMethod(_syck_Parser_methods, (PyObject *)self, name); 
     292} 
     293 
     294static char _syck_Parser_doc[] = 
     295    "_syck.Parser(yaml_string_or_file, implicit_typing=True, taguri_expansion=True) -> Parser object\n" 
     296    "\n" 
     297    "Methods of the Parser object:\n\n" 
     298    "parse() -- Parses the next document in the YAML stream, return the root Node object or None on EOF.\n" 
     299    "parse_documents() -- Parses the entire YAML stream and returns list of documents.\n" 
     300    "close() -- Closes the parser and frees memory.\n"; 
     301 
     302static PyTypeObject _syck_ParserType = { 
     303    PyObject_HEAD_INIT(NULL) 
     304    0,                                  /* ob_size */ 
     305    "_syck.Parser",                     /* tp_name */ 
     306    sizeof(_syck_Parser),               /* tp_basicsize */ 
     307    0,                                  /* tp_itemsize */ 
     308    (destructor)_syck_Parser_dealloc,   /* tp_dealloc */ 
     309    0,                                  /* tp_print */ 
     310    (getattrfunc)_syck_Parser_getattr,  /* tp_getattr */ 
     311    0,                                  /* tp_setattr */ 
     312    0,                                  /* tp_compare */ 
     313    0,                                  /* tp_repr */ 
     314    0,                                  /* tp_as_number */ 
     315    0,                                  /* tp_as_sequence */ 
     316    0,                                  /* tp_as_mapping */ 
     317    0,                                  /* tp_hash */ 
     318    0,                                  /* tp_call */ 
     319    0,                                  /* tp_str */ 
     320    0,                                  /* tp_getattro */ 
     321    0,                                  /* tp_setattro */ 
     322    0,                                  /* tp_as_buffer */ 
     323    Py_TPFLAGS_DEFAULT,                 /* tp_flags */ 
     324    _syck_Parser_doc,                   /* tp_doc */ 
     325}; 
     326 
     327static long 
     328_syck_Parser_io_file_read(char *buf, SyckIoFile *file, long max_size, long skip) 
     329{ 
     330    _syck_Parser *runtime = (_syck_Parser *)file->ptr; 
     331 
     332    PyObject *value; 
     333 
     334    char *str; 
     335    int length; 
     336 
     337    buf[skip] = '\0'; 
     338 
     339    if (runtime->error_state) { 
     340        return skip; 
     341    } 
     342     
     343    max_size -= skip; 
     344 
     345    value = PyObject_CallMethod(runtime->source, "read", "(i)", max_size); 
     346    if (!value) { 
     347        runtime->error_state = 1; 
     348        return skip; 
     349    } 
     350 
     351    if (!PyString_Check(value)) { 
     352        Py_DECREF(value); 
     353        PyErr_SetString(PyExc_TypeError, "file-like object should return a string"); 
     354        runtime->error_state = 1; 
     355         
     356        return skip; 
     357    } 
     358 
     359    str = PyString_AS_STRING(value); 
     360    length = PyString_GET_SIZE(value); 
     361    if (!length) { 
     362        Py_DECREF(value); 
     363        return skip; 
     364    } 
     365 
     366    if (length > max_size) { 
     367        Py_DECREF(value); 
     368        PyErr_SetString(PyExc_ValueError, "read returns an overly long string"); 
     369        runtime->error_state = 1; 
     370        return skip; 
     371    } 
     372 
     373    memcpy(buf+skip, str, length); 
     374    length += skip; 
     375    buf[length] = '\0'; 
     376 
     377    Py_DECREF(value); 
     378 
     379    return length; 
     380} 
     381 
     382static SYMID 
     383_syck_Parser_node_handler(SyckParser *parser, SyckNode *node) 
     384{ 
     385    _syck_Parser *runtime = (_syck_Parser *)parser->bonus; 
     386 
     387    SYMID index; 
     388    PyObject *object = NULL; 
     389 
     390    PyObject *key, *value, *item; 
     391    int k; 
     392 
     393    if (runtime->error_state) 
     394        return 0; 
     395 
     396    switch (node->kind) { 
     397 
     398        case syck_str_kind: 
     399            object = PyString_FromStringAndSize(node->data.str->ptr, 
     400                    node->data.str->len); 
     401            if (!object) goto error; 
     402            break; 
     403 
     404        case syck_seq_kind: 
     405            object = PyList_New(node->data.list->idx); 
     406            if (!object) goto error; 
     407            for (k = 0; k < node->data.list->idx; k++) { 
     408                index = syck_seq_read(node, k); 
     409                item = PyList_GetItem(runtime->symbols, index-1); 
     410                if (!item) goto error; 
     411                Py_INCREF(item); 
     412                PyList_SET_ITEM(object, k, item); 
     413            } 
     414            break; 
     415 
     416        case syck_map_kind: 
     417            object = PyDict_New(); 
     418            if (!object) goto error; 
     419            for (k = 0; k < node->data.pairs->idx; k++) 
     420            { 
     421                index = syck_map_read(node, map_key, k); 
     422                key = PyList_GetItem(runtime->symbols, index-1); 
     423                if (!key) goto error; 
     424                index = syck_map_read(node, map_value, k); 
     425                value = PyList_GetItem(runtime->symbols, index-1); 
     426                if (!value) goto error; 
     427                if (PyDict_SetItem(object, key, value) < 0) 
     428                    goto error; 
     429            } 
     430            break; 
     431    } 
     432 
     433    object = _syck_NewNode_FromValue(node->type_id, object); 
     434    if (!object) goto error; 
     435 
     436    if (PyList_Append(runtime->symbols, object) < 0) 
     437        goto error; 
     438 
     439    index = PyList_Size(runtime->symbols); 
     440    return index; 
     441 
     442error: 
     443    Py_XDECREF(object); 
     444    runtime->error_state = 1; 
     445    return 0; 
     446} 
     447 
     448static void 
     449_syck_Parser_error_handler(SyckParser *parser, char *str) 
     450{ 
     451    _syck_Parser *runtime = (_syck_Parser *)parser->bonus; 
     452    PyObject *value; 
     453 
     454    if (runtime->error_state) return; 
     455 
     456    runtime->error_state = 1; 
     457 
     458    value = Py_BuildValue("(sii)", str, parser->linect, parser->cursor-parser->lineptr); 
     459    if (value) { 
     460        PyErr_SetObject(_syck_Error, value); 
     461    } 
     462} 
     463 
     464static PyObject * 
     465_syck_NewParser(PyObject *self, PyObject *args, PyObject *kwds) 
     466{ 
     467    _syck_Parser *parser; 
     468    PyObject *source; 
     469    int implicit_typing = 1; 
     470    int taguri_expansion = 1; 
     471 
     472    static char *kwdlist[] = {"source", "implicit_typing", "taguri_expansion", NULL}; 
     473 
     474    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ii", kwdlist, 
     475                &source, &implicit_typing, &taguri_expansion)) 
     476        return NULL; 
     477 
     478    parser = PyObject_NEW(_syck_Parser, &_syck_ParserType); 
     479    if (!parser) 
     480        return NULL; 
     481 
     482    Py_INCREF(source); 
     483    parser->source = source; 
     484    parser->error_state = 0; 
     485 
     486    parser->parser = syck_new_parser(); 
     487    parser->parser->bonus = parser; 
     488 
     489    if (PyString_Check(source)) { 
     490        syck_parser_str_auto(parser->parser, PyString_AS_STRING(source), NULL); 
     491    } 
     492    else { 
     493        syck_parser_file(parser->parser, (FILE *)parser, _syck_Parser_io_file_read); 
     494    } 
     495    syck_parser_implicit_typing(parser->parser, implicit_typing); 
     496    syck_parser_taguri_expansion(parser->parser, taguri_expansion); 
     497 
     498    syck_parser_handler(parser->parser, _syck_Parser_node_handler); 
     499    syck_parser_error_handler(parser->parser, _syck_Parser_error_handler); 
     500    /* 
     501    syck_parser_bad_anchor_handler(parser, _syck_Parser_bad_anchor_handler); 
     502    */ 
     503 
     504    return (PyObject *)parser; 
     505} 
     506 
     507static char _syck_NewParser_doc[] = 
     508    "Creates a new Parser object."; 
     509 
     510/* The module definitions. */ 
     511 
     512static PyMethodDef _syck_methods[] = { 
     513    {"Node",  (PyCFunction)_syck_NewNode, METH_VARARGS, _syck_NewNode_doc}, 
     514    {"Parser",  (PyCFunction)_syck_NewParser, METH_VARARGS|METH_KEYWORDS, _syck_NewParser_doc}, 
     515    {NULL}  /* Sentinel */ 
     516}; 
     517 
    9518static char _syck_doc[] = 
    10519    "This module provides low-level access to the Syck parser and emitter.\n" 
    11     "Do not use this module directly, use the module 'syck' instead.\n"; 
     520    "Do not use this module directly, use the package 'syck' instead.\n"; 
    12521 
    13522PyMODINIT_FUNC 
    14523init_syck(void) 
    15524{ 
    16     Py_InitModule3("_syck", _syck_methods, _syck_doc); 
    17 } 
    18  
     525    PyObject *m; 
     526 
     527    _syck_NodeType.ob_type = &PyType_Type; 
     528    _syck_ParserType.ob_type = &PyType_Type; 
     529 
     530    _syck_Error = PyErr_NewException("_syck.error", NULL, NULL); 
     531    if (!_syck_Error) 
     532        return; 
     533 
     534    _syck_ScalarKind = PyString_FromString("scalar"); 
     535    if (!_syck_ScalarKind) 
     536        return; 
     537    _syck_SeqKind = PyString_FromString("seq"); 
     538    if (!_syck_SeqKind) 
     539        return; 
     540    _syck_MapKind = PyString_FromString("map"); 
     541    if (!_syck_MapKind) 
     542        return; 
     543 
     544    m = Py_InitModule3("_syck", _syck_methods, _syck_doc); 
     545 
     546    Py_INCREF(_syck_Error); 
     547    if (!PyModule_AddObject(m, "error", _syck_Error) < 0) 
     548        return; 
     549 
     550    Py_INCREF(&_syck_NodeType); 
     551    if (PyModule_AddObject(m, "NodeType", (PyObject *)&_syck_NodeType) < 0) 
     552        return; 
     553 
     554    Py_INCREF(&_syck_ParserType); 
     555    if (PyModule_AddObject(m, "ParserType", (PyObject *)&_syck_ParserType) < 0) 
     556        return; 
     557} 
     558 
Note: See TracChangeset for help on using the changeset viewer.