diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 0e78663c..39321964 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -142,8 +142,12 @@ static StackNode *stack_node_new(StackNode *previous_node, const Subtree *subtre if (subtree) { node->error_cost += subtree->error_cost; node->position = length_add(node->position, ts_subtree_total_size(subtree)); - node->dynamic_precedence += subtree->dynamic_precedence; - if (!subtree->extra) node->node_count += subtree->node_count; + if (subtree->child_count) { + node->node_count += subtree->node_count; + node->dynamic_precedence += subtree->dynamic_precedence; + } else { + node->node_count++; + } } } else { node->position = length_zero(); @@ -162,6 +166,7 @@ static bool stack__subtree_is_equivalent(const Subtree *left, const Subtree *rig ((left->error_cost > 0 && right->error_cost > 0) || (left->padding.bytes == right->padding.bytes && left->size.bytes == right->size.bytes && + left->child_count == right->child_count && left->extra == right->extra && ts_subtree_external_scanner_state_eq(left, right)))); } @@ -177,7 +182,10 @@ static void stack_node_add_link(StackNode *self, StackLink link, SubtreePool *su // the special case where two links directly connect the same pair of nodes, // we can safely remove the ambiguity ahead of time without changing behavior. if (existing_link->node == link.node) { - if (link.subtree->dynamic_precedence > existing_link->subtree->dynamic_precedence) { + if ( + link.subtree->child_count > 0 && + link.subtree->dynamic_precedence > existing_link->subtree->dynamic_precedence + ) { ts_subtree_retain(link.subtree); ts_subtree_release(subtree_pool, existing_link->subtree); existing_link->subtree = link.subtree; @@ -205,15 +213,21 @@ static void stack_node_add_link(StackNode *self, StackLink link, SubtreePool *su if (self->link_count == MAX_LINK_COUNT) return; stack_node_retain(link.node); - if (link.subtree) ts_subtree_retain(link.subtree); + unsigned node_count = link.node->node_count; + int dynamic_precedence = link.node->dynamic_precedence; self->links[self->link_count++] = link; - unsigned node_count = link.node->node_count; - if (link.subtree) node_count += link.subtree->node_count; - if (node_count > self->node_count) self->node_count = node_count; + if (link.subtree) { + ts_subtree_retain(link.subtree); + if (link.subtree->child_count > 0) { + node_count += link.subtree->node_count; + dynamic_precedence += link.subtree->dynamic_precedence; + } else { + node_count++; + } + } - int dynamic_precedence = link.node->dynamic_precedence; - if (link.subtree) dynamic_precedence += link.subtree->dynamic_precedence; + if (node_count > self->node_count) self->node_count = node_count; if (dynamic_precedence > self->dynamic_precedence) self->dynamic_precedence = dynamic_precedence; } diff --git a/src/runtime/subtree.c b/src/runtime/subtree.c index 08d4aca7..6ba8dcfa 100644 --- a/src/runtime/subtree.c +++ b/src/runtime/subtree.c @@ -171,8 +171,6 @@ Subtree *ts_subtree_new_leaf(SubtreePool *pool, TSSymbol symbol, Length padding, result->ref_count = 1; result->bytes_scanned = 0; result->error_cost = 0; - result->node_count = 0; - result->dynamic_precedence = 0; result->child_count = 0; result->is_small = is_small; result->visible = metadata.visible; @@ -336,8 +334,13 @@ void ts_subtree_set_children(Subtree *self, const Subtree **children, uint32_t c if (child->symbol != ts_builtin_sym_error_repeat) { self->error_cost += child->error_cost; } - self->dynamic_precedence += child->dynamic_precedence; - self->node_count += child->node_count; + + if (child->child_count > 0) { + self->dynamic_precedence += child->dynamic_precedence; + self->node_count += child->node_count; + } else { + self->node_count++; + } if (alias_sequence && alias_sequence[non_extra_index] != 0 && !child->extra) { self->visible_child_count++; diff --git a/src/runtime/subtree.h b/src/runtime/subtree.h index 1a766f4f..3b0a2da8 100644 --- a/src/runtime/subtree.h +++ b/src/runtime/subtree.h @@ -17,7 +17,7 @@ extern TSStateId TS_TREE_STATE_NONE; typedef struct { union { char *long_data; - char short_data[16]; + char short_data[24]; }; uint32_t length; } ExternalScannerState; @@ -25,14 +25,18 @@ typedef struct { typedef struct Subtree Subtree; struct Subtree { + volatile uint32_t ref_count; Length padding; Length size; - volatile uint32_t ref_count; uint32_t bytes_scanned; uint32_t error_cost; - uint32_t node_count; - int32_t dynamic_precedence; uint32_t child_count; + TSSymbol symbol; + TSStateId parse_state; + struct { + TSSymbol symbol; + TSLexMode lex_mode; + } first_leaf; bool is_small : 1; bool visible : 1; @@ -44,12 +48,6 @@ struct Subtree { bool has_external_tokens : 1; bool is_missing : 1; bool is_keyword : 1; - TSSymbol symbol; - TSStateId parse_state; - struct { - TSSymbol symbol; - TSLexMode lex_mode; - } first_leaf; union { // Non-terminal subtrees (`child_count > 0`) @@ -57,11 +55,13 @@ struct Subtree { const Subtree **children; uint32_t visible_child_count; uint32_t named_child_count; + uint32_t node_count; uint32_t repeat_depth; + int32_t dynamic_precedence; uint16_t alias_sequence_id; }; - // Normal terminal subtrees (`child_count == 0 && symbol != ts_builtin_sym_error`) + // External terminal subtrees (`child_count == 0 && has_external_tokens`) ExternalScannerState external_scanner_state; // Error terminal subtrees (`child_count == 0 && symbol == ts_builtin_sym_error`)