| @@ -26,15 +26,20 @@ SOFTWARE. | |||||
| #endif | #endif | ||||
| #include <Python.h> | #include <Python.h> | ||||
| #include "setjmp.h" | |||||
| #include "structmember.h" | #include "structmember.h" | ||||
| static PyObject* EMPTY; | |||||
| #define PU (Py_UNICODE*) | #define PU (Py_UNICODE*) | ||||
| static const Py_UNICODE* OUT_OF_BOUNDS = PU""; | |||||
| static const Py_UNICODE* MARKERS[] = {PU"{", PU"}", PU"[", PU"]", PU"<", PU">", | static const Py_UNICODE* MARKERS[] = {PU"{", PU"}", PU"[", PU"]", PU"<", PU">", | ||||
| PU"|", PU"=", PU"&", PU"#", PU"*", PU";", | PU"|", PU"=", PU"&", PU"#", PU"*", PU";", | ||||
| PU":", PU"/", PU"-", PU"!", PU"\n", PU""}; | PU":", PU"/", PU"-", PU"!", PU"\n", PU""}; | ||||
| #undef PU | #undef PU | ||||
| static jmp_buf exception_env; | |||||
| static const int BAD_ROUTE = 1; | |||||
| static PyObject* contexts; | static PyObject* contexts; | ||||
| static PyObject* tokens; | static PyObject* tokens; | ||||
| @@ -142,10 +147,7 @@ static int | |||||
| Tokenizer_push_textbuffer(Tokenizer* self) | Tokenizer_push_textbuffer(Tokenizer* self) | ||||
| { | { | ||||
| if (PySequence_Fast_GET_SIZE(Tokenizer_TEXTBUFFER(self)) > 0) { | if (PySequence_Fast_GET_SIZE(Tokenizer_TEXTBUFFER(self)) > 0) { | ||||
| PyObject* sep = PyUnicode_FromString(""); | |||||
| if (!sep) return -1; | |||||
| PyObject* text = PyUnicode_Join(sep, Tokenizer_TEXTBUFFER(self)); | |||||
| Py_DECREF(sep); | |||||
| PyObject* text = PyUnicode_Join(EMPTY, Tokenizer_TEXTBUFFER(self)); | |||||
| if (!text) return -1; | if (!text) return -1; | ||||
| PyObject* klass = PyObject_GetAttrString(tokens, "Text"); | PyObject* klass = PyObject_GetAttrString(tokens, "Text"); | ||||
| @@ -174,7 +176,7 @@ Tokenizer_push_textbuffer(Tokenizer* self) | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| Py_XDECREF(token); | |||||
| Py_DECREF(token); | |||||
| if (Tokenizer_set_textbuffer(self, PyList_New(0))) | if (Tokenizer_set_textbuffer(self, PyList_New(0))) | ||||
| return -1; | return -1; | ||||
| @@ -245,19 +247,104 @@ Tokenizer_pop_keeping_context(Tokenizer* self) | |||||
| } | } | ||||
| /* | /* | ||||
| Fail the current tokenization route. | |||||
| Discards the current stack/context/textbuffer and "raises a BAD_ROUTE | |||||
| exception", which is implemented using longjmp(). | |||||
| */ | |||||
| static void | |||||
| Tokenizer_fail_route(Tokenizer* self) | |||||
| { | |||||
| Tokenizer_pop(self); | |||||
| longjmp(exception_env, BAD_ROUTE); | |||||
| } | |||||
| /* | |||||
| Write a token to the end of the current token stack. | |||||
| */ | |||||
| static int | |||||
| Tokenizer_write(Tokenizer* self, PyObject* token) | |||||
| { | |||||
| if (Tokenizer_push_textbuffer(self)) | |||||
| return -1; | |||||
| if (PyList_Append(Tokenizer_STACK(self), token)) { | |||||
| Py_XDECREF(token); | |||||
| return -1; | |||||
| } | |||||
| Py_XDECREF(token); | |||||
| return 0; | |||||
| } | |||||
| /* | |||||
| Write a token to the beginning of the current token stack. | |||||
| */ | |||||
| static int | |||||
| Tokenizer_write_first(Tokenizer* self, PyObject* token) | |||||
| { | |||||
| if (Tokenizer_push_textbuffer(self)) | |||||
| return -1; | |||||
| if (PyList_Insert(Tokenizer_STACK(self), 0, token)) { | |||||
| Py_XDECREF(token); | |||||
| return -1; | |||||
| } | |||||
| Py_XDECREF(token); | |||||
| return 0; | |||||
| } | |||||
| /* | |||||
| Write text to the current textbuffer. | |||||
| */ | |||||
| static int | |||||
| Tokenizer_write_text(Tokenizer* self, PyObject* text) | |||||
| { | |||||
| if (PyList_Append(Tokenizer_TEXTBUFFER(self), text)) { | |||||
| Py_XDECREF(text); | |||||
| return -1; | |||||
| } | |||||
| Py_XDECREF(text); | |||||
| return 0; | |||||
| } | |||||
| /* | |||||
| Write a series of tokens to the current stack at once. | |||||
| */ | |||||
| static int | |||||
| Tokenizer_write_all(Tokenizer* self, PyObject* tokenlist) | |||||
| { | |||||
| if (Tokenizer_push_textbuffer(self)) | |||||
| Py_XDECREF(tokenlist); | |||||
| return -1; | |||||
| PyObject* stack = Tokenizer_STACK(self); | |||||
| Py_ssize_t size = PySequence_Fast_GET_SIZE(stack); | |||||
| if (PyList_SetSlice(stack, size, size, tokenlist)) { | |||||
| Py_XDECREF(tokenlist); | |||||
| return -1; | |||||
| } | |||||
| Py_XDECREF(tokenlist); | |||||
| return 0; | |||||
| } | |||||
| /* | |||||
| Read the value at a relative point in the wikicode. | Read the value at a relative point in the wikicode. | ||||
| */ | */ | ||||
| static Py_UNICODE* | |||||
| static PyObject* | |||||
| Tokenizer_read(Tokenizer* self, Py_ssize_t delta) | Tokenizer_read(Tokenizer* self, Py_ssize_t delta) | ||||
| { | { | ||||
| Py_ssize_t index = self->head + delta; | Py_ssize_t index = self->head + delta; | ||||
| if (index >= self->length) { | if (index >= self->length) { | ||||
| return (Py_UNICODE*) OUT_OF_BOUNDS; | |||||
| return EMPTY; | |||||
| } | } | ||||
| PyObject* item = PySequence_Fast_GET_ITEM(self->text, index); | |||||
| return PyUnicode_AS_UNICODE(item); | |||||
| return PySequence_Fast_GET_ITEM(self->text, index); | |||||
| } | } | ||||
| /* | /* | ||||
| @@ -266,7 +353,7 @@ Tokenizer_read(Tokenizer* self, Py_ssize_t delta) | |||||
| static PyObject* | static PyObject* | ||||
| Tokenizer_parse(Tokenizer* self, int context) | Tokenizer_parse(Tokenizer* self, int context) | ||||
| { | { | ||||
| Py_UNICODE* this; | |||||
| PyObject* this; | |||||
| Tokenizer_push(self, context); | Tokenizer_push(self, context); | ||||
| @@ -275,10 +362,9 @@ Tokenizer_parse(Tokenizer* self, int context) | |||||
| /* if (this not in MARKERS) { | /* if (this not in MARKERS) { | ||||
| WRITE TEXT | WRITE TEXT | ||||
| } */ | } */ | ||||
| if (this == OUT_OF_BOUNDS) { | |||||
| if (this == EMPTY) { | |||||
| return Tokenizer_pop(self); | return Tokenizer_pop(self); | ||||
| } | } | ||||
| printf("%p %i %c\n", this, *this, *this); | |||||
| self->head++; | self->head++; | ||||
| } | } | ||||
| } | } | ||||
| @@ -390,6 +476,8 @@ init_tokenizer(void) | |||||
| Py_INCREF(&TokenizerType); | Py_INCREF(&TokenizerType); | ||||
| PyModule_AddObject(module, "CTokenizer", (PyObject*) &TokenizerType); | PyModule_AddObject(module, "CTokenizer", (PyObject*) &TokenizerType); | ||||
| EMPTY = PyUnicode_FromString(""); | |||||
| PyObject* globals = PyEval_GetGlobals(); | PyObject* globals = PyEval_GetGlobals(); | ||||
| PyObject* locals = PyEval_GetLocals(); | PyObject* locals = PyEval_GetLocals(); | ||||
| PyObject* fromlist = PyList_New(0); | PyObject* fromlist = PyList_New(0); | ||||