| @@ -26,8 +26,8 @@ SOFTWARE. | |||||
| #endif | #endif | ||||
| #include <Python.h> | #include <Python.h> | ||||
| #include "setjmp.h" | |||||
| #include "structmember.h" | |||||
| #include <setjmp.h> | |||||
| #include <structmember.h> | |||||
| static PyObject* EMPTY; | static PyObject* EMPTY; | ||||
| @@ -35,7 +35,10 @@ static PyObject* EMPTY; | |||||
| 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 | |||||
| static const int NUM_MARKERS = 17; | |||||
| #define CONTEXT(name) PyInt_AsSsize_t((PyIntObject*) \ | |||||
| PyObject_GetAttrString(contexts, name)) | |||||
| static jmp_buf exception_env; | static jmp_buf exception_env; | ||||
| static const int BAD_ROUTE = 1; | static const int BAD_ROUTE = 1; | ||||
| @@ -103,6 +106,7 @@ Tokenizer_init(Tokenizer* self, PyObject* args, PyObject* kwds) | |||||
| #define Tokenizer_STACK(self) PySequence_Fast_GET_ITEM(self->topstack, 0) | #define Tokenizer_STACK(self) PySequence_Fast_GET_ITEM(self->topstack, 0) | ||||
| #define Tokenizer_CONTEXT(self) PySequence_Fast_GET_ITEM(self->topstack, 1) | #define Tokenizer_CONTEXT(self) PySequence_Fast_GET_ITEM(self->topstack, 1) | ||||
| #define Tokenizer_CONTEXT_VAL(self) PyInt_AsSsize_t((PyIntObject*) Tokenizer_CONTEXT(self)) | |||||
| #define Tokenizer_TEXTBUFFER(self) PySequence_Fast_GET_ITEM(self->topstack, 2) | #define Tokenizer_TEXTBUFFER(self) PySequence_Fast_GET_ITEM(self->topstack, 2) | ||||
| static int | static int | ||||
| @@ -125,11 +129,11 @@ Tokenizer_set_textbuffer(Tokenizer* self, PyObject* value) | |||||
| Add a new token stack, context, and textbuffer to the list. | Add a new token stack, context, and textbuffer to the list. | ||||
| */ | */ | ||||
| static int | static int | ||||
| Tokenizer_push(Tokenizer* self, int context) | |||||
| Tokenizer_push(Tokenizer* self, Py_ssize_t context) | |||||
| { | { | ||||
| PyObject* top = PyList_New(3); | PyObject* top = PyList_New(3); | ||||
| PyList_SET_ITEM(top, 0, PyList_New(0)); | PyList_SET_ITEM(top, 0, PyList_New(0)); | ||||
| PyList_SET_ITEM(top, 1, PyInt_FromSsize_t(0)); | |||||
| PyList_SET_ITEM(top, 1, PyInt_FromSsize_t(context)); | |||||
| PyList_SET_ITEM(top, 2, PyList_New(0)); | PyList_SET_ITEM(top, 2, PyList_New(0)); | ||||
| Py_XDECREF(self->topstack); | Py_XDECREF(self->topstack); | ||||
| @@ -345,7 +349,7 @@ Tokenizer_write_text_then_stack(Tokenizer* self, PyObject* text) | |||||
| } | } | ||||
| /* | /* | ||||
| Read the value at a relative point in the wikicode. | |||||
| Read the value at a relative point in the wikicode, forwards. | |||||
| */ | */ | ||||
| static PyObject* | static PyObject* | ||||
| Tokenizer_read(Tokenizer* self, Py_ssize_t delta) | Tokenizer_read(Tokenizer* self, Py_ssize_t delta) | ||||
| @@ -360,23 +364,247 @@ Tokenizer_read(Tokenizer* self, Py_ssize_t delta) | |||||
| } | } | ||||
| /* | /* | ||||
| Parse the wikicode string, using *context* for when to stop. | |||||
| Read the value at a relative point in the wikicode, backwards. | |||||
| */ | */ | ||||
| static PyObject* | static PyObject* | ||||
| Tokenizer_parse(Tokenizer* self, int context) | |||||
| Tokenizer_read_backwards(Tokenizer* self, Py_ssize_t delta) | |||||
| { | |||||
| if (delta > self->head) { | |||||
| return EMPTY; | |||||
| } | |||||
| Py_ssize_t index = self->head - delta; | |||||
| return PySequence_Fast_GET_ITEM(self->text, index); | |||||
| } | |||||
| static int | |||||
| Tokenizer_parse_template_or_argument(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_parse_template(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_parse_argument(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_verify_safe(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_handle_template_param(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_handle_template_param_value(Tokenizer* self) | |||||
| { | { | ||||
| PyObject* this; | |||||
| } | |||||
| static PyObject* | |||||
| Tokenizer_handle_template_end(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_handle_argument_separator(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static PyObject* | |||||
| Tokenizer_handle_argument_end(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_parse_wikilink(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_handle_wikilink_separator(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static PyObject* | |||||
| Tokenizer_handle_wikilink_end(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_parse_heading(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static PyObject* | |||||
| Tokenizer_handle_heading_end(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_really_parse_entity(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_parse_entity(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| static int | |||||
| Tokenizer_parse_comment(Tokenizer* self) | |||||
| { | |||||
| } | |||||
| /* | |||||
| Parse the wikicode string, using context for when to stop. | |||||
| */ | |||||
| static PyObject* | |||||
| Tokenizer_parse(Tokenizer* self, Py_ssize_t context) | |||||
| { | |||||
| Py_ssize_t fail_contexts = ( | |||||
| CONTEXT("TEMPLATE") | CONTEXT("ARGUMENT") | CONTEXT("HEADING") | | |||||
| CONTEXT("COMMENT")); | |||||
| PyObject *this, *next; | |||||
| Py_UNICODE *this_data, *next_data, *next_next_data, *last_data; | |||||
| Py_ssize_t this_context; | |||||
| int is_marker, i; | |||||
| Tokenizer_push(self, context); | Tokenizer_push(self, context); | ||||
| while (1) { | while (1) { | ||||
| this = Tokenizer_read(self, 0); | this = Tokenizer_read(self, 0); | ||||
| /* if (this not in MARKERS) { | |||||
| WRITE TEXT | |||||
| } */ | |||||
| this_data = PyUnicode_AS_UNICODE(this); | |||||
| is_marker = 0; | |||||
| for (i = 0; i < NUM_MARKERS; i++) { | |||||
| if (MARKERS[i] == this_data) { | |||||
| is_marker = 1; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!is_marker) { | |||||
| Tokenizer_write_text(self, this); | |||||
| self->head++; | |||||
| continue; | |||||
| } | |||||
| this_context = Tokenizer_CONTEXT_VAL(self); | |||||
| if (this == EMPTY) { | if (this == EMPTY) { | ||||
| if (this_context & fail_contexts) { | |||||
| Tokenizer_fail_route(self); | |||||
| } | |||||
| return Tokenizer_pop(self); | return Tokenizer_pop(self); | ||||
| } | } | ||||
| next = Tokenizer_read(self, 1); | |||||
| next_data = PyUnicode_AS_UNICODE(next); | |||||
| if (this_context & CONTEXT("COMMENT")) { | |||||
| if (this_data == next_data && next_data == PU "-") { | |||||
| if (PyUnicode_AS_UNICODE(Tokenizer_read(self, 2)) == PU ">") { | |||||
| return Tokenizer_pop(self); | |||||
| } | |||||
| } | |||||
| Tokenizer_write_text(self, this); | |||||
| } | |||||
| else if (this_data == next_data && next_data == PU "{") { | |||||
| Tokenizer_parse_template_or_argument(self); | |||||
| } | |||||
| else if (this_data == PU "|" && this_context & CONTEXT("TEMPLATE")) { | |||||
| Tokenizer_handle_template_param(self); | |||||
| } | |||||
| else if (this_data == PU "=" && this_context & CONTEXT("TEMPLATE_PARAM_KEY")) { | |||||
| Tokenizer_handle_template_param_value(self); | |||||
| } | |||||
| else if (this_data == next_data && next_data == PU "}" && | |||||
| this_context & CONTEXT("TEMPLATE")) { | |||||
| Tokenizer_handle_template_end(self); | |||||
| } | |||||
| else if (this_data == PU "|" && this_context & CONTEXT("ARGUMENT_NAME")) { | |||||
| Tokenizer_handle_argument_separator(self); | |||||
| } | |||||
| else if (this_data == next_data && next_data == PU "}" && | |||||
| this_context & CONTEXT("ARGUMENT")) { | |||||
| if (PyUnicode_AS_UNICODE(Tokenizer_read(self, 2)) == PU "}") { | |||||
| return Tokenizer_handle_argument_end(self); | |||||
| } | |||||
| Tokenizer_write_text(self, this); | |||||
| } | |||||
| else if (this_data == next_data && next_data == PU "[") { | |||||
| if (!(this_context & CONTEXT("WIKILINK_TITLE"))) { | |||||
| Tokenizer_parse_wikilink(self); | |||||
| } | |||||
| else { | |||||
| Tokenizer_write_text(self, this); | |||||
| } | |||||
| } | |||||
| else if (this_data == PU "|" && this_context & CONTEXT("WIKILINK_TITLE")) { | |||||
| Tokenizer_handle_wikilink_separator(self); | |||||
| } | |||||
| else if (this_data == next_data && next_data == PU "]" && | |||||
| this_context & CONTEXT("WIKILINK")) { | |||||
| return Tokenizer_handle_wikilink_end(self); | |||||
| } | |||||
| else if (this_data == PU "=" && !(self->global & CONTEXT("GL_HEADING"))) { | |||||
| last_data = PyUnicode_AS_UNICODE(Tokenizer_read_backwards(self, 1)); | |||||
| if (last_data == PU "\n" || last_data == PU "") { | |||||
| Tokenizer_parse_heading(self); | |||||
| } | |||||
| else { | |||||
| Tokenizer_write_text(self, this); | |||||
| } | |||||
| } | |||||
| else if (this_data == PU "=" && this_context & CONTEXT("HEADING")) { | |||||
| return Tokenizer_handle_heading_end(self); | |||||
| } | |||||
| else if (this_data == PU "\n" && this_context & CONTEXT("HEADING")) { | |||||
| Tokenizer_fail_route(self); | |||||
| } | |||||
| else if (this_data == PU "&") { | |||||
| Tokenizer_parse_entity(self); | |||||
| } | |||||
| else if (this_data == PU "<" && next_data == PU "!") { | |||||
| next_next_data = PyUnicode_AS_UNICODE(Tokenizer_read(self, 2)); | |||||
| if (next_next_data == PyUnicode_AS_UNICODE(Tokenizer_read(self, 3)) && | |||||
| next_next_data == PU "-") { | |||||
| Tokenizer_parse_comment(self); | |||||
| } | |||||
| else { | |||||
| Tokenizer_write_text(self, this); | |||||
| } | |||||
| } | |||||
| else { | |||||
| Tokenizer_write_text(self, this); | |||||
| } | |||||
| self->head++; | self->head++; | ||||
| } | } | ||||
| } | } | ||||