nokogumbo 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a428cfbfd91671cfd185171daf3004072448636054260e4e4cfbf4f9c71a392
4
- data.tar.gz: a4d2e15843d42f89b8152dafbdc816e452f73114dd7b13f177db62e21a290d6b
3
+ metadata.gz: dbc23d3b7a9665b48d0516f523756407ca46733286e89edaf2b5b01b05820ffd
4
+ data.tar.gz: 9d777f65fe5170fe66fde53dd9fa0d2904e2ca2d73d25d6fd240fc383cb20804
5
5
  SHA512:
6
- metadata.gz: 145cb3d69a3bab4c0bcd60f3f5253f46a6df49b76ed6bdc88147fe059da2805fc93fa7fedeb1ea4002440cc789e259f9049b472e225170273a3709bb011decda
7
- data.tar.gz: 8d29a5317ccda466accc132aa300048de6cc237e99e26827dcae3c081941abe1ed00f6feb93a35b36a16a3e6fa27fe88cfe1ea753f5677793a49ff0113ac7f28
6
+ metadata.gz: 602ecadc3afd998eb380a9d4fed204cdd7fd48e5ee8539e4ae5713289fa65a923d27c4b67835546c048522f1a04a165d87f257f1389c591e41e127be06e98109
7
+ data.tar.gz: 88a714a552e5cc6f11b65da15bd9816d21bfc383dd5c68e1b6e8ab82ce842adf3159ad56579428b87b7c1dba002b9e38758494865153285f2563aeae9edeba54
@@ -1,3 +1,4 @@
1
+ require 'rubygems'
1
2
  require 'fileutils'
2
3
  require 'mkmf'
3
4
  require 'nokogiri'
@@ -23,7 +24,6 @@ def download_headers
23
24
  return nil if dep_index.nil?
24
25
  requirement = NG_SPEC.dependencies[dep_index].requirement.to_s
25
26
 
26
- require 'rubygems'
27
27
  gem 'mini_portile2', requirement
28
28
  require 'mini_portile2'
29
29
  p = MiniPortile::new('libxml2', version).tap do |r|
@@ -33,6 +33,7 @@ static ID parent;
33
33
 
34
34
  /* Backwards compatibility to Ruby 2.1.0 */
35
35
  #if RUBY_API_VERSION_CODE < 20200
36
+ #define ONIG_ESCAPE_UCHAR_COLLISION 1
36
37
  #include <ruby/encoding.h>
37
38
 
38
39
  static VALUE rb_utf8_str_new(const char *str, long length) {
@@ -365,11 +365,14 @@ static void handle_parser_error (
365
365
  // pointer to the beginning of the string if this is the first line.
366
366
  static const char* find_prev_newline (
367
367
  const char* source_text,
368
+ size_t source_length,
368
369
  const char* error_location
369
370
  ) {
371
+ const char* source_end = source_text + source_length;
370
372
  assert(error_location >= source_text);
373
+ assert(error_location <= source_end);
371
374
  const char* c = error_location;
372
- if (*c == '\n' && c != source_text)
375
+ if (c != source_text && (error_location == source_end || *c == '\n'))
373
376
  --c;
374
377
  while (c != source_text && *c != '\n')
375
378
  --c;
@@ -377,20 +380,25 @@ static const char* find_prev_newline (
377
380
  }
378
381
 
379
382
  // Finds the next newline in the original source buffer from a given byte
380
- // location. Returns a character pointer to that newline, or a pointer to the
381
- // terminating null byte if this is the last line.
383
+ // location. Returns a character pointer to that newline, or a pointer to
384
+ // source_text + source_length if this is the last line.
382
385
  static const char* find_next_newline(
383
- const char* source_text_end,
386
+ const char* source_text,
387
+ size_t source_length,
384
388
  const char* error_location
385
389
  ) {
386
- assert(error_location <= source_text_end);
390
+ const char* source_end = source_text + source_length;
391
+ assert(error_location >= source_text);
392
+ assert(error_location <= source_end);
387
393
  const char* c = error_location;
388
- while (c != source_text_end && *c != '\n')
394
+ while (c != source_end && *c != '\n')
389
395
  ++c;
390
396
  return c;
391
397
  }
392
398
 
393
399
  GumboError* gumbo_add_error(GumboParser* parser) {
400
+ parser->_output->document_error = true;
401
+
394
402
  int max_errors = parser->_options->max_errors;
395
403
  if (max_errors >= 0 && parser->_output->errors.length >= (unsigned int) max_errors) {
396
404
  return NULL;
@@ -547,8 +555,9 @@ void caret_diagnostic_to_string (
547
555
  ) {
548
556
  error_to_string(error, output);
549
557
 
550
- const char* line_start = find_prev_newline(source_text, error->original_text.data);
551
- const char* line_end = find_next_newline(source_text + source_length, error->original_text.data);
558
+ const char* error_text = error->original_text.data;
559
+ const char* line_start = find_prev_newline(source_text, source_length, error_text);
560
+ const char* line_end = find_next_newline(source_text, source_length, error_text);
552
561
  GumboStringPiece original_line;
553
562
  original_line.data = line_start;
554
563
  original_line.length = line_end - line_start;
@@ -820,6 +820,14 @@ typedef struct GumboInternalOutput {
820
820
  */
821
821
  GumboVector /* GumboError */ errors;
822
822
 
823
+ /**
824
+ * True if the parser encounted an error.
825
+ *
826
+ * This can be true and `errors` an empty `GumboVector` if the `max_errors`
827
+ * option was set to 0.
828
+ */
829
+ bool document_error;
830
+
823
831
  /**
824
832
  * A status code indicating whether parsing finished successfully or was
825
833
  * stopped mid-document due to exceptional circumstances.
@@ -336,6 +336,7 @@ static void output_init(GumboParser* parser) {
336
336
  GumboOutput* output = gumbo_alloc(sizeof(GumboOutput));
337
337
  output->root = NULL;
338
338
  output->document = new_document_node();
339
+ output->document_error = false;
339
340
  output->status = GUMBO_STATUS_OK;
340
341
  parser->_output = output;
341
342
  gumbo_init_errors(parser);
@@ -608,6 +609,14 @@ static bool node_qualified_tagname_is (
608
609
  return !gumbo_ascii_strcasecmp(element_name, name);
609
610
  }
610
611
 
612
+ static bool node_html_tagname_is (
613
+ const GumboNode* node,
614
+ GumboTag tag,
615
+ const char *name
616
+ ) {
617
+ return node_qualified_tagname_is(node, GUMBO_NAMESPACE_HTML, tag, name);
618
+ }
619
+
611
620
  static bool node_tagname_is (
612
621
  const GumboNode* node,
613
622
  GumboTag tag,
@@ -633,7 +642,6 @@ static bool node_qualified_tag_is (
633
642
 
634
643
  // Like node_tag_in, but for the single-tag case in the HTML namespace
635
644
  static bool node_html_tag_is(const GumboNode* node, GumboTag tag) {
636
- assert(tag != GUMBO_TAG_UNKNOWN);
637
645
  return node_qualified_tag_is(node, GUMBO_NAMESPACE_HTML, tag);
638
646
  }
639
647
 
@@ -1675,14 +1683,18 @@ static bool has_an_element_in_select_scope(const GumboParser* parser, GumboTag t
1675
1683
  // https://html.spec.whatwg.org/multipage/parsing.html#generate-implied-end-tags
1676
1684
  // "exception" is the "element to exclude from the process" listed in the spec.
1677
1685
  // Pass GUMBO_TAG_LAST to not exclude any of them.
1678
- static void generate_implied_end_tags(GumboParser* parser, GumboTag exception) {
1686
+ static void generate_implied_end_tags (
1687
+ GumboParser* parser,
1688
+ GumboTag exception,
1689
+ const char* exception_name
1690
+ ) {
1679
1691
  static const TagSet tags = {
1680
1692
  TAG(DD), TAG(DT), TAG(LI), TAG(OPTGROUP), TAG(OPTION),
1681
1693
  TAG(P), TAG(RB), TAG(RP), TAG(RT), TAG(RTC)
1682
1694
  };
1683
1695
  while (
1684
1696
  node_tag_in_set(get_current_node(parser), &tags)
1685
- && !node_html_tag_is(get_current_node(parser), exception)
1697
+ && !node_html_tagname_is(get_current_node(parser), exception, exception_name)
1686
1698
  ) {
1687
1699
  pop_current_node(parser);
1688
1700
  }
@@ -1741,30 +1753,26 @@ static bool close_table(GumboParser* parser) {
1741
1753
 
1742
1754
  // This factors out the clauses relating to "act as if an end tag token with tag
1743
1755
  // name `cell_tag` had been seen".
1744
- static bool close_table_cell (
1756
+ static void close_table_cell (
1745
1757
  GumboParser* parser,
1746
1758
  const GumboToken* token,
1747
1759
  GumboTag cell_tag
1748
1760
  ) {
1749
- bool result = true;
1750
- generate_implied_end_tags(parser, GUMBO_TAG_LAST);
1761
+ generate_implied_end_tags(parser, GUMBO_TAG_LAST, NULL);
1751
1762
  const GumboNode* node = get_current_node(parser);
1752
- if (!node_html_tag_is(node, cell_tag)) {
1763
+ if (!node_html_tag_is(node, cell_tag))
1753
1764
  parser_add_parse_error(parser, token);
1754
- result = false;
1755
- }
1756
1765
  do {
1757
1766
  node = pop_current_node(parser);
1758
1767
  } while (!node_html_tag_is(node, cell_tag));
1759
1768
 
1760
1769
  clear_active_formatting_elements(parser);
1761
1770
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW);
1762
- return result;
1763
1771
  }
1764
1772
 
1765
1773
  // https://html.spec.whatwg.org/multipage/parsing.html#close-the-cell
1766
1774
  // This holds the logic to determine whether we should close a <td> or a <th>.
1767
- static bool close_current_cell(GumboParser* parser, const GumboToken* token) {
1775
+ static void close_current_cell(GumboParser* parser, const GumboToken* token) {
1768
1776
  GumboTag cell_tag;
1769
1777
  if (has_an_element_in_table_scope(parser, GUMBO_TAG_TD)) {
1770
1778
  assert(!has_an_element_in_table_scope(parser, GUMBO_TAG_TH));
@@ -1773,7 +1781,7 @@ static bool close_current_cell(GumboParser* parser, const GumboToken* token) {
1773
1781
  assert(has_an_element_in_table_scope(parser, GUMBO_TAG_TH));
1774
1782
  cell_tag = GUMBO_TAG_TH;
1775
1783
  }
1776
- return close_table_cell(parser, token, cell_tag);
1784
+ close_table_cell(parser, token, cell_tag);
1777
1785
  }
1778
1786
 
1779
1787
  // This factors out the "act as if an end tag of tag name 'select' had been
@@ -1830,14 +1838,14 @@ static bool is_special_node(const GumboNode* node) {
1830
1838
  // specified qualified name. If the elements closed are in the set handled by
1831
1839
  // generate_implied_end_tags, this is normal operation and this function returns
1832
1840
  // true. Otherwise, a parse error is recorded and this function returns false.
1833
- static bool implicitly_close_tags (
1841
+ static void implicitly_close_tags (
1834
1842
  GumboParser* parser,
1835
1843
  GumboToken* token,
1836
1844
  GumboNamespaceEnum target_ns,
1837
1845
  GumboTag target
1838
1846
  ) {
1839
- bool result = true;
1840
- generate_implied_end_tags(parser, target);
1847
+ assert(target != GUMBO_TAG_UNKNOWN);
1848
+ generate_implied_end_tags(parser, target, NULL);
1841
1849
  if (!node_qualified_tag_is(get_current_node(parser), target_ns, target)) {
1842
1850
  parser_add_parse_error(parser, token);
1843
1851
  while (
@@ -1845,35 +1853,32 @@ static bool implicitly_close_tags (
1845
1853
  ) {
1846
1854
  pop_current_node(parser);
1847
1855
  }
1848
- result = false;
1849
1856
  }
1850
1857
  assert(node_qualified_tag_is(get_current_node(parser), target_ns, target));
1851
1858
  pop_current_node(parser);
1852
- return result;
1853
1859
  }
1854
1860
 
1855
1861
  // If the stack of open elements has a <p> tag in button scope, this acts as if
1856
1862
  // a </p> tag was encountered, implicitly closing tags. Returns false if a
1857
1863
  // parse error occurs. This is a convenience function because this particular
1858
1864
  // clause appears several times in the spec.
1859
- static bool maybe_implicitly_close_p_tag (
1865
+ static void maybe_implicitly_close_p_tag (
1860
1866
  GumboParser* parser,
1861
1867
  GumboToken* token
1862
1868
  ) {
1863
1869
  if (has_an_element_in_button_scope(parser, GUMBO_TAG_P)) {
1864
- return implicitly_close_tags (
1870
+ implicitly_close_tags (
1865
1871
  parser,
1866
1872
  token,
1867
1873
  GUMBO_NAMESPACE_HTML,
1868
1874
  GUMBO_TAG_P
1869
1875
  );
1870
1876
  }
1871
- return true;
1872
1877
  }
1873
1878
 
1874
1879
  // Convenience function to encapsulate the logic for closing <li> or <dd>/<dt>
1875
1880
  // tags. Pass true to is_li for handling <li> tags, false for <dd> and <dt>.
1876
- static bool maybe_implicitly_close_list_tag (
1881
+ static void maybe_implicitly_close_list_tag (
1877
1882
  GumboParser* parser,
1878
1883
  GumboToken* token,
1879
1884
  bool is_li
@@ -1887,21 +1892,22 @@ static bool maybe_implicitly_close_list_tag (
1887
1892
  : node_tag_in_set(node, &dd_dt_tags)
1888
1893
  ;
1889
1894
  if (is_list_tag) {
1890
- return implicitly_close_tags (
1895
+ implicitly_close_tags (
1891
1896
  parser,
1892
1897
  token,
1893
1898
  node->v.element.tag_namespace,
1894
1899
  node->v.element.tag
1895
1900
  );
1901
+ return;
1896
1902
  }
1903
+
1897
1904
  if (
1898
1905
  is_special_node(node)
1899
1906
  && !node_tag_in_set(node, &(const TagSet){TAG(ADDRESS), TAG(DIV), TAG(P)})
1900
1907
  ) {
1901
- return true;
1908
+ return;
1902
1909
  }
1903
1910
  }
1904
- return true;
1905
1911
  }
1906
1912
 
1907
1913
  static void merge_attributes (
@@ -2020,7 +2026,7 @@ static void adjust_mathml_attributes(GumboToken* token) {
2020
2026
  attr->name = gumbo_strdup("definitionURL");
2021
2027
  }
2022
2028
 
2023
- static bool maybe_add_doctype_error (
2029
+ static void maybe_add_doctype_error (
2024
2030
  GumboParser* parser,
2025
2031
  const GumboToken* token
2026
2032
  ) {
@@ -2032,9 +2038,7 @@ static bool maybe_add_doctype_error (
2032
2038
  && strcmp(doctype->system_identifier, "about:legacy-compat"))
2033
2039
  ) {
2034
2040
  parser_add_parse_error(parser, token);
2035
- return false;
2036
2041
  }
2037
- return true;
2038
2042
  }
2039
2043
 
2040
2044
  static void remove_from_parent(GumboNode* node) {
@@ -2059,30 +2063,103 @@ static void remove_from_parent(GumboNode* node) {
2059
2063
  }
2060
2064
  }
2061
2065
 
2066
+ // This is here to clean up memory when the spec says "Ignore current token."
2067
+ static void ignore_token(GumboParser* parser) {
2068
+ GumboToken* token = parser->_parser_state->_current_token;
2069
+ // Ownership of the token's internal buffers are normally transferred to the
2070
+ // element, but if no element is emitted (as happens in non-verbatim-mode
2071
+ // when a token is ignored), we need to free it here to prevent a memory
2072
+ // leak.
2073
+ gumbo_token_destroy(token);
2074
+ #ifndef NDEBUG
2075
+ if (token->type == GUMBO_TOKEN_START_TAG) {
2076
+ // Mark this sentinel so the assertion in the main loop knows it's been
2077
+ // destroyed.
2078
+ token->v.start_tag.attributes = kGumboEmptyVector;
2079
+ token->v.start_tag.name = NULL;
2080
+ }
2081
+ #endif
2082
+ }
2083
+
2084
+ // The token is usually an end tag; however, the adoption agency algorithm may
2085
+ // invoke this for an 'a' or 'nobr' start tag.
2086
+ // Returns false if there was an error.
2087
+ static void in_body_any_other_end_tag(GumboParser* parser, GumboToken* token)
2088
+ {
2089
+ GumboParserState* state = parser->_parser_state;
2090
+ GumboTag tag;
2091
+ const char* tagname;
2092
+
2093
+ if (token->type == GUMBO_TOKEN_END_TAG) {
2094
+ tag = token->v.end_tag.tag;
2095
+ tagname = token->v.end_tag.name;
2096
+ } else {
2097
+ assert(token->type == GUMBO_TOKEN_START_TAG);
2098
+ tag = token->v.start_tag.tag;
2099
+ tagname = token->v.start_tag.name;
2100
+ }
2101
+
2102
+ assert(state->_open_elements.length > 0);
2103
+ assert(node_html_tag_is(state->_open_elements.data[0], GUMBO_TAG_HTML));
2104
+ // Walk up the stack of open elements until we find one that either:
2105
+ // a) Matches the tag name we saw
2106
+ // b) Is in the "special" category.
2107
+ // If we see a), implicitly close everything up to and including it. If we
2108
+ // see b), then record a parse error, don't close anything (except the
2109
+ // implied end tags) and ignore the end tag token.
2110
+ for (int i = state->_open_elements.length; --i >= 0;) {
2111
+ const GumboNode* node = state->_open_elements.data[i];
2112
+ if (node_qualified_tagname_is(node, GUMBO_NAMESPACE_HTML, tag, tagname)) {
2113
+ generate_implied_end_tags(parser, tag, tagname);
2114
+ // <!DOCTYPE><body><sarcasm><foo></sarcasm> is an example of an error.
2115
+ // foo is the "current node" but sarcasm is node.
2116
+ // XXX: Write a test for this.
2117
+ if (node != get_current_node(parser)) {
2118
+ parser_add_parse_error(parser, token);
2119
+ }
2120
+ while (node != pop_current_node(parser))
2121
+ ; // Pop everything.
2122
+ return;
2123
+ } else if (is_special_node(node)) {
2124
+ parser_add_parse_error(parser, token);
2125
+ ignore_token(parser);
2126
+ return;
2127
+ }
2128
+ }
2129
+ // <html> is in the special category, so we should never get here.
2130
+ assert(0 && "unreachable");
2131
+ }
2132
+
2062
2133
  // https://html.spec.whatwg.org/multipage/parsing.html#an-introduction-to-error-handling-and-strange-cases-in-the-parser
2063
2134
  // Also described in the "in body" handling for end formatting tags.
2064
- // Returns true if the algorithm handled the token and false to indicate that
2065
- // it should be handled according to "any other end tag."
2066
- static bool adoption_agency_algorithm (
2067
- GumboParser* parser,
2068
- GumboToken* token,
2069
- GumboTag subject
2070
- ) {
2135
+ // Returns false if there was an error.
2136
+ static void adoption_agency_algorithm(GumboParser* parser, GumboToken* token)
2137
+ {
2071
2138
  GumboParserState* state = parser->_parser_state;
2072
2139
  gumbo_debug("Entering adoption agency algorithm.\n");
2140
+ // Step 1.
2141
+ GumboTag subject;
2142
+ if (token->type == GUMBO_TOKEN_START_TAG) {
2143
+ subject = token->v.start_tag.tag;
2144
+ } else {
2145
+ assert(token->type == GUMBO_TOKEN_END_TAG);
2146
+ subject = token->v.end_tag.tag;
2147
+ }
2148
+ assert(subject != GUMBO_TAG_UNKNOWN);
2149
+
2073
2150
  // Step 2.
2074
2151
  GumboNode* current_node = get_current_node(parser);
2075
2152
  if (
2076
- current_node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML
2077
- && current_node->v.element.tag == subject
2153
+ node_html_tag_is(current_node, subject)
2078
2154
  && -1 == gumbo_vector_index_of (
2079
2155
  &state->_active_formatting_elements,
2080
2156
  current_node
2081
2157
  )
2082
2158
  ) {
2083
2159
  pop_current_node(parser);
2084
- return true;
2160
+ return;
2085
2161
  }
2162
+
2086
2163
  // Steps 3-5 & 21:
2087
2164
  for (unsigned int i = 0; i < 8; ++i) {
2088
2165
  // Step 6.
@@ -2093,8 +2170,8 @@ static bool adoption_agency_algorithm (
2093
2170
  if (current_node == &kActiveFormattingScopeMarker) {
2094
2171
  gumbo_debug("Broke on scope marker; aborting.\n");
2095
2172
  // Last scope marker; abort the algorithm and handle according to "any
2096
- // other end tag."
2097
- return false;
2173
+ // other end tag" (below).
2174
+ break;
2098
2175
  }
2099
2176
  if (node_html_tag_is(current_node, subject)) {
2100
2177
  // Found it.
@@ -2116,7 +2193,8 @@ static bool adoption_agency_algorithm (
2116
2193
  // "any other end tag" clause (which may potentially add a parse error,
2117
2194
  // but not always).
2118
2195
  gumbo_debug("No active formatting elements; aborting.\n");
2119
- return false;
2196
+ in_body_any_other_end_tag(parser, token);
2197
+ return;
2120
2198
  }
2121
2199
 
2122
2200
  // Step 7
@@ -2127,20 +2205,19 @@ static bool adoption_agency_algorithm (
2127
2205
  formatting_node,
2128
2206
  &state->_active_formatting_elements
2129
2207
  );
2130
- return true;
2208
+ return;
2131
2209
  }
2132
2210
 
2133
2211
  // Step 8
2134
2212
  if (!has_an_element_in_scope(parser, formatting_node->v.element.tag)) {
2135
2213
  parser_add_parse_error(parser, token);
2136
2214
  gumbo_debug("Element not in scope.\n");
2137
- return true;
2215
+ return;
2138
2216
  }
2139
2217
 
2140
2218
  // Step 9
2141
- if (formatting_node != get_current_node(parser)) {
2219
+ if (formatting_node != get_current_node(parser))
2142
2220
  parser_add_parse_error(parser, token); // But continue onwards.
2143
- }
2144
2221
  assert(formatting_node);
2145
2222
  assert(!node_html_tag_is(formatting_node, GUMBO_TAG_HTML));
2146
2223
  assert(!node_html_tag_is(formatting_node, GUMBO_TAG_BODY));
@@ -2167,7 +2244,7 @@ static bool adoption_agency_algorithm (
2167
2244
  formatting_node,
2168
2245
  &state->_active_formatting_elements
2169
2246
  );
2170
- return true;
2247
+ return;
2171
2248
  }
2172
2249
  assert(!node_html_tag_is(furthest_block, GUMBO_TAG_HTML));
2173
2250
 
@@ -2348,25 +2425,6 @@ static bool adoption_agency_algorithm (
2348
2425
  &state->_open_elements
2349
2426
  );
2350
2427
  } // Step 21.
2351
- return true;
2352
- }
2353
-
2354
- // This is here to clean up memory when the spec says "Ignore current token."
2355
- static void ignore_token(GumboParser* parser) {
2356
- GumboToken* token = parser->_parser_state->_current_token;
2357
- // Ownership of the token's internal buffers are normally transferred to the
2358
- // element, but if no element is emitted (as happens in non-verbatim-mode
2359
- // when a token is ignored), we need to free it here to prevent a memory
2360
- // leak.
2361
- gumbo_token_destroy(token);
2362
- #ifndef NDEBUG
2363
- if (token->type == GUMBO_TOKEN_START_TAG) {
2364
- // Mark this sentinel so the assertion in the main loop knows it's been
2365
- // destroyed.
2366
- token->v.start_tag.attributes = kGumboEmptyVector;
2367
- token->v.start_tag.name = NULL;
2368
- }
2369
- #endif
2370
2428
  }
2371
2429
 
2372
2430
  // https://html.spec.whatwg.org/multipage/parsing.html#the-end
@@ -2391,15 +2449,15 @@ static void finish_parsing(GumboParser* parser) {
2391
2449
  ; // Pop them all.
2392
2450
  }
2393
2451
 
2394
- static bool handle_initial(GumboParser* parser, GumboToken* token) {
2452
+ static void handle_initial(GumboParser* parser, GumboToken* token) {
2395
2453
  GumboDocument* document = &get_document_node(parser)->v.document;
2396
2454
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
2397
2455
  ignore_token(parser);
2398
- return true;
2456
+ return;
2399
2457
  }
2400
2458
  if (token->type == GUMBO_TOKEN_COMMENT) {
2401
2459
  append_comment_node(parser, get_document_node(parser), token);
2402
- return true;
2460
+ return;
2403
2461
  }
2404
2462
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
2405
2463
  document->has_doctype = true;
@@ -2408,35 +2466,35 @@ static bool handle_initial(GumboParser* parser, GumboToken* token) {
2408
2466
  document->system_identifier = token->v.doc_type.system_identifier;
2409
2467
  document->doc_type_quirks_mode = compute_quirks_mode(&token->v.doc_type);
2410
2468
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HTML);
2411
- return maybe_add_doctype_error(parser, token);
2469
+ maybe_add_doctype_error(parser, token);
2470
+ return;
2412
2471
  }
2413
2472
  parser_add_parse_error(parser, token);
2414
2473
  document->doc_type_quirks_mode = GUMBO_DOCTYPE_QUIRKS;
2415
2474
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HTML);
2416
2475
  parser->_parser_state->_reprocess_current_token = true;
2417
- return true;
2418
2476
  }
2419
2477
 
2420
2478
  // https://html.spec.whatwg.org/multipage/parsing.html#the-before-html-insertion-mode
2421
- static bool handle_before_html(GumboParser* parser, GumboToken* token) {
2479
+ static void handle_before_html(GumboParser* parser, GumboToken* token) {
2422
2480
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
2423
2481
  parser_add_parse_error(parser, token);
2424
2482
  ignore_token(parser);
2425
- return false;
2483
+ return;
2426
2484
  }
2427
2485
  if (token->type == GUMBO_TOKEN_COMMENT) {
2428
2486
  append_comment_node(parser, get_document_node(parser), token);
2429
- return true;
2487
+ return;
2430
2488
  }
2431
2489
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
2432
2490
  ignore_token(parser);
2433
- return true;
2491
+ return;
2434
2492
  }
2435
2493
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
2436
2494
  GumboNode* html_node = insert_element_from_token(parser, token);
2437
2495
  parser->_output->root = html_node;
2438
2496
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HEAD);
2439
- return true;
2497
+ return;
2440
2498
  }
2441
2499
  if (
2442
2500
  token->type == GUMBO_TOKEN_END_TAG
@@ -2444,7 +2502,7 @@ static bool handle_before_html(GumboParser* parser, GumboToken* token) {
2444
2502
  ) {
2445
2503
  parser_add_parse_error(parser, token);
2446
2504
  ignore_token(parser);
2447
- return false;
2505
+ return;
2448
2506
  }
2449
2507
  GumboNode* html_node = insert_element_of_tag_type (
2450
2508
  parser,
@@ -2455,37 +2513,37 @@ static bool handle_before_html(GumboParser* parser, GumboToken* token) {
2455
2513
  parser->_output->root = html_node;
2456
2514
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HEAD);
2457
2515
  parser->_parser_state->_reprocess_current_token = true;
2458
- return true;
2459
2516
  }
2460
2517
 
2461
2518
  // Forward declarations because of mutual dependencies.
2462
- static bool handle_token(GumboParser* parser, GumboToken* token);
2463
- static bool handle_in_body(GumboParser* parser, GumboToken* token);
2464
- static bool handle_in_template(GumboParser* parser, GumboToken* token);
2519
+ static void handle_token(GumboParser* parser, GumboToken* token);
2520
+ static void handle_in_body(GumboParser* parser, GumboToken* token);
2521
+ static void handle_in_template(GumboParser* parser, GumboToken* token);
2465
2522
 
2466
2523
  // https://html.spec.whatwg.org/multipage/parsing.html#the-before-head-insertion-mode
2467
- static bool handle_before_head(GumboParser* parser, GumboToken* token) {
2524
+ static void handle_before_head(GumboParser* parser, GumboToken* token) {
2468
2525
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
2469
2526
  ignore_token(parser);
2470
- return true;
2527
+ return;
2471
2528
  }
2472
2529
  if (token->type == GUMBO_TOKEN_COMMENT) {
2473
2530
  append_comment_node(parser, get_current_node(parser), token);
2474
- return true;
2531
+ return;
2475
2532
  }
2476
2533
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
2477
2534
  parser_add_parse_error(parser, token);
2478
2535
  ignore_token(parser);
2479
- return false;
2536
+ return;
2480
2537
  }
2481
2538
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
2482
- return handle_in_body(parser, token);
2539
+ handle_in_body(parser, token);
2540
+ return;
2483
2541
  }
2484
2542
  if (tag_is(token, kStartTag, GUMBO_TAG_HEAD)) {
2485
2543
  GumboNode* node = insert_element_from_token(parser, token);
2486
2544
  parser->_parser_state->_head_element = node;
2487
2545
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD);
2488
- return true;
2546
+ return;
2489
2547
  }
2490
2548
  if (
2491
2549
  token->type == GUMBO_TOKEN_END_TAG
@@ -2493,7 +2551,7 @@ static bool handle_before_head(GumboParser* parser, GumboToken* token) {
2493
2551
  ) {
2494
2552
  parser_add_parse_error(parser, token);
2495
2553
  ignore_token(parser);
2496
- return false;
2554
+ return;
2497
2555
  }
2498
2556
  GumboNode* node = insert_element_of_tag_type (
2499
2557
  parser,
@@ -2503,23 +2561,22 @@ static bool handle_before_head(GumboParser* parser, GumboToken* token) {
2503
2561
  parser->_parser_state->_head_element = node;
2504
2562
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD);
2505
2563
  parser->_parser_state->_reprocess_current_token = true;
2506
- return true;
2507
2564
  }
2508
2565
 
2509
2566
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead
2510
- static bool handle_in_head(GumboParser* parser, GumboToken* token) {
2567
+ static void handle_in_head(GumboParser* parser, GumboToken* token) {
2511
2568
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
2512
2569
  insert_text_token(parser, token);
2513
- return true;
2570
+ return;
2514
2571
  }
2515
2572
  if (token->type == GUMBO_TOKEN_COMMENT) {
2516
2573
  append_comment_node(parser, get_current_node(parser), token);
2517
- return true;
2574
+ return;
2518
2575
  }
2519
2576
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
2520
2577
  parser_add_parse_error(parser, token);
2521
2578
  ignore_token(parser);
2522
- return false;
2579
+ return;
2523
2580
  }
2524
2581
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
2525
2582
  return handle_in_body(parser, token);
@@ -2532,7 +2589,7 @@ static bool handle_in_head(GumboParser* parser, GumboToken* token) {
2532
2589
  insert_element_from_token(parser, token);
2533
2590
  pop_current_node(parser);
2534
2591
  acknowledge_self_closing_tag(parser);
2535
- return true;
2592
+ return;
2536
2593
  }
2537
2594
  if (tag_is(token, kStartTag, GUMBO_TAG_META)) {
2538
2595
  insert_element_from_token(parser, token);
@@ -2542,33 +2599,33 @@ static bool handle_in_head(GumboParser* parser, GumboToken* token) {
2542
2599
  // spec doesn't apply. If clients want to handle meta-tag re-encoding, they
2543
2600
  // should specifically look for that string in the document and re-encode it
2544
2601
  // before passing to Gumbo.
2545
- return true;
2602
+ return;
2546
2603
  }
2547
2604
  if (tag_is(token, kStartTag, GUMBO_TAG_TITLE)) {
2548
2605
  run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RCDATA);
2549
- return true;
2606
+ return;
2550
2607
  }
2551
2608
  if (
2552
2609
  tag_in(token, kStartTag, &(const TagSet){TAG(NOFRAMES), TAG(STYLE)})
2553
2610
  ) {
2554
2611
  run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT);
2555
- return true;
2612
+ return;
2556
2613
  }
2557
2614
  if (tag_is(token, kStartTag, GUMBO_TAG_NOSCRIPT)) {
2558
2615
  insert_element_from_token(parser, token);
2559
2616
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD_NOSCRIPT);
2560
- return true;
2617
+ return;
2561
2618
  }
2562
2619
  if (tag_is(token, kStartTag, GUMBO_TAG_SCRIPT)) {
2563
2620
  run_generic_parsing_algorithm(parser, token, GUMBO_LEX_SCRIPT_DATA);
2564
- return true;
2621
+ return;
2565
2622
  }
2566
2623
  if (tag_is(token, kEndTag, GUMBO_TAG_HEAD)) {
2567
2624
  GumboNode* head = pop_current_node(parser);
2568
2625
  UNUSED_IF_NDEBUG(head);
2569
2626
  assert(node_html_tag_is(head, GUMBO_TAG_HEAD));
2570
2627
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_HEAD);
2571
- return true;
2628
+ return;
2572
2629
  }
2573
2630
  if (
2574
2631
  tag_in(token, kEndTag, &(const TagSet){TAG(BODY), TAG(HTML), TAG(BR)})
@@ -2576,7 +2633,7 @@ static bool handle_in_head(GumboParser* parser, GumboToken* token) {
2576
2633
  pop_current_node(parser);
2577
2634
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_HEAD);
2578
2635
  parser->_parser_state->_reprocess_current_token = true;
2579
- return true;
2636
+ return;
2580
2637
  }
2581
2638
  if (tag_is(token, kStartTag, GUMBO_TAG_TEMPLATE)) {
2582
2639
  insert_element_from_token(parser, token);
@@ -2584,26 +2641,23 @@ static bool handle_in_head(GumboParser* parser, GumboToken* token) {
2584
2641
  set_frameset_not_ok(parser);
2585
2642
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TEMPLATE);
2586
2643
  push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TEMPLATE);
2587
- return true;
2644
+ return;
2588
2645
  }
2589
2646
  if (tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)) {
2590
2647
  if (!has_open_element(parser, GUMBO_TAG_TEMPLATE)) {
2591
2648
  parser_add_parse_error(parser, token);
2592
2649
  ignore_token(parser);
2593
- return false;
2650
+ return;
2594
2651
  }
2595
2652
  generate_all_implied_end_tags_thoroughly(parser);
2596
- bool success = true;
2597
- if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_TEMPLATE)) {
2653
+ if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_TEMPLATE))
2598
2654
  parser_add_parse_error(parser, token);
2599
- success = false;
2600
- }
2601
2655
  while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_TEMPLATE))
2602
2656
  ;
2603
2657
  clear_active_formatting_elements(parser);
2604
2658
  pop_template_insertion_mode(parser);
2605
2659
  reset_insertion_mode_appropriately(parser);
2606
- return success;
2660
+ return;
2607
2661
  }
2608
2662
  if (
2609
2663
  tag_is(token, kStartTag, GUMBO_TAG_HEAD)
@@ -2611,29 +2665,30 @@ static bool handle_in_head(GumboParser* parser, GumboToken* token) {
2611
2665
  ) {
2612
2666
  parser_add_parse_error(parser, token);
2613
2667
  ignore_token(parser);
2614
- return false;
2668
+ return;
2615
2669
  }
2616
2670
  pop_current_node(parser);
2617
2671
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_HEAD);
2618
2672
  parser->_parser_state->_reprocess_current_token = true;
2619
- return true;
2673
+ return;
2620
2674
  }
2621
2675
 
2622
2676
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inheadnoscript
2623
- static bool handle_in_head_noscript(GumboParser* parser, GumboToken* token) {
2677
+ static void handle_in_head_noscript(GumboParser* parser, GumboToken* token) {
2624
2678
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
2625
2679
  parser_add_parse_error(parser, token);
2626
- return false;
2680
+ return;
2627
2681
  }
2628
2682
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
2629
- return handle_in_body(parser, token);
2683
+ handle_in_body(parser, token);
2684
+ return;
2630
2685
  }
2631
2686
  if (tag_is(token, kEndTag, GUMBO_TAG_NOSCRIPT)) {
2632
2687
  const GumboNode* node = pop_current_node(parser);
2633
2688
  assert(node_html_tag_is(node, GUMBO_TAG_NOSCRIPT));
2634
2689
  UNUSED_IF_NDEBUG(node);
2635
2690
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD);
2636
- return true;
2691
+ return;
2637
2692
  }
2638
2693
  if (
2639
2694
  token->type == GUMBO_TOKEN_WHITESPACE
@@ -2643,7 +2698,8 @@ static bool handle_in_head_noscript(GumboParser* parser, GumboToken* token) {
2643
2698
  TAG(META), TAG(NOFRAMES), TAG(STYLE)
2644
2699
  })
2645
2700
  ) {
2646
- return handle_in_head(parser, token);
2701
+ handle_in_head(parser, token);
2702
+ return;
2647
2703
  }
2648
2704
  if (
2649
2705
  tag_in(token, kStartTag, &(const TagSet){TAG(HEAD), TAG(NOSCRIPT)})
@@ -2654,7 +2710,7 @@ static bool handle_in_head_noscript(GumboParser* parser, GumboToken* token) {
2654
2710
  ) {
2655
2711
  parser_add_parse_error(parser, token);
2656
2712
  ignore_token(parser);
2657
- return false;
2713
+ return;
2658
2714
  }
2659
2715
  parser_add_parse_error(parser, token);
2660
2716
  const GumboNode* node = pop_current_node(parser);
@@ -2662,38 +2718,38 @@ static bool handle_in_head_noscript(GumboParser* parser, GumboToken* token) {
2662
2718
  UNUSED_IF_NDEBUG(node);
2663
2719
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD);
2664
2720
  parser->_parser_state->_reprocess_current_token = true;
2665
- return false;
2666
2721
  }
2667
2722
 
2668
2723
  // https://html.spec.whatwg.org/multipage/parsing.html#the-after-head-insertion-mode
2669
- static bool handle_after_head(GumboParser* parser, GumboToken* token) {
2724
+ static void handle_after_head(GumboParser* parser, GumboToken* token) {
2670
2725
  GumboParserState* state = parser->_parser_state;
2671
2726
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
2672
2727
  insert_text_token(parser, token);
2673
- return true;
2728
+ return;
2674
2729
  }
2675
2730
  if (token->type == GUMBO_TOKEN_COMMENT) {
2676
2731
  append_comment_node(parser, get_current_node(parser), token);
2677
- return true;
2732
+ return;
2678
2733
  }
2679
2734
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
2680
2735
  parser_add_parse_error(parser, token);
2681
2736
  ignore_token(parser);
2682
- return false;
2737
+ return;
2683
2738
  }
2684
2739
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
2685
- return handle_in_body(parser, token);
2740
+ handle_in_body(parser, token);
2741
+ return;
2686
2742
  }
2687
2743
  if (tag_is(token, kStartTag, GUMBO_TAG_BODY)) {
2688
2744
  insert_element_from_token(parser, token);
2689
2745
  set_frameset_not_ok(parser);
2690
2746
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);
2691
- return true;
2747
+ return;
2692
2748
  }
2693
2749
  if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) {
2694
2750
  insert_element_from_token(parser, token);
2695
2751
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_FRAMESET);
2696
- return true;
2752
+ return;
2697
2753
  }
2698
2754
  if (
2699
2755
  tag_in(token, kStartTag, &(const TagSet) {
@@ -2709,10 +2765,11 @@ static bool handle_after_head(GumboParser* parser, GumboToken* token) {
2709
2765
  gumbo_vector_add(state->_head_element, &state->_open_elements);
2710
2766
  handle_in_head(parser, token);
2711
2767
  gumbo_vector_remove(state->_head_element, &state->_open_elements);
2712
- return false;
2768
+ return;
2713
2769
  }
2714
2770
  if (tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)) {
2715
- return handle_in_head(parser, token);
2771
+ handle_in_head(parser, token);
2772
+ return;
2716
2773
  }
2717
2774
  if (
2718
2775
  tag_is(token, kStartTag, GUMBO_TAG_HEAD)
@@ -2723,27 +2780,26 @@ static bool handle_after_head(GumboParser* parser, GumboToken* token) {
2723
2780
  ) {
2724
2781
  parser_add_parse_error(parser, token);
2725
2782
  ignore_token(parser);
2726
- return false;
2783
+ return;
2727
2784
  }
2728
2785
  insert_element_of_tag_type(parser, GUMBO_TAG_BODY, GUMBO_INSERTION_IMPLIED);
2729
2786
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);
2730
2787
  state->_reprocess_current_token = true;
2731
- return true;
2732
2788
  }
2733
2789
 
2734
2790
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody
2735
- static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2791
+ static void handle_in_body(GumboParser* parser, GumboToken* token) {
2736
2792
  GumboParserState* state = parser->_parser_state;
2737
2793
  assert(state->_open_elements.length > 0);
2738
2794
  if (token->type == GUMBO_TOKEN_NULL) {
2739
2795
  parser_add_parse_error(parser, token);
2740
2796
  ignore_token(parser);
2741
- return false;
2797
+ return;
2742
2798
  }
2743
2799
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
2744
2800
  reconstruct_active_formatting_elements(parser);
2745
2801
  insert_text_token(parser, token);
2746
- return true;
2802
+ return;
2747
2803
  }
2748
2804
  if (
2749
2805
  token->type == GUMBO_TOKEN_CHARACTER
@@ -2752,27 +2808,27 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2752
2808
  reconstruct_active_formatting_elements(parser);
2753
2809
  insert_text_token(parser, token);
2754
2810
  set_frameset_not_ok(parser);
2755
- return true;
2811
+ return;
2756
2812
  }
2757
2813
  if (token->type == GUMBO_TOKEN_COMMENT) {
2758
2814
  append_comment_node(parser, get_current_node(parser), token);
2759
- return true;
2815
+ return;
2760
2816
  }
2761
2817
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
2762
2818
  parser_add_parse_error(parser, token);
2763
2819
  ignore_token(parser);
2764
- return false;
2820
+ return;
2765
2821
  }
2766
2822
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
2767
2823
  parser_add_parse_error(parser, token);
2768
2824
  if (has_open_element(parser, GUMBO_TAG_TEMPLATE)) {
2769
2825
  ignore_token(parser);
2770
- return false;
2826
+ return;
2771
2827
  }
2772
2828
  assert(parser->_output->root != NULL);
2773
2829
  assert(parser->_output->root->type == GUMBO_NODE_ELEMENT);
2774
2830
  merge_attributes(token, parser->_output->root);
2775
- return false;
2831
+ return;
2776
2832
  }
2777
2833
  if (
2778
2834
  tag_in(token, kStartTag, &(const TagSet) {
@@ -2782,7 +2838,8 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2782
2838
  })
2783
2839
  || tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)
2784
2840
  ) {
2785
- return handle_in_head(parser, token);
2841
+ handle_in_head(parser, token);
2842
+ return;
2786
2843
  }
2787
2844
  if (tag_is(token, kStartTag, GUMBO_TAG_BODY)) {
2788
2845
  parser_add_parse_error(parser, token);
@@ -2796,7 +2853,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2796
2853
  set_frameset_not_ok(parser);
2797
2854
  merge_attributes(token, state->_open_elements.data[1]);
2798
2855
  }
2799
- return false;
2856
+ return;
2800
2857
  }
2801
2858
  if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) {
2802
2859
  parser_add_parse_error(parser, token);
@@ -2806,7 +2863,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2806
2863
  || !state->_frameset_ok
2807
2864
  ) {
2808
2865
  ignore_token(parser);
2809
- return false;
2866
+ return;
2810
2867
  }
2811
2868
  // Save the body node for later removal.
2812
2869
  GumboNode* body_node = state->_open_elements.data[1];
@@ -2838,50 +2895,43 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2838
2895
  // Insert the <frameset>, and switch the insertion mode.
2839
2896
  insert_element_from_token(parser, token);
2840
2897
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_FRAMESET);
2841
- return true;
2898
+ return;
2842
2899
  }
2843
2900
  if (token->type == GUMBO_TOKEN_EOF) {
2844
2901
  if (get_current_template_insertion_mode(parser) !=
2845
2902
  GUMBO_INSERTION_MODE_INITIAL) {
2846
- return handle_in_template(parser, token);
2903
+ handle_in_template(parser, token);
2904
+ return;
2847
2905
  }
2848
- if (stack_contains_nonclosable_element(parser)) {
2906
+ if (stack_contains_nonclosable_element(parser))
2849
2907
  parser_add_parse_error(parser, token);
2850
- return false;
2851
- }
2852
- return true;
2908
+ return;
2853
2909
  }
2854
2910
  if (tag_is(token, kEndTag, GUMBO_TAG_BODY)) {
2855
2911
  if (!has_an_element_in_scope(parser, GUMBO_TAG_BODY)) {
2856
2912
  parser_add_parse_error(parser, token);
2857
2913
  ignore_token(parser);
2858
- return false;
2914
+ return;
2859
2915
  }
2860
- bool success = true;
2861
- if (stack_contains_nonclosable_element(parser)) {
2916
+ if (stack_contains_nonclosable_element(parser))
2862
2917
  parser_add_parse_error(parser, token);
2863
- success = false;
2864
- }
2865
2918
  GumboNode* body = state->_open_elements.data[1];
2866
2919
  assert(node_html_tag_is(body, GUMBO_TAG_BODY));
2867
2920
  record_end_of_element(state->_current_token, &body->v.element);
2868
2921
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_BODY);
2869
- return success;
2922
+ return;
2870
2923
  }
2871
2924
  if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) {
2872
2925
  if (!has_an_element_in_scope(parser, GUMBO_TAG_BODY)) {
2873
2926
  parser_add_parse_error(parser, token);
2874
2927
  ignore_token(parser);
2875
- return false;
2928
+ return;
2876
2929
  }
2877
- bool success = true;
2878
- if (stack_contains_nonclosable_element(parser)) {
2930
+ if (stack_contains_nonclosable_element(parser))
2879
2931
  parser_add_parse_error(parser, token);
2880
- success = false;
2881
- }
2882
2932
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_BODY);
2883
2933
  parser->_parser_state->_reprocess_current_token = true;
2884
- return success;
2934
+ return;
2885
2935
  }
2886
2936
  if (
2887
2937
  tag_in(token, kStartTag, &(const TagSet) {
@@ -2892,26 +2942,25 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2892
2942
  TAG(SUMMARY), TAG(UL)
2893
2943
  })
2894
2944
  ) {
2895
- bool result = maybe_implicitly_close_p_tag(parser, token);
2945
+ maybe_implicitly_close_p_tag(parser, token);
2896
2946
  insert_element_from_token(parser, token);
2897
- return result;
2947
+ return;
2898
2948
  }
2899
2949
  if (tag_in(token, kStartTag, &heading_tags)) {
2900
- bool result = maybe_implicitly_close_p_tag(parser, token);
2950
+ maybe_implicitly_close_p_tag(parser, token);
2901
2951
  if (node_tag_in_set(get_current_node(parser), &heading_tags)) {
2902
2952
  parser_add_parse_error(parser, token);
2903
2953
  pop_current_node(parser);
2904
- result = false;
2905
2954
  }
2906
2955
  insert_element_from_token(parser, token);
2907
- return result;
2956
+ return;
2908
2957
  }
2909
2958
  if (tag_in(token, kStartTag, &(const TagSet){TAG(PRE), TAG(LISTING)})) {
2910
- bool result = maybe_implicitly_close_p_tag(parser, token);
2959
+ maybe_implicitly_close_p_tag(parser, token);
2911
2960
  insert_element_from_token(parser, token);
2912
2961
  state->_ignore_next_linefeed = true;
2913
2962
  set_frameset_not_ok(parser);
2914
- return result;
2963
+ return;
2915
2964
  }
2916
2965
  if (tag_is(token, kStartTag, GUMBO_TAG_FORM)) {
2917
2966
  if (
@@ -2921,48 +2970,46 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2921
2970
  gumbo_debug("Ignoring nested form.\n");
2922
2971
  parser_add_parse_error(parser, token);
2923
2972
  ignore_token(parser);
2924
- return false;
2973
+ return;
2925
2974
  }
2926
- bool result = maybe_implicitly_close_p_tag(parser, token);
2975
+ maybe_implicitly_close_p_tag(parser, token);
2927
2976
  GumboNode* form_element = insert_element_from_token(parser, token);
2928
2977
  if (!has_open_element(parser, GUMBO_TAG_TEMPLATE)) {
2929
2978
  state->_form_element = form_element;
2930
2979
  }
2931
- return result;
2980
+ return;
2932
2981
  }
2933
2982
  if (tag_is(token, kStartTag, GUMBO_TAG_LI)) {
2934
- bool result = maybe_implicitly_close_list_tag(parser, token, true);
2935
- result = maybe_implicitly_close_p_tag(parser, token) && result;
2983
+ maybe_implicitly_close_list_tag(parser, token, true);
2984
+ maybe_implicitly_close_p_tag(parser, token);
2936
2985
  insert_element_from_token(parser, token);
2937
- return result;
2986
+ return;
2938
2987
  }
2939
2988
  if (tag_in(token, kStartTag, &dd_dt_tags)) {
2940
- bool result = maybe_implicitly_close_list_tag(parser, token, false);
2941
- result = maybe_implicitly_close_p_tag(parser, token) && result;
2989
+ maybe_implicitly_close_list_tag(parser, token, false);
2990
+ maybe_implicitly_close_p_tag(parser, token);
2942
2991
  insert_element_from_token(parser, token);
2943
- return result;
2992
+ return;
2944
2993
  }
2945
2994
  if (tag_is(token, kStartTag, GUMBO_TAG_PLAINTEXT)) {
2946
- bool result = maybe_implicitly_close_p_tag(parser, token);
2995
+ maybe_implicitly_close_p_tag(parser, token);
2947
2996
  insert_element_from_token(parser, token);
2948
2997
  gumbo_tokenizer_set_state(parser, GUMBO_LEX_PLAINTEXT);
2949
- return result;
2998
+ return;
2950
2999
  }
2951
3000
  if (tag_is(token, kStartTag, GUMBO_TAG_BUTTON)) {
2952
- bool success = true;
2953
3001
  if (has_an_element_in_scope(parser, GUMBO_TAG_BUTTON)) {
2954
3002
  parser_add_parse_error(parser, token);
2955
- success = false;
2956
3003
  // We don't want to use implicitly_close_tags here because it may add an
2957
3004
  // error and we've already added the only error the standard specifies.
2958
- generate_implied_end_tags(parser, GUMBO_TAG_LAST);
3005
+ generate_implied_end_tags(parser, GUMBO_TAG_LAST, NULL);
2959
3006
  while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_BUTTON))
2960
3007
  ;
2961
3008
  }
2962
3009
  reconstruct_active_formatting_elements(parser);
2963
3010
  insert_element_from_token(parser, token);
2964
3011
  set_frameset_not_ok(parser);
2965
- return success;
3012
+ return;
2966
3013
  }
2967
3014
  if (
2968
3015
  tag_in(token, kEndTag, &(const TagSet) {
@@ -2977,7 +3024,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2977
3024
  if (!has_an_element_in_scope(parser, tag)) {
2978
3025
  parser_add_parse_error(parser, token);
2979
3026
  ignore_token(parser);
2980
- return false;
3027
+ return;
2981
3028
  }
2982
3029
  return implicitly_close_tags (
2983
3030
  parser,
@@ -2991,19 +3038,15 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
2991
3038
  if (!has_an_element_in_scope(parser, GUMBO_TAG_FORM)) {
2992
3039
  parser_add_parse_error(parser, token);
2993
3040
  ignore_token(parser);
2994
- return false;
3041
+ return;
2995
3042
  }
2996
- bool success = true;
2997
- generate_implied_end_tags(parser, GUMBO_TAG_LAST);
2998
- if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_FORM)) {
3043
+ generate_implied_end_tags(parser, GUMBO_TAG_LAST, NULL);
3044
+ if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_FORM))
2999
3045
  parser_add_parse_error(parser, token);
3000
- success = false;
3001
- }
3002
3046
  while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_FORM))
3003
3047
  ;
3004
- return success;
3048
+ return;
3005
3049
  } else {
3006
- bool result = true;
3007
3050
  GumboNode* node = state->_form_element;
3008
3051
  assert(!node || node->type == GUMBO_NODE_ELEMENT);
3009
3052
  state->_form_element = NULL;
@@ -3011,27 +3054,24 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3011
3054
  gumbo_debug("Closing an unopened form.\n");
3012
3055
  parser_add_parse_error(parser, token);
3013
3056
  ignore_token(parser);
3014
- return false;
3057
+ return;
3015
3058
  }
3016
3059
  // This differs from implicitly_close_tags because we remove *only* the
3017
3060
  // <form> element; other nodes are left in scope.
3018
- generate_implied_end_tags(parser, GUMBO_TAG_LAST);
3019
- if (get_current_node(parser) != node) {
3061
+ generate_implied_end_tags(parser, GUMBO_TAG_LAST, NULL);
3062
+ if (get_current_node(parser) != node)
3020
3063
  parser_add_parse_error(parser, token);
3021
- result = false;
3022
- } else {
3064
+ else
3023
3065
  record_end_of_element(token, &node->v.element);
3024
- }
3025
3066
 
3026
3067
  GumboVector* open_elements = &state->_open_elements;
3027
3068
  int index = gumbo_vector_index_of(open_elements, node);
3028
3069
  assert(index >= 0);
3029
3070
  gumbo_vector_remove_at(index, open_elements);
3030
- return result;
3071
+ return;
3031
3072
  }
3032
3073
  }
3033
3074
  if (tag_is(token, kEndTag, GUMBO_TAG_P)) {
3034
- bool success = true;
3035
3075
  if (!has_an_element_in_button_scope(parser, GUMBO_TAG_P)) {
3036
3076
  parser_add_parse_error(parser, token);
3037
3077
  // reconstruct_active_formatting_elements(parser);
@@ -3040,41 +3080,43 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3040
3080
  GUMBO_TAG_P,
3041
3081
  GUMBO_INSERTION_CONVERTED_FROM_END_TAG
3042
3082
  );
3043
- success = false;
3044
3083
  }
3045
- return implicitly_close_tags (
3084
+ implicitly_close_tags (
3046
3085
  parser,
3047
3086
  token,
3048
3087
  GUMBO_NAMESPACE_HTML,
3049
3088
  GUMBO_TAG_P
3050
- ) && success;
3089
+ );
3090
+ return;
3051
3091
  }
3052
3092
  if (tag_is(token, kEndTag, GUMBO_TAG_LI)) {
3053
3093
  if (!has_an_element_in_list_scope(parser, GUMBO_TAG_LI)) {
3054
3094
  parser_add_parse_error(parser, token);
3055
3095
  ignore_token(parser);
3056
- return false;
3096
+ return;
3057
3097
  }
3058
- return implicitly_close_tags (
3098
+ implicitly_close_tags (
3059
3099
  parser,
3060
3100
  token,
3061
3101
  GUMBO_NAMESPACE_HTML,
3062
3102
  GUMBO_TAG_LI
3063
3103
  );
3104
+ return;
3064
3105
  }
3065
3106
  if (tag_in(token, kEndTag, &dd_dt_tags)) {
3066
3107
  GumboTag token_tag = token->v.end_tag.tag;
3067
3108
  if (!has_an_element_in_scope(parser, token_tag)) {
3068
3109
  parser_add_parse_error(parser, token);
3069
3110
  ignore_token(parser);
3070
- return false;
3111
+ return;
3071
3112
  }
3072
- return implicitly_close_tags (
3113
+ implicitly_close_tags (
3073
3114
  parser,
3074
3115
  token,
3075
3116
  GUMBO_NAMESPACE_HTML,
3076
3117
  token_tag
3077
3118
  );
3119
+ return;
3078
3120
  }
3079
3121
  if (tag_in(token, kEndTag, &heading_tags)) {
3080
3122
  if (
@@ -3086,12 +3128,11 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3086
3128
  // No heading open; ignore the token entirely.
3087
3129
  parser_add_parse_error(parser, token);
3088
3130
  ignore_token(parser);
3089
- return false;
3131
+ return;
3090
3132
  }
3091
- generate_implied_end_tags(parser, GUMBO_TAG_LAST);
3133
+ generate_implied_end_tags(parser, GUMBO_TAG_LAST, NULL);
3092
3134
  const GumboNode* current_node = get_current_node(parser);
3093
- bool success = node_html_tag_is(current_node, token->v.end_tag.tag);
3094
- if (!success) {
3135
+ if (!node_html_tag_is(current_node, token->v.end_tag.tag)) {
3095
3136
  // There're children of the heading currently open; close them below and
3096
3137
  // record a parse error.
3097
3138
  // TODO(jdtang): Add a way to distinguish this error case from the one
@@ -3101,17 +3142,15 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3101
3142
  do {
3102
3143
  current_node = pop_current_node(parser);
3103
3144
  } while (!node_tag_in_set(current_node, &heading_tags));
3104
- return success;
3145
+ return;
3105
3146
  }
3106
3147
  if (tag_is(token, kStartTag, GUMBO_TAG_A)) {
3107
- bool success = true;
3108
3148
  int last_a;
3109
3149
  int has_matching_a = find_last_anchor_index(parser, &last_a);
3110
3150
  if (has_matching_a) {
3111
3151
  assert(has_matching_a == 1);
3112
3152
  parser_add_parse_error(parser, token);
3113
- bool handled = adoption_agency_algorithm(parser, token, GUMBO_TAG_A);
3114
- assert(handled);
3153
+ (void)adoption_agency_algorithm(parser, token);
3115
3154
  // The adoption agency algorithm usually removes all instances of <a>
3116
3155
  // from the list of active formatting elements, but in case it doesn't,
3117
3156
  // we're supposed to do this. (The conditions where it might not are
@@ -3123,11 +3162,10 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3123
3162
  );
3124
3163
  gumbo_vector_remove(last_element, &state->_open_elements);
3125
3164
  }
3126
- success = false;
3127
3165
  }
3128
3166
  reconstruct_active_formatting_elements(parser);
3129
3167
  add_formatting_element(parser, insert_element_from_token(parser, token));
3130
- return success;
3168
+ return;
3131
3169
  }
3132
3170
  if (
3133
3171
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3137,21 +3175,18 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3137
3175
  ) {
3138
3176
  reconstruct_active_formatting_elements(parser);
3139
3177
  add_formatting_element(parser, insert_element_from_token(parser, token));
3140
- return true;
3178
+ return;
3141
3179
  }
3142
3180
  if (tag_is(token, kStartTag, GUMBO_TAG_NOBR)) {
3143
- bool result = true;
3144
3181
  reconstruct_active_formatting_elements(parser);
3145
3182
  if (has_an_element_in_scope(parser, GUMBO_TAG_NOBR)) {
3146
- result = false;
3147
3183
  parser_add_parse_error(parser, token);
3148
- bool handled = adoption_agency_algorithm(parser, token, GUMBO_TAG_NOBR);
3149
- assert(handled);
3184
+ adoption_agency_algorithm(parser, token);
3150
3185
  reconstruct_active_formatting_elements(parser);
3151
3186
  }
3152
3187
  insert_element_from_token(parser, token);
3153
3188
  add_formatting_element(parser, get_current_node(parser));
3154
- return result;
3189
+ return;
3155
3190
  }
3156
3191
  if (
3157
3192
  tag_in(token, kEndTag, &(const TagSet) {
@@ -3160,9 +3195,8 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3160
3195
  TAG(U)
3161
3196
  })
3162
3197
  ) {
3163
- if (!adoption_agency_algorithm(parser, token, token->v.end_tag.tag))
3164
- goto any_other_end_tag;
3165
- return true;
3198
+ adoption_agency_algorithm(parser, token);
3199
+ return;
3166
3200
  }
3167
3201
  if (
3168
3202
  tag_in(token, kStartTag, &(const TagSet){TAG(APPLET), TAG(MARQUEE), TAG(OBJECT)})
@@ -3171,7 +3205,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3171
3205
  insert_element_from_token(parser, token);
3172
3206
  add_formatting_element(parser, &kActiveFormattingScopeMarker);
3173
3207
  set_frameset_not_ok(parser);
3174
- return true;
3208
+ return;
3175
3209
  }
3176
3210
  if (
3177
3211
  tag_in(token, kEndTag, &(const TagSet){TAG(APPLET), TAG(MARQUEE), TAG(OBJECT)})
@@ -3180,11 +3214,11 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3180
3214
  if (!has_an_element_in_scope(parser, token_tag)) {
3181
3215
  parser_add_parse_error(parser, token);
3182
3216
  ignore_token(parser);
3183
- return false;
3217
+ return;
3184
3218
  }
3185
- bool success = implicitly_close_tags(parser, token, GUMBO_NAMESPACE_HTML, token_tag);
3219
+ implicitly_close_tags(parser, token, GUMBO_NAMESPACE_HTML, token_tag);
3186
3220
  clear_active_formatting_elements(parser);
3187
- return success;
3221
+ return;
3188
3222
  }
3189
3223
  if (tag_is(token, kStartTag, GUMBO_TAG_TABLE)) {
3190
3224
  if (
@@ -3196,7 +3230,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3196
3230
  insert_element_from_token(parser, token);
3197
3231
  set_frameset_not_ok(parser);
3198
3232
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
3199
- return true;
3233
+ return;
3200
3234
  }
3201
3235
  if (tag_is(token, kEndTag, GUMBO_TAG_BR)) {
3202
3236
  parser_add_parse_error(parser, token);
@@ -3209,7 +3243,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3209
3243
  pop_current_node(parser);
3210
3244
  acknowledge_self_closing_tag(parser);
3211
3245
  set_frameset_not_ok(parser);
3212
- return false;
3246
+ return;
3213
3247
  }
3214
3248
  if (
3215
3249
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3229,7 +3263,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3229
3263
  pop_current_node(parser);
3230
3264
  acknowledge_self_closing_tag(parser);
3231
3265
  set_frameset_not_ok(parser);
3232
- return !is_image;
3266
+ return;
3233
3267
  }
3234
3268
  if (tag_is(token, kStartTag, GUMBO_TAG_INPUT)) {
3235
3269
  reconstruct_active_formatting_elements(parser);
@@ -3238,7 +3272,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3238
3272
  acknowledge_self_closing_tag(parser);
3239
3273
  if (!attribute_matches(&input->v.element.attributes, "type", "hidden"))
3240
3274
  set_frameset_not_ok(parser);
3241
- return true;
3275
+ return;
3242
3276
  }
3243
3277
  if (
3244
3278
  tag_in(token, kStartTag, &(const TagSet){TAG(PARAM), TAG(SOURCE), TAG(TRACK)})
@@ -3246,37 +3280,37 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3246
3280
  insert_element_from_token(parser, token);
3247
3281
  pop_current_node(parser);
3248
3282
  acknowledge_self_closing_tag(parser);
3249
- return true;
3283
+ return;
3250
3284
  }
3251
3285
  if (tag_is(token, kStartTag, GUMBO_TAG_HR)) {
3252
- bool result = maybe_implicitly_close_p_tag(parser, token);
3286
+ maybe_implicitly_close_p_tag(parser, token);
3253
3287
  insert_element_from_token(parser, token);
3254
3288
  pop_current_node(parser);
3255
3289
  acknowledge_self_closing_tag(parser);
3256
3290
  set_frameset_not_ok(parser);
3257
- return result;
3291
+ return;
3258
3292
  }
3259
3293
  if (tag_is(token, kStartTag, GUMBO_TAG_TEXTAREA)) {
3260
3294
  run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RCDATA);
3261
3295
  parser->_parser_state->_ignore_next_linefeed = true;
3262
3296
  set_frameset_not_ok(parser);
3263
- return true;
3297
+ return;
3264
3298
  }
3265
3299
  if (tag_is(token, kStartTag, GUMBO_TAG_XMP)) {
3266
- bool result = maybe_implicitly_close_p_tag(parser, token);
3300
+ maybe_implicitly_close_p_tag(parser, token);
3267
3301
  reconstruct_active_formatting_elements(parser);
3268
3302
  set_frameset_not_ok(parser);
3269
3303
  run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT);
3270
- return result;
3304
+ return;
3271
3305
  }
3272
3306
  if (tag_is(token, kStartTag, GUMBO_TAG_IFRAME)) {
3273
3307
  set_frameset_not_ok(parser);
3274
3308
  run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT);
3275
- return true;
3309
+ return;
3276
3310
  }
3277
3311
  if (tag_is(token, kStartTag, GUMBO_TAG_NOEMBED)) {
3278
3312
  run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT);
3279
- return true;
3313
+ return;
3280
3314
  }
3281
3315
  if (tag_is(token, kStartTag, GUMBO_TAG_SELECT)) {
3282
3316
  reconstruct_active_formatting_elements(parser);
@@ -3294,7 +3328,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3294
3328
  } else {
3295
3329
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_SELECT);
3296
3330
  }
3297
- return true;
3331
+ return;
3298
3332
  }
3299
3333
  if (
3300
3334
  tag_in(token, kStartTag, &(const TagSet){TAG(OPTGROUP), TAG(OPTION)})
@@ -3304,33 +3338,28 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3304
3338
  }
3305
3339
  reconstruct_active_formatting_elements(parser);
3306
3340
  insert_element_from_token(parser, token);
3307
- return true;
3341
+ return;
3308
3342
  }
3309
3343
  if (tag_in(token, kStartTag, &(const TagSet){TAG(RB), TAG(RTC)})) {
3310
- bool success = true;
3311
3344
  if (has_an_element_in_scope(parser, GUMBO_TAG_RUBY)) {
3312
- generate_implied_end_tags(parser, GUMBO_TAG_LAST);
3313
- if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_RUBY)) {
3345
+ generate_implied_end_tags(parser, GUMBO_TAG_LAST, NULL);
3346
+ if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_RUBY))
3314
3347
  parser_add_parse_error(parser, token);
3315
- success = false;
3316
- }
3317
3348
  }
3318
3349
  insert_element_from_token(parser, token);
3319
- return success;
3350
+ return;
3320
3351
  }
3321
3352
  if (tag_in(token, kStartTag, &(const TagSet){TAG(RP), TAG(RT)})) {
3322
- bool success = true;
3323
3353
  if (has_an_element_in_scope(parser, GUMBO_TAG_RUBY)) {
3324
- generate_implied_end_tags(parser, GUMBO_TAG_RTC);
3354
+ generate_implied_end_tags(parser, GUMBO_TAG_RTC, NULL);
3325
3355
  GumboNode* current = get_current_node(parser);
3326
3356
  if (!node_html_tag_is(current, GUMBO_TAG_RUBY) &&
3327
3357
  !node_html_tag_is(current, GUMBO_TAG_RTC)) {
3328
3358
  parser_add_parse_error(parser, token);
3329
- success = false;
3330
3359
  }
3331
3360
  }
3332
3361
  insert_element_from_token(parser, token);
3333
- return success;
3362
+ return;
3334
3363
  }
3335
3364
  if (tag_is(token, kStartTag, GUMBO_TAG_MATH)) {
3336
3365
  reconstruct_active_formatting_elements(parser);
@@ -3341,7 +3370,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3341
3370
  pop_current_node(parser);
3342
3371
  acknowledge_self_closing_tag(parser);
3343
3372
  }
3344
- return true;
3373
+ return;
3345
3374
  }
3346
3375
  if (tag_is(token, kStartTag, GUMBO_TAG_SVG)) {
3347
3376
  reconstruct_active_formatting_elements(parser);
@@ -3352,7 +3381,7 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3352
3381
  pop_current_node(parser);
3353
3382
  acknowledge_self_closing_tag(parser);
3354
3383
  }
3355
- return true;
3384
+ return;
3356
3385
  }
3357
3386
  if (
3358
3387
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3362,60 +3391,24 @@ static bool handle_in_body(GumboParser* parser, GumboToken* token) {
3362
3391
  ) {
3363
3392
  parser_add_parse_error(parser, token);
3364
3393
  ignore_token(parser);
3365
- return false;
3394
+ return;
3366
3395
  }
3367
3396
  if (token->type == GUMBO_TOKEN_START_TAG) {
3368
3397
  reconstruct_active_formatting_elements(parser);
3369
3398
  insert_element_from_token(parser, token);
3370
- return true;
3371
- }
3372
- any_other_end_tag:
3373
- assert(token->type == GUMBO_TOKEN_END_TAG);
3374
- GumboTag end_tag = token->v.end_tag.tag;
3375
- const char *end_tagname = token->v.end_tag.name;
3376
- assert(state->_open_elements.length > 0);
3377
- assert(node_html_tag_is(state->_open_elements.data[0], GUMBO_TAG_HTML));
3378
- // Walk up the stack of open elements until we find one that either:
3379
- // a) Matches the tag name we saw
3380
- // b) Is in the "special" category.
3381
- // If we see a), implicitly close everything up to and including it. If we
3382
- // see b), then record a parse error, don't close anything (except the
3383
- // implied end tags) and ignore the end tag token.
3384
- for (int i = state->_open_elements.length; --i >= 0;) {
3385
- const GumboNode* node = state->_open_elements.data[i];
3386
- if (node_qualified_tagname_is(node, GUMBO_NAMESPACE_HTML, end_tag, end_tagname)) {
3387
- generate_implied_end_tags(parser, end_tag);
3388
- // TODO(jdtang): Do I need to add a parse error here? The condition in
3389
- // the spec seems like it's the inverse of the loop condition above, and
3390
- // so would never fire.
3391
- // sfc: Yes, an error is needed here.
3392
- // <!DOCTYPE><body><sarcasm><foo></sarcasm> is an example.
3393
- // foo is the "current node" but sarcasm is node.
3394
- // XXX: Write a test for this.
3395
- if (node != get_current_node(parser))
3396
- parser_add_parse_error(parser, token);
3397
- while (node != pop_current_node(parser))
3398
- ; // Pop everything.
3399
- return true;
3400
- } else if (is_special_node(node)) {
3401
- parser_add_parse_error(parser, token);
3402
- ignore_token(parser);
3403
- return false;
3404
- }
3399
+ return;
3405
3400
  }
3406
- // <html> is in the special category, so we should never get here.
3407
- assert(0);
3408
- return false;
3401
+ in_body_any_other_end_tag(parser, token);
3409
3402
  }
3410
3403
 
3411
3404
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-incdata
3412
- static bool handle_text(GumboParser* parser, GumboToken* token) {
3405
+ static void handle_text(GumboParser* parser, GumboToken* token) {
3413
3406
  if (
3414
3407
  token->type == GUMBO_TOKEN_CHARACTER
3415
3408
  || token->type == GUMBO_TOKEN_WHITESPACE
3416
3409
  ) {
3417
3410
  insert_text_token(parser, token);
3418
- return true;
3411
+ return;
3419
3412
  }
3420
3413
  // We provide only bare-bones script handling that doesn't involve any of
3421
3414
  // the parser-pause/already-started/script-nesting flags or re-entrant
@@ -3424,19 +3417,16 @@ static bool handle_text(GumboParser* parser, GumboToken* token) {
3424
3417
  // provide the script body as a text-node child of the <script> element.
3425
3418
  // This behavior doesn't support document.write of partial HTML elements,
3426
3419
  // but should be adequate for almost all other scripting support.
3427
- bool success = true;
3428
3420
  if (token->type == GUMBO_TOKEN_EOF) {
3429
3421
  parser_add_parse_error(parser, token);
3430
- success = false;
3431
3422
  parser->_parser_state->_reprocess_current_token = true;
3432
3423
  }
3433
3424
  pop_current_node(parser);
3434
3425
  set_insertion_mode(parser, parser->_parser_state->_original_insertion_mode);
3435
- return success;
3436
3426
  }
3437
3427
 
3438
3428
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intable
3439
- static bool handle_in_table(GumboParser* parser, GumboToken* token) {
3429
+ static void handle_in_table(GumboParser* parser, GumboToken* token) {
3440
3430
  GumboParserState* state = parser->_parser_state;
3441
3431
  if (
3442
3432
  (token->type == GUMBO_TOKEN_CHARACTER
@@ -3456,29 +3446,29 @@ static bool handle_in_table(GumboParser* parser, GumboToken* token) {
3456
3446
  state->_original_insertion_mode = state->_insertion_mode;
3457
3447
  state->_reprocess_current_token = true;
3458
3448
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_TEXT);
3459
- return true;
3449
+ return;
3460
3450
  }
3461
3451
  if (token->type == GUMBO_TOKEN_COMMENT) {
3462
3452
  append_comment_node(parser, get_current_node(parser), token);
3463
- return true;
3453
+ return;
3464
3454
  }
3465
3455
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
3466
3456
  parser_add_parse_error(parser, token);
3467
3457
  ignore_token(parser);
3468
- return false;
3458
+ return;
3469
3459
  }
3470
3460
  if (tag_is(token, kStartTag, GUMBO_TAG_CAPTION)) {
3471
3461
  clear_stack_to_table_context(parser);
3472
3462
  add_formatting_element(parser, &kActiveFormattingScopeMarker);
3473
3463
  insert_element_from_token(parser, token);
3474
3464
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_CAPTION);
3475
- return true;
3465
+ return;
3476
3466
  }
3477
3467
  if (tag_is(token, kStartTag, GUMBO_TAG_COLGROUP)) {
3478
3468
  clear_stack_to_table_context(parser);
3479
3469
  insert_element_from_token(parser, token);
3480
3470
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP);
3481
- return true;
3471
+ return;
3482
3472
  }
3483
3473
  if (tag_is(token, kStartTag, GUMBO_TAG_COL)) {
3484
3474
  clear_stack_to_table_context(parser);
@@ -3489,7 +3479,7 @@ static bool handle_in_table(GumboParser* parser, GumboToken* token) {
3489
3479
  );
3490
3480
  state->_reprocess_current_token = true;
3491
3481
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP);
3492
- return true;
3482
+ return;
3493
3483
  }
3494
3484
  if (
3495
3485
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3499,7 +3489,7 @@ static bool handle_in_table(GumboParser* parser, GumboToken* token) {
3499
3489
  clear_stack_to_table_context(parser);
3500
3490
  insert_element_from_token(parser, token);
3501
3491
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);
3502
- return true;
3492
+ return;
3503
3493
  }
3504
3494
  if (
3505
3495
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3514,7 +3504,7 @@ static bool handle_in_table(GumboParser* parser, GumboToken* token) {
3514
3504
  );
3515
3505
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);
3516
3506
  state->_reprocess_current_token = true;
3517
- return true;
3507
+ return;
3518
3508
  }
3519
3509
  if (tag_is(token, kStartTag, GUMBO_TAG_TABLE)) {
3520
3510
  parser_add_parse_error(parser, token);
@@ -3523,14 +3513,14 @@ static bool handle_in_table(GumboParser* parser, GumboToken* token) {
3523
3513
  } else {
3524
3514
  ignore_token(parser);
3525
3515
  }
3526
- return false;
3516
+ return;
3527
3517
  }
3528
3518
  if (tag_is(token, kEndTag, GUMBO_TAG_TABLE)) {
3529
3519
  if (!close_table(parser)) {
3530
3520
  parser_add_parse_error(parser, token);
3531
- return false;
3521
+ return;
3532
3522
  }
3533
- return true;
3523
+ return;
3534
3524
  }
3535
3525
  if (
3536
3526
  tag_in(token, kEndTag, &(const TagSet) {
@@ -3540,13 +3530,14 @@ static bool handle_in_table(GumboParser* parser, GumboToken* token) {
3540
3530
  ) {
3541
3531
  parser_add_parse_error(parser, token);
3542
3532
  ignore_token(parser);
3543
- return false;
3533
+ return;
3544
3534
  }
3545
3535
  if (
3546
3536
  tag_in(token, kStartTag, &(const TagSet){TAG(STYLE), TAG(SCRIPT), TAG(TEMPLATE)})
3547
3537
  || (tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE))
3548
3538
  ) {
3549
- return handle_in_head(parser, token);
3539
+ handle_in_head(parser, token);
3540
+ return;
3550
3541
  }
3551
3542
  if (
3552
3543
  tag_is(token, kStartTag, GUMBO_TAG_INPUT)
@@ -3556,35 +3547,35 @@ static bool handle_in_table(GumboParser* parser, GumboToken* token) {
3556
3547
  insert_element_from_token(parser, token);
3557
3548
  pop_current_node(parser);
3558
3549
  acknowledge_self_closing_tag(parser);
3559
- return false;
3550
+ return;
3560
3551
  }
3561
3552
  if (tag_is(token, kStartTag, GUMBO_TAG_FORM)) {
3562
3553
  parser_add_parse_error(parser, token);
3563
3554
  if (state->_form_element || has_open_element(parser, GUMBO_TAG_TEMPLATE)) {
3564
3555
  ignore_token(parser);
3565
- return false;
3556
+ return;
3566
3557
  }
3567
3558
  state->_form_element = insert_element_from_token(parser, token);
3568
3559
  pop_current_node(parser);
3569
- return false;
3560
+ return;
3570
3561
  }
3571
3562
  if (token->type == GUMBO_TOKEN_EOF) {
3572
- return handle_in_body(parser, token);
3563
+ handle_in_body(parser, token);
3564
+ return;
3573
3565
  }
3574
3566
  // foster-parenting-start-tag or foster-parenting-end-tag error
3575
3567
  parser_add_parse_error(parser, token);
3576
3568
  state->_foster_parent_insertions = true;
3577
- bool result = handle_in_body(parser, token);
3569
+ handle_in_body(parser, token);
3578
3570
  state->_foster_parent_insertions = false;
3579
- return result;
3580
3571
  }
3581
3572
 
3582
3573
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intabletext
3583
- static bool handle_in_table_text(GumboParser* parser, GumboToken* token) {
3574
+ static void handle_in_table_text(GumboParser* parser, GumboToken* token) {
3584
3575
  if (token->type == GUMBO_TOKEN_NULL) {
3585
3576
  parser_add_parse_error(parser, token);
3586
3577
  ignore_token(parser);
3587
- return false;
3578
+ return;
3588
3579
  }
3589
3580
  GumboParserState* state = parser->_parser_state;
3590
3581
  // Non-whitespace tokens will cause parse errors later.
@@ -3594,7 +3585,7 @@ static bool handle_in_table_text(GumboParser* parser, GumboToken* token) {
3594
3585
  || token->type == GUMBO_TOKEN_CHARACTER) {
3595
3586
  insert_text_token(parser, token);
3596
3587
  gumbo_character_token_buffer_append(token, &state->_table_character_tokens);
3597
- return true;
3588
+ return;
3598
3589
  }
3599
3590
 
3600
3591
  GumboCharacterTokenBuffer* buffer = &state->_table_character_tokens;
@@ -3616,26 +3607,24 @@ static bool handle_in_table_text(GumboParser* parser, GumboToken* token) {
3616
3607
  state->_foster_parent_insertions = false;
3617
3608
  state->_reprocess_current_token = true;
3618
3609
  state->_insertion_mode = state->_original_insertion_mode;
3619
- return true;
3620
3610
  }
3621
3611
 
3622
3612
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-incaption
3623
- static bool handle_in_caption(GumboParser* parser, GumboToken* token) {
3613
+ static void handle_in_caption(GumboParser* parser, GumboToken* token) {
3624
3614
  if (tag_is(token, kEndTag, GUMBO_TAG_CAPTION)) {
3625
3615
  if (!has_an_element_in_table_scope(parser, GUMBO_TAG_CAPTION)) {
3626
3616
  parser_add_parse_error(parser, token);
3627
3617
  ignore_token(parser);
3628
- return false;
3618
+ return;
3629
3619
  }
3630
- generate_implied_end_tags(parser, GUMBO_TAG_LAST);
3631
- bool result = node_html_tag_is(get_current_node(parser), GUMBO_TAG_CAPTION);
3632
- if (!result)
3620
+ generate_implied_end_tags(parser, GUMBO_TAG_LAST, NULL);
3621
+ if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_CAPTION))
3633
3622
  parser_add_parse_error(parser, token);
3634
3623
  while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_CAPTION))
3635
3624
  ;
3636
3625
  clear_active_formatting_elements(parser);
3637
3626
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
3638
- return result;
3627
+ return;
3639
3628
  }
3640
3629
  if (
3641
3630
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3647,18 +3636,17 @@ static bool handle_in_caption(GumboParser* parser, GumboToken* token) {
3647
3636
  if (!has_an_element_in_table_scope(parser, GUMBO_TAG_CAPTION)) {
3648
3637
  parser_add_parse_error(parser, token);
3649
3638
  ignore_token(parser);
3650
- return false;
3639
+ return;
3651
3640
  }
3652
- generate_implied_end_tags(parser, GUMBO_TAG_LAST);
3653
- bool result = node_html_tag_is(get_current_node(parser), GUMBO_TAG_CAPTION);
3654
- if (!result)
3641
+ generate_implied_end_tags(parser, GUMBO_TAG_LAST, NULL);
3642
+ if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_CAPTION))
3655
3643
  parser_add_parse_error(parser, token);
3656
3644
  while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_CAPTION))
3657
3645
  ;
3658
3646
  clear_active_formatting_elements(parser);
3659
3647
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
3660
3648
  parser->_parser_state->_reprocess_current_token = true;
3661
- return result;
3649
+ return;
3662
3650
  }
3663
3651
  if (
3664
3652
  tag_in(token, kEndTag, &(const TagSet) {
@@ -3668,77 +3656,79 @@ static bool handle_in_caption(GumboParser* parser, GumboToken* token) {
3668
3656
  ) {
3669
3657
  parser_add_parse_error(parser, token);
3670
3658
  ignore_token(parser);
3671
- return false;
3659
+ return;
3672
3660
  }
3673
- return handle_in_body(parser, token);
3661
+ handle_in_body(parser, token);
3674
3662
  }
3675
3663
 
3676
3664
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-incolgroup
3677
- static bool handle_in_column_group(GumboParser* parser, GumboToken* token) {
3665
+ static void handle_in_column_group(GumboParser* parser, GumboToken* token) {
3678
3666
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
3679
3667
  insert_text_token(parser, token);
3680
- return true;
3668
+ return;
3681
3669
  }
3682
3670
  if (token->type == GUMBO_TOKEN_COMMENT) {
3683
3671
  append_comment_node(parser, get_current_node(parser), token);
3684
- return true;
3672
+ return;
3685
3673
  }
3686
3674
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
3687
3675
  parser_add_parse_error(parser, token);
3688
3676
  ignore_token(parser);
3689
- return false;
3677
+ return;
3690
3678
  }
3691
3679
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
3692
- return handle_in_body(parser, token);
3680
+ handle_in_body(parser, token);
3681
+ return;
3693
3682
  }
3694
3683
  if (tag_is(token, kStartTag, GUMBO_TAG_COL)) {
3695
3684
  insert_element_from_token(parser, token);
3696
3685
  pop_current_node(parser);
3697
3686
  acknowledge_self_closing_tag(parser);
3698
- return true;
3687
+ return;
3699
3688
  }
3700
3689
  if (tag_is(token, kEndTag, GUMBO_TAG_COLGROUP)) {
3701
3690
  if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_COLGROUP)) {
3702
3691
  parser_add_parse_error(parser, token);
3703
3692
  ignore_token(parser);
3704
- return false;
3693
+ return;
3705
3694
  }
3706
3695
  pop_current_node(parser);
3707
3696
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
3708
- return false;
3697
+ return;
3709
3698
  }
3710
3699
  if (tag_is(token, kEndTag, GUMBO_TAG_COL)) {
3711
3700
  parser_add_parse_error(parser, token);
3712
3701
  ignore_token(parser);
3713
- return false;
3702
+ return;
3714
3703
  }
3715
3704
  if (
3716
3705
  tag_is(token, kStartTag, GUMBO_TAG_TEMPLATE)
3717
3706
  || tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)
3718
3707
  ) {
3719
- return handle_in_head(parser, token);
3708
+ handle_in_head(parser, token);
3709
+ return;
3720
3710
  }
3721
3711
  if (token->type == GUMBO_TOKEN_EOF) {
3722
- return handle_in_body(parser, token);
3712
+ handle_in_body(parser, token);
3713
+ return;
3723
3714
  }
3724
3715
  if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_COLGROUP)) {
3725
3716
  parser_add_parse_error(parser, token);
3726
3717
  ignore_token(parser);
3727
- return false;
3718
+ return;
3728
3719
  }
3729
3720
  pop_current_node(parser);
3730
3721
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
3731
3722
  parser->_parser_state->_reprocess_current_token = true;
3732
- return true;
3733
3723
  }
3734
3724
 
3735
3725
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intbody
3736
- static bool handle_in_table_body(GumboParser* parser, GumboToken* token) {
3726
+ static void handle_in_table_body(GumboParser* parser, GumboToken* token) {
3737
3727
  if (tag_is(token, kStartTag, GUMBO_TAG_TR)) {
3738
3728
  clear_stack_to_table_body_context(parser);
3739
3729
  insert_element_from_token(parser, token);
3740
3730
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW);
3741
- return true;
3731
+ return;
3742
3732
  }
3743
3733
  if (tag_in(token, kStartTag, &td_th_tags)) {
3744
3734
  parser_add_parse_error(parser, token);
@@ -3746,7 +3736,7 @@ static bool handle_in_table_body(GumboParser* parser, GumboToken* token) {
3746
3736
  insert_element_of_tag_type(parser, GUMBO_TAG_TR, GUMBO_INSERTION_IMPLIED);
3747
3737
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW);
3748
3738
  parser->_parser_state->_reprocess_current_token = true;
3749
- return false;
3739
+ return;
3750
3740
  }
3751
3741
  if (
3752
3742
  tag_in(token, kEndTag, &(const TagSet){TAG(TBODY), TAG(TFOOT), TAG(THEAD)})
@@ -3754,12 +3744,12 @@ static bool handle_in_table_body(GumboParser* parser, GumboToken* token) {
3754
3744
  if (!has_an_element_in_table_scope(parser, token->v.end_tag.tag)) {
3755
3745
  parser_add_parse_error(parser, token);
3756
3746
  ignore_token(parser);
3757
- return false;
3747
+ return;
3758
3748
  }
3759
3749
  clear_stack_to_table_body_context(parser);
3760
3750
  pop_current_node(parser);
3761
3751
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
3762
- return true;
3752
+ return;
3763
3753
  }
3764
3754
  if (
3765
3755
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3777,13 +3767,13 @@ static bool handle_in_table_body(GumboParser* parser, GumboToken* token) {
3777
3767
  ) {
3778
3768
  parser_add_parse_error(parser, token);
3779
3769
  ignore_token(parser);
3780
- return false;
3770
+ return;
3781
3771
  }
3782
3772
  clear_stack_to_table_body_context(parser);
3783
3773
  pop_current_node(parser);
3784
3774
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
3785
3775
  parser->_parser_state->_reprocess_current_token = true;
3786
- return true;
3776
+ return;
3787
3777
  }
3788
3778
  if (
3789
3779
  tag_in(token, kEndTag, &(const TagSet) {
@@ -3793,30 +3783,30 @@ static bool handle_in_table_body(GumboParser* parser, GumboToken* token) {
3793
3783
  ) {
3794
3784
  parser_add_parse_error(parser, token);
3795
3785
  ignore_token(parser);
3796
- return false;
3786
+ return;
3797
3787
  }
3798
- return handle_in_table(parser, token);
3788
+ handle_in_table(parser, token);
3799
3789
  }
3800
3790
 
3801
3791
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intr
3802
- static bool handle_in_row(GumboParser* parser, GumboToken* token) {
3792
+ static void handle_in_row(GumboParser* parser, GumboToken* token) {
3803
3793
  if (tag_in(token, kStartTag, &td_th_tags)) {
3804
3794
  clear_stack_to_table_row_context(parser);
3805
3795
  insert_element_from_token(parser, token);
3806
3796
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_CELL);
3807
3797
  add_formatting_element(parser, &kActiveFormattingScopeMarker);
3808
- return true;
3798
+ return;
3809
3799
  }
3810
3800
  if (tag_is(token, kEndTag, GUMBO_TAG_TR)) {
3811
3801
  if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TR)) {
3812
3802
  parser_add_parse_error(parser, token);
3813
3803
  ignore_token(parser);
3814
- return false;
3804
+ return;
3815
3805
  }
3816
3806
  clear_stack_to_table_row_context(parser);
3817
3807
  pop_current_node(parser);
3818
3808
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);
3819
- return true;
3809
+ return;
3820
3810
  }
3821
3811
  if (
3822
3812
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3828,13 +3818,13 @@ static bool handle_in_row(GumboParser* parser, GumboToken* token) {
3828
3818
  if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TR)) {
3829
3819
  parser_add_parse_error(parser, token);
3830
3820
  ignore_token(parser);
3831
- return false;
3821
+ return;
3832
3822
  }
3833
3823
  clear_stack_to_table_row_context(parser);
3834
3824
  pop_current_node(parser);
3835
3825
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);
3836
3826
  parser->_parser_state->_reprocess_current_token = true;
3837
- return true;
3827
+ return;
3838
3828
  }
3839
3829
  if (
3840
3830
  tag_in(token, kEndTag, &(const TagSet) {TAG(TBODY), TAG(TFOOT), TAG(THEAD)})
@@ -3842,17 +3832,17 @@ static bool handle_in_row(GumboParser* parser, GumboToken* token) {
3842
3832
  if (!has_an_element_in_table_scope(parser, token->v.end_tag.tag)) {
3843
3833
  parser_add_parse_error(parser, token);
3844
3834
  ignore_token(parser);
3845
- return false;
3835
+ return;
3846
3836
  }
3847
3837
  if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TR)) {
3848
3838
  ignore_token(parser);
3849
- return true;
3839
+ return;
3850
3840
  }
3851
3841
  clear_stack_to_table_row_context(parser);
3852
3842
  pop_current_node(parser);
3853
3843
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);
3854
3844
  parser->_parser_state->_reprocess_current_token = true;
3855
- return true;
3845
+ return;
3856
3846
  }
3857
3847
  if (
3858
3848
  tag_in(token, kEndTag, &(const TagSet) {
@@ -3862,21 +3852,22 @@ static bool handle_in_row(GumboParser* parser, GumboToken* token) {
3862
3852
  ) {
3863
3853
  parser_add_parse_error(parser, token);
3864
3854
  ignore_token(parser);
3865
- return false;
3855
+ return;
3866
3856
  }
3867
- return handle_in_table(parser, token);
3857
+ handle_in_table(parser, token);
3868
3858
  }
3869
3859
 
3870
3860
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intd
3871
- static bool handle_in_cell(GumboParser* parser, GumboToken* token) {
3861
+ static void handle_in_cell(GumboParser* parser, GumboToken* token) {
3872
3862
  if (tag_in(token, kEndTag, &td_th_tags)) {
3873
3863
  GumboTag token_tag = token->v.end_tag.tag;
3874
3864
  if (!has_an_element_in_table_scope(parser, token_tag)) {
3875
3865
  parser_add_parse_error(parser, token);
3876
3866
  ignore_token(parser);
3877
- return false;
3867
+ return;
3878
3868
  }
3879
- return close_table_cell(parser, token, token_tag);
3869
+ close_table_cell(parser, token, token_tag);
3870
+ return;
3880
3871
  }
3881
3872
  if (
3882
3873
  tag_in(token, kStartTag, &(const TagSet) {
@@ -3892,10 +3883,11 @@ static bool handle_in_cell(GumboParser* parser, GumboToken* token) {
3892
3883
  gumbo_debug("Bailing out because there's no <td> or <th> in scope.\n");
3893
3884
  parser_add_parse_error(parser, token);
3894
3885
  ignore_token(parser);
3895
- return false;
3886
+ return;
3896
3887
  }
3897
3888
  parser->_parser_state->_reprocess_current_token = true;
3898
- return close_current_cell(parser, token);
3889
+ close_current_cell(parser, token);
3890
+ return;
3899
3891
  }
3900
3892
  if (
3901
3893
  tag_in(token, kEndTag, &(const TagSet) {
@@ -3904,7 +3896,7 @@ static bool handle_in_cell(GumboParser* parser, GumboToken* token) {
3904
3896
  ) {
3905
3897
  parser_add_parse_error(parser, token);
3906
3898
  ignore_token(parser);
3907
- return false;
3899
+ return;
3908
3900
  }
3909
3901
  if (
3910
3902
  tag_in(token, kEndTag, &(const TagSet) {
@@ -3914,46 +3906,48 @@ static bool handle_in_cell(GumboParser* parser, GumboToken* token) {
3914
3906
  if (!has_an_element_in_table_scope(parser, token->v.end_tag.tag)) {
3915
3907
  parser_add_parse_error(parser, token);
3916
3908
  ignore_token(parser);
3917
- return false;
3909
+ return;
3918
3910
  }
3919
3911
  parser->_parser_state->_reprocess_current_token = true;
3920
- return close_current_cell(parser, token);
3912
+ close_current_cell(parser, token);
3913
+ return;
3921
3914
  }
3922
- return handle_in_body(parser, token);
3915
+ handle_in_body(parser, token);
3923
3916
  }
3924
3917
 
3925
3918
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inselect
3926
- static bool handle_in_select(GumboParser* parser, GumboToken* token) {
3919
+ static void handle_in_select(GumboParser* parser, GumboToken* token) {
3927
3920
  if (token->type == GUMBO_TOKEN_NULL) {
3928
3921
  parser_add_parse_error(parser, token);
3929
3922
  ignore_token(parser);
3930
- return false;
3923
+ return;
3931
3924
  }
3932
3925
  if (
3933
3926
  token->type == GUMBO_TOKEN_CHARACTER
3934
3927
  || token->type == GUMBO_TOKEN_WHITESPACE
3935
3928
  ) {
3936
3929
  insert_text_token(parser, token);
3937
- return true;
3930
+ return;
3938
3931
  }
3939
3932
  if (token->type == GUMBO_TOKEN_COMMENT) {
3940
3933
  append_comment_node(parser, get_current_node(parser), token);
3941
- return true;
3934
+ return;
3942
3935
  }
3943
3936
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
3944
3937
  parser_add_parse_error(parser, token);
3945
3938
  ignore_token(parser);
3946
- return false;
3939
+ return;
3947
3940
  }
3948
3941
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
3949
- return handle_in_body(parser, token);
3942
+ handle_in_body(parser, token);
3943
+ return;
3950
3944
  }
3951
3945
  if (tag_is(token, kStartTag, GUMBO_TAG_OPTION)) {
3952
3946
  if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) {
3953
3947
  pop_current_node(parser);
3954
3948
  }
3955
3949
  insert_element_from_token(parser, token);
3956
- return true;
3950
+ return;
3957
3951
  }
3958
3952
  if (tag_is(token, kStartTag, GUMBO_TAG_OPTGROUP)) {
3959
3953
  if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) {
@@ -3963,7 +3957,7 @@ static bool handle_in_select(GumboParser* parser, GumboToken* token) {
3963
3957
  pop_current_node(parser);
3964
3958
  }
3965
3959
  insert_element_from_token(parser, token);
3966
- return true;
3960
+ return;
3967
3961
  }
3968
3962
  if (tag_is(token, kEndTag, GUMBO_TAG_OPTGROUP)) {
3969
3963
  GumboVector* open_elements = &parser->_parser_state->_open_elements;
@@ -3978,29 +3972,29 @@ static bool handle_in_select(GumboParser* parser, GumboToken* token) {
3978
3972
  }
3979
3973
  if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTGROUP)) {
3980
3974
  pop_current_node(parser);
3981
- return true;
3975
+ return;
3982
3976
  }
3983
3977
  parser_add_parse_error(parser, token);
3984
3978
  ignore_token(parser);
3985
- return false;
3979
+ return;
3986
3980
  }
3987
3981
  if (tag_is(token, kEndTag, GUMBO_TAG_OPTION)) {
3988
3982
  if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) {
3989
3983
  pop_current_node(parser);
3990
- return true;
3984
+ return;
3991
3985
  }
3992
3986
  parser_add_parse_error(parser, token);
3993
3987
  ignore_token(parser);
3994
- return false;
3988
+ return;
3995
3989
  }
3996
3990
  if (tag_is(token, kEndTag, GUMBO_TAG_SELECT)) {
3997
3991
  if (!has_an_element_in_select_scope(parser, GUMBO_TAG_SELECT)) {
3998
3992
  parser_add_parse_error(parser, token);
3999
3993
  ignore_token(parser);
4000
- return false;
3994
+ return;
4001
3995
  }
4002
3996
  close_current_select(parser);
4003
- return true;
3997
+ return;
4004
3998
  }
4005
3999
  if (tag_is(token, kStartTag, GUMBO_TAG_SELECT)) {
4006
4000
  parser_add_parse_error(parser, token);
@@ -4008,7 +4002,7 @@ static bool handle_in_select(GumboParser* parser, GumboToken* token) {
4008
4002
  if (has_an_element_in_select_scope(parser, GUMBO_TAG_SELECT)) {
4009
4003
  close_current_select(parser);
4010
4004
  }
4011
- return false;
4005
+ return;
4012
4006
  }
4013
4007
  if (
4014
4008
  tag_in(token, kStartTag, &(const TagSet) {TAG(INPUT), TAG(KEYGEN), TAG(TEXTAREA)})
@@ -4020,23 +4014,25 @@ static bool handle_in_select(GumboParser* parser, GumboToken* token) {
4020
4014
  close_current_select(parser);
4021
4015
  parser->_parser_state->_reprocess_current_token = true;
4022
4016
  }
4023
- return false;
4017
+ return;
4024
4018
  }
4025
4019
  if (
4026
4020
  tag_in(token, kStartTag, &(const TagSet){TAG(SCRIPT), TAG(TEMPLATE)})
4027
4021
  || tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)
4028
4022
  ) {
4029
- return handle_in_head(parser, token);
4023
+ handle_in_head(parser, token);
4024
+ return;
4025
+ }
4026
+ if (token->type == GUMBO_TOKEN_EOF) {
4027
+ handle_in_body(parser, token);
4028
+ return;
4030
4029
  }
4031
- if (token->type == GUMBO_TOKEN_EOF)
4032
- return handle_in_body(parser, token);
4033
4030
  parser_add_parse_error(parser, token);
4034
4031
  ignore_token(parser);
4035
- return false;
4036
4032
  }
4037
4033
 
4038
4034
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inselectintable
4039
- static bool handle_in_select_in_table(GumboParser* parser, GumboToken* token) {
4035
+ static void handle_in_select_in_table(GumboParser* parser, GumboToken* token) {
4040
4036
  static const TagSet tags = {
4041
4037
  TAG(CAPTION), TAG(TABLE), TAG(TBODY), TAG(TFOOT), TAG(THEAD),
4042
4038
  TAG(TR), TAG(TD), TAG(TH)
@@ -4045,23 +4041,23 @@ static bool handle_in_select_in_table(GumboParser* parser, GumboToken* token) {
4045
4041
  parser_add_parse_error(parser, token);
4046
4042
  close_current_select(parser);
4047
4043
  parser->_parser_state->_reprocess_current_token = true;
4048
- return false;
4044
+ return;
4049
4045
  }
4050
4046
  if (tag_in(token, kEndTag, &tags)) {
4051
4047
  parser_add_parse_error(parser, token);
4052
4048
  if (!has_an_element_in_table_scope(parser, token->v.end_tag.tag)) {
4053
4049
  ignore_token(parser);
4054
- return false;
4050
+ return;
4055
4051
  }
4056
4052
  close_current_select(parser);
4057
4053
  parser->_parser_state->_reprocess_current_token = true;
4058
- return false;
4054
+ return;
4059
4055
  }
4060
- return handle_in_select(parser, token);
4056
+ handle_in_select(parser, token);
4061
4057
  }
4062
4058
 
4063
4059
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intemplate
4064
- static bool handle_in_template(GumboParser* parser, GumboToken* token) {
4060
+ static void handle_in_template(GumboParser* parser, GumboToken* token) {
4065
4061
  GumboParserState* state = parser->_parser_state;
4066
4062
  switch (token->type) {
4067
4063
  case GUMBO_TOKEN_WHITESPACE:
@@ -4069,7 +4065,8 @@ static bool handle_in_template(GumboParser* parser, GumboToken* token) {
4069
4065
  case GUMBO_TOKEN_COMMENT:
4070
4066
  case GUMBO_TOKEN_NULL:
4071
4067
  case GUMBO_TOKEN_DOCTYPE:
4072
- return handle_in_body(parser, token);
4068
+ handle_in_body(parser, token);
4069
+ return;
4073
4070
  default:
4074
4071
  break;
4075
4072
  }
@@ -4080,7 +4077,8 @@ static bool handle_in_template(GumboParser* parser, GumboToken* token) {
4080
4077
  })
4081
4078
  || tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)
4082
4079
  ) {
4083
- return handle_in_head(parser, token);
4080
+ handle_in_head(parser, token);
4081
+ return;
4084
4082
  }
4085
4083
  if (
4086
4084
  tag_in(token, kStartTag, &(const TagSet) {
@@ -4091,45 +4089,45 @@ static bool handle_in_template(GumboParser* parser, GumboToken* token) {
4091
4089
  push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
4092
4090
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE);
4093
4091
  state->_reprocess_current_token = true;
4094
- return true;
4092
+ return;
4095
4093
  }
4096
4094
  if (tag_is(token, kStartTag, GUMBO_TAG_COL)) {
4097
4095
  pop_template_insertion_mode(parser);
4098
4096
  push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP);
4099
4097
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP);
4100
4098
  state->_reprocess_current_token = true;
4101
- return true;
4099
+ return;
4102
4100
  }
4103
4101
  if (tag_is(token, kStartTag, GUMBO_TAG_TR)) {
4104
4102
  pop_template_insertion_mode(parser);
4105
4103
  push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);
4106
4104
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY);
4107
4105
  state->_reprocess_current_token = true;
4108
- return true;
4106
+ return;
4109
4107
  }
4110
4108
  if (tag_in(token, kStartTag, &td_th_tags)) {
4111
4109
  pop_template_insertion_mode(parser);
4112
4110
  push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW);
4113
4111
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW);
4114
4112
  state->_reprocess_current_token = true;
4115
- return true;
4113
+ return;
4116
4114
  }
4117
4115
  if (token->type == GUMBO_TOKEN_START_TAG) {
4118
4116
  pop_template_insertion_mode(parser);
4119
4117
  push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);
4120
4118
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);
4121
4119
  state->_reprocess_current_token = true;
4122
- return true;
4120
+ return;
4123
4121
  }
4124
4122
  if (token->type == GUMBO_TOKEN_END_TAG) {
4125
4123
  parser_add_parse_error(parser, token);
4126
4124
  ignore_token(parser);
4127
- return false;
4125
+ return;
4128
4126
  }
4129
4127
  if (token->type == GUMBO_TOKEN_EOF) {
4130
4128
  if (!has_open_element(parser, GUMBO_TAG_TEMPLATE)) {
4131
4129
  // Stop parsing.
4132
- return true;
4130
+ return;
4133
4131
  }
4134
4132
  parser_add_parse_error(parser, token);
4135
4133
  while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_TEMPLATE))
@@ -4138,40 +4136,41 @@ static bool handle_in_template(GumboParser* parser, GumboToken* token) {
4138
4136
  pop_template_insertion_mode(parser);
4139
4137
  reset_insertion_mode_appropriately(parser);
4140
4138
  state->_reprocess_current_token = true;
4141
- return false;
4139
+ return;
4142
4140
  }
4143
4141
  assert(0 && "unreachable");
4144
- return false;
4145
4142
  }
4146
4143
 
4147
4144
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-afterbody
4148
- static bool handle_after_body(GumboParser* parser, GumboToken* token) {
4145
+ static void handle_after_body(GumboParser* parser, GumboToken* token) {
4149
4146
  if (
4150
4147
  token->type == GUMBO_TOKEN_WHITESPACE
4151
4148
  || tag_is(token, kStartTag, GUMBO_TAG_HTML)
4152
4149
  ) {
4153
- return handle_in_body(parser, token);
4150
+ handle_in_body(parser, token);
4151
+ return;
4154
4152
  }
4155
4153
  if (token->type == GUMBO_TOKEN_COMMENT) {
4156
4154
  GumboNode* html_node = parser->_output->root;
4157
4155
  assert(html_node != NULL);
4158
4156
  append_comment_node(parser, html_node, token);
4159
- return true;
4157
+ return;
4160
4158
  }
4161
4159
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
4162
4160
  parser_add_parse_error(parser, token);
4163
4161
  ignore_token(parser);
4164
- return false;
4162
+ return;
4165
4163
  }
4166
4164
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
4167
- return handle_in_body(parser, token);
4165
+ handle_in_body(parser, token);
4166
+ return;
4168
4167
  }
4169
4168
  if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) {
4170
4169
  /* fragment case: ignore the closing HTML token */
4171
4170
  if (is_fragment_parser(parser)) {
4172
4171
  parser_add_parse_error(parser, token);
4173
4172
  ignore_token(parser);
4174
- return false;
4173
+ return;
4175
4174
  }
4176
4175
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_AFTER_BODY);
4177
4176
  GumboNode* html = parser->_parser_state->_open_elements.data[0];
@@ -4180,44 +4179,44 @@ static bool handle_after_body(GumboParser* parser, GumboToken* token) {
4180
4179
  parser->_parser_state->_current_token,
4181
4180
  &html->v.element
4182
4181
  );
4183
- return true;
4182
+ return;
4184
4183
  }
4185
4184
  if (token->type == GUMBO_TOKEN_EOF) {
4186
- return true;
4185
+ return;
4187
4186
  }
4188
4187
  parser_add_parse_error(parser, token);
4189
4188
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);
4190
4189
  parser->_parser_state->_reprocess_current_token = true;
4191
- return false;
4192
4190
  }
4193
4191
 
4194
4192
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inframeset
4195
- static bool handle_in_frameset(GumboParser* parser, GumboToken* token) {
4193
+ static void handle_in_frameset(GumboParser* parser, GumboToken* token) {
4196
4194
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
4197
4195
  insert_text_token(parser, token);
4198
- return true;
4196
+ return;
4199
4197
  }
4200
4198
  if (token->type == GUMBO_TOKEN_COMMENT) {
4201
4199
  append_comment_node(parser, get_current_node(parser), token);
4202
- return true;
4200
+ return;
4203
4201
  }
4204
4202
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
4205
4203
  parser_add_parse_error(parser, token);
4206
4204
  ignore_token(parser);
4207
- return false;
4205
+ return;
4208
4206
  }
4209
4207
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
4210
- return handle_in_body(parser, token);
4208
+ handle_in_body(parser, token);
4209
+ return;
4211
4210
  }
4212
4211
  if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) {
4213
4212
  insert_element_from_token(parser, token);
4214
- return true;
4213
+ return;
4215
4214
  }
4216
4215
  if (tag_is(token, kEndTag, GUMBO_TAG_FRAMESET)) {
4217
4216
  if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_HTML)) {
4218
4217
  parser_add_parse_error(parser, token);
4219
4218
  ignore_token(parser);
4220
- return false;
4219
+ return;
4221
4220
  }
4222
4221
  pop_current_node(parser);
4223
4222
  if (
@@ -4226,46 +4225,45 @@ static bool handle_in_frameset(GumboParser* parser, GumboToken* token) {
4226
4225
  ) {
4227
4226
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_FRAMESET);
4228
4227
  }
4229
- return true;
4228
+ return;
4230
4229
  }
4231
4230
  if (tag_is(token, kStartTag, GUMBO_TAG_FRAME)) {
4232
4231
  insert_element_from_token(parser, token);
4233
4232
  pop_current_node(parser);
4234
4233
  acknowledge_self_closing_tag(parser);
4235
- return true;
4234
+ return;
4236
4235
  }
4237
4236
  if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) {
4238
- return handle_in_head(parser, token);
4237
+ handle_in_head(parser, token);
4238
+ return;
4239
4239
  }
4240
4240
  if (token->type == GUMBO_TOKEN_EOF) {
4241
- if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_HTML)) {
4241
+ if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_HTML))
4242
4242
  parser_add_parse_error(parser, token);
4243
- return false;
4244
- }
4245
- return true;
4243
+ return;
4246
4244
  }
4247
4245
  parser_add_parse_error(parser, token);
4248
4246
  ignore_token(parser);
4249
- return false;
4250
4247
  }
4251
4248
 
4252
4249
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-afterframeset
4253
- static bool handle_after_frameset(GumboParser* parser, GumboToken* token) {
4250
+ static void handle_after_frameset(GumboParser* parser, GumboToken* token) {
4254
4251
  if (token->type == GUMBO_TOKEN_WHITESPACE) {
4255
4252
  insert_text_token(parser, token);
4256
- return true;
4253
+ return;
4257
4254
  }
4258
4255
  if (token->type == GUMBO_TOKEN_COMMENT) {
4259
4256
  append_comment_node(parser, get_current_node(parser), token);
4260
- return true;
4257
+ return;
4261
4258
  }
4262
4259
  if (token->type == GUMBO_TOKEN_DOCTYPE) {
4263
4260
  parser_add_parse_error(parser, token);
4264
4261
  ignore_token(parser);
4265
- return false;
4262
+ return;
4266
4263
  }
4267
4264
  if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) {
4268
- return handle_in_body(parser, token);
4265
+ handle_in_body(parser, token);
4266
+ return;
4269
4267
  }
4270
4268
  if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) {
4271
4269
  GumboNode* html = parser->_parser_state->_open_elements.data[0];
@@ -4275,71 +4273,71 @@ static bool handle_after_frameset(GumboParser* parser, GumboToken* token) {
4275
4273
  &html->v.element
4276
4274
  );
4277
4275
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_AFTER_FRAMESET);
4278
- return true;
4276
+ return;
4279
4277
  }
4280
4278
  if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) {
4281
4279
  return handle_in_head(parser, token);
4282
4280
  }
4283
4281
  if (token->type == GUMBO_TOKEN_EOF) {
4284
- return true;
4282
+ return;
4285
4283
  }
4286
4284
  parser_add_parse_error(parser, token);
4287
4285
  ignore_token(parser);
4288
- return false;
4289
4286
  }
4290
4287
 
4291
4288
  // https://html.spec.whatwg.org/multipage/parsing.html#the-after-after-body-insertion-mode
4292
- static bool handle_after_after_body(GumboParser* parser, GumboToken* token) {
4289
+ static void handle_after_after_body(GumboParser* parser, GumboToken* token) {
4293
4290
  if (token->type == GUMBO_TOKEN_COMMENT) {
4294
4291
  append_comment_node(parser, get_document_node(parser), token);
4295
- return true;
4292
+ return;
4296
4293
  }
4297
4294
  if (
4298
4295
  token->type == GUMBO_TOKEN_DOCTYPE
4299
4296
  || token->type == GUMBO_TOKEN_WHITESPACE
4300
4297
  || tag_is(token, kStartTag, GUMBO_TAG_HTML)
4301
4298
  ) {
4302
- return handle_in_body(parser, token);
4299
+ handle_in_body(parser, token);
4300
+ return;
4303
4301
  }
4304
4302
  if (token->type == GUMBO_TOKEN_EOF) {
4305
- return true;
4303
+ return;
4306
4304
  }
4307
4305
  parser_add_parse_error(parser, token);
4308
4306
  set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY);
4309
4307
  parser->_parser_state->_reprocess_current_token = true;
4310
- return false;
4311
4308
  }
4312
4309
 
4313
4310
  // https://html.spec.whatwg.org/multipage/parsing.html#the-after-after-frameset-insertion-mode
4314
- static bool handle_after_after_frameset (
4311
+ static void handle_after_after_frameset (
4315
4312
  GumboParser* parser,
4316
4313
  GumboToken* token
4317
4314
  ) {
4318
4315
  if (token->type == GUMBO_TOKEN_COMMENT) {
4319
4316
  append_comment_node(parser, get_document_node(parser), token);
4320
- return true;
4317
+ return;
4321
4318
  }
4322
4319
  if (
4323
4320
  token->type == GUMBO_TOKEN_DOCTYPE
4324
4321
  || token->type == GUMBO_TOKEN_WHITESPACE
4325
4322
  || tag_is(token, kStartTag, GUMBO_TAG_HTML)
4326
4323
  ) {
4327
- return handle_in_body(parser, token);
4324
+ handle_in_body(parser, token);
4325
+ return;
4328
4326
  }
4329
4327
  if (token->type == GUMBO_TOKEN_EOF) {
4330
- return true;
4328
+ return;
4331
4329
  }
4332
4330
  if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) {
4333
- return handle_in_head(parser, token);
4331
+ handle_in_head(parser, token);
4332
+ return;
4334
4333
  }
4335
4334
  parser_add_parse_error(parser, token);
4336
4335
  ignore_token(parser);
4337
- return false;
4338
4336
  }
4339
4337
 
4340
4338
  // Function pointers for each insertion mode.
4341
4339
  // Keep in sync with insertion_mode.h.
4342
- typedef bool (*TokenHandler)(GumboParser* parser, GumboToken* token);
4340
+ typedef void (*TokenHandler)(GumboParser* parser, GumboToken* token);
4343
4341
  static const TokenHandler kTokenHandlers[] = {
4344
4342
  handle_initial,
4345
4343
  handle_before_html,
@@ -4366,36 +4364,36 @@ static const TokenHandler kTokenHandlers[] = {
4366
4364
  handle_after_after_frameset
4367
4365
  };
4368
4366
 
4369
- static bool handle_html_content(GumboParser* parser, GumboToken* token) {
4367
+ static void handle_html_content(GumboParser* parser, GumboToken* token) {
4370
4368
  const GumboInsertionMode mode = parser->_parser_state->_insertion_mode;
4371
4369
  const TokenHandler handler = kTokenHandlers[mode];
4372
- return handler(parser, token);
4370
+ handler(parser, token);
4373
4371
  }
4374
4372
 
4375
4373
  // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign
4376
- static bool handle_in_foreign_content(GumboParser* parser, GumboToken* token) {
4374
+ static void handle_in_foreign_content(GumboParser* parser, GumboToken* token) {
4377
4375
  gumbo_debug("Handling foreign content");
4378
4376
  switch (token->type) {
4379
4377
  case GUMBO_TOKEN_NULL:
4380
4378
  parser_add_parse_error(parser, token);
4381
4379
  token->v.character = kUtf8ReplacementChar;
4382
4380
  insert_text_token(parser, token);
4383
- return false;
4381
+ return;
4384
4382
  case GUMBO_TOKEN_WHITESPACE:
4385
4383
  insert_text_token(parser, token);
4386
- return true;
4384
+ return;
4387
4385
  case GUMBO_TOKEN_CDATA:
4388
4386
  case GUMBO_TOKEN_CHARACTER:
4389
4387
  insert_text_token(parser, token);
4390
4388
  set_frameset_not_ok(parser);
4391
- return true;
4389
+ return;
4392
4390
  case GUMBO_TOKEN_COMMENT:
4393
4391
  append_comment_node(parser, get_current_node(parser), token);
4394
- return true;
4392
+ return;
4395
4393
  case GUMBO_TOKEN_DOCTYPE:
4396
4394
  parser_add_parse_error(parser, token);
4397
4395
  ignore_token(parser);
4398
- return false;
4396
+ return;
4399
4397
  default:
4400
4398
  // Fall through to the if-statements below.
4401
4399
  break;
@@ -4439,7 +4437,7 @@ static bool handle_in_foreign_content(GumboParser* parser, GumboToken* token) {
4439
4437
  )
4440
4438
  );
4441
4439
  parser->_parser_state->_reprocess_current_token = true;
4442
- return false;
4440
+ return;
4443
4441
  }
4444
4442
  // This is a start tag so the next if's then branch will be taken.
4445
4443
  }
@@ -4460,7 +4458,7 @@ static bool handle_in_foreign_content(GumboParser* parser, GumboToken* token) {
4460
4458
  pop_current_node(parser);
4461
4459
  acknowledge_self_closing_tag(parser);
4462
4460
  }
4463
- return true;
4461
+ return;
4464
4462
  // </script> tags are handled like any other end tag, putting the script's
4465
4463
  // text into a text node child and closing the current node.
4466
4464
  }
@@ -4470,11 +4468,8 @@ static bool handle_in_foreign_content(GumboParser* parser, GumboToken* token) {
4470
4468
  const char* name = token->v.end_tag.name;
4471
4469
  assert(node != NULL);
4472
4470
 
4473
- bool is_success = true;
4474
- if (!node_tagname_is(node, tag, name)) {
4471
+ if (!node_tagname_is(node, tag, name))
4475
4472
  parser_add_parse_error(parser, token);
4476
- is_success = false;
4477
- }
4478
4473
  int i = parser->_parser_state->_open_elements.length;
4479
4474
  for (--i; i > 0;) {
4480
4475
  // Here we move up the stack until we find an HTML element (in which
@@ -4489,7 +4484,7 @@ static bool handle_in_foreign_content(GumboParser* parser, GumboToken* token) {
4489
4484
  // be an element on the stack of open elements (set below), so
4490
4485
  // this loop is guaranteed to terminate.
4491
4486
  }
4492
- return is_success;
4487
+ return;
4493
4488
  }
4494
4489
  --i;
4495
4490
  node = parser->_parser_state->_open_elements.data[i];
@@ -4500,22 +4495,22 @@ static bool handle_in_foreign_content(GumboParser* parser, GumboToken* token) {
4500
4495
  }
4501
4496
  assert(node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML);
4502
4497
  if (i == 0)
4503
- return is_success;
4498
+ return;
4504
4499
  // We can't call handle_token directly because the current node is still in
4505
4500
  // a foriegn namespace, so it would re-enter this and result in infinite
4506
4501
  // recursion.
4507
- return handle_html_content(parser, token) && is_success;
4502
+ handle_html_content(parser, token);
4508
4503
  }
4509
4504
 
4510
4505
  // https://html.spec.whatwg.org/multipage/parsing.html#tree-construction
4511
- static bool handle_token(GumboParser* parser, GumboToken* token) {
4506
+ static void handle_token(GumboParser* parser, GumboToken* token) {
4512
4507
  if (
4513
4508
  parser->_parser_state->_ignore_next_linefeed
4514
4509
  && token->type == GUMBO_TOKEN_WHITESPACE && token->v.character == '\n'
4515
4510
  ) {
4516
4511
  parser->_parser_state->_ignore_next_linefeed = false;
4517
4512
  ignore_token(parser);
4518
- return true;
4513
+ return;
4519
4514
  }
4520
4515
  // This needs to be reset both here and in the conditional above to catch both
4521
4516
  // the case where the next token is not whitespace (so we don't ignore
@@ -4557,9 +4552,9 @@ static bool handle_token(GumboParser* parser, GumboToken* token) {
4557
4552
  token->type == GUMBO_TOKEN_NULL ||
4558
4553
  token->type == GUMBO_TOKEN_WHITESPACE)) ||
4559
4554
  token->type == GUMBO_TOKEN_EOF) {
4560
- return handle_html_content(parser, token);
4555
+ handle_html_content(parser, token);
4561
4556
  } else {
4562
- return handle_in_foreign_content(parser, token);
4557
+ handle_in_foreign_content(parser, token);
4563
4558
  }
4564
4559
  }
4565
4560
 
@@ -4746,7 +4741,6 @@ GumboOutput* gumbo_parse_with_options (
4746
4741
 
4747
4742
  const unsigned int max_tree_depth = options->max_tree_depth;
4748
4743
  GumboToken token;
4749
- bool has_error = false;
4750
4744
 
4751
4745
  do {
4752
4746
  if (state->_reprocess_current_token) {
@@ -4758,7 +4752,7 @@ GumboOutput* gumbo_parse_with_options (
4758
4752
  adjusted_current_node &&
4759
4753
  adjusted_current_node->v.element.tag_namespace != GUMBO_NAMESPACE_HTML
4760
4754
  );
4761
- has_error = !gumbo_lex(&parser, &token) || has_error;
4755
+ gumbo_lex(&parser, &token);
4762
4756
  }
4763
4757
 
4764
4758
  const char* token_type = "text";
@@ -4792,7 +4786,7 @@ GumboOutput* gumbo_parse_with_options (
4792
4786
  state->_current_token = &token;
4793
4787
  state->_self_closing_flag_acknowledged = false;
4794
4788
 
4795
- has_error = !handle_token(&parser, &token) || has_error;
4789
+ handle_token(&parser, &token);
4796
4790
 
4797
4791
  // Check for memory leaks when ownership is transferred from start tag
4798
4792
  // tokens to nodes.
@@ -4809,7 +4803,6 @@ GumboOutput* gumbo_parse_with_options (
4809
4803
  if (token.type == GUMBO_TOKEN_START_TAG &&
4810
4804
  token.v.start_tag.is_self_closing &&
4811
4805
  !state->_self_closing_flag_acknowledged) {
4812
- has_error = true;
4813
4806
  GumboError* error = gumbo_add_error(&parser);
4814
4807
  if (error) {
4815
4808
  // This is essentially a tokenizer error that's only caught during
@@ -4837,7 +4830,7 @@ GumboOutput* gumbo_parse_with_options (
4837
4830
 
4838
4831
  } while (
4839
4832
  (token.type != GUMBO_TOKEN_EOF || state->_reprocess_current_token)
4840
- && !(options->stop_on_first_error && has_error)
4833
+ && !(options->stop_on_first_error && parser._output->document_error)
4841
4834
  );
4842
4835
 
4843
4836
  finish_parsing(&parser);