cmark

My personal build of CMark ✏️

Commit
a6c0a1e8b3d2f3456972dad61a435684cac52cb5
Parent
4a7d4e01348660c8deb71bd55231439a4149ab05
Author
John MacFarlane <jgm@berkeley.edu>
Date

Make parse_inlines add directly to parent.

Previously parse_inlines returned a list of parsed inlines. This had to be added to the parent, and fix_parents had to be called to manually add the 'parent' links to the children, and the 'last_child' link to the parent.

Now parse_inlines takes the parent block as a parameter, and uses cmark_node_append_child to add the children, so that the pointers should be properly managed. This avoids the need for the fix_parents pass.

Diffstat

4 files changed, 21 insertions, 68 deletions

Status File Name N° Changes Insertions Deletions
Modified src/blocks.c 16 1 15
Modified src/inlines.c 70 18 52
Modified src/inlines.h 2 1 1
Modified src/node.c 1 1 0
diff --git a/src/blocks.c b/src/blocks.c
@@ -283,19 +283,6 @@ 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)
@@ -308,8 +295,7 @@ static void process_inlines(cmark_node* cur, reference_map *refmap)
 			case NODE_PARAGRAPH:
 			case NODE_ATX_HEADER:
 			case NODE_SETEXT_HEADER:
-				cur->first_child = parse_inlines(&cur->string_content, refmap);
-				fix_parents(cur);
+				parse_inlines(cur, refmap);
 				break;
 
 			default:
diff --git a/src/inlines.c b/src/inlines.c
@@ -41,8 +41,7 @@ typedef struct Subject {
 	delimiter_stack *delimiters;
 } subject;
 
-static cmark_node *parse_inlines_from_subject(subject* subj);
-static int parse_inline(subject* subj, cmark_node ** last);
+static int parse_inline(subject* subj, cmark_node * parent);
 
 static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap);
 static int subject_find_special_char(subject *subj);
@@ -184,22 +183,6 @@ static inline chunk take_while(subject* subj, int (*f)(int))
 	return chunk_dup(&subj->input, startpos, len);
 }
 
-// Append inline list b to the end of inline list a.
-// Return pointer to head of new list.
-static inline cmark_node* cmark_append_inlines(cmark_node* a, cmark_node* b)
-{
-	if (a == NULL) {  // NULL acts like an empty list
-		return b;
-	}
-	cmark_node* cur = a;
-	while (cur->next != NULL) {
-		cur = cur->next;
-	}
-	cur->next = b;
-	b->prev = cur;
-	return a;
-}
-
 // Try to process a backtick code span that began with a
 // span of ticks of length openticklength length (already
 // parsed).  Return 0 if you don't find matching closing
@@ -327,7 +310,7 @@ static delimiter_stack * push_delimiter(subject *subj,
 
 // Parse strong/emph or a fallback.
 // Assumes the subject has '_' or '*' at the current position.
-static cmark_node* handle_strong_emph(subject* subj, unsigned char c, cmark_node **last)
+static cmark_node* handle_strong_emph(subject* subj, unsigned char c)
 {
 	int numdelims;
 	cmark_node * inl_text;
@@ -436,7 +419,7 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom)
 					if (tmp->next) {
 						tmp->next->prev = emph;
 					}
-					tmp->next = NULL;
+					cmark_node_unlink(tmp);
 					cmark_free_nodes(tmp);
 					// remove closer from stack
 					tempstack = closer->next;
@@ -637,7 +620,7 @@ static int link_label(subject* subj, chunk *raw_label)
 }
 
 // Return a link, an image, or a literal close bracket.
-static cmark_node* handle_close_bracket(subject* subj, cmark_node **last)
+static cmark_node* handle_close_bracket(subject* subj, cmark_node *parent)
 {
 	int initial_pos;
 	int starturl, endurl, starttitle, endtitle, endall;
@@ -752,7 +735,7 @@ match:
 		tmp->parent = inl;
 		inl->last_child = tmp;
 	}
-	*last = inl;
+	parent->last_child = inl;
 
 	// process_emphasis will remove this delimiter and all later ones.
 	// Now, if we have a link, we also want to remove earlier link
@@ -792,23 +775,6 @@ static cmark_node* handle_newline(subject *subj)
 	}
 }
 
-// Parse inlines til end of subject, returning inlines.
-extern cmark_node* parse_inlines_from_subject(subject* subj)
-{
-	cmark_node* result = NULL;
-	cmark_node** last = &result;
-	cmark_node* first = NULL;
-	while (!is_eof(subj) && parse_inline(subj, last)) {
-		if (!first) {
-			first = *last;
-		}
-	}
-
-	process_emphasis(subj, NULL);
-
-	return first;
-}
-
 static int subject_find_special_char(subject *subj)
 {
 	// "\n\\`&_*[]<!"
@@ -841,10 +807,9 @@ static int subject_find_special_char(subject *subj)
 	return subj->input.len;
 }
 
-// Parse an inline, advancing subject, and add it to last element.
-// Adjust tail to point to new last element of list.
+// Parse an inline, advancing subject, and add it as a child of parent.
 // Return 0 if no inline can be parsed, 1 otherwise.
-static int parse_inline(subject* subj, cmark_node ** last)
+static int parse_inline(subject* subj, cmark_node * parent)
 {
 	cmark_node* new_inl = NULL;
 	chunk contents;
@@ -872,7 +837,7 @@ static int parse_inline(subject* subj, cmark_node ** last)
 		break;
 	case '*':
 	case '_':
-		new_inl = handle_strong_emph(subj, c, last);
+		new_inl = handle_strong_emph(subj, c);
 		break;
 	case '[':
 		advance(subj);
@@ -880,7 +845,7 @@ static int parse_inline(subject* subj, cmark_node ** last)
 		subj->delimiters = push_delimiter(subj, 1, '[', true, false, new_inl);
 		break;
 	case ']':
-		new_inl = handle_close_bracket(subj, last);
+		new_inl = handle_close_bracket(subj, parent);
 		break;
 	case '!':
 		advance(subj);
@@ -904,21 +869,22 @@ static int parse_inline(subject* subj, cmark_node ** last)
 
 		new_inl = make_str(contents);
 	}
-	if (*last == NULL) {
-		*last = new_inl;
-	} else if (new_inl) {
-		cmark_append_inlines(*last, new_inl);
-		*last = new_inl;
+	if (new_inl != NULL) {
+		cmark_node_append_child(parent, new_inl);
 	}
 
 	return 1;
 }
 
-extern cmark_node* parse_inlines(strbuf *input, reference_map *refmap)
+// Parse inlines from parent's string_content, adding as children of parent.
+extern void cmark_parse_inlines(cmark_node* parent, cmark_reference_map *refmap)
 {
 	subject subj;
-	subject_from_buf(&subj, input, refmap);
-	return parse_inlines_from_subject(&subj);
+	subject_from_buf(&subj, &parent->string_content, refmap);
+
+	while (!is_eof(&subj) && parse_inline(&subj, parent)) ;
+
+	process_emphasis(&subj, NULL);
 }
 
 // Parse zero or more space characters, including at most one newline.
diff --git a/src/inlines.h b/src/inlines.h
@@ -8,7 +8,7 @@ extern "C" {
 unsigned char *cmark_clean_url(cmark_chunk *url);
 unsigned char *cmark_clean_title(cmark_chunk *title);
 
-cmark_node* cmark_parse_inlines(cmark_strbuf *input, cmark_reference_map *refmap);
+void cmark_parse_inlines(cmark_node* parent, cmark_reference_map *refmap);
 
 int cmark_parse_reference_inline(cmark_strbuf *input, cmark_reference_map *refmap);
 
diff --git a/src/node.c b/src/node.c
@@ -114,6 +114,7 @@ cmark_node_unlink(cmark_node *node) {
 	node->next   = NULL;
 	node->prev   = NULL;
 	node->parent = NULL;
+
 }
 
 int