From decf525cf60f8db8ffe1ee525a328b488d16f35b Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 29 Nov 2014 18:37:48 +0100 Subject: Fix prev pointer of emph->first_child --- src/inlines.c | 1 + src/node.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/inlines.c b/src/inlines.c index e08b757..5a8024d 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -431,6 +431,7 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) // fix tree structure tmp = emph->first_child; + tmp->prev = NULL; while (tmp->next != NULL && tmp->next != closer->first_inline) { tmp->parent = emph; tmp = tmp->next; diff --git a/src/node.c b/src/node.c index 4054881..fd92fdc 100644 --- a/src/node.c +++ b/src/node.c @@ -607,6 +607,11 @@ cmark_node_check(cmark_node *node, FILE *out) cur = node; while (true) { if (cur->first_child) { + if (cur->first_child->prev != NULL) { + S_print_error(out, cur->first_child, "prev"); + cur->first_child->prev = NULL; + ++errors; + } if (cur->first_child->parent != cur) { S_print_error(out, cur->first_child, "parent"); cur->first_child->parent = cur; -- cgit v1.2.3 From 51a0aa703209b831dce503b88655951b24957b51 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 29 Nov 2014 18:47:23 +0100 Subject: Split process_emphasis into two functions Makes the code more readable. --- src/inlines.c | 165 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 89 insertions(+), 76 deletions(-) diff --git a/src/inlines.c b/src/inlines.c index 5a8024d..3403cb0 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -41,6 +41,9 @@ typedef struct Subject { delimiter_stack *delimiters; } subject; +static delimiter_stack* +S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer); + static int parse_inline(subject* subj, cmark_node * parent); static void subject_from_buf(subject *e, strbuf *buffer, @@ -361,9 +364,7 @@ static cmark_node* handle_strong_emph(subject* subj, unsigned char c) static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) { delimiter_stack *closer = subj->delimiters; - delimiter_stack *opener, *tempstack, *nextstack; - int use_delims; - cmark_node *inl, *tmp, *emph; + delimiter_stack *opener; // move back to first relevant delim. while (closer != NULL && closer->previous != stack_bottom) { @@ -384,79 +385,7 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) opener = opener->previous; } if (opener != NULL && opener != stack_bottom) { - // calculate the actual number of delimeters used from this closer - if (closer->delim_count < 3 || opener->delim_count < 3) { - use_delims = closer->delim_count <= opener->delim_count ? - closer->delim_count : opener->delim_count; - } else { // closer and opener both have >= 3 delims - use_delims = closer->delim_count % 2 == 0 ? 2 : 1; - } - - inl = opener->first_inline; - - // remove used delimiters from stack elements and associated inlines. - opener->delim_count -= use_delims; - closer->delim_count -= use_delims; - inl->as.literal.len = opener->delim_count; - closer->first_inline->as.literal.len = closer->delim_count; - - // free delimiters between opener and closer - tempstack = closer->previous; - while (tempstack != NULL && tempstack != opener) { - nextstack = tempstack->previous; - remove_delimiter(subj, tempstack); - tempstack = nextstack; - } - - // create new emph or strong, and splice it in to our inlines - // 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; - emph->parent = inl->parent; - inl->next = emph; - - // if opener has 0 delims, remove it and its associated inline - if (opener->delim_count == 0) { - // replace empty opener inline with emph - chunk_free(&(inl->as.literal)); - inl->type = emph->type; - inl->next = emph->next; - inl->first_child = emph->first_child; - free(emph); - emph = inl; - // remove opener from stack - remove_delimiter(subj, opener); - } - - // fix tree structure - tmp = emph->first_child; - tmp->prev = NULL; - 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; - } - cmark_node_free(tmp); - // remove closer from stack - tempstack = closer->next; - remove_delimiter(subj, closer); - closer = tempstack; - } + closer = S_insert_emph(subj, opener, closer); } else { closer = closer->next; } @@ -470,6 +399,90 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) } } +static delimiter_stack* +S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) +{ + delimiter_stack *tempstack, *nextstack; + int use_delims; + cmark_node *inl, *tmp, *emph; + + // calculate the actual number of delimeters used from this closer + if (closer->delim_count < 3 || opener->delim_count < 3) { + use_delims = closer->delim_count <= opener->delim_count ? + closer->delim_count : opener->delim_count; + } else { // closer and opener both have >= 3 delims + use_delims = closer->delim_count % 2 == 0 ? 2 : 1; + } + + inl = opener->first_inline; + + // remove used delimiters from stack elements and associated inlines. + opener->delim_count -= use_delims; + closer->delim_count -= use_delims; + inl->as.literal.len = opener->delim_count; + closer->first_inline->as.literal.len = closer->delim_count; + + // free delimiters between opener and closer + tempstack = closer->previous; + while (tempstack != NULL && tempstack != opener) { + nextstack = tempstack->previous; + remove_delimiter(subj, tempstack); + tempstack = nextstack; + } + + // create new emph or strong, and splice it in to our inlines + // 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; + emph->parent = inl->parent; + inl->next = emph; + + // if opener has 0 delims, remove it and its associated inline + if (opener->delim_count == 0) { + // replace empty opener inline with emph + chunk_free(&(inl->as.literal)); + inl->type = emph->type; + inl->next = emph->next; + inl->first_child = emph->first_child; + free(emph); + emph = inl; + // remove opener from stack + remove_delimiter(subj, opener); + } + + // fix tree structure + tmp = emph->first_child; + tmp->prev = NULL; + 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; + } + cmark_node_free(tmp); + // remove closer from stack + tempstack = closer->next; + remove_delimiter(subj, closer); + closer = tempstack; + } + + return closer; +} + // Parse backslash-escape or just a backslash, returning an inline. static cmark_node* handle_backslash(subject *subj) { -- cgit v1.2.3 From a05151f75aa93a16b39333ba3d30e31930d61dec Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 29 Nov 2014 18:49:46 +0100 Subject: Remove redundant code next/prev pointers are handled by cmark_node_free. --- src/inlines.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/inlines.c b/src/inlines.c index 3403cb0..8487bf8 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -468,12 +468,7 @@ S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) // 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; - } - cmark_node_free(tmp); + cmark_node_free(closer->first_inline); // remove closer from stack tempstack = closer->next; remove_delimiter(subj, closer); -- cgit v1.2.3 From 664adf32706274333fe1053dc01853b117c31bce Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 29 Nov 2014 19:00:53 +0100 Subject: Optimize emph insertion Avoid unnecessary malloc/free if opener is removed. --- src/inlines.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/inlines.c b/src/inlines.c index 8487bf8..2652342 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -430,26 +430,26 @@ S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) tempstack = nextstack; } - // create new emph or strong, and splice it in to our inlines - // 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; - emph->parent = inl->parent; - inl->next = emph; - // if opener has 0 delims, remove it and its associated inline if (opener->delim_count == 0) { // replace empty opener inline with emph chunk_free(&(inl->as.literal)); - inl->type = emph->type; - inl->next = emph->next; - inl->first_child = emph->first_child; - free(emph); emph = inl; + emph->type = use_delims == 1 ? NODE_EMPH : NODE_STRONG; + emph->first_child = inl->next; // remove opener from stack remove_delimiter(subj, opener); } + else { + // create new emph or strong, and splice it in to our inlines + // between the opener and closer + emph = use_delims == 1 ? make_emph(inl->next) : make_strong(inl->next); + emph->parent = inl->parent; + emph->prev = inl; + inl->next = emph; + } + + emph->next = closer->first_inline; // fix tree structure tmp = emph->first_child; -- cgit v1.2.3 From a430f87ce8381efaead59c105b8d9b63e76a4c2f Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 29 Nov 2014 19:06:02 +0100 Subject: Add local variable for closer inline --- src/inlines.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/inlines.c b/src/inlines.c index 2652342..d36fdb6 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -404,7 +404,9 @@ S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) { delimiter_stack *tempstack, *nextstack; int use_delims; - cmark_node *inl, *tmp, *emph; + cmark_node *opener_inl = opener->first_inline; + cmark_node *closer_inl = closer->first_inline; + cmark_node *tmp, *emph; // calculate the actual number of delimeters used from this closer if (closer->delim_count < 3 || opener->delim_count < 3) { @@ -414,13 +416,11 @@ S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) use_delims = closer->delim_count % 2 == 0 ? 2 : 1; } - inl = opener->first_inline; - // remove used delimiters from stack elements and associated inlines. opener->delim_count -= use_delims; closer->delim_count -= use_delims; - inl->as.literal.len = opener->delim_count; - closer->first_inline->as.literal.len = closer->delim_count; + opener_inl->as.literal.len = opener->delim_count; + closer_inl->as.literal.len = closer->delim_count; // free delimiters between opener and closer tempstack = closer->previous; @@ -433,28 +433,29 @@ S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) // if opener has 0 delims, remove it and its associated inline if (opener->delim_count == 0) { // replace empty opener inline with emph - chunk_free(&(inl->as.literal)); - emph = inl; + chunk_free(&(opener_inl->as.literal)); + emph = opener_inl; emph->type = use_delims == 1 ? NODE_EMPH : NODE_STRONG; - emph->first_child = inl->next; + emph->first_child = opener_inl->next; // remove opener from stack remove_delimiter(subj, opener); } else { // create new emph or strong, and splice it in to our inlines // between the opener and closer - emph = use_delims == 1 ? make_emph(inl->next) : make_strong(inl->next); - emph->parent = inl->parent; - emph->prev = inl; - inl->next = emph; + emph = use_delims == 1 ? make_emph(opener_inl->next) + : make_strong(opener_inl->next); + emph->parent = opener_inl->parent; + emph->prev = opener_inl; + opener_inl->next = emph; } - emph->next = closer->first_inline; + emph->next = closer_inl; // fix tree structure tmp = emph->first_child; tmp->prev = NULL; - while (tmp->next != NULL && tmp->next != closer->first_inline) { + while (tmp->next != NULL && tmp->next != closer_inl) { tmp->parent = emph; tmp = tmp->next; } @@ -468,7 +469,7 @@ S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) // if closer has 0 delims, remove it and its associated inline if (closer->delim_count == 0) { // remove empty closer inline - cmark_node_free(closer->first_inline); + cmark_node_free(closer_inl); // remove closer from stack tempstack = closer->next; remove_delimiter(subj, closer); -- cgit v1.2.3 From 1d564e1fa3e8035bd9468a2f82348315b2e7b324 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 29 Nov 2014 19:13:40 +0100 Subject: Clarify code in insert_emph --- src/inlines.c | 52 ++++++++++++++++------------------------------------ 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/src/inlines.c b/src/inlines.c index d36fdb6..fdff57a 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -20,8 +20,8 @@ #define make_raw_html(s) make_literal(CMARK_NODE_INLINE_HTML, s) #define make_linebreak() make_simple(CMARK_NODE_LINEBREAK) #define make_softbreak() make_simple(CMARK_NODE_SOFTBREAK) -#define make_emph(contents) make_inlines(CMARK_NODE_EMPH, contents) -#define make_strong(contents) make_inlines(CMARK_NODE_STRONG, contents) +#define make_emph() make_simple(CMARK_NODE_EMPH) +#define make_strong() make_simple(CMARK_NODE_STRONG) typedef struct DelimiterStack { struct DelimiterStack *previous; @@ -86,24 +86,6 @@ static inline cmark_node* make_autolink(cmark_node* label, cmark_chunk url, int return make_link(label, cmark_clean_autolink(&url, is_email), NULL); } -// Setting 'last_child' and the parent of 'contents' is up to the caller. -static inline cmark_node* make_inlines(cmark_node_type t, cmark_node* contents) -{ - cmark_node * e = (cmark_node *)calloc(1, sizeof(*e)); - if(e != NULL) { - e->type = t; - e->first_child = contents; - e->next = NULL; - e->prev = NULL; - e->parent = NULL; - // These fields aren't used for inlines: - e->start_line = 0; - e->start_column = 0; - e->end_line = 0; - } - return e; -} - // Create an inline with a literal string value. static inline cmark_node* make_literal(cmark_node_type t, cmark_chunk s) { @@ -406,7 +388,7 @@ S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) int use_delims; cmark_node *opener_inl = opener->first_inline; cmark_node *closer_inl = closer->first_inline; - cmark_node *tmp, *emph; + cmark_node *tmp, *emph, *first_child, *last_child; // calculate the actual number of delimeters used from this closer if (closer->delim_count < 3 || opener->delim_count < 3) { @@ -430,41 +412,39 @@ S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) tempstack = nextstack; } + first_child = opener_inl->next; + last_child = closer_inl->prev; + // if opener has 0 delims, remove it and its associated inline if (opener->delim_count == 0) { // replace empty opener inline with emph chunk_free(&(opener_inl->as.literal)); emph = opener_inl; emph->type = use_delims == 1 ? NODE_EMPH : NODE_STRONG; - emph->first_child = opener_inl->next; // remove opener from stack remove_delimiter(subj, opener); } else { // create new emph or strong, and splice it in to our inlines // between the opener and closer - emph = use_delims == 1 ? make_emph(opener_inl->next) - : make_strong(opener_inl->next); + emph = use_delims == 1 ? make_emph() : make_strong(); emph->parent = opener_inl->parent; emph->prev = opener_inl; opener_inl->next = emph; } + // push children below emph emph->next = closer_inl; - - // fix tree structure - tmp = emph->first_child; - tmp->prev = NULL; - while (tmp->next != NULL && tmp->next != closer_inl) { + closer_inl->prev = emph; + emph->first_child = first_child; + emph->last_child = last_child; + + // fix children pointers + first_child->prev = NULL; + last_child->next = NULL; + for (tmp = first_child; tmp != NULL; tmp = tmp->next) { 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) { -- cgit v1.2.3