static StackVersion ts_parser__reduce()

in lib/src/parser.c [687:781]


static StackVersion ts_parser__reduce(TSParser *self, StackVersion version, TSSymbol symbol,
                                      uint32_t count, int dynamic_precedence,
                                      uint16_t production_id, bool fragile) {
  uint32_t initial_version_count = ts_stack_version_count(self->stack);
  uint32_t removed_version_count = 0;
  StackSliceArray pop = ts_stack_pop_count(self->stack, version, count);

  for (uint32_t i = 0; i < pop.size; i++) {
    StackSlice slice = pop.contents[i];
    StackVersion slice_version = slice.version - removed_version_count;

    // Error recovery can sometimes cause lots of stack versions to merge,
    // such that a single pop operation can produce a lots of slices.
    // Avoid creating too many stack versions in that situation.
    if (i > 0 && slice_version > MAX_VERSION_COUNT + MAX_VERSION_COUNT_OVERFLOW) {
      ts_stack_remove_version(self->stack, slice_version);
      ts_subtree_array_delete(&self->tree_pool, &slice.subtrees);
      removed_version_count++;
      while (i + 1 < pop.size) {
        StackSlice next_slice = pop.contents[i + 1];
        if (next_slice.version != slice.version) break;
        ts_subtree_array_delete(&self->tree_pool, &next_slice.subtrees);
        i++;
      }
      continue;
    }

    // Extra tokens on top of the stack should not be included in this new parent
    // node. They will be re-pushed onto the stack after the parent node is
    // created and pushed.
    SubtreeArray children = slice.subtrees;
    while (children.size > 0 && ts_subtree_extra(children.contents[children.size - 1])) {
      children.size--;
    }

    MutableSubtree parent = ts_subtree_new_node(&self->tree_pool,
      symbol, &children, production_id, self->language
    );

    // This pop operation may have caused multiple stack versions to collapse
    // into one, because they all diverged from a common state. In that case,
    // choose one of the arrays of trees to be the parent node's children, and
    // delete the rest of the tree arrays.
    while (i + 1 < pop.size) {
      StackSlice next_slice = pop.contents[i + 1];
      if (next_slice.version != slice.version) break;
      i++;

      SubtreeArray children = next_slice.subtrees;
      while (children.size > 0 && ts_subtree_extra(children.contents[children.size - 1])) {
        children.size--;
      }

      if (ts_parser__replace_children(self, &parent, &children)) {
        ts_subtree_array_delete(&self->tree_pool, &slice.subtrees);
        slice = next_slice;
      } else {
        ts_subtree_array_delete(&self->tree_pool, &next_slice.subtrees);
      }
    }

    parent.ptr->dynamic_precedence += dynamic_precedence;
    parent.ptr->production_id = production_id;

    TSStateId state = ts_stack_state(self->stack, slice_version);
    TSStateId next_state = ts_language_next_state(self->language, state, symbol);
    if (fragile || pop.size > 1 || initial_version_count > 1) {
      parent.ptr->fragile_left = true;
      parent.ptr->fragile_right = true;
      parent.ptr->parse_state = TS_TREE_STATE_NONE;
    } else {
      parent.ptr->parse_state = state;
    }

    // Push the parent node onto the stack, along with any extra tokens that
    // were previously on top of the stack.
    ts_stack_push(self->stack, slice_version, ts_subtree_from_mut(parent), false, next_state);
    for (uint32_t j = parent.ptr->child_count; j < slice.subtrees.size; j++) {
      ts_stack_push(self->stack, slice_version, slice.subtrees.contents[j], false, next_state);
    }

    for (StackVersion j = 0; j < slice_version; j++) {
      if (j == version) continue;
      if (ts_stack_merge(self->stack, j, slice_version)) {
        removed_version_count++;
        break;
      }
    }
  }

  // Return the first new stack version that was created.
  return ts_stack_version_count(self->stack) > initial_version_count
    ? initial_version_count
    : STACK_VERSION_NONE;
}