From 59fd5633da5395cbd3627af4a2ab855dc43ce1e0 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Tue, 18 Nov 2014 00:12:27 +0100 Subject: Set prev, parent and last_child for inlines --- src/blocks.c | 19 +++++++++++++++++++ src/inlines.c | 32 +++++++++++++++++++++++++++----- src/node.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/node.h | 3 +++ 4 files changed, 107 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/blocks.c b/src/blocks.c index cf5e08c..0e68259 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -283,6 +283,19 @@ typedef struct BlockStack { cmark_node *next_sibling; } block_stack; +static void fix_parents(cmark_node *node) { + cmark_node *cur = node->first_child; + if (cur == NULL) { + return; + } + while (cur->next != NULL) { + cur->parent = node; + cur = cur->next; + } + cur->parent = node; + node->last_child = cur; +} + // Walk through cmark_node and all children, recursively, parsing // string content into inline content where appropriate. static void process_inlines(cmark_node* cur, reference_map *refmap) @@ -296,6 +309,7 @@ static void process_inlines(cmark_node* cur, reference_map *refmap) case NODE_ATX_HEADER: case NODE_SETEXT_HEADER: cur->first_child = parse_inlines(&cur->string_content, refmap); + fix_parents(cur); break; default: @@ -817,6 +831,11 @@ cmark_node *cmark_finish(cmark_doc_parser *parser) { finalize_document(parser); strbuf_free(parser->curline); +#if CMARK_DEBUG_NODES + if (cmark_node_check(parser->root)) { + abort(); + } +#endif return parser->root; } diff --git a/src/inlines.c b/src/inlines.c index 078afd4..96b1792 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -193,6 +193,7 @@ static inline cmark_node* cmark_append_inlines(cmark_node* a, cmark_node* b) cur = cur->next; } cur->next = b; + b->prev = cur; return a; } @@ -395,12 +396,8 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) // between the opener and closer emph = use_delims == 1 ? make_emph(inl->next) : make_strong(inl->next); emph->next = closer->first_inline; + emph->prev = inl; inl->next = emph; - tmp = emph->first_child; - while (tmp->next != NULL && tmp->next != closer->first_inline) { - tmp = tmp->next; - } - tmp->next = NULL; // if opener has 0 delims, remove it and its associated inline if (opener->delim_count == 0) { @@ -415,11 +412,27 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) remove_delimiter(subj, opener); } + // fix tree structure + tmp = emph->first_child; + while (tmp->next != NULL && tmp->next != closer->first_inline) { + tmp->parent = emph; + tmp = tmp->next; + } + tmp->parent = emph; + if (tmp->next) { + tmp->next->prev = emph; + } + tmp->next = NULL; + emph->last_child = tmp; + // if closer has 0 delims, remove it and its associated inline if (closer->delim_count == 0) { // remove empty closer inline tmp = closer->first_inline; emph->next = tmp->next; + if (tmp->next) { + tmp->next->prev = emph; + } tmp->next = NULL; cmark_free_nodes(tmp); // remove closer from stack @@ -727,6 +740,15 @@ match: inl->as.link.url = url; inl->as.link.title = title; inl->next = NULL; + if (link_text) { + cmark_node *tmp; + link_text->prev = NULL; + for (tmp = link_text; tmp->next != NULL; tmp = tmp->next) { + tmp->parent = inl; + } + tmp->parent = inl; + inl->last_child = tmp; + } *last = inl; // process_emphasis will remove this delimiter and all later ones. diff --git a/src/node.c b/src/node.c index 547382a..ed58e90 100644 --- a/src/node.c +++ b/src/node.c @@ -249,6 +249,64 @@ static void splice_into_list(cmark_node* e, cmark_node* children) { return ; } +int +cmark_node_check(cmark_node *node) { + cmark_node *cur = node; + int errors = 0; + + while (cur) { + if (cur->first_child) { + if (cur->first_child->parent != cur) { + fprintf(stderr, + "Invalid 'parent' in node type %d\n", + cur->first_child->type); + cur->first_child->parent = cur; + ++errors; + } + cur = cur->first_child; + } + else if (cur->next) { + if (cur->next->prev != cur) { + fprintf(stderr, + "Invalid 'prev' in node type %d\n", + cur->next->type); + cur->next->prev = cur; + ++errors; + } + if (cur->next->parent != cur->parent) { + fprintf(stderr, + "Invalid 'parent' in node type %d\n", + cur->next->type); + cur->next->parent = cur->parent; + ++errors; + } + cur = cur->next; + } + else { + if (cur->parent->last_child != cur) { + fprintf(stderr, + "Invalid 'last_child' in node type %d\n", + cur->parent->type); + cur->parent->last_child = cur; + ++errors; + } + + cmark_node *ancestor = cur->parent; + cur = NULL; + + while (ancestor != node->parent) { + if (ancestor->next) { + cur = ancestor->next; + break; + } + ancestor = ancestor->parent; + } + } + } + + return errors; +} + // Free a cmark_node list and any children. void cmark_free_nodes(cmark_node *e) { diff --git a/src/node.h b/src/node.h index 755274e..f57ee3b 100644 --- a/src/node.h +++ b/src/node.h @@ -62,6 +62,9 @@ struct cmark_node { } as; }; +int +cmark_node_check(cmark_node *node); + #ifdef __cplusplus } #endif -- cgit v1.2.3