summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn MacFarlane <jgm@berkeley.edu>2014-11-29 13:01:55 -0800
committerJohn MacFarlane <jgm@berkeley.edu>2014-11-29 13:01:55 -0800
commite7efe2af56ceae5df00f23bb6090c81bb734bb5c (patch)
treefe8cff41001a17afd4d78b9ecbf1be303b3b31cf /src
parent5d16af6b134477d0e9b281cd1e9d962dc52b5088 (diff)
parent1d564e1fa3e8035bd9468a2f82348315b2e7b324 (diff)
Merge pull request #227 from nwellnhof/process_emph
Optimize and clarify process_emph
Diffstat (limited to 'src')
-rw-r--r--src/inlines.c180
-rw-r--r--src/node.c5
2 files changed, 90 insertions, 95 deletions
diff --git a/src/inlines.c b/src/inlines.c
index 2d26e81..0dcfd72 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;
@@ -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,
@@ -83,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)
{
@@ -361,9 +346,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,78 +367,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;
- 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;
}
@@ -469,6 +381,84 @@ 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 *opener_inl = opener->first_inline;
+ cmark_node *closer_inl = closer->first_inline;
+ 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) {
+ 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;
+ }
+
+ // remove used delimiters from stack elements and associated inlines.
+ opener->delim_count -= use_delims;
+ closer->delim_count -= use_delims;
+ 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;
+ while (tempstack != NULL && tempstack != opener) {
+ nextstack = tempstack->previous;
+ remove_delimiter(subj, tempstack);
+ 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;
+ // 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() : make_strong();
+ emph->parent = opener_inl->parent;
+ emph->prev = opener_inl;
+ opener_inl->next = emph;
+ }
+
+ // push children below emph
+ emph->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;
+ }
+
+ // if closer has 0 delims, remove it and its associated inline
+ if (closer->delim_count == 0) {
+ // remove empty closer inline
+ cmark_node_free(closer_inl);
+ // 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)
{
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;