Skip to content

Commit

Permalink
Early-terminate the loop in check_open_blocks when the current line i…
Browse files Browse the repository at this point in the history
…s blank.
  • Loading branch information
kevinbackhouse committed Mar 6, 2023
1 parent c72487d commit aa73711
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
32 changes: 29 additions & 3 deletions src/blocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,11 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
// in parser. (Used to check that the counts in parser, which are updated incrementally, are
// correct.)
bool check_open_block_counts(cmark_parser *parser) {
cmark_parser tmp_parser = {0}; // Only used for its open_block_counts field.
cmark_parser tmp_parser = {0}; // Only used for its open_block_counts and total_open_blocks fields.
add_open_block_counts(&tmp_parser, parser->root);
return memcmp(tmp_parser.open_block_counts, parser->open_block_counts, sizeof(parser->open_block_counts)) == 0;
return
tmp_parser.total_open_blocks == parser->total_open_blocks &&
memcmp(tmp_parser.open_block_counts, parser->open_block_counts, sizeof(parser->open_block_counts)) == 0;
}

// Add a node as child of another. Return pointer to child.
Expand Down Expand Up @@ -1082,10 +1084,14 @@ static cmark_node *check_open_blocks(cmark_parser *parser, cmark_chunk *input,
*all_matched = false;
cmark_node *container = parser->root;
cmark_node_type cont_type;
cmark_parser tmp_parser; // Only used for its open_block_counts and total_open_blocks fields.
memcpy(tmp_parser.open_block_counts, parser->open_block_counts, sizeof(parser->open_block_counts));
tmp_parser.total_open_blocks = parser->total_open_blocks;

assert(check_open_block_counts(parser));

while (S_last_child_is_open(container)) {
decr_open_block_count(&tmp_parser, S_type(container));
container = container->last_child;
cont_type = S_type(container);

Expand All @@ -1097,6 +1103,26 @@ static cmark_node *check_open_blocks(cmark_parser *parser, cmark_chunk *input,
continue;
}

if (parser->blank) {
const size_t n_list = read_open_block_count(&tmp_parser, CMARK_NODE_LIST);
const size_t n_item = read_open_block_count(&tmp_parser, CMARK_NODE_ITEM);
const size_t n_para = read_open_block_count(&tmp_parser, CMARK_NODE_PARAGRAPH);
if (n_list + n_item + n_para == tmp_parser.total_open_blocks) {
if (parser->current->flags & CMARK_NODE__OPEN_BLOCK) {
if (S_type(parser->current) == CMARK_NODE_PARAGRAPH) {
container = parser->current;
goto done;
}
if (S_type(parser->current) == CMARK_NODE_ITEM) {
if (parser->current->flags & CMARK_NODE__OPEN) {
container = parser->current;
cont_type = S_type(container);
}
}
}
}
}

switch (cont_type) {
case CMARK_NODE_BLOCK_QUOTE:
if (!parse_block_quote_prefix(parser, input))
Expand Down Expand Up @@ -1387,7 +1413,7 @@ static void add_text_to_container(cmark_parser *parser, cmark_node *container,
S_set_last_line_blank(container, last_line_blank);

tmp = container;
while (tmp->parent) {
while (tmp->parent && S_last_line_blank(tmp->parent)) {
S_set_last_line_blank(tmp->parent, false);
tmp = tmp->parent;
}
Expand Down
10 changes: 10 additions & 0 deletions src/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,29 @@ struct cmark_parser {
* For example, CMARK_NODE_LIST (0x8003) is stored at offset 2.
*/
size_t open_block_counts[CMARK_NODE_TYPE_BLOCK_LIMIT];
size_t total_open_blocks;
};

static CMARK_INLINE void incr_open_block_count(cmark_parser *parser, cmark_node_type type) {
assert(type > CMARK_NODE_TYPE_BLOCK);
assert(type <= CMARK_NODE_TYPE_BLOCK + CMARK_NODE_TYPE_BLOCK_LIMIT);
parser->open_block_counts[type - CMARK_NODE_TYPE_BLOCK - 1]++;
parser->total_open_blocks++;
}

static CMARK_INLINE void decr_open_block_count(cmark_parser *parser, cmark_node_type type) {
assert(type > CMARK_NODE_TYPE_BLOCK);
assert(type <= CMARK_NODE_TYPE_BLOCK + CMARK_NODE_TYPE_BLOCK_LIMIT);
assert(parser->open_block_counts[type - CMARK_NODE_TYPE_BLOCK - 1] > 0);
parser->open_block_counts[type - CMARK_NODE_TYPE_BLOCK - 1]--;
assert(parser->total_open_blocks > 0);
parser->total_open_blocks--;
}

static CMARK_INLINE size_t read_open_block_count(cmark_parser *parser, cmark_node_type type) {
assert(type > CMARK_NODE_TYPE_BLOCK);
assert(type <= CMARK_NODE_TYPE_BLOCK + CMARK_NODE_TYPE_BLOCK_LIMIT);
return parser->open_block_counts[type - CMARK_NODE_TYPE_BLOCK - 1];
}

#ifdef __cplusplus
Expand Down

0 comments on commit aa73711

Please sign in to comment.