// NOTE: This file is generated by the templates/template.rb script and should not
// be modified manually. See /home/runner/work/herb/herb/templates/src/ast/ast_nodes.c.erb

#include <stdio.h>
#include <stdbool.h>

#include <prism.h>

#include "../include/analyze/analyzed_ruby.h"
#include "../include/ast/ast_node.h"
#include "../include/ast/ast_nodes.h"
#include "../include/errors.h"
#include "../include/lexer/token.h"
#include "../include/util/util.h"
#include "../include/lib/hb_allocator.h"
#include "../include/lib/hb_array.h"
#include "../include/lib/hb_string.h"


AST_DOCUMENT_NODE_T* ast_document_node_init(hb_array_T* children, herb_prism_context_T* prism_context, herb_prism_node_T prism_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_DOCUMENT_NODE_T* document_node = hb_allocator_alloc(allocator, sizeof(AST_DOCUMENT_NODE_T));

  if (!document_node) { return NULL; }

  ast_node_init(&document_node->base, AST_DOCUMENT_NODE, start_position, end_position, errors, allocator);

  document_node->children = children;
  document_node->prism_context = prism_context;
  document_node->prism_node = prism_node;

  return document_node;
}

AST_LITERAL_NODE_T* ast_literal_node_init(hb_string_T content, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_LITERAL_NODE_T* literal_node = hb_allocator_alloc(allocator, sizeof(AST_LITERAL_NODE_T));

  if (!literal_node) { return NULL; }

  ast_node_init(&literal_node->base, AST_LITERAL_NODE, start_position, end_position, errors, allocator);

  literal_node->content = hb_string_copy(content, allocator);

  return literal_node;
}

AST_HTML_OPEN_TAG_NODE_T* ast_html_open_tag_node_init(token_T* tag_opening, token_T* tag_name, token_T* tag_closing, hb_array_T* children, bool is_void, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_OPEN_TAG_NODE_T* html_open_tag_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_OPEN_TAG_NODE_T));

  if (!html_open_tag_node) { return NULL; }

  ast_node_init(&html_open_tag_node->base, AST_HTML_OPEN_TAG_NODE, start_position, end_position, errors, allocator);

  html_open_tag_node->tag_opening = token_copy(tag_opening, allocator);
  html_open_tag_node->tag_name = token_copy(tag_name, allocator);
  html_open_tag_node->tag_closing = token_copy(tag_closing, allocator);
  html_open_tag_node->children = children;
  html_open_tag_node->is_void = is_void;

  return html_open_tag_node;
}

AST_HTML_CONDITIONAL_OPEN_TAG_NODE_T* ast_html_conditional_open_tag_node_init(AST_NODE_T* conditional, token_T* tag_name, bool is_void, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_CONDITIONAL_OPEN_TAG_NODE_T* html_conditional_open_tag_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_CONDITIONAL_OPEN_TAG_NODE_T));

  if (!html_conditional_open_tag_node) { return NULL; }

  ast_node_init(&html_conditional_open_tag_node->base, AST_HTML_CONDITIONAL_OPEN_TAG_NODE, start_position, end_position, errors, allocator);

  html_conditional_open_tag_node->conditional = conditional;
  html_conditional_open_tag_node->tag_name = token_copy(tag_name, allocator);
  html_conditional_open_tag_node->is_void = is_void;

  return html_conditional_open_tag_node;
}

AST_HTML_CLOSE_TAG_NODE_T* ast_html_close_tag_node_init(token_T* tag_opening, token_T* tag_name, hb_array_T* children, token_T* tag_closing, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_CLOSE_TAG_NODE_T* html_close_tag_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_CLOSE_TAG_NODE_T));

  if (!html_close_tag_node) { return NULL; }

  ast_node_init(&html_close_tag_node->base, AST_HTML_CLOSE_TAG_NODE, start_position, end_position, errors, allocator);

  html_close_tag_node->tag_opening = token_copy(tag_opening, allocator);
  html_close_tag_node->tag_name = token_copy(tag_name, allocator);
  html_close_tag_node->children = children;
  html_close_tag_node->tag_closing = token_copy(tag_closing, allocator);

  return html_close_tag_node;
}

AST_HTML_OMITTED_CLOSE_TAG_NODE_T* ast_html_omitted_close_tag_node_init(token_T* tag_name, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_OMITTED_CLOSE_TAG_NODE_T* html_omitted_close_tag_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_OMITTED_CLOSE_TAG_NODE_T));

  if (!html_omitted_close_tag_node) { return NULL; }

  ast_node_init(&html_omitted_close_tag_node->base, AST_HTML_OMITTED_CLOSE_TAG_NODE, start_position, end_position, errors, allocator);

  html_omitted_close_tag_node->tag_name = token_copy(tag_name, allocator);

  return html_omitted_close_tag_node;
}

AST_HTML_VIRTUAL_CLOSE_TAG_NODE_T* ast_html_virtual_close_tag_node_init(token_T* tag_name, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_VIRTUAL_CLOSE_TAG_NODE_T* html_virtual_close_tag_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_VIRTUAL_CLOSE_TAG_NODE_T));

  if (!html_virtual_close_tag_node) { return NULL; }

  ast_node_init(&html_virtual_close_tag_node->base, AST_HTML_VIRTUAL_CLOSE_TAG_NODE, start_position, end_position, errors, allocator);

  html_virtual_close_tag_node->tag_name = token_copy(tag_name, allocator);

  return html_virtual_close_tag_node;
}

AST_HTML_ELEMENT_NODE_T* ast_html_element_node_init(AST_NODE_T* open_tag, token_T* tag_name, hb_array_T* body, AST_NODE_T* close_tag, bool is_void, hb_string_T element_source, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_ELEMENT_NODE_T* html_element_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_ELEMENT_NODE_T));

  if (!html_element_node) { return NULL; }

  ast_node_init(&html_element_node->base, AST_HTML_ELEMENT_NODE, start_position, end_position, errors, allocator);

  html_element_node->open_tag = open_tag;
  html_element_node->tag_name = token_copy(tag_name, allocator);
  html_element_node->body = body;
  html_element_node->close_tag = close_tag;
  html_element_node->is_void = is_void;
  html_element_node->element_source = element_source;

  return html_element_node;
}

AST_HTML_CONDITIONAL_ELEMENT_NODE_T* ast_html_conditional_element_node_init(hb_string_T condition, AST_NODE_T* open_conditional, struct AST_HTML_OPEN_TAG_NODE_STRUCT* open_tag, hb_array_T* body, AST_NODE_T* close_tag, AST_NODE_T* close_conditional, token_T* tag_name, hb_string_T element_source, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_CONDITIONAL_ELEMENT_NODE_T* html_conditional_element_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_CONDITIONAL_ELEMENT_NODE_T));

  if (!html_conditional_element_node) { return NULL; }

  ast_node_init(&html_conditional_element_node->base, AST_HTML_CONDITIONAL_ELEMENT_NODE, start_position, end_position, errors, allocator);

  html_conditional_element_node->condition = hb_string_copy(condition, allocator);
  html_conditional_element_node->open_conditional = open_conditional;
  html_conditional_element_node->open_tag = open_tag;
  html_conditional_element_node->body = body;
  html_conditional_element_node->close_tag = close_tag;
  html_conditional_element_node->close_conditional = close_conditional;
  html_conditional_element_node->tag_name = token_copy(tag_name, allocator);
  html_conditional_element_node->element_source = element_source;

  return html_conditional_element_node;
}

AST_HTML_ATTRIBUTE_VALUE_NODE_T* ast_html_attribute_value_node_init(token_T* open_quote, hb_array_T* children, token_T* close_quote, bool quoted, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_ATTRIBUTE_VALUE_NODE_T* html_attribute_value_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_ATTRIBUTE_VALUE_NODE_T));

  if (!html_attribute_value_node) { return NULL; }

  ast_node_init(&html_attribute_value_node->base, AST_HTML_ATTRIBUTE_VALUE_NODE, start_position, end_position, errors, allocator);

  html_attribute_value_node->open_quote = token_copy(open_quote, allocator);
  html_attribute_value_node->children = children;
  html_attribute_value_node->close_quote = token_copy(close_quote, allocator);
  html_attribute_value_node->quoted = quoted;

  return html_attribute_value_node;
}

AST_HTML_ATTRIBUTE_NAME_NODE_T* ast_html_attribute_name_node_init(hb_array_T* children, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_ATTRIBUTE_NAME_NODE_T* html_attribute_name_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_ATTRIBUTE_NAME_NODE_T));

  if (!html_attribute_name_node) { return NULL; }

  ast_node_init(&html_attribute_name_node->base, AST_HTML_ATTRIBUTE_NAME_NODE, start_position, end_position, errors, allocator);

  html_attribute_name_node->children = children;

  return html_attribute_name_node;
}

AST_HTML_ATTRIBUTE_NODE_T* ast_html_attribute_node_init(struct AST_HTML_ATTRIBUTE_NAME_NODE_STRUCT* name, token_T* equals, struct AST_HTML_ATTRIBUTE_VALUE_NODE_STRUCT* value, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_ATTRIBUTE_NODE_T* html_attribute_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_ATTRIBUTE_NODE_T));

  if (!html_attribute_node) { return NULL; }

  ast_node_init(&html_attribute_node->base, AST_HTML_ATTRIBUTE_NODE, start_position, end_position, errors, allocator);

  html_attribute_node->name = name;
  html_attribute_node->equals = token_copy(equals, allocator);
  html_attribute_node->value = value;

  return html_attribute_node;
}

AST_RUBY_LITERAL_NODE_T* ast_ruby_literal_node_init(hb_string_T content, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_RUBY_LITERAL_NODE_T* ruby_literal_node = hb_allocator_alloc(allocator, sizeof(AST_RUBY_LITERAL_NODE_T));

  if (!ruby_literal_node) { return NULL; }

  ast_node_init(&ruby_literal_node->base, AST_RUBY_LITERAL_NODE, start_position, end_position, errors, allocator);

  ruby_literal_node->content = hb_string_copy(content, allocator);

  return ruby_literal_node;
}

AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE_T* ast_ruby_html_attributes_splat_node_init(hb_string_T content, hb_string_T prefix, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE_T* ruby_html_attributes_splat_node = hb_allocator_alloc(allocator, sizeof(AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE_T));

  if (!ruby_html_attributes_splat_node) { return NULL; }

  ast_node_init(&ruby_html_attributes_splat_node->base, AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE, start_position, end_position, errors, allocator);

  ruby_html_attributes_splat_node->content = hb_string_copy(content, allocator);
  ruby_html_attributes_splat_node->prefix = hb_string_copy(prefix, allocator);

  return ruby_html_attributes_splat_node;
}

AST_ERB_OPEN_TAG_NODE_T* ast_erb_open_tag_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, token_T* tag_name, hb_array_T* children, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_OPEN_TAG_NODE_T* erb_open_tag_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_OPEN_TAG_NODE_T));

  if (!erb_open_tag_node) { return NULL; }

  ast_node_init(&erb_open_tag_node->base, AST_ERB_OPEN_TAG_NODE, start_position, end_position, errors, allocator);

  erb_open_tag_node->tag_opening = token_copy(tag_opening, allocator);
  erb_open_tag_node->content = token_copy(content, allocator);
  erb_open_tag_node->tag_closing = token_copy(tag_closing, allocator);
  erb_open_tag_node->tag_name = token_copy(tag_name, allocator);
  erb_open_tag_node->children = children;

  return erb_open_tag_node;
}

AST_HTML_TEXT_NODE_T* ast_html_text_node_init(hb_string_T content, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_TEXT_NODE_T* html_text_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_TEXT_NODE_T));

  if (!html_text_node) { return NULL; }

  ast_node_init(&html_text_node->base, AST_HTML_TEXT_NODE, start_position, end_position, errors, allocator);

  html_text_node->content = hb_string_copy(content, allocator);

  return html_text_node;
}

AST_HTML_COMMENT_NODE_T* ast_html_comment_node_init(token_T* comment_start, hb_array_T* children, token_T* comment_end, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_COMMENT_NODE_T* html_comment_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_COMMENT_NODE_T));

  if (!html_comment_node) { return NULL; }

  ast_node_init(&html_comment_node->base, AST_HTML_COMMENT_NODE, start_position, end_position, errors, allocator);

  html_comment_node->comment_start = token_copy(comment_start, allocator);
  html_comment_node->children = children;
  html_comment_node->comment_end = token_copy(comment_end, allocator);

  return html_comment_node;
}

AST_HTML_DOCTYPE_NODE_T* ast_html_doctype_node_init(token_T* tag_opening, hb_array_T* children, token_T* tag_closing, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_HTML_DOCTYPE_NODE_T* html_doctype_node = hb_allocator_alloc(allocator, sizeof(AST_HTML_DOCTYPE_NODE_T));

  if (!html_doctype_node) { return NULL; }

  ast_node_init(&html_doctype_node->base, AST_HTML_DOCTYPE_NODE, start_position, end_position, errors, allocator);

  html_doctype_node->tag_opening = token_copy(tag_opening, allocator);
  html_doctype_node->children = children;
  html_doctype_node->tag_closing = token_copy(tag_closing, allocator);

  return html_doctype_node;
}

AST_XML_DECLARATION_NODE_T* ast_xml_declaration_node_init(token_T* tag_opening, hb_array_T* children, token_T* tag_closing, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_XML_DECLARATION_NODE_T* xml_declaration_node = hb_allocator_alloc(allocator, sizeof(AST_XML_DECLARATION_NODE_T));

  if (!xml_declaration_node) { return NULL; }

  ast_node_init(&xml_declaration_node->base, AST_XML_DECLARATION_NODE, start_position, end_position, errors, allocator);

  xml_declaration_node->tag_opening = token_copy(tag_opening, allocator);
  xml_declaration_node->children = children;
  xml_declaration_node->tag_closing = token_copy(tag_closing, allocator);

  return xml_declaration_node;
}

AST_CDATA_NODE_T* ast_cdata_node_init(token_T* tag_opening, hb_array_T* children, token_T* tag_closing, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_CDATA_NODE_T* cdata_node = hb_allocator_alloc(allocator, sizeof(AST_CDATA_NODE_T));

  if (!cdata_node) { return NULL; }

  ast_node_init(&cdata_node->base, AST_CDATA_NODE, start_position, end_position, errors, allocator);

  cdata_node->tag_opening = token_copy(tag_opening, allocator);
  cdata_node->children = children;
  cdata_node->tag_closing = token_copy(tag_closing, allocator);

  return cdata_node;
}

AST_WHITESPACE_NODE_T* ast_whitespace_node_init(token_T* value, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_WHITESPACE_NODE_T* whitespace_node = hb_allocator_alloc(allocator, sizeof(AST_WHITESPACE_NODE_T));

  if (!whitespace_node) { return NULL; }

  ast_node_init(&whitespace_node->base, AST_WHITESPACE_NODE, start_position, end_position, errors, allocator);

  whitespace_node->value = token_copy(value, allocator);

  return whitespace_node;
}

AST_ERB_CONTENT_NODE_T* ast_erb_content_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, analyzed_ruby_T* analyzed_ruby, bool parsed, bool valid, herb_prism_node_T prism_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_CONTENT_NODE_T* erb_content_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_CONTENT_NODE_T));

  if (!erb_content_node) { return NULL; }

  ast_node_init(&erb_content_node->base, AST_ERB_CONTENT_NODE, start_position, end_position, errors, allocator);

  erb_content_node->tag_opening = token_copy(tag_opening, allocator);
  erb_content_node->content = token_copy(content, allocator);
  erb_content_node->tag_closing = token_copy(tag_closing, allocator);
  erb_content_node->analyzed_ruby = analyzed_ruby;
  erb_content_node->parsed = parsed;
  erb_content_node->valid = valid;
  erb_content_node->prism_node = prism_node;

  return erb_content_node;
}

AST_ERB_END_NODE_T* ast_erb_end_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_END_NODE_T* erb_end_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_END_NODE_T));

  if (!erb_end_node) { return NULL; }

  ast_node_init(&erb_end_node->base, AST_ERB_END_NODE, start_position, end_position, errors, allocator);

  erb_end_node->tag_opening = token_copy(tag_opening, allocator);
  erb_end_node->content = token_copy(content, allocator);
  erb_end_node->tag_closing = token_copy(tag_closing, allocator);

  return erb_end_node;
}

AST_ERB_ELSE_NODE_T* ast_erb_else_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_ELSE_NODE_T* erb_else_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_ELSE_NODE_T));

  if (!erb_else_node) { return NULL; }

  ast_node_init(&erb_else_node->base, AST_ERB_ELSE_NODE, start_position, end_position, errors, allocator);

  erb_else_node->tag_opening = token_copy(tag_opening, allocator);
  erb_else_node->content = token_copy(content, allocator);
  erb_else_node->tag_closing = token_copy(tag_closing, allocator);
  erb_else_node->statements = statements;

  return erb_else_node;
}

AST_ERB_IF_NODE_T* ast_erb_if_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, location_T* then_keyword, herb_prism_node_T prism_node, hb_array_T* statements, AST_NODE_T* subsequent, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_IF_NODE_T* erb_if_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_IF_NODE_T));

  if (!erb_if_node) { return NULL; }

  ast_node_init(&erb_if_node->base, AST_ERB_IF_NODE, start_position, end_position, errors, allocator);

  erb_if_node->tag_opening = token_copy(tag_opening, allocator);
  erb_if_node->content = token_copy(content, allocator);
  erb_if_node->tag_closing = token_copy(tag_closing, allocator);
  erb_if_node->then_keyword = then_keyword;
  erb_if_node->prism_node = prism_node;
  erb_if_node->statements = statements;
  erb_if_node->subsequent = subsequent;
  erb_if_node->end_node = end_node;

  return erb_if_node;
}

AST_ERB_BLOCK_NODE_T* ast_erb_block_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, herb_prism_node_T prism_node, hb_array_T* body, struct AST_ERB_RESCUE_NODE_STRUCT* rescue_clause, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_ENSURE_NODE_STRUCT* ensure_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_BLOCK_NODE_T* erb_block_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_BLOCK_NODE_T));

  if (!erb_block_node) { return NULL; }

  ast_node_init(&erb_block_node->base, AST_ERB_BLOCK_NODE, start_position, end_position, errors, allocator);

  erb_block_node->tag_opening = token_copy(tag_opening, allocator);
  erb_block_node->content = token_copy(content, allocator);
  erb_block_node->tag_closing = token_copy(tag_closing, allocator);
  erb_block_node->prism_node = prism_node;
  erb_block_node->body = body;
  erb_block_node->rescue_clause = rescue_clause;
  erb_block_node->else_clause = else_clause;
  erb_block_node->ensure_clause = ensure_clause;
  erb_block_node->end_node = end_node;

  return erb_block_node;
}

AST_ERB_WHEN_NODE_T* ast_erb_when_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, location_T* then_keyword, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_WHEN_NODE_T* erb_when_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_WHEN_NODE_T));

  if (!erb_when_node) { return NULL; }

  ast_node_init(&erb_when_node->base, AST_ERB_WHEN_NODE, start_position, end_position, errors, allocator);

  erb_when_node->tag_opening = token_copy(tag_opening, allocator);
  erb_when_node->content = token_copy(content, allocator);
  erb_when_node->tag_closing = token_copy(tag_closing, allocator);
  erb_when_node->then_keyword = then_keyword;
  erb_when_node->statements = statements;

  return erb_when_node;
}

AST_ERB_CASE_NODE_T* ast_erb_case_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* children, herb_prism_node_T prism_node, hb_array_T* conditions, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_CASE_NODE_T* erb_case_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_CASE_NODE_T));

  if (!erb_case_node) { return NULL; }

  ast_node_init(&erb_case_node->base, AST_ERB_CASE_NODE, start_position, end_position, errors, allocator);

  erb_case_node->tag_opening = token_copy(tag_opening, allocator);
  erb_case_node->content = token_copy(content, allocator);
  erb_case_node->tag_closing = token_copy(tag_closing, allocator);
  erb_case_node->children = children;
  erb_case_node->prism_node = prism_node;
  erb_case_node->conditions = conditions;
  erb_case_node->else_clause = else_clause;
  erb_case_node->end_node = end_node;

  return erb_case_node;
}

AST_ERB_CASE_MATCH_NODE_T* ast_erb_case_match_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* children, herb_prism_node_T prism_node, hb_array_T* conditions, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_CASE_MATCH_NODE_T* erb_case_match_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_CASE_MATCH_NODE_T));

  if (!erb_case_match_node) { return NULL; }

  ast_node_init(&erb_case_match_node->base, AST_ERB_CASE_MATCH_NODE, start_position, end_position, errors, allocator);

  erb_case_match_node->tag_opening = token_copy(tag_opening, allocator);
  erb_case_match_node->content = token_copy(content, allocator);
  erb_case_match_node->tag_closing = token_copy(tag_closing, allocator);
  erb_case_match_node->children = children;
  erb_case_match_node->prism_node = prism_node;
  erb_case_match_node->conditions = conditions;
  erb_case_match_node->else_clause = else_clause;
  erb_case_match_node->end_node = end_node;

  return erb_case_match_node;
}

AST_ERB_WHILE_NODE_T* ast_erb_while_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, herb_prism_node_T prism_node, hb_array_T* statements, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_WHILE_NODE_T* erb_while_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_WHILE_NODE_T));

  if (!erb_while_node) { return NULL; }

  ast_node_init(&erb_while_node->base, AST_ERB_WHILE_NODE, start_position, end_position, errors, allocator);

  erb_while_node->tag_opening = token_copy(tag_opening, allocator);
  erb_while_node->content = token_copy(content, allocator);
  erb_while_node->tag_closing = token_copy(tag_closing, allocator);
  erb_while_node->prism_node = prism_node;
  erb_while_node->statements = statements;
  erb_while_node->end_node = end_node;

  return erb_while_node;
}

AST_ERB_UNTIL_NODE_T* ast_erb_until_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, herb_prism_node_T prism_node, hb_array_T* statements, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_UNTIL_NODE_T* erb_until_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_UNTIL_NODE_T));

  if (!erb_until_node) { return NULL; }

  ast_node_init(&erb_until_node->base, AST_ERB_UNTIL_NODE, start_position, end_position, errors, allocator);

  erb_until_node->tag_opening = token_copy(tag_opening, allocator);
  erb_until_node->content = token_copy(content, allocator);
  erb_until_node->tag_closing = token_copy(tag_closing, allocator);
  erb_until_node->prism_node = prism_node;
  erb_until_node->statements = statements;
  erb_until_node->end_node = end_node;

  return erb_until_node;
}

AST_ERB_FOR_NODE_T* ast_erb_for_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, herb_prism_node_T prism_node, hb_array_T* statements, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_FOR_NODE_T* erb_for_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_FOR_NODE_T));

  if (!erb_for_node) { return NULL; }

  ast_node_init(&erb_for_node->base, AST_ERB_FOR_NODE, start_position, end_position, errors, allocator);

  erb_for_node->tag_opening = token_copy(tag_opening, allocator);
  erb_for_node->content = token_copy(content, allocator);
  erb_for_node->tag_closing = token_copy(tag_closing, allocator);
  erb_for_node->prism_node = prism_node;
  erb_for_node->statements = statements;
  erb_for_node->end_node = end_node;

  return erb_for_node;
}

AST_ERB_RESCUE_NODE_T* ast_erb_rescue_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, struct AST_ERB_RESCUE_NODE_STRUCT* subsequent, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_RESCUE_NODE_T* erb_rescue_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_RESCUE_NODE_T));

  if (!erb_rescue_node) { return NULL; }

  ast_node_init(&erb_rescue_node->base, AST_ERB_RESCUE_NODE, start_position, end_position, errors, allocator);

  erb_rescue_node->tag_opening = token_copy(tag_opening, allocator);
  erb_rescue_node->content = token_copy(content, allocator);
  erb_rescue_node->tag_closing = token_copy(tag_closing, allocator);
  erb_rescue_node->statements = statements;
  erb_rescue_node->subsequent = subsequent;

  return erb_rescue_node;
}

AST_ERB_ENSURE_NODE_T* ast_erb_ensure_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_ENSURE_NODE_T* erb_ensure_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_ENSURE_NODE_T));

  if (!erb_ensure_node) { return NULL; }

  ast_node_init(&erb_ensure_node->base, AST_ERB_ENSURE_NODE, start_position, end_position, errors, allocator);

  erb_ensure_node->tag_opening = token_copy(tag_opening, allocator);
  erb_ensure_node->content = token_copy(content, allocator);
  erb_ensure_node->tag_closing = token_copy(tag_closing, allocator);
  erb_ensure_node->statements = statements;

  return erb_ensure_node;
}

AST_ERB_BEGIN_NODE_T* ast_erb_begin_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, herb_prism_node_T prism_node, hb_array_T* statements, struct AST_ERB_RESCUE_NODE_STRUCT* rescue_clause, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_ENSURE_NODE_STRUCT* ensure_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_BEGIN_NODE_T* erb_begin_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_BEGIN_NODE_T));

  if (!erb_begin_node) { return NULL; }

  ast_node_init(&erb_begin_node->base, AST_ERB_BEGIN_NODE, start_position, end_position, errors, allocator);

  erb_begin_node->tag_opening = token_copy(tag_opening, allocator);
  erb_begin_node->content = token_copy(content, allocator);
  erb_begin_node->tag_closing = token_copy(tag_closing, allocator);
  erb_begin_node->prism_node = prism_node;
  erb_begin_node->statements = statements;
  erb_begin_node->rescue_clause = rescue_clause;
  erb_begin_node->else_clause = else_clause;
  erb_begin_node->ensure_clause = ensure_clause;
  erb_begin_node->end_node = end_node;

  return erb_begin_node;
}

AST_ERB_UNLESS_NODE_T* ast_erb_unless_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, location_T* then_keyword, herb_prism_node_T prism_node, hb_array_T* statements, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_UNLESS_NODE_T* erb_unless_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_UNLESS_NODE_T));

  if (!erb_unless_node) { return NULL; }

  ast_node_init(&erb_unless_node->base, AST_ERB_UNLESS_NODE, start_position, end_position, errors, allocator);

  erb_unless_node->tag_opening = token_copy(tag_opening, allocator);
  erb_unless_node->content = token_copy(content, allocator);
  erb_unless_node->tag_closing = token_copy(tag_closing, allocator);
  erb_unless_node->then_keyword = then_keyword;
  erb_unless_node->prism_node = prism_node;
  erb_unless_node->statements = statements;
  erb_unless_node->else_clause = else_clause;
  erb_unless_node->end_node = end_node;

  return erb_unless_node;
}

AST_RUBY_RENDER_LOCAL_NODE_T* ast_ruby_render_local_node_init(token_T* name, struct AST_RUBY_LITERAL_NODE_STRUCT* value, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_RUBY_RENDER_LOCAL_NODE_T* ruby_render_local_node = hb_allocator_alloc(allocator, sizeof(AST_RUBY_RENDER_LOCAL_NODE_T));

  if (!ruby_render_local_node) { return NULL; }

  ast_node_init(&ruby_render_local_node->base, AST_RUBY_RENDER_LOCAL_NODE, start_position, end_position, errors, allocator);

  ruby_render_local_node->name = token_copy(name, allocator);
  ruby_render_local_node->value = value;

  return ruby_render_local_node;
}

AST_ERB_RENDER_NODE_T* ast_erb_render_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, analyzed_ruby_T* analyzed_ruby, herb_prism_node_T prism_node, token_T* partial, token_T* template_path, token_T* layout, token_T* file, token_T* inline_template, token_T* body, token_T* plain, token_T* html, token_T* renderable, token_T* collection, token_T* object, token_T* as_name, token_T* spacer_template, token_T* formats, token_T* variants, token_T* handlers, token_T* content_type, hb_array_T* locals, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_RENDER_NODE_T* erb_render_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_RENDER_NODE_T));

  if (!erb_render_node) { return NULL; }

  ast_node_init(&erb_render_node->base, AST_ERB_RENDER_NODE, start_position, end_position, errors, allocator);

  erb_render_node->tag_opening = token_copy(tag_opening, allocator);
  erb_render_node->content = token_copy(content, allocator);
  erb_render_node->tag_closing = token_copy(tag_closing, allocator);
  erb_render_node->analyzed_ruby = analyzed_ruby;
  erb_render_node->prism_node = prism_node;
  erb_render_node->partial = token_copy(partial, allocator);
  erb_render_node->template_path = token_copy(template_path, allocator);
  erb_render_node->layout = token_copy(layout, allocator);
  erb_render_node->file = token_copy(file, allocator);
  erb_render_node->inline_template = token_copy(inline_template, allocator);
  erb_render_node->body = token_copy(body, allocator);
  erb_render_node->plain = token_copy(plain, allocator);
  erb_render_node->html = token_copy(html, allocator);
  erb_render_node->renderable = token_copy(renderable, allocator);
  erb_render_node->collection = token_copy(collection, allocator);
  erb_render_node->object = token_copy(object, allocator);
  erb_render_node->as_name = token_copy(as_name, allocator);
  erb_render_node->spacer_template = token_copy(spacer_template, allocator);
  erb_render_node->formats = token_copy(formats, allocator);
  erb_render_node->variants = token_copy(variants, allocator);
  erb_render_node->handlers = token_copy(handlers, allocator);
  erb_render_node->content_type = token_copy(content_type, allocator);
  erb_render_node->locals = locals;

  return erb_render_node;
}

AST_RUBY_STRICT_LOCAL_NODE_T* ast_ruby_strict_local_node_init(token_T* name, struct AST_RUBY_LITERAL_NODE_STRUCT* default_value, bool required, bool double_splat, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_RUBY_STRICT_LOCAL_NODE_T* ruby_strict_local_node = hb_allocator_alloc(allocator, sizeof(AST_RUBY_STRICT_LOCAL_NODE_T));

  if (!ruby_strict_local_node) { return NULL; }

  ast_node_init(&ruby_strict_local_node->base, AST_RUBY_STRICT_LOCAL_NODE, start_position, end_position, errors, allocator);

  ruby_strict_local_node->name = token_copy(name, allocator);
  ruby_strict_local_node->default_value = default_value;
  ruby_strict_local_node->required = required;
  ruby_strict_local_node->double_splat = double_splat;

  return ruby_strict_local_node;
}

AST_ERB_STRICT_LOCALS_NODE_T* ast_erb_strict_locals_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, analyzed_ruby_T* analyzed_ruby, herb_prism_node_T prism_node, hb_array_T* locals, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_STRICT_LOCALS_NODE_T* erb_strict_locals_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_STRICT_LOCALS_NODE_T));

  if (!erb_strict_locals_node) { return NULL; }

  ast_node_init(&erb_strict_locals_node->base, AST_ERB_STRICT_LOCALS_NODE, start_position, end_position, errors, allocator);

  erb_strict_locals_node->tag_opening = token_copy(tag_opening, allocator);
  erb_strict_locals_node->content = token_copy(content, allocator);
  erb_strict_locals_node->tag_closing = token_copy(tag_closing, allocator);
  erb_strict_locals_node->analyzed_ruby = analyzed_ruby;
  erb_strict_locals_node->prism_node = prism_node;
  erb_strict_locals_node->locals = locals;

  return erb_strict_locals_node;
}

AST_ERB_YIELD_NODE_T* ast_erb_yield_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_YIELD_NODE_T* erb_yield_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_YIELD_NODE_T));

  if (!erb_yield_node) { return NULL; }

  ast_node_init(&erb_yield_node->base, AST_ERB_YIELD_NODE, start_position, end_position, errors, allocator);

  erb_yield_node->tag_opening = token_copy(tag_opening, allocator);
  erb_yield_node->content = token_copy(content, allocator);
  erb_yield_node->tag_closing = token_copy(tag_closing, allocator);

  return erb_yield_node;
}

AST_ERB_IN_NODE_T* ast_erb_in_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, location_T* then_keyword, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator) {
  AST_ERB_IN_NODE_T* erb_in_node = hb_allocator_alloc(allocator, sizeof(AST_ERB_IN_NODE_T));

  if (!erb_in_node) { return NULL; }

  ast_node_init(&erb_in_node->base, AST_ERB_IN_NODE, start_position, end_position, errors, allocator);

  erb_in_node->tag_opening = token_copy(tag_opening, allocator);
  erb_in_node->content = token_copy(content, allocator);
  erb_in_node->tag_closing = token_copy(tag_closing, allocator);
  erb_in_node->then_keyword = then_keyword;
  erb_in_node->statements = statements;

  return erb_in_node;
}

hb_string_T ast_node_type_to_string(AST_NODE_T* node) {
  switch (node->type) {
    case AST_DOCUMENT_NODE: return hb_string("AST_DOCUMENT_NODE");
    case AST_LITERAL_NODE: return hb_string("AST_LITERAL_NODE");
    case AST_HTML_OPEN_TAG_NODE: return hb_string("AST_HTML_OPEN_TAG_NODE");
    case AST_HTML_CONDITIONAL_OPEN_TAG_NODE: return hb_string("AST_HTML_CONDITIONAL_OPEN_TAG_NODE");
    case AST_HTML_CLOSE_TAG_NODE: return hb_string("AST_HTML_CLOSE_TAG_NODE");
    case AST_HTML_OMITTED_CLOSE_TAG_NODE: return hb_string("AST_HTML_OMITTED_CLOSE_TAG_NODE");
    case AST_HTML_VIRTUAL_CLOSE_TAG_NODE: return hb_string("AST_HTML_VIRTUAL_CLOSE_TAG_NODE");
    case AST_HTML_ELEMENT_NODE: return hb_string("AST_HTML_ELEMENT_NODE");
    case AST_HTML_CONDITIONAL_ELEMENT_NODE: return hb_string("AST_HTML_CONDITIONAL_ELEMENT_NODE");
    case AST_HTML_ATTRIBUTE_VALUE_NODE: return hb_string("AST_HTML_ATTRIBUTE_VALUE_NODE");
    case AST_HTML_ATTRIBUTE_NAME_NODE: return hb_string("AST_HTML_ATTRIBUTE_NAME_NODE");
    case AST_HTML_ATTRIBUTE_NODE: return hb_string("AST_HTML_ATTRIBUTE_NODE");
    case AST_RUBY_LITERAL_NODE: return hb_string("AST_RUBY_LITERAL_NODE");
    case AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE: return hb_string("AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE");
    case AST_ERB_OPEN_TAG_NODE: return hb_string("AST_ERB_OPEN_TAG_NODE");
    case AST_HTML_TEXT_NODE: return hb_string("AST_HTML_TEXT_NODE");
    case AST_HTML_COMMENT_NODE: return hb_string("AST_HTML_COMMENT_NODE");
    case AST_HTML_DOCTYPE_NODE: return hb_string("AST_HTML_DOCTYPE_NODE");
    case AST_XML_DECLARATION_NODE: return hb_string("AST_XML_DECLARATION_NODE");
    case AST_CDATA_NODE: return hb_string("AST_CDATA_NODE");
    case AST_WHITESPACE_NODE: return hb_string("AST_WHITESPACE_NODE");
    case AST_ERB_CONTENT_NODE: return hb_string("AST_ERB_CONTENT_NODE");
    case AST_ERB_END_NODE: return hb_string("AST_ERB_END_NODE");
    case AST_ERB_ELSE_NODE: return hb_string("AST_ERB_ELSE_NODE");
    case AST_ERB_IF_NODE: return hb_string("AST_ERB_IF_NODE");
    case AST_ERB_BLOCK_NODE: return hb_string("AST_ERB_BLOCK_NODE");
    case AST_ERB_WHEN_NODE: return hb_string("AST_ERB_WHEN_NODE");
    case AST_ERB_CASE_NODE: return hb_string("AST_ERB_CASE_NODE");
    case AST_ERB_CASE_MATCH_NODE: return hb_string("AST_ERB_CASE_MATCH_NODE");
    case AST_ERB_WHILE_NODE: return hb_string("AST_ERB_WHILE_NODE");
    case AST_ERB_UNTIL_NODE: return hb_string("AST_ERB_UNTIL_NODE");
    case AST_ERB_FOR_NODE: return hb_string("AST_ERB_FOR_NODE");
    case AST_ERB_RESCUE_NODE: return hb_string("AST_ERB_RESCUE_NODE");
    case AST_ERB_ENSURE_NODE: return hb_string("AST_ERB_ENSURE_NODE");
    case AST_ERB_BEGIN_NODE: return hb_string("AST_ERB_BEGIN_NODE");
    case AST_ERB_UNLESS_NODE: return hb_string("AST_ERB_UNLESS_NODE");
    case AST_RUBY_RENDER_LOCAL_NODE: return hb_string("AST_RUBY_RENDER_LOCAL_NODE");
    case AST_ERB_RENDER_NODE: return hb_string("AST_ERB_RENDER_NODE");
    case AST_RUBY_STRICT_LOCAL_NODE: return hb_string("AST_RUBY_STRICT_LOCAL_NODE");
    case AST_ERB_STRICT_LOCALS_NODE: return hb_string("AST_ERB_STRICT_LOCALS_NODE");
    case AST_ERB_YIELD_NODE: return hb_string("AST_ERB_YIELD_NODE");
    case AST_ERB_IN_NODE: return hb_string("AST_ERB_IN_NODE");
  }

  return hb_string("Unknown ast_node_type_T");
}

hb_string_T ast_node_human_type(AST_NODE_T* node) {
  switch (node->type) {
    case AST_DOCUMENT_NODE: return hb_string("DocumentNode");
    case AST_LITERAL_NODE: return hb_string("LiteralNode");
    case AST_HTML_OPEN_TAG_NODE: return hb_string("HTMLOpenTagNode");
    case AST_HTML_CONDITIONAL_OPEN_TAG_NODE: return hb_string("HTMLConditionalOpenTagNode");
    case AST_HTML_CLOSE_TAG_NODE: return hb_string("HTMLCloseTagNode");
    case AST_HTML_OMITTED_CLOSE_TAG_NODE: return hb_string("HTMLOmittedCloseTagNode");
    case AST_HTML_VIRTUAL_CLOSE_TAG_NODE: return hb_string("HTMLVirtualCloseTagNode");
    case AST_HTML_ELEMENT_NODE: return hb_string("HTMLElementNode");
    case AST_HTML_CONDITIONAL_ELEMENT_NODE: return hb_string("HTMLConditionalElementNode");
    case AST_HTML_ATTRIBUTE_VALUE_NODE: return hb_string("HTMLAttributeValueNode");
    case AST_HTML_ATTRIBUTE_NAME_NODE: return hb_string("HTMLAttributeNameNode");
    case AST_HTML_ATTRIBUTE_NODE: return hb_string("HTMLAttributeNode");
    case AST_RUBY_LITERAL_NODE: return hb_string("RubyLiteralNode");
    case AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE: return hb_string("RubyHTMLAttributesSplatNode");
    case AST_ERB_OPEN_TAG_NODE: return hb_string("ERBOpenTagNode");
    case AST_HTML_TEXT_NODE: return hb_string("HTMLTextNode");
    case AST_HTML_COMMENT_NODE: return hb_string("HTMLCommentNode");
    case AST_HTML_DOCTYPE_NODE: return hb_string("HTMLDoctypeNode");
    case AST_XML_DECLARATION_NODE: return hb_string("XMLDeclarationNode");
    case AST_CDATA_NODE: return hb_string("CDATANode");
    case AST_WHITESPACE_NODE: return hb_string("WhitespaceNode");
    case AST_ERB_CONTENT_NODE: return hb_string("ERBContentNode");
    case AST_ERB_END_NODE: return hb_string("ERBEndNode");
    case AST_ERB_ELSE_NODE: return hb_string("ERBElseNode");
    case AST_ERB_IF_NODE: return hb_string("ERBIfNode");
    case AST_ERB_BLOCK_NODE: return hb_string("ERBBlockNode");
    case AST_ERB_WHEN_NODE: return hb_string("ERBWhenNode");
    case AST_ERB_CASE_NODE: return hb_string("ERBCaseNode");
    case AST_ERB_CASE_MATCH_NODE: return hb_string("ERBCaseMatchNode");
    case AST_ERB_WHILE_NODE: return hb_string("ERBWhileNode");
    case AST_ERB_UNTIL_NODE: return hb_string("ERBUntilNode");
    case AST_ERB_FOR_NODE: return hb_string("ERBForNode");
    case AST_ERB_RESCUE_NODE: return hb_string("ERBRescueNode");
    case AST_ERB_ENSURE_NODE: return hb_string("ERBEnsureNode");
    case AST_ERB_BEGIN_NODE: return hb_string("ERBBeginNode");
    case AST_ERB_UNLESS_NODE: return hb_string("ERBUnlessNode");
    case AST_RUBY_RENDER_LOCAL_NODE: return hb_string("RubyRenderLocalNode");
    case AST_ERB_RENDER_NODE: return hb_string("ERBRenderNode");
    case AST_RUBY_STRICT_LOCAL_NODE: return hb_string("RubyStrictLocalNode");
    case AST_ERB_STRICT_LOCALS_NODE: return hb_string("ERBStrictLocalsNode");
    case AST_ERB_YIELD_NODE: return hb_string("ERBYieldNode");
    case AST_ERB_IN_NODE: return hb_string("ERBInNode");
  }

  return hb_string("Unknown ast_node_type_T");
}

void ast_free_base_node(AST_NODE_T* node, hb_allocator_T* allocator) {
  if (node == NULL) { return; }

  if (node->errors) {
    for (size_t i = 0; i < hb_array_size(node->errors); i++) {
      ERROR_T* child = hb_array_get(node->errors, i);
      if (child != NULL) { error_free(child, allocator); }
    }

    hb_array_free(&node->errors);
  }

  hb_allocator_dealloc(allocator, node);
}


static void ast_free_document_node(AST_DOCUMENT_NODE_T* document_node, hb_allocator_T* allocator) {
  if (document_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(document_node->children); i++) {
      AST_NODE_T* child = hb_array_get(document_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&document_node->children);
  }
  if (document_node->prism_context != NULL) { herb_prism_context_free(document_node->prism_context); }
  /* prism_node is a borrowed reference into the prism context, not freed here */

  ast_free_base_node(&document_node->base, allocator);
}

static void ast_free_literal_node(AST_LITERAL_NODE_T* literal_node, hb_allocator_T* allocator) {
  if (literal_node->content.data != NULL) { hb_allocator_dealloc(allocator, literal_node->content.data); }

  ast_free_base_node(&literal_node->base, allocator);
}

static void ast_free_html_open_tag_node(AST_HTML_OPEN_TAG_NODE_T* html_open_tag_node, hb_allocator_T* allocator) {
  if (html_open_tag_node->tag_opening != NULL) { token_free(html_open_tag_node->tag_opening, allocator); }
  if (html_open_tag_node->tag_name != NULL) { token_free(html_open_tag_node->tag_name, allocator); }
  if (html_open_tag_node->tag_closing != NULL) { token_free(html_open_tag_node->tag_closing, allocator); }
  if (html_open_tag_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(html_open_tag_node->children); i++) {
      AST_NODE_T* child = hb_array_get(html_open_tag_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&html_open_tag_node->children);
  }

  ast_free_base_node(&html_open_tag_node->base, allocator);
}

static void ast_free_html_conditional_open_tag_node(AST_HTML_CONDITIONAL_OPEN_TAG_NODE_T* html_conditional_open_tag_node, hb_allocator_T* allocator) {
  ast_node_free((AST_NODE_T*) html_conditional_open_tag_node->conditional, allocator);
  if (html_conditional_open_tag_node->tag_name != NULL) { token_free(html_conditional_open_tag_node->tag_name, allocator); }

  ast_free_base_node(&html_conditional_open_tag_node->base, allocator);
}

static void ast_free_html_close_tag_node(AST_HTML_CLOSE_TAG_NODE_T* html_close_tag_node, hb_allocator_T* allocator) {
  if (html_close_tag_node->tag_opening != NULL) { token_free(html_close_tag_node->tag_opening, allocator); }
  if (html_close_tag_node->tag_name != NULL) { token_free(html_close_tag_node->tag_name, allocator); }
  if (html_close_tag_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(html_close_tag_node->children); i++) {
      AST_NODE_T* child = hb_array_get(html_close_tag_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&html_close_tag_node->children);
  }
  if (html_close_tag_node->tag_closing != NULL) { token_free(html_close_tag_node->tag_closing, allocator); }

  ast_free_base_node(&html_close_tag_node->base, allocator);
}

static void ast_free_html_omitted_close_tag_node(AST_HTML_OMITTED_CLOSE_TAG_NODE_T* html_omitted_close_tag_node, hb_allocator_T* allocator) {
  if (html_omitted_close_tag_node->tag_name != NULL) { token_free(html_omitted_close_tag_node->tag_name, allocator); }

  ast_free_base_node(&html_omitted_close_tag_node->base, allocator);
}

static void ast_free_html_virtual_close_tag_node(AST_HTML_VIRTUAL_CLOSE_TAG_NODE_T* html_virtual_close_tag_node, hb_allocator_T* allocator) {
  if (html_virtual_close_tag_node->tag_name != NULL) { token_free(html_virtual_close_tag_node->tag_name, allocator); }

  ast_free_base_node(&html_virtual_close_tag_node->base, allocator);
}

static void ast_free_html_element_node(AST_HTML_ELEMENT_NODE_T* html_element_node, hb_allocator_T* allocator) {
  ast_node_free((AST_NODE_T*) html_element_node->open_tag, allocator);
  if (html_element_node->tag_name != NULL) { token_free(html_element_node->tag_name, allocator); }
  if (html_element_node->body != NULL) {
    for (size_t i = 0; i < hb_array_size(html_element_node->body); i++) {
      AST_NODE_T* child = hb_array_get(html_element_node->body, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&html_element_node->body);
  }
  ast_node_free((AST_NODE_T*) html_element_node->close_tag, allocator);

  ast_free_base_node(&html_element_node->base, allocator);
}

static void ast_free_html_conditional_element_node(AST_HTML_CONDITIONAL_ELEMENT_NODE_T* html_conditional_element_node, hb_allocator_T* allocator) {
  if (html_conditional_element_node->condition.data != NULL) { hb_allocator_dealloc(allocator, html_conditional_element_node->condition.data); }
  ast_node_free((AST_NODE_T*) html_conditional_element_node->open_conditional, allocator);
  /* open_tag is a borrowed reference, not freed here (owned by another field) */
  if (html_conditional_element_node->body != NULL) {
    for (size_t i = 0; i < hb_array_size(html_conditional_element_node->body); i++) {
      AST_NODE_T* child = hb_array_get(html_conditional_element_node->body, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&html_conditional_element_node->body);
  }
  /* close_tag is a borrowed reference, not freed here (owned by another field) */
  ast_node_free((AST_NODE_T*) html_conditional_element_node->close_conditional, allocator);
  if (html_conditional_element_node->tag_name != NULL) { token_free(html_conditional_element_node->tag_name, allocator); }

  ast_free_base_node(&html_conditional_element_node->base, allocator);
}

static void ast_free_html_attribute_value_node(AST_HTML_ATTRIBUTE_VALUE_NODE_T* html_attribute_value_node, hb_allocator_T* allocator) {
  if (html_attribute_value_node->open_quote != NULL) { token_free(html_attribute_value_node->open_quote, allocator); }
  if (html_attribute_value_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(html_attribute_value_node->children); i++) {
      AST_NODE_T* child = hb_array_get(html_attribute_value_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&html_attribute_value_node->children);
  }
  if (html_attribute_value_node->close_quote != NULL) { token_free(html_attribute_value_node->close_quote, allocator); }

  ast_free_base_node(&html_attribute_value_node->base, allocator);
}

static void ast_free_html_attribute_name_node(AST_HTML_ATTRIBUTE_NAME_NODE_T* html_attribute_name_node, hb_allocator_T* allocator) {
  if (html_attribute_name_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(html_attribute_name_node->children); i++) {
      AST_NODE_T* child = hb_array_get(html_attribute_name_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&html_attribute_name_node->children);
  }

  ast_free_base_node(&html_attribute_name_node->base, allocator);
}

static void ast_free_html_attribute_node(AST_HTML_ATTRIBUTE_NODE_T* html_attribute_node, hb_allocator_T* allocator) {
  ast_node_free((AST_NODE_T*) html_attribute_node->name, allocator);
  if (html_attribute_node->equals != NULL) { token_free(html_attribute_node->equals, allocator); }
  ast_node_free((AST_NODE_T*) html_attribute_node->value, allocator);

  ast_free_base_node(&html_attribute_node->base, allocator);
}

static void ast_free_ruby_literal_node(AST_RUBY_LITERAL_NODE_T* ruby_literal_node, hb_allocator_T* allocator) {
  if (ruby_literal_node->content.data != NULL) { hb_allocator_dealloc(allocator, ruby_literal_node->content.data); }

  ast_free_base_node(&ruby_literal_node->base, allocator);
}

static void ast_free_ruby_html_attributes_splat_node(AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE_T* ruby_html_attributes_splat_node, hb_allocator_T* allocator) {
  if (ruby_html_attributes_splat_node->content.data != NULL) { hb_allocator_dealloc(allocator, ruby_html_attributes_splat_node->content.data); }
  if (ruby_html_attributes_splat_node->prefix.data != NULL) { hb_allocator_dealloc(allocator, ruby_html_attributes_splat_node->prefix.data); }

  ast_free_base_node(&ruby_html_attributes_splat_node->base, allocator);
}

static void ast_free_erb_open_tag_node(AST_ERB_OPEN_TAG_NODE_T* erb_open_tag_node, hb_allocator_T* allocator) {
  if (erb_open_tag_node->tag_opening != NULL) { token_free(erb_open_tag_node->tag_opening, allocator); }
  if (erb_open_tag_node->content != NULL) { token_free(erb_open_tag_node->content, allocator); }
  if (erb_open_tag_node->tag_closing != NULL) { token_free(erb_open_tag_node->tag_closing, allocator); }
  if (erb_open_tag_node->tag_name != NULL) { token_free(erb_open_tag_node->tag_name, allocator); }
  if (erb_open_tag_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_open_tag_node->children); i++) {
      AST_NODE_T* child = hb_array_get(erb_open_tag_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_open_tag_node->children);
  }

  ast_free_base_node(&erb_open_tag_node->base, allocator);
}

static void ast_free_html_text_node(AST_HTML_TEXT_NODE_T* html_text_node, hb_allocator_T* allocator) {
  if (html_text_node->content.data != NULL) { hb_allocator_dealloc(allocator, html_text_node->content.data); }

  ast_free_base_node(&html_text_node->base, allocator);
}

static void ast_free_html_comment_node(AST_HTML_COMMENT_NODE_T* html_comment_node, hb_allocator_T* allocator) {
  if (html_comment_node->comment_start != NULL) { token_free(html_comment_node->comment_start, allocator); }
  if (html_comment_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(html_comment_node->children); i++) {
      AST_NODE_T* child = hb_array_get(html_comment_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&html_comment_node->children);
  }
  if (html_comment_node->comment_end != NULL) { token_free(html_comment_node->comment_end, allocator); }

  ast_free_base_node(&html_comment_node->base, allocator);
}

static void ast_free_html_doctype_node(AST_HTML_DOCTYPE_NODE_T* html_doctype_node, hb_allocator_T* allocator) {
  if (html_doctype_node->tag_opening != NULL) { token_free(html_doctype_node->tag_opening, allocator); }
  if (html_doctype_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(html_doctype_node->children); i++) {
      AST_NODE_T* child = hb_array_get(html_doctype_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&html_doctype_node->children);
  }
  if (html_doctype_node->tag_closing != NULL) { token_free(html_doctype_node->tag_closing, allocator); }

  ast_free_base_node(&html_doctype_node->base, allocator);
}

static void ast_free_xml_declaration_node(AST_XML_DECLARATION_NODE_T* xml_declaration_node, hb_allocator_T* allocator) {
  if (xml_declaration_node->tag_opening != NULL) { token_free(xml_declaration_node->tag_opening, allocator); }
  if (xml_declaration_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(xml_declaration_node->children); i++) {
      AST_NODE_T* child = hb_array_get(xml_declaration_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&xml_declaration_node->children);
  }
  if (xml_declaration_node->tag_closing != NULL) { token_free(xml_declaration_node->tag_closing, allocator); }

  ast_free_base_node(&xml_declaration_node->base, allocator);
}

static void ast_free_cdata_node(AST_CDATA_NODE_T* cdata_node, hb_allocator_T* allocator) {
  if (cdata_node->tag_opening != NULL) { token_free(cdata_node->tag_opening, allocator); }
  if (cdata_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(cdata_node->children); i++) {
      AST_NODE_T* child = hb_array_get(cdata_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&cdata_node->children);
  }
  if (cdata_node->tag_closing != NULL) { token_free(cdata_node->tag_closing, allocator); }

  ast_free_base_node(&cdata_node->base, allocator);
}

static void ast_free_whitespace_node(AST_WHITESPACE_NODE_T* whitespace_node, hb_allocator_T* allocator) {
  if (whitespace_node->value != NULL) { token_free(whitespace_node->value, allocator); }

  ast_free_base_node(&whitespace_node->base, allocator);
}

static void ast_free_erb_content_node(AST_ERB_CONTENT_NODE_T* erb_content_node, hb_allocator_T* allocator) {
  if (erb_content_node->tag_opening != NULL) { token_free(erb_content_node->tag_opening, allocator); }
  if (erb_content_node->content != NULL) { token_free(erb_content_node->content, allocator); }
  if (erb_content_node->tag_closing != NULL) { token_free(erb_content_node->tag_closing, allocator); }
  if (erb_content_node->analyzed_ruby != NULL) {
    free_analyzed_ruby(erb_content_node->analyzed_ruby);
  }
  /* prism_node is a borrowed reference into the prism context, not freed here */

  ast_free_base_node(&erb_content_node->base, allocator);
}

static void ast_free_erb_end_node(AST_ERB_END_NODE_T* erb_end_node, hb_allocator_T* allocator) {
  if (erb_end_node->tag_opening != NULL) { token_free(erb_end_node->tag_opening, allocator); }
  if (erb_end_node->content != NULL) { token_free(erb_end_node->content, allocator); }
  if (erb_end_node->tag_closing != NULL) { token_free(erb_end_node->tag_closing, allocator); }

  ast_free_base_node(&erb_end_node->base, allocator);
}

static void ast_free_erb_else_node(AST_ERB_ELSE_NODE_T* erb_else_node, hb_allocator_T* allocator) {
  if (erb_else_node->tag_opening != NULL) { token_free(erb_else_node->tag_opening, allocator); }
  if (erb_else_node->content != NULL) { token_free(erb_else_node->content, allocator); }
  if (erb_else_node->tag_closing != NULL) { token_free(erb_else_node->tag_closing, allocator); }
  if (erb_else_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_else_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_else_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_else_node->statements);
  }

  ast_free_base_node(&erb_else_node->base, allocator);
}

static void ast_free_erb_if_node(AST_ERB_IF_NODE_T* erb_if_node, hb_allocator_T* allocator) {
  if (erb_if_node->tag_opening != NULL) { token_free(erb_if_node->tag_opening, allocator); }
  if (erb_if_node->content != NULL) { token_free(erb_if_node->content, allocator); }
  if (erb_if_node->tag_closing != NULL) { token_free(erb_if_node->tag_closing, allocator); }
  if (erb_if_node->then_keyword != NULL) { hb_allocator_dealloc(allocator, erb_if_node->then_keyword); }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_if_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_if_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_if_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_if_node->statements);
  }
  ast_node_free((AST_NODE_T*) erb_if_node->subsequent, allocator);
  ast_node_free((AST_NODE_T*) erb_if_node->end_node, allocator);

  ast_free_base_node(&erb_if_node->base, allocator);
}

static void ast_free_erb_block_node(AST_ERB_BLOCK_NODE_T* erb_block_node, hb_allocator_T* allocator) {
  if (erb_block_node->tag_opening != NULL) { token_free(erb_block_node->tag_opening, allocator); }
  if (erb_block_node->content != NULL) { token_free(erb_block_node->content, allocator); }
  if (erb_block_node->tag_closing != NULL) { token_free(erb_block_node->tag_closing, allocator); }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_block_node->body != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_block_node->body); i++) {
      AST_NODE_T* child = hb_array_get(erb_block_node->body, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_block_node->body);
  }
  ast_node_free((AST_NODE_T*) erb_block_node->rescue_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_block_node->else_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_block_node->ensure_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_block_node->end_node, allocator);

  ast_free_base_node(&erb_block_node->base, allocator);
}

static void ast_free_erb_when_node(AST_ERB_WHEN_NODE_T* erb_when_node, hb_allocator_T* allocator) {
  if (erb_when_node->tag_opening != NULL) { token_free(erb_when_node->tag_opening, allocator); }
  if (erb_when_node->content != NULL) { token_free(erb_when_node->content, allocator); }
  if (erb_when_node->tag_closing != NULL) { token_free(erb_when_node->tag_closing, allocator); }
  if (erb_when_node->then_keyword != NULL) { hb_allocator_dealloc(allocator, erb_when_node->then_keyword); }
  if (erb_when_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_when_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_when_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_when_node->statements);
  }

  ast_free_base_node(&erb_when_node->base, allocator);
}

static void ast_free_erb_case_node(AST_ERB_CASE_NODE_T* erb_case_node, hb_allocator_T* allocator) {
  if (erb_case_node->tag_opening != NULL) { token_free(erb_case_node->tag_opening, allocator); }
  if (erb_case_node->content != NULL) { token_free(erb_case_node->content, allocator); }
  if (erb_case_node->tag_closing != NULL) { token_free(erb_case_node->tag_closing, allocator); }
  if (erb_case_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_case_node->children); i++) {
      AST_NODE_T* child = hb_array_get(erb_case_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_case_node->children);
  }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_case_node->conditions != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_case_node->conditions); i++) {
      AST_NODE_T* child = hb_array_get(erb_case_node->conditions, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_case_node->conditions);
  }
  ast_node_free((AST_NODE_T*) erb_case_node->else_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_case_node->end_node, allocator);

  ast_free_base_node(&erb_case_node->base, allocator);
}

static void ast_free_erb_case_match_node(AST_ERB_CASE_MATCH_NODE_T* erb_case_match_node, hb_allocator_T* allocator) {
  if (erb_case_match_node->tag_opening != NULL) { token_free(erb_case_match_node->tag_opening, allocator); }
  if (erb_case_match_node->content != NULL) { token_free(erb_case_match_node->content, allocator); }
  if (erb_case_match_node->tag_closing != NULL) { token_free(erb_case_match_node->tag_closing, allocator); }
  if (erb_case_match_node->children != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_case_match_node->children); i++) {
      AST_NODE_T* child = hb_array_get(erb_case_match_node->children, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_case_match_node->children);
  }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_case_match_node->conditions != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_case_match_node->conditions); i++) {
      AST_NODE_T* child = hb_array_get(erb_case_match_node->conditions, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_case_match_node->conditions);
  }
  ast_node_free((AST_NODE_T*) erb_case_match_node->else_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_case_match_node->end_node, allocator);

  ast_free_base_node(&erb_case_match_node->base, allocator);
}

static void ast_free_erb_while_node(AST_ERB_WHILE_NODE_T* erb_while_node, hb_allocator_T* allocator) {
  if (erb_while_node->tag_opening != NULL) { token_free(erb_while_node->tag_opening, allocator); }
  if (erb_while_node->content != NULL) { token_free(erb_while_node->content, allocator); }
  if (erb_while_node->tag_closing != NULL) { token_free(erb_while_node->tag_closing, allocator); }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_while_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_while_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_while_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_while_node->statements);
  }
  ast_node_free((AST_NODE_T*) erb_while_node->end_node, allocator);

  ast_free_base_node(&erb_while_node->base, allocator);
}

static void ast_free_erb_until_node(AST_ERB_UNTIL_NODE_T* erb_until_node, hb_allocator_T* allocator) {
  if (erb_until_node->tag_opening != NULL) { token_free(erb_until_node->tag_opening, allocator); }
  if (erb_until_node->content != NULL) { token_free(erb_until_node->content, allocator); }
  if (erb_until_node->tag_closing != NULL) { token_free(erb_until_node->tag_closing, allocator); }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_until_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_until_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_until_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_until_node->statements);
  }
  ast_node_free((AST_NODE_T*) erb_until_node->end_node, allocator);

  ast_free_base_node(&erb_until_node->base, allocator);
}

static void ast_free_erb_for_node(AST_ERB_FOR_NODE_T* erb_for_node, hb_allocator_T* allocator) {
  if (erb_for_node->tag_opening != NULL) { token_free(erb_for_node->tag_opening, allocator); }
  if (erb_for_node->content != NULL) { token_free(erb_for_node->content, allocator); }
  if (erb_for_node->tag_closing != NULL) { token_free(erb_for_node->tag_closing, allocator); }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_for_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_for_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_for_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_for_node->statements);
  }
  ast_node_free((AST_NODE_T*) erb_for_node->end_node, allocator);

  ast_free_base_node(&erb_for_node->base, allocator);
}

static void ast_free_erb_rescue_node(AST_ERB_RESCUE_NODE_T* erb_rescue_node, hb_allocator_T* allocator) {
  if (erb_rescue_node->tag_opening != NULL) { token_free(erb_rescue_node->tag_opening, allocator); }
  if (erb_rescue_node->content != NULL) { token_free(erb_rescue_node->content, allocator); }
  if (erb_rescue_node->tag_closing != NULL) { token_free(erb_rescue_node->tag_closing, allocator); }
  if (erb_rescue_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_rescue_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_rescue_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_rescue_node->statements);
  }
  ast_node_free((AST_NODE_T*) erb_rescue_node->subsequent, allocator);

  ast_free_base_node(&erb_rescue_node->base, allocator);
}

static void ast_free_erb_ensure_node(AST_ERB_ENSURE_NODE_T* erb_ensure_node, hb_allocator_T* allocator) {
  if (erb_ensure_node->tag_opening != NULL) { token_free(erb_ensure_node->tag_opening, allocator); }
  if (erb_ensure_node->content != NULL) { token_free(erb_ensure_node->content, allocator); }
  if (erb_ensure_node->tag_closing != NULL) { token_free(erb_ensure_node->tag_closing, allocator); }
  if (erb_ensure_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_ensure_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_ensure_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_ensure_node->statements);
  }

  ast_free_base_node(&erb_ensure_node->base, allocator);
}

static void ast_free_erb_begin_node(AST_ERB_BEGIN_NODE_T* erb_begin_node, hb_allocator_T* allocator) {
  if (erb_begin_node->tag_opening != NULL) { token_free(erb_begin_node->tag_opening, allocator); }
  if (erb_begin_node->content != NULL) { token_free(erb_begin_node->content, allocator); }
  if (erb_begin_node->tag_closing != NULL) { token_free(erb_begin_node->tag_closing, allocator); }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_begin_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_begin_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_begin_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_begin_node->statements);
  }
  ast_node_free((AST_NODE_T*) erb_begin_node->rescue_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_begin_node->else_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_begin_node->ensure_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_begin_node->end_node, allocator);

  ast_free_base_node(&erb_begin_node->base, allocator);
}

static void ast_free_erb_unless_node(AST_ERB_UNLESS_NODE_T* erb_unless_node, hb_allocator_T* allocator) {
  if (erb_unless_node->tag_opening != NULL) { token_free(erb_unless_node->tag_opening, allocator); }
  if (erb_unless_node->content != NULL) { token_free(erb_unless_node->content, allocator); }
  if (erb_unless_node->tag_closing != NULL) { token_free(erb_unless_node->tag_closing, allocator); }
  if (erb_unless_node->then_keyword != NULL) { hb_allocator_dealloc(allocator, erb_unless_node->then_keyword); }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_unless_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_unless_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_unless_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_unless_node->statements);
  }
  ast_node_free((AST_NODE_T*) erb_unless_node->else_clause, allocator);
  ast_node_free((AST_NODE_T*) erb_unless_node->end_node, allocator);

  ast_free_base_node(&erb_unless_node->base, allocator);
}

static void ast_free_ruby_render_local_node(AST_RUBY_RENDER_LOCAL_NODE_T* ruby_render_local_node, hb_allocator_T* allocator) {
  if (ruby_render_local_node->name != NULL) { token_free(ruby_render_local_node->name, allocator); }
  ast_node_free((AST_NODE_T*) ruby_render_local_node->value, allocator);

  ast_free_base_node(&ruby_render_local_node->base, allocator);
}

static void ast_free_erb_render_node(AST_ERB_RENDER_NODE_T* erb_render_node, hb_allocator_T* allocator) {
  if (erb_render_node->tag_opening != NULL) { token_free(erb_render_node->tag_opening, allocator); }
  if (erb_render_node->content != NULL) { token_free(erb_render_node->content, allocator); }
  if (erb_render_node->tag_closing != NULL) { token_free(erb_render_node->tag_closing, allocator); }
  if (erb_render_node->analyzed_ruby != NULL) {
    free_analyzed_ruby(erb_render_node->analyzed_ruby);
  }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_render_node->partial != NULL) { token_free(erb_render_node->partial, allocator); }
  if (erb_render_node->template_path != NULL) { token_free(erb_render_node->template_path, allocator); }
  if (erb_render_node->layout != NULL) { token_free(erb_render_node->layout, allocator); }
  if (erb_render_node->file != NULL) { token_free(erb_render_node->file, allocator); }
  if (erb_render_node->inline_template != NULL) { token_free(erb_render_node->inline_template, allocator); }
  if (erb_render_node->body != NULL) { token_free(erb_render_node->body, allocator); }
  if (erb_render_node->plain != NULL) { token_free(erb_render_node->plain, allocator); }
  if (erb_render_node->html != NULL) { token_free(erb_render_node->html, allocator); }
  if (erb_render_node->renderable != NULL) { token_free(erb_render_node->renderable, allocator); }
  if (erb_render_node->collection != NULL) { token_free(erb_render_node->collection, allocator); }
  if (erb_render_node->object != NULL) { token_free(erb_render_node->object, allocator); }
  if (erb_render_node->as_name != NULL) { token_free(erb_render_node->as_name, allocator); }
  if (erb_render_node->spacer_template != NULL) { token_free(erb_render_node->spacer_template, allocator); }
  if (erb_render_node->formats != NULL) { token_free(erb_render_node->formats, allocator); }
  if (erb_render_node->variants != NULL) { token_free(erb_render_node->variants, allocator); }
  if (erb_render_node->handlers != NULL) { token_free(erb_render_node->handlers, allocator); }
  if (erb_render_node->content_type != NULL) { token_free(erb_render_node->content_type, allocator); }
  if (erb_render_node->locals != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_render_node->locals); i++) {
      AST_NODE_T* child = hb_array_get(erb_render_node->locals, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_render_node->locals);
  }

  ast_free_base_node(&erb_render_node->base, allocator);
}

static void ast_free_ruby_strict_local_node(AST_RUBY_STRICT_LOCAL_NODE_T* ruby_strict_local_node, hb_allocator_T* allocator) {
  if (ruby_strict_local_node->name != NULL) { token_free(ruby_strict_local_node->name, allocator); }
  ast_node_free((AST_NODE_T*) ruby_strict_local_node->default_value, allocator);

  ast_free_base_node(&ruby_strict_local_node->base, allocator);
}

static void ast_free_erb_strict_locals_node(AST_ERB_STRICT_LOCALS_NODE_T* erb_strict_locals_node, hb_allocator_T* allocator) {
  if (erb_strict_locals_node->tag_opening != NULL) { token_free(erb_strict_locals_node->tag_opening, allocator); }
  if (erb_strict_locals_node->content != NULL) { token_free(erb_strict_locals_node->content, allocator); }
  if (erb_strict_locals_node->tag_closing != NULL) { token_free(erb_strict_locals_node->tag_closing, allocator); }
  if (erb_strict_locals_node->analyzed_ruby != NULL) {
    free_analyzed_ruby(erb_strict_locals_node->analyzed_ruby);
  }
  /* prism_node is a borrowed reference into the prism context, not freed here */
  if (erb_strict_locals_node->locals != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_strict_locals_node->locals); i++) {
      AST_NODE_T* child = hb_array_get(erb_strict_locals_node->locals, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_strict_locals_node->locals);
  }

  ast_free_base_node(&erb_strict_locals_node->base, allocator);
}

static void ast_free_erb_yield_node(AST_ERB_YIELD_NODE_T* erb_yield_node, hb_allocator_T* allocator) {
  if (erb_yield_node->tag_opening != NULL) { token_free(erb_yield_node->tag_opening, allocator); }
  if (erb_yield_node->content != NULL) { token_free(erb_yield_node->content, allocator); }
  if (erb_yield_node->tag_closing != NULL) { token_free(erb_yield_node->tag_closing, allocator); }

  ast_free_base_node(&erb_yield_node->base, allocator);
}

static void ast_free_erb_in_node(AST_ERB_IN_NODE_T* erb_in_node, hb_allocator_T* allocator) {
  if (erb_in_node->tag_opening != NULL) { token_free(erb_in_node->tag_opening, allocator); }
  if (erb_in_node->content != NULL) { token_free(erb_in_node->content, allocator); }
  if (erb_in_node->tag_closing != NULL) { token_free(erb_in_node->tag_closing, allocator); }
  if (erb_in_node->then_keyword != NULL) { hb_allocator_dealloc(allocator, erb_in_node->then_keyword); }
  if (erb_in_node->statements != NULL) {
    for (size_t i = 0; i < hb_array_size(erb_in_node->statements); i++) {
      AST_NODE_T* child = hb_array_get(erb_in_node->statements, i);
      if (child) { ast_node_free(child, allocator); }
    }

    hb_array_free(&erb_in_node->statements);
  }

  ast_free_base_node(&erb_in_node->base, allocator);
}

void ast_node_free(AST_NODE_T* node, hb_allocator_T* allocator) {
  if (!node) { return; }

  switch (node->type) {
    case AST_DOCUMENT_NODE: ast_free_document_node((AST_DOCUMENT_NODE_T*) node, allocator); break;
    case AST_LITERAL_NODE: ast_free_literal_node((AST_LITERAL_NODE_T*) node, allocator); break;
    case AST_HTML_OPEN_TAG_NODE: ast_free_html_open_tag_node((AST_HTML_OPEN_TAG_NODE_T*) node, allocator); break;
    case AST_HTML_CONDITIONAL_OPEN_TAG_NODE: ast_free_html_conditional_open_tag_node((AST_HTML_CONDITIONAL_OPEN_TAG_NODE_T*) node, allocator); break;
    case AST_HTML_CLOSE_TAG_NODE: ast_free_html_close_tag_node((AST_HTML_CLOSE_TAG_NODE_T*) node, allocator); break;
    case AST_HTML_OMITTED_CLOSE_TAG_NODE: ast_free_html_omitted_close_tag_node((AST_HTML_OMITTED_CLOSE_TAG_NODE_T*) node, allocator); break;
    case AST_HTML_VIRTUAL_CLOSE_TAG_NODE: ast_free_html_virtual_close_tag_node((AST_HTML_VIRTUAL_CLOSE_TAG_NODE_T*) node, allocator); break;
    case AST_HTML_ELEMENT_NODE: ast_free_html_element_node((AST_HTML_ELEMENT_NODE_T*) node, allocator); break;
    case AST_HTML_CONDITIONAL_ELEMENT_NODE: ast_free_html_conditional_element_node((AST_HTML_CONDITIONAL_ELEMENT_NODE_T*) node, allocator); break;
    case AST_HTML_ATTRIBUTE_VALUE_NODE: ast_free_html_attribute_value_node((AST_HTML_ATTRIBUTE_VALUE_NODE_T*) node, allocator); break;
    case AST_HTML_ATTRIBUTE_NAME_NODE: ast_free_html_attribute_name_node((AST_HTML_ATTRIBUTE_NAME_NODE_T*) node, allocator); break;
    case AST_HTML_ATTRIBUTE_NODE: ast_free_html_attribute_node((AST_HTML_ATTRIBUTE_NODE_T*) node, allocator); break;
    case AST_RUBY_LITERAL_NODE: ast_free_ruby_literal_node((AST_RUBY_LITERAL_NODE_T*) node, allocator); break;
    case AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE: ast_free_ruby_html_attributes_splat_node((AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE_T*) node, allocator); break;
    case AST_ERB_OPEN_TAG_NODE: ast_free_erb_open_tag_node((AST_ERB_OPEN_TAG_NODE_T*) node, allocator); break;
    case AST_HTML_TEXT_NODE: ast_free_html_text_node((AST_HTML_TEXT_NODE_T*) node, allocator); break;
    case AST_HTML_COMMENT_NODE: ast_free_html_comment_node((AST_HTML_COMMENT_NODE_T*) node, allocator); break;
    case AST_HTML_DOCTYPE_NODE: ast_free_html_doctype_node((AST_HTML_DOCTYPE_NODE_T*) node, allocator); break;
    case AST_XML_DECLARATION_NODE: ast_free_xml_declaration_node((AST_XML_DECLARATION_NODE_T*) node, allocator); break;
    case AST_CDATA_NODE: ast_free_cdata_node((AST_CDATA_NODE_T*) node, allocator); break;
    case AST_WHITESPACE_NODE: ast_free_whitespace_node((AST_WHITESPACE_NODE_T*) node, allocator); break;
    case AST_ERB_CONTENT_NODE: ast_free_erb_content_node((AST_ERB_CONTENT_NODE_T*) node, allocator); break;
    case AST_ERB_END_NODE: ast_free_erb_end_node((AST_ERB_END_NODE_T*) node, allocator); break;
    case AST_ERB_ELSE_NODE: ast_free_erb_else_node((AST_ERB_ELSE_NODE_T*) node, allocator); break;
    case AST_ERB_IF_NODE: ast_free_erb_if_node((AST_ERB_IF_NODE_T*) node, allocator); break;
    case AST_ERB_BLOCK_NODE: ast_free_erb_block_node((AST_ERB_BLOCK_NODE_T*) node, allocator); break;
    case AST_ERB_WHEN_NODE: ast_free_erb_when_node((AST_ERB_WHEN_NODE_T*) node, allocator); break;
    case AST_ERB_CASE_NODE: ast_free_erb_case_node((AST_ERB_CASE_NODE_T*) node, allocator); break;
    case AST_ERB_CASE_MATCH_NODE: ast_free_erb_case_match_node((AST_ERB_CASE_MATCH_NODE_T*) node, allocator); break;
    case AST_ERB_WHILE_NODE: ast_free_erb_while_node((AST_ERB_WHILE_NODE_T*) node, allocator); break;
    case AST_ERB_UNTIL_NODE: ast_free_erb_until_node((AST_ERB_UNTIL_NODE_T*) node, allocator); break;
    case AST_ERB_FOR_NODE: ast_free_erb_for_node((AST_ERB_FOR_NODE_T*) node, allocator); break;
    case AST_ERB_RESCUE_NODE: ast_free_erb_rescue_node((AST_ERB_RESCUE_NODE_T*) node, allocator); break;
    case AST_ERB_ENSURE_NODE: ast_free_erb_ensure_node((AST_ERB_ENSURE_NODE_T*) node, allocator); break;
    case AST_ERB_BEGIN_NODE: ast_free_erb_begin_node((AST_ERB_BEGIN_NODE_T*) node, allocator); break;
    case AST_ERB_UNLESS_NODE: ast_free_erb_unless_node((AST_ERB_UNLESS_NODE_T*) node, allocator); break;
    case AST_RUBY_RENDER_LOCAL_NODE: ast_free_ruby_render_local_node((AST_RUBY_RENDER_LOCAL_NODE_T*) node, allocator); break;
    case AST_ERB_RENDER_NODE: ast_free_erb_render_node((AST_ERB_RENDER_NODE_T*) node, allocator); break;
    case AST_RUBY_STRICT_LOCAL_NODE: ast_free_ruby_strict_local_node((AST_RUBY_STRICT_LOCAL_NODE_T*) node, allocator); break;
    case AST_ERB_STRICT_LOCALS_NODE: ast_free_erb_strict_locals_node((AST_ERB_STRICT_LOCALS_NODE_T*) node, allocator); break;
    case AST_ERB_YIELD_NODE: ast_free_erb_yield_node((AST_ERB_YIELD_NODE_T*) node, allocator); break;
    case AST_ERB_IN_NODE: ast_free_erb_in_node((AST_ERB_IN_NODE_T*) node, allocator); break;
  }
}
