/[suikacvs]/markup/html/whatpm/Whatpm/HTML.pm
Suika

Contents of /markup/html/whatpm/Whatpm/HTML.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.85 - (hide annotations) (download)
Thu Mar 6 15:29:39 2008 UTC (18 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.84: +17 -93 lines
++ whatpm/Whatpm/ChangeLog	6 Mar 2008 15:28:32 -0000
2008-03-07  Wakaba  <wakaba@suika.fam.cx>

	* HTML.pm.src (_tree_construction_main): Merge rules for "h1"
	and "div" (HTML5 revision 1318).  Add comments to where
	|form| pointer association codes should be inserted (HTML5 revision
	1319).

1 wakaba 1.2 package Whatpm::HTML;
2 wakaba 1.1 use strict;
3 wakaba 1.85 our $VERSION=do{my @r=(q$Revision: 1.84 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4 wakaba 1.65 use Error qw(:try);
5 wakaba 1.1
6 wakaba 1.18 ## ISSUE:
7     ## var doc = implementation.createDocument (null, null, null);
8     ## doc.write ('');
9     ## alert (doc.compatMode);
10 wakaba 1.1
11 wakaba 1.71 ## TODO: Control charcters and noncharacters are not allowed (HTML5 revision 1263)
12     ## TODO: 1252 parse error (revision 1264)
13     ## TODO: 8859-11 = 874 (revision 1271)
14 wakaba 1.31
15 wakaba 1.1 my $permitted_slash_tag_name = {
16     base => 1,
17     link => 1,
18     meta => 1,
19     hr => 1,
20     br => 1,
21 wakaba 1.71 img => 1,
22 wakaba 1.1 embed => 1,
23     param => 1,
24     area => 1,
25     col => 1,
26     input => 1,
27     };
28    
29 wakaba 1.4 my $c1_entity_char = {
30 wakaba 1.9 0x80 => 0x20AC,
31     0x81 => 0xFFFD,
32     0x82 => 0x201A,
33     0x83 => 0x0192,
34     0x84 => 0x201E,
35     0x85 => 0x2026,
36     0x86 => 0x2020,
37     0x87 => 0x2021,
38     0x88 => 0x02C6,
39     0x89 => 0x2030,
40     0x8A => 0x0160,
41     0x8B => 0x2039,
42     0x8C => 0x0152,
43     0x8D => 0xFFFD,
44     0x8E => 0x017D,
45     0x8F => 0xFFFD,
46     0x90 => 0xFFFD,
47     0x91 => 0x2018,
48     0x92 => 0x2019,
49     0x93 => 0x201C,
50     0x94 => 0x201D,
51     0x95 => 0x2022,
52     0x96 => 0x2013,
53     0x97 => 0x2014,
54     0x98 => 0x02DC,
55     0x99 => 0x2122,
56     0x9A => 0x0161,
57     0x9B => 0x203A,
58     0x9C => 0x0153,
59     0x9D => 0xFFFD,
60     0x9E => 0x017E,
61     0x9F => 0x0178,
62 wakaba 1.4 }; # $c1_entity_char
63 wakaba 1.1
64     my $special_category = {
65     address => 1, area => 1, base => 1, basefont => 1, bgsound => 1,
66     blockquote => 1, body => 1, br => 1, center => 1, col => 1, colgroup => 1,
67     dd => 1, dir => 1, div => 1, dl => 1, dt => 1, embed => 1, fieldset => 1,
68     form => 1, frame => 1, frameset => 1, h1 => 1, h2 => 1, h3 => 1,
69     h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, iframe => 1, image => 1,
70     img => 1, input => 1, isindex => 1, li => 1, link => 1, listing => 1,
71     menu => 1, meta => 1, noembed => 1, noframes => 1, noscript => 1,
72     ol => 1, optgroup => 1, option => 1, p => 1, param => 1, plaintext => 1,
73     pre => 1, script => 1, select => 1, spacer => 1, style => 1, tbody => 1,
74     textarea => 1, tfoot => 1, thead => 1, title => 1, tr => 1, ul => 1, wbr => 1,
75     };
76     my $scoping_category = {
77     button => 1, caption => 1, html => 1, marquee => 1, object => 1,
78     table => 1, td => 1, th => 1,
79     };
80     my $formatting_category = {
81     a => 1, b => 1, big => 1, em => 1, font => 1, i => 1, nobr => 1,
82     s => 1, small => 1, strile => 1, strong => 1, tt => 1, u => 1,
83     };
84     # $phrasing_category: all other elements
85    
86 wakaba 1.65 sub parse_byte_string ($$$$;$) {
87     my $self = ref $_[0] ? shift : shift->new;
88     my $charset = shift;
89     my $bytes_s = ref $_[0] ? $_[0] : \($_[0]);
90     my $s;
91    
92     if (defined $charset) {
93 wakaba 1.66 require Encode; ## TODO: decode(utf8) don't delete BOM
94 wakaba 1.65 $s = \ (Encode::decode ($charset, $$bytes_s));
95 wakaba 1.66 $self->{input_encoding} = lc $charset; ## TODO: normalize name
96 wakaba 1.65 $self->{confident} = 1;
97     } else {
98 wakaba 1.67 ## TODO: Implement HTML5 detection algorithm
99     require Whatpm::Charset::UniversalCharDet;
100     $charset = Whatpm::Charset::UniversalCharDet->detect_byte_string
101     (substr ($$bytes_s, 0, 1024));
102     $charset ||= 'windows-1252';
103 wakaba 1.66 $s = \ (Encode::decode ($charset, $$bytes_s));
104     $self->{input_encoding} = $charset;
105 wakaba 1.65 $self->{confident} = 0;
106     }
107    
108     $self->{change_encoding} = sub {
109     my $self = shift;
110     my $charset = lc shift;
111     ## TODO: if $charset is supported
112     ## TODO: normalize charset name
113    
114     ## "Change the encoding" algorithm:
115    
116     ## Step 1
117     if ($charset eq 'utf-16') { ## ISSUE: UTF-16BE -> UTF-8? UTF-16LE -> UTF-8?
118     $charset = 'utf-8';
119     }
120    
121     ## Step 2
122     if (defined $self->{input_encoding} and
123     $self->{input_encoding} eq $charset) {
124     $self->{confident} = 1;
125     return;
126     }
127    
128 wakaba 1.66 $self->{parse_error}-> (type => 'charset label detected:'.$self->{input_encoding}.
129     ':'.$charset, level => 'w');
130 wakaba 1.65
131     ## Step 3
132     # if (can) {
133     ## change the encoding on the fly.
134     #$self->{confident} = 1;
135     #return;
136     # }
137    
138     ## Step 4
139     throw Whatpm::HTML::RestartParser (charset => $charset);
140     }; # $self->{change_encoding}
141    
142     my @args = @_; shift @args; # $s
143     my $return;
144     try {
145     $return = $self->parse_char_string ($s, @args);
146     } catch Whatpm::HTML::RestartParser with {
147     my $charset = shift->{charset};
148     $s = \ (Encode::decode ($charset, $$bytes_s));
149 wakaba 1.66 $self->{input_encoding} = $charset; ## TODO: normalize
150 wakaba 1.65 $self->{confident} = 1;
151     $return = $self->parse_char_string ($s, @args);
152     };
153     return $return;
154     } # parse_byte_string
155    
156 wakaba 1.71 ## NOTE: HTML5 spec says that the encoding layer MUST NOT strip BOM
157     ## and the HTML layer MUST ignore it. However, we does strip BOM in
158     ## the encoding layer and the HTML layer does not ignore any U+FEFF,
159     ## because the core part of our HTML parser expects a string of character,
160     ## not a string of bytes or code units or anything which might contain a BOM.
161     ## Therefore, any parser interface that accepts a string of bytes,
162     ## such as |parse_byte_string| in this module, must ensure that it does
163     ## strip the BOM and never strip any ZWNBSP.
164    
165 wakaba 1.65 *parse_char_string = \&parse_string;
166    
167 wakaba 1.1 sub parse_string ($$$;$) {
168 wakaba 1.65 my $self = ref $_[0] ? shift : shift->new;
169     my $s = ref $_[0] ? $_[0] : \($_[0]);
170 wakaba 1.1 $self->{document} = $_[1];
171 wakaba 1.65 @{$self->{document}->child_nodes} = ();
172 wakaba 1.1
173 wakaba 1.3 ## NOTE: |set_inner_html| copies most of this method's code
174    
175 wakaba 1.65 $self->{confident} = 1 unless exists $self->{confident};
176 wakaba 1.66 $self->{document}->input_encoding ($self->{input_encoding})
177     if defined $self->{input_encoding};
178 wakaba 1.65
179 wakaba 1.1 my $i = 0;
180 wakaba 1.3 my $line = 1;
181     my $column = 0;
182 wakaba 1.76 $self->{set_next_char} = sub {
183 wakaba 1.1 my $self = shift;
184 wakaba 1.13
185 wakaba 1.76 pop @{$self->{prev_char}};
186     unshift @{$self->{prev_char}}, $self->{next_char};
187 wakaba 1.13
188 wakaba 1.76 $self->{next_char} = -1 and return if $i >= length $$s;
189     $self->{next_char} = ord substr $$s, $i++, 1;
190 wakaba 1.3 $column++;
191 wakaba 1.1
192 wakaba 1.76 if ($self->{next_char} == 0x000A) { # LF
193 wakaba 1.4 $line++;
194     $column = 0;
195 wakaba 1.76 } elsif ($self->{next_char} == 0x000D) { # CR
196 wakaba 1.15 $i++ if substr ($$s, $i, 1) eq "\x0A";
197 wakaba 1.76 $self->{next_char} = 0x000A; # LF # MUST
198 wakaba 1.3 $line++;
199 wakaba 1.4 $column = 0;
200 wakaba 1.76 } elsif ($self->{next_char} > 0x10FFFF) {
201     $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
202     } elsif ($self->{next_char} == 0x0000) { # NULL
203 wakaba 1.8 $self->{parse_error}-> (type => 'NULL');
204 wakaba 1.76 $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
205 wakaba 1.1 }
206     };
207 wakaba 1.76 $self->{prev_char} = [-1, -1, -1];
208     $self->{next_char} = -1;
209 wakaba 1.1
210 wakaba 1.3 my $onerror = $_[2] || sub {
211     my (%opt) = @_;
212     warn "Parse error ($opt{type}) at line $opt{line} column $opt{column}\n";
213     };
214     $self->{parse_error} = sub {
215     $onerror->(@_, line => $line, column => $column);
216 wakaba 1.1 };
217    
218     $self->_initialize_tokenizer;
219     $self->_initialize_tree_constructor;
220     $self->_construct_tree;
221     $self->_terminate_tree_constructor;
222    
223     return $self->{document};
224     } # parse_string
225    
226     sub new ($) {
227     my $class = shift;
228     my $self = bless {}, $class;
229 wakaba 1.76 $self->{set_next_char} = sub {
230     $self->{next_char} = -1;
231 wakaba 1.1 };
232     $self->{parse_error} = sub {
233     #
234     };
235 wakaba 1.65 $self->{change_encoding} = sub {
236     # if ($_[0] is a supported encoding) {
237     # run "change the encoding" algorithm;
238     # throw Whatpm::HTML::RestartParser (charset => $new_encoding);
239     # }
240     };
241 wakaba 1.63 $self->{application_cache_selection} = sub {
242     #
243     };
244 wakaba 1.1 return $self;
245     } # new
246    
247 wakaba 1.41 sub CM_ENTITY () { 0b001 } # & markup in data
248     sub CM_LIMITED_MARKUP () { 0b010 } # < markup in data (limited)
249     sub CM_FULL_MARKUP () { 0b100 } # < markup in data (any)
250    
251     sub PLAINTEXT_CONTENT_MODEL () { 0 }
252     sub CDATA_CONTENT_MODEL () { CM_LIMITED_MARKUP }
253     sub RCDATA_CONTENT_MODEL () { CM_ENTITY | CM_LIMITED_MARKUP }
254     sub PCDATA_CONTENT_MODEL () { CM_ENTITY | CM_FULL_MARKUP }
255    
256 wakaba 1.59 sub DATA_STATE () { 0 }
257     sub ENTITY_DATA_STATE () { 1 }
258     sub TAG_OPEN_STATE () { 2 }
259     sub CLOSE_TAG_OPEN_STATE () { 3 }
260     sub TAG_NAME_STATE () { 4 }
261     sub BEFORE_ATTRIBUTE_NAME_STATE () { 5 }
262     sub ATTRIBUTE_NAME_STATE () { 6 }
263     sub AFTER_ATTRIBUTE_NAME_STATE () { 7 }
264     sub BEFORE_ATTRIBUTE_VALUE_STATE () { 8 }
265     sub ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE () { 9 }
266     sub ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE () { 10 }
267     sub ATTRIBUTE_VALUE_UNQUOTED_STATE () { 11 }
268     sub ENTITY_IN_ATTRIBUTE_VALUE_STATE () { 12 }
269     sub MARKUP_DECLARATION_OPEN_STATE () { 13 }
270     sub COMMENT_START_STATE () { 14 }
271     sub COMMENT_START_DASH_STATE () { 15 }
272     sub COMMENT_STATE () { 16 }
273     sub COMMENT_END_STATE () { 17 }
274     sub COMMENT_END_DASH_STATE () { 18 }
275     sub BOGUS_COMMENT_STATE () { 19 }
276     sub DOCTYPE_STATE () { 20 }
277     sub BEFORE_DOCTYPE_NAME_STATE () { 21 }
278     sub DOCTYPE_NAME_STATE () { 22 }
279     sub AFTER_DOCTYPE_NAME_STATE () { 23 }
280     sub BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE () { 24 }
281     sub DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE () { 25 }
282     sub DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE () { 26 }
283     sub AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE () { 27 }
284     sub BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE () { 28 }
285     sub DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE () { 29 }
286     sub DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE () { 30 }
287     sub AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE () { 31 }
288     sub BOGUS_DOCTYPE_STATE () { 32 }
289 wakaba 1.72 sub AFTER_ATTRIBUTE_VALUE_QUOTED_STATE () { 33 }
290 wakaba 1.59
291 wakaba 1.57 sub DOCTYPE_TOKEN () { 1 }
292     sub COMMENT_TOKEN () { 2 }
293     sub START_TAG_TOKEN () { 3 }
294     sub END_TAG_TOKEN () { 4 }
295     sub END_OF_FILE_TOKEN () { 5 }
296     sub CHARACTER_TOKEN () { 6 }
297    
298 wakaba 1.56 sub AFTER_HTML_IMS () { 0b100 }
299     sub HEAD_IMS () { 0b1000 }
300     sub BODY_IMS () { 0b10000 }
301 wakaba 1.58 sub BODY_TABLE_IMS () { 0b100000 }
302 wakaba 1.56 sub TABLE_IMS () { 0b1000000 }
303 wakaba 1.58 sub ROW_IMS () { 0b10000000 }
304 wakaba 1.56 sub BODY_AFTER_IMS () { 0b100000000 }
305     sub FRAME_IMS () { 0b1000000000 }
306    
307 wakaba 1.85 ## NOTE: "initial" and "before html" insertion modes have no constants.
308 wakaba 1.84
309     ## NOTE: "after after body" insertion mode.
310 wakaba 1.56 sub AFTER_HTML_BODY_IM () { AFTER_HTML_IMS | BODY_AFTER_IMS }
311 wakaba 1.84
312     ## NOTE: "after after frameset" insertion mode.
313 wakaba 1.56 sub AFTER_HTML_FRAMESET_IM () { AFTER_HTML_IMS | FRAME_IMS }
314 wakaba 1.84
315 wakaba 1.56 sub IN_HEAD_IM () { HEAD_IMS | 0b00 }
316     sub IN_HEAD_NOSCRIPT_IM () { HEAD_IMS | 0b01 }
317     sub AFTER_HEAD_IM () { HEAD_IMS | 0b10 }
318     sub BEFORE_HEAD_IM () { HEAD_IMS | 0b11 }
319     sub IN_BODY_IM () { BODY_IMS }
320 wakaba 1.58 sub IN_CELL_IM () { BODY_IMS | BODY_TABLE_IMS | 0b01 }
321     sub IN_CAPTION_IM () { BODY_IMS | BODY_TABLE_IMS | 0b10 }
322     sub IN_ROW_IM () { TABLE_IMS | ROW_IMS | 0b01 }
323     sub IN_TABLE_BODY_IM () { TABLE_IMS | ROW_IMS | 0b10 }
324 wakaba 1.56 sub IN_TABLE_IM () { TABLE_IMS }
325     sub AFTER_BODY_IM () { BODY_AFTER_IMS }
326     sub IN_FRAMESET_IM () { FRAME_IMS | 0b01 }
327     sub AFTER_FRAMESET_IM () { FRAME_IMS | 0b10 }
328     sub IN_SELECT_IM () { 0b01 }
329     sub IN_COLUMN_GROUP_IM () { 0b10 }
330    
331 wakaba 1.1 ## Implementations MUST act as if state machine in the spec
332    
333     sub _initialize_tokenizer ($) {
334     my $self = shift;
335 wakaba 1.59 $self->{state} = DATA_STATE; # MUST
336 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # be
337 wakaba 1.1 undef $self->{current_token}; # start tag, end tag, comment, or DOCTYPE
338     undef $self->{current_attribute};
339     undef $self->{last_emitted_start_tag_name};
340     undef $self->{last_attribute_value_state};
341     $self->{char} = [];
342 wakaba 1.76 # $self->{next_char}
343 wakaba 1.1
344     if (@{$self->{char}}) {
345 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
346 wakaba 1.1 } else {
347 wakaba 1.76 $self->{set_next_char}->($self);
348 wakaba 1.1 }
349    
350     $self->{token} = [];
351 wakaba 1.18 # $self->{escape}
352 wakaba 1.1 } # _initialize_tokenizer
353    
354     ## A token has:
355 wakaba 1.57 ## ->{type} == DOCTYPE_TOKEN, START_TAG_TOKEN, END_TAG_TOKEN, COMMENT_TOKEN,
356     ## CHARACTER_TOKEN, or END_OF_FILE_TOKEN
357     ## ->{name} (DOCTYPE_TOKEN)
358     ## ->{tag_name} (START_TAG_TOKEN, END_TAG_TOKEN)
359     ## ->{public_identifier} (DOCTYPE_TOKEN)
360     ## ->{system_identifier} (DOCTYPE_TOKEN)
361 wakaba 1.75 ## ->{quirks} == 1 or 0 (DOCTYPE_TOKEN): "force-quirks" flag
362 wakaba 1.57 ## ->{attributes} isa HASH (START_TAG_TOKEN, END_TAG_TOKEN)
363 wakaba 1.68 ## ->{name}
364     ## ->{value}
365     ## ->{has_reference} == 1 or 0
366 wakaba 1.57 ## ->{data} (COMMENT_TOKEN, CHARACTER_TOKEN)
367 wakaba 1.1
368     ## Emitted token MUST immediately be handled by the tree construction state.
369    
370     ## Before each step, UA MAY check to see if either one of the scripts in
371     ## "list of scripts that will execute as soon as possible" or the first
372     ## script in the "list of scripts that will execute asynchronously",
373     ## has completed loading. If one has, then it MUST be executed
374     ## and removed from the list.
375    
376 wakaba 1.61 ## NOTE: HTML5 "Writing HTML documents" section, applied to
377     ## documents and not to user agents and conformance checkers,
378     ## contains some requirements that are not detected by the
379     ## parsing algorithm:
380     ## - Some requirements on character encoding declarations. ## TODO
381     ## - "Elements MUST NOT contain content that their content model disallows."
382     ## ... Some are parse error, some are not (will be reported by c.c.).
383     ## - Polytheistic slash SHOULD NOT be used. (Applied only to atheists.) ## TODO
384     ## - Text (in elements, attributes, and comments) SHOULD NOT contain
385     ## control characters other than space characters. ## TODO: (what is control character? C0, C1 and DEL? Unicode control character?)
386    
387     ## TODO: HTML5 poses authors two SHOULD-level requirements that cannot
388     ## be detected by the HTML5 parsing algorithm:
389     ## - Text,
390    
391 wakaba 1.1 sub _get_next_token ($) {
392     my $self = shift;
393     if (@{$self->{token}}) {
394     return shift @{$self->{token}};
395     }
396    
397     A: {
398 wakaba 1.59 if ($self->{state} == DATA_STATE) {
399 wakaba 1.76 if ($self->{next_char} == 0x0026) { # &
400 wakaba 1.72 if ($self->{content_model} & CM_ENTITY and # PCDATA | RCDATA
401     not $self->{escape}) {
402 wakaba 1.77
403     $Whatpm::HTML::Debug::cp_pass->(1) if $Whatpm::HTML::Debug::cp_pass;
404     BEGIN {
405     $Whatpm::HTML::Debug::cp->{1} = 1;
406     }
407    
408 wakaba 1.59 $self->{state} = ENTITY_DATA_STATE;
409 wakaba 1.1
410     if (@{$self->{char}}) {
411 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
412 wakaba 1.1 } else {
413 wakaba 1.76 $self->{set_next_char}->($self);
414 wakaba 1.1 }
415    
416     redo A;
417     } else {
418 wakaba 1.77
419     $Whatpm::HTML::Debug::cp_pass->(2) if $Whatpm::HTML::Debug::cp_pass;
420     BEGIN {
421     $Whatpm::HTML::Debug::cp->{2} = 1;
422     }
423    
424 wakaba 1.1 #
425     }
426 wakaba 1.76 } elsif ($self->{next_char} == 0x002D) { # -
427 wakaba 1.41 if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
428 wakaba 1.13 unless ($self->{escape}) {
429 wakaba 1.76 if ($self->{prev_char}->[0] == 0x002D and # -
430     $self->{prev_char}->[1] == 0x0021 and # !
431     $self->{prev_char}->[2] == 0x003C) { # <
432 wakaba 1.77
433     $Whatpm::HTML::Debug::cp_pass->(3) if $Whatpm::HTML::Debug::cp_pass;
434     BEGIN {
435     $Whatpm::HTML::Debug::cp->{3} = 1;
436     }
437    
438 wakaba 1.13 $self->{escape} = 1;
439 wakaba 1.77 } else {
440    
441     $Whatpm::HTML::Debug::cp_pass->(4) if $Whatpm::HTML::Debug::cp_pass;
442     BEGIN {
443     $Whatpm::HTML::Debug::cp->{4} = 1;
444     }
445    
446 wakaba 1.13 }
447 wakaba 1.77 } else {
448    
449     $Whatpm::HTML::Debug::cp_pass->(5) if $Whatpm::HTML::Debug::cp_pass;
450     BEGIN {
451     $Whatpm::HTML::Debug::cp->{5} = 1;
452     }
453    
454 wakaba 1.13 }
455     }
456    
457     #
458 wakaba 1.76 } elsif ($self->{next_char} == 0x003C) { # <
459 wakaba 1.41 if ($self->{content_model} & CM_FULL_MARKUP or # PCDATA
460     (($self->{content_model} & CM_LIMITED_MARKUP) and # CDATA | RCDATA
461 wakaba 1.13 not $self->{escape})) {
462 wakaba 1.77
463     $Whatpm::HTML::Debug::cp_pass->(6) if $Whatpm::HTML::Debug::cp_pass;
464     BEGIN {
465     $Whatpm::HTML::Debug::cp->{6} = 1;
466     }
467    
468 wakaba 1.59 $self->{state} = TAG_OPEN_STATE;
469 wakaba 1.1
470     if (@{$self->{char}}) {
471 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
472 wakaba 1.1 } else {
473 wakaba 1.76 $self->{set_next_char}->($self);
474 wakaba 1.1 }
475    
476     redo A;
477     } else {
478 wakaba 1.77
479     $Whatpm::HTML::Debug::cp_pass->(7) if $Whatpm::HTML::Debug::cp_pass;
480     BEGIN {
481     $Whatpm::HTML::Debug::cp->{7} = 1;
482     }
483    
484 wakaba 1.1 #
485     }
486 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
487 wakaba 1.13 if ($self->{escape} and
488 wakaba 1.41 ($self->{content_model} & CM_LIMITED_MARKUP)) { # RCDATA | CDATA
489 wakaba 1.76 if ($self->{prev_char}->[0] == 0x002D and # -
490     $self->{prev_char}->[1] == 0x002D) { # -
491 wakaba 1.77
492     $Whatpm::HTML::Debug::cp_pass->(8) if $Whatpm::HTML::Debug::cp_pass;
493     BEGIN {
494     $Whatpm::HTML::Debug::cp->{8} = 1;
495     }
496    
497 wakaba 1.13 delete $self->{escape};
498 wakaba 1.77 } else {
499    
500     $Whatpm::HTML::Debug::cp_pass->(9) if $Whatpm::HTML::Debug::cp_pass;
501     BEGIN {
502     $Whatpm::HTML::Debug::cp->{9} = 1;
503     }
504    
505 wakaba 1.13 }
506 wakaba 1.77 } else {
507    
508     $Whatpm::HTML::Debug::cp_pass->(10) if $Whatpm::HTML::Debug::cp_pass;
509     BEGIN {
510     $Whatpm::HTML::Debug::cp->{10} = 1;
511     }
512    
513 wakaba 1.13 }
514    
515     #
516 wakaba 1.76 } elsif ($self->{next_char} == -1) {
517 wakaba 1.77
518     $Whatpm::HTML::Debug::cp_pass->(11) if $Whatpm::HTML::Debug::cp_pass;
519     BEGIN {
520     $Whatpm::HTML::Debug::cp->{11} = 1;
521     }
522    
523 wakaba 1.57 return ({type => END_OF_FILE_TOKEN});
524 wakaba 1.1 last A; ## TODO: ok?
525 wakaba 1.77 } else {
526    
527     $Whatpm::HTML::Debug::cp_pass->(12) if $Whatpm::HTML::Debug::cp_pass;
528     BEGIN {
529     $Whatpm::HTML::Debug::cp->{12} = 1;
530     }
531    
532 wakaba 1.1 }
533     # Anything else
534 wakaba 1.57 my $token = {type => CHARACTER_TOKEN,
535 wakaba 1.76 data => chr $self->{next_char}};
536 wakaba 1.1 ## Stay in the data state
537    
538     if (@{$self->{char}}) {
539 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
540 wakaba 1.1 } else {
541 wakaba 1.76 $self->{set_next_char}->($self);
542 wakaba 1.1 }
543    
544    
545     return ($token);
546    
547     redo A;
548 wakaba 1.59 } elsif ($self->{state} == ENTITY_DATA_STATE) {
549 wakaba 1.1 ## (cannot happen in CDATA state)
550    
551 wakaba 1.72 my $token = $self->_tokenize_attempt_to_consume_an_entity (0, -1);
552 wakaba 1.1
553 wakaba 1.59 $self->{state} = DATA_STATE;
554 wakaba 1.1 # next-input-character is already done
555    
556     unless (defined $token) {
557 wakaba 1.77
558     $Whatpm::HTML::Debug::cp_pass->(13) if $Whatpm::HTML::Debug::cp_pass;
559     BEGIN {
560     $Whatpm::HTML::Debug::cp->{13} = 1;
561     }
562    
563 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '&'});
564 wakaba 1.1 } else {
565 wakaba 1.77
566     $Whatpm::HTML::Debug::cp_pass->(14) if $Whatpm::HTML::Debug::cp_pass;
567     BEGIN {
568     $Whatpm::HTML::Debug::cp->{14} = 1;
569     }
570    
571 wakaba 1.1 return ($token);
572     }
573    
574     redo A;
575 wakaba 1.59 } elsif ($self->{state} == TAG_OPEN_STATE) {
576 wakaba 1.41 if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
577 wakaba 1.76 if ($self->{next_char} == 0x002F) { # /
578 wakaba 1.1
579 wakaba 1.77 $Whatpm::HTML::Debug::cp_pass->(15) if $Whatpm::HTML::Debug::cp_pass;
580     BEGIN {
581     $Whatpm::HTML::Debug::cp->{15} = 1;
582     }
583    
584    
585 wakaba 1.1 if (@{$self->{char}}) {
586 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
587 wakaba 1.1 } else {
588 wakaba 1.76 $self->{set_next_char}->($self);
589 wakaba 1.1 }
590    
591 wakaba 1.59 $self->{state} = CLOSE_TAG_OPEN_STATE;
592 wakaba 1.1 redo A;
593     } else {
594 wakaba 1.77
595     $Whatpm::HTML::Debug::cp_pass->(16) if $Whatpm::HTML::Debug::cp_pass;
596     BEGIN {
597     $Whatpm::HTML::Debug::cp->{16} = 1;
598     }
599    
600 wakaba 1.1 ## reconsume
601 wakaba 1.59 $self->{state} = DATA_STATE;
602 wakaba 1.1
603 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '<'});
604 wakaba 1.1
605     redo A;
606     }
607 wakaba 1.41 } elsif ($self->{content_model} & CM_FULL_MARKUP) { # PCDATA
608 wakaba 1.76 if ($self->{next_char} == 0x0021) { # !
609 wakaba 1.77
610     $Whatpm::HTML::Debug::cp_pass->(17) if $Whatpm::HTML::Debug::cp_pass;
611     BEGIN {
612     $Whatpm::HTML::Debug::cp->{17} = 1;
613     }
614    
615 wakaba 1.59 $self->{state} = MARKUP_DECLARATION_OPEN_STATE;
616 wakaba 1.1
617     if (@{$self->{char}}) {
618 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
619 wakaba 1.1 } else {
620 wakaba 1.76 $self->{set_next_char}->($self);
621 wakaba 1.1 }
622    
623     redo A;
624 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
625 wakaba 1.77
626     $Whatpm::HTML::Debug::cp_pass->(18) if $Whatpm::HTML::Debug::cp_pass;
627     BEGIN {
628     $Whatpm::HTML::Debug::cp->{18} = 1;
629     }
630    
631 wakaba 1.59 $self->{state} = CLOSE_TAG_OPEN_STATE;
632 wakaba 1.1
633     if (@{$self->{char}}) {
634 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
635 wakaba 1.1 } else {
636 wakaba 1.76 $self->{set_next_char}->($self);
637 wakaba 1.1 }
638    
639     redo A;
640 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
641     $self->{next_char} <= 0x005A) { # A..Z
642 wakaba 1.77
643     $Whatpm::HTML::Debug::cp_pass->(19) if $Whatpm::HTML::Debug::cp_pass;
644     BEGIN {
645     $Whatpm::HTML::Debug::cp->{19} = 1;
646     }
647    
648 wakaba 1.1 $self->{current_token}
649 wakaba 1.57 = {type => START_TAG_TOKEN,
650 wakaba 1.76 tag_name => chr ($self->{next_char} + 0x0020)};
651 wakaba 1.59 $self->{state} = TAG_NAME_STATE;
652 wakaba 1.1
653     if (@{$self->{char}}) {
654 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
655 wakaba 1.1 } else {
656 wakaba 1.76 $self->{set_next_char}->($self);
657 wakaba 1.1 }
658    
659     redo A;
660 wakaba 1.76 } elsif (0x0061 <= $self->{next_char} and
661     $self->{next_char} <= 0x007A) { # a..z
662 wakaba 1.77
663     $Whatpm::HTML::Debug::cp_pass->(20) if $Whatpm::HTML::Debug::cp_pass;
664     BEGIN {
665     $Whatpm::HTML::Debug::cp->{20} = 1;
666     }
667    
668 wakaba 1.57 $self->{current_token} = {type => START_TAG_TOKEN,
669 wakaba 1.76 tag_name => chr ($self->{next_char})};
670 wakaba 1.59 $self->{state} = TAG_NAME_STATE;
671 wakaba 1.1
672     if (@{$self->{char}}) {
673 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
674 wakaba 1.1 } else {
675 wakaba 1.76 $self->{set_next_char}->($self);
676 wakaba 1.1 }
677    
678     redo A;
679 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
680 wakaba 1.77
681     $Whatpm::HTML::Debug::cp_pass->(21) if $Whatpm::HTML::Debug::cp_pass;
682     BEGIN {
683     $Whatpm::HTML::Debug::cp->{21} = 1;
684     }
685    
686 wakaba 1.3 $self->{parse_error}-> (type => 'empty start tag');
687 wakaba 1.59 $self->{state} = DATA_STATE;
688 wakaba 1.1
689     if (@{$self->{char}}) {
690 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
691 wakaba 1.1 } else {
692 wakaba 1.76 $self->{set_next_char}->($self);
693 wakaba 1.1 }
694    
695    
696 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '<>'});
697 wakaba 1.1
698     redo A;
699 wakaba 1.76 } elsif ($self->{next_char} == 0x003F) { # ?
700 wakaba 1.77
701     $Whatpm::HTML::Debug::cp_pass->(22) if $Whatpm::HTML::Debug::cp_pass;
702     BEGIN {
703     $Whatpm::HTML::Debug::cp->{22} = 1;
704     }
705    
706 wakaba 1.3 $self->{parse_error}-> (type => 'pio');
707 wakaba 1.59 $self->{state} = BOGUS_COMMENT_STATE;
708 wakaba 1.76 ## $self->{next_char} is intentionally left as is
709 wakaba 1.1 redo A;
710     } else {
711 wakaba 1.77
712     $Whatpm::HTML::Debug::cp_pass->(23) if $Whatpm::HTML::Debug::cp_pass;
713     BEGIN {
714     $Whatpm::HTML::Debug::cp->{23} = 1;
715     }
716    
717 wakaba 1.3 $self->{parse_error}-> (type => 'bare stago');
718 wakaba 1.59 $self->{state} = DATA_STATE;
719 wakaba 1.1 ## reconsume
720    
721 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '<'});
722 wakaba 1.1
723     redo A;
724     }
725     } else {
726 wakaba 1.41 die "$0: $self->{content_model} in tag open";
727 wakaba 1.1 }
728 wakaba 1.59 } elsif ($self->{state} == CLOSE_TAG_OPEN_STATE) {
729 wakaba 1.41 if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
730 wakaba 1.23 if (defined $self->{last_emitted_start_tag_name}) {
731 wakaba 1.30 ## NOTE: <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>
732 wakaba 1.23 my @next_char;
733     TAGNAME: for (my $i = 0; $i < length $self->{last_emitted_start_tag_name}; $i++) {
734 wakaba 1.76 push @next_char, $self->{next_char};
735 wakaba 1.23 my $c = ord substr ($self->{last_emitted_start_tag_name}, $i, 1);
736     my $C = 0x0061 <= $c && $c <= 0x007A ? $c - 0x0020 : $c;
737 wakaba 1.76 if ($self->{next_char} == $c or $self->{next_char} == $C) {
738 wakaba 1.23
739 wakaba 1.77 $Whatpm::HTML::Debug::cp_pass->(24) if $Whatpm::HTML::Debug::cp_pass;
740     BEGIN {
741     $Whatpm::HTML::Debug::cp->{24} = 1;
742     }
743    
744    
745 wakaba 1.1 if (@{$self->{char}}) {
746 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
747 wakaba 1.1 } else {
748 wakaba 1.76 $self->{set_next_char}->($self);
749 wakaba 1.1 }
750    
751 wakaba 1.23 next TAGNAME;
752     } else {
753 wakaba 1.77
754     $Whatpm::HTML::Debug::cp_pass->(25) if $Whatpm::HTML::Debug::cp_pass;
755     BEGIN {
756     $Whatpm::HTML::Debug::cp->{25} = 1;
757     }
758    
759 wakaba 1.76 $self->{next_char} = shift @next_char; # reconsume
760 wakaba 1.23 unshift @{$self->{char}}, (@next_char);
761 wakaba 1.59 $self->{state} = DATA_STATE;
762 wakaba 1.23
763 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '</'});
764 wakaba 1.23
765     redo A;
766     }
767     }
768 wakaba 1.76 push @next_char, $self->{next_char};
769 wakaba 1.23
770 wakaba 1.76 unless ($self->{next_char} == 0x0009 or # HT
771     $self->{next_char} == 0x000A or # LF
772     $self->{next_char} == 0x000B or # VT
773     $self->{next_char} == 0x000C or # FF
774     $self->{next_char} == 0x0020 or # SP
775     $self->{next_char} == 0x003E or # >
776     $self->{next_char} == 0x002F or # /
777     $self->{next_char} == -1) {
778 wakaba 1.77
779     $Whatpm::HTML::Debug::cp_pass->(26) if $Whatpm::HTML::Debug::cp_pass;
780     BEGIN {
781     $Whatpm::HTML::Debug::cp->{26} = 1;
782     }
783    
784 wakaba 1.76 $self->{next_char} = shift @next_char; # reconsume
785 wakaba 1.1 unshift @{$self->{char}}, (@next_char);
786 wakaba 1.59 $self->{state} = DATA_STATE;
787 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '</'});
788 wakaba 1.1 redo A;
789 wakaba 1.23 } else {
790 wakaba 1.77
791     $Whatpm::HTML::Debug::cp_pass->(27) if $Whatpm::HTML::Debug::cp_pass;
792     BEGIN {
793     $Whatpm::HTML::Debug::cp->{27} = 1;
794     }
795    
796 wakaba 1.76 $self->{next_char} = shift @next_char;
797 wakaba 1.23 unshift @{$self->{char}}, (@next_char);
798     # and consume...
799 wakaba 1.1 }
800 wakaba 1.23 } else {
801     ## No start tag token has ever been emitted
802 wakaba 1.77
803     $Whatpm::HTML::Debug::cp_pass->(28) if $Whatpm::HTML::Debug::cp_pass;
804     BEGIN {
805     $Whatpm::HTML::Debug::cp->{28} = 1;
806     }
807    
808 wakaba 1.23 # next-input-character is already done
809 wakaba 1.59 $self->{state} = DATA_STATE;
810 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '</'});
811 wakaba 1.1 redo A;
812     }
813     }
814    
815 wakaba 1.76 if (0x0041 <= $self->{next_char} and
816     $self->{next_char} <= 0x005A) { # A..Z
817 wakaba 1.77
818     $Whatpm::HTML::Debug::cp_pass->(29) if $Whatpm::HTML::Debug::cp_pass;
819     BEGIN {
820     $Whatpm::HTML::Debug::cp->{29} = 1;
821     }
822    
823 wakaba 1.57 $self->{current_token} = {type => END_TAG_TOKEN,
824 wakaba 1.76 tag_name => chr ($self->{next_char} + 0x0020)};
825 wakaba 1.59 $self->{state} = TAG_NAME_STATE;
826 wakaba 1.1
827     if (@{$self->{char}}) {
828 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
829 wakaba 1.1 } else {
830 wakaba 1.76 $self->{set_next_char}->($self);
831 wakaba 1.1 }
832    
833     redo A;
834 wakaba 1.76 } elsif (0x0061 <= $self->{next_char} and
835     $self->{next_char} <= 0x007A) { # a..z
836 wakaba 1.77
837     $Whatpm::HTML::Debug::cp_pass->(30) if $Whatpm::HTML::Debug::cp_pass;
838     BEGIN {
839     $Whatpm::HTML::Debug::cp->{30} = 1;
840     }
841    
842 wakaba 1.57 $self->{current_token} = {type => END_TAG_TOKEN,
843 wakaba 1.76 tag_name => chr ($self->{next_char})};
844 wakaba 1.59 $self->{state} = TAG_NAME_STATE;
845 wakaba 1.1
846     if (@{$self->{char}}) {
847 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
848 wakaba 1.1 } else {
849 wakaba 1.76 $self->{set_next_char}->($self);
850 wakaba 1.1 }
851    
852     redo A;
853 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
854 wakaba 1.77
855     $Whatpm::HTML::Debug::cp_pass->(31) if $Whatpm::HTML::Debug::cp_pass;
856     BEGIN {
857     $Whatpm::HTML::Debug::cp->{31} = 1;
858     }
859    
860 wakaba 1.3 $self->{parse_error}-> (type => 'empty end tag');
861 wakaba 1.59 $self->{state} = DATA_STATE;
862 wakaba 1.1
863     if (@{$self->{char}}) {
864 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
865 wakaba 1.1 } else {
866 wakaba 1.76 $self->{set_next_char}->($self);
867 wakaba 1.1 }
868    
869     redo A;
870 wakaba 1.76 } elsif ($self->{next_char} == -1) {
871 wakaba 1.77
872     $Whatpm::HTML::Debug::cp_pass->(32) if $Whatpm::HTML::Debug::cp_pass;
873     BEGIN {
874     $Whatpm::HTML::Debug::cp->{32} = 1;
875     }
876    
877 wakaba 1.3 $self->{parse_error}-> (type => 'bare etago');
878 wakaba 1.59 $self->{state} = DATA_STATE;
879 wakaba 1.1 # reconsume
880    
881 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '</'});
882 wakaba 1.1
883     redo A;
884     } else {
885 wakaba 1.77
886     $Whatpm::HTML::Debug::cp_pass->(33) if $Whatpm::HTML::Debug::cp_pass;
887     BEGIN {
888     $Whatpm::HTML::Debug::cp->{33} = 1;
889     }
890    
891 wakaba 1.3 $self->{parse_error}-> (type => 'bogus end tag');
892 wakaba 1.59 $self->{state} = BOGUS_COMMENT_STATE;
893 wakaba 1.76 ## $self->{next_char} is intentionally left as is
894 wakaba 1.1 redo A;
895     }
896 wakaba 1.59 } elsif ($self->{state} == TAG_NAME_STATE) {
897 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
898     $self->{next_char} == 0x000A or # LF
899     $self->{next_char} == 0x000B or # VT
900     $self->{next_char} == 0x000C or # FF
901     $self->{next_char} == 0x0020) { # SP
902 wakaba 1.77
903     $Whatpm::HTML::Debug::cp_pass->(34) if $Whatpm::HTML::Debug::cp_pass;
904     BEGIN {
905     $Whatpm::HTML::Debug::cp->{34} = 1;
906     }
907    
908 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
909 wakaba 1.1
910     if (@{$self->{char}}) {
911 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
912 wakaba 1.1 } else {
913 wakaba 1.76 $self->{set_next_char}->($self);
914 wakaba 1.1 }
915    
916     redo A;
917 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
918 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
919 wakaba 1.77
920     $Whatpm::HTML::Debug::cp_pass->(35) if $Whatpm::HTML::Debug::cp_pass;
921     BEGIN {
922     $Whatpm::HTML::Debug::cp->{35} = 1;
923     }
924    
925 wakaba 1.28 $self->{current_token}->{first_start_tag}
926     = not defined $self->{last_emitted_start_tag_name};
927 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
928 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
929 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
930 wakaba 1.78 #if ($self->{current_token}->{attributes}) {
931     # ## NOTE: This should never be reached.
932     # !!! cp (36);
933     # !!! parse-error (type => 'end tag attribute');
934     #} else {
935 wakaba 1.77
936     $Whatpm::HTML::Debug::cp_pass->(37) if $Whatpm::HTML::Debug::cp_pass;
937     BEGIN {
938     $Whatpm::HTML::Debug::cp->{37} = 1;
939     }
940    
941 wakaba 1.78 #}
942 wakaba 1.1 } else {
943     die "$0: $self->{current_token}->{type}: Unknown token type";
944     }
945 wakaba 1.59 $self->{state} = DATA_STATE;
946 wakaba 1.1
947     if (@{$self->{char}}) {
948 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
949 wakaba 1.1 } else {
950 wakaba 1.76 $self->{set_next_char}->($self);
951 wakaba 1.1 }
952    
953    
954     return ($self->{current_token}); # start tag or end tag
955    
956     redo A;
957 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
958     $self->{next_char} <= 0x005A) { # A..Z
959 wakaba 1.77
960     $Whatpm::HTML::Debug::cp_pass->(38) if $Whatpm::HTML::Debug::cp_pass;
961     BEGIN {
962     $Whatpm::HTML::Debug::cp->{38} = 1;
963     }
964    
965 wakaba 1.76 $self->{current_token}->{tag_name} .= chr ($self->{next_char} + 0x0020);
966 wakaba 1.1 # start tag or end tag
967     ## Stay in this state
968    
969     if (@{$self->{char}}) {
970 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
971 wakaba 1.1 } else {
972 wakaba 1.76 $self->{set_next_char}->($self);
973 wakaba 1.1 }
974    
975     redo A;
976 wakaba 1.76 } elsif ($self->{next_char} == -1) {
977 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
978 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
979 wakaba 1.77
980     $Whatpm::HTML::Debug::cp_pass->(39) if $Whatpm::HTML::Debug::cp_pass;
981     BEGIN {
982     $Whatpm::HTML::Debug::cp->{39} = 1;
983     }
984    
985 wakaba 1.28 $self->{current_token}->{first_start_tag}
986     = not defined $self->{last_emitted_start_tag_name};
987 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
988 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
989 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
990 wakaba 1.78 #if ($self->{current_token}->{attributes}) {
991     # ## NOTE: This state should never be reached.
992     # !!! cp (40);
993     # !!! parse-error (type => 'end tag attribute');
994     #} else {
995 wakaba 1.77
996     $Whatpm::HTML::Debug::cp_pass->(41) if $Whatpm::HTML::Debug::cp_pass;
997     BEGIN {
998     $Whatpm::HTML::Debug::cp->{41} = 1;
999     }
1000    
1001 wakaba 1.78 #}
1002 wakaba 1.1 } else {
1003     die "$0: $self->{current_token}->{type}: Unknown token type";
1004     }
1005 wakaba 1.59 $self->{state} = DATA_STATE;
1006 wakaba 1.1 # reconsume
1007    
1008     return ($self->{current_token}); # start tag or end tag
1009    
1010     redo A;
1011 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
1012 wakaba 1.1
1013     if (@{$self->{char}}) {
1014 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1015 wakaba 1.1 } else {
1016 wakaba 1.76 $self->{set_next_char}->($self);
1017 wakaba 1.1 }
1018    
1019 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
1020 wakaba 1.57 $self->{current_token}->{type} == START_TAG_TOKEN and
1021 wakaba 1.1 $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
1022     # permitted slash
1023 wakaba 1.77
1024     $Whatpm::HTML::Debug::cp_pass->(42) if $Whatpm::HTML::Debug::cp_pass;
1025     BEGIN {
1026     $Whatpm::HTML::Debug::cp->{42} = 1;
1027     }
1028    
1029 wakaba 1.1 #
1030     } else {
1031 wakaba 1.77
1032     $Whatpm::HTML::Debug::cp_pass->(43) if $Whatpm::HTML::Debug::cp_pass;
1033     BEGIN {
1034     $Whatpm::HTML::Debug::cp->{43} = 1;
1035     }
1036    
1037 wakaba 1.3 $self->{parse_error}-> (type => 'nestc');
1038 wakaba 1.1 }
1039 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1040 wakaba 1.1 # next-input-character is already done
1041     redo A;
1042     } else {
1043 wakaba 1.77
1044     $Whatpm::HTML::Debug::cp_pass->(44) if $Whatpm::HTML::Debug::cp_pass;
1045     BEGIN {
1046     $Whatpm::HTML::Debug::cp->{44} = 1;
1047     }
1048    
1049 wakaba 1.76 $self->{current_token}->{tag_name} .= chr $self->{next_char};
1050 wakaba 1.1 # start tag or end tag
1051     ## Stay in the state
1052    
1053     if (@{$self->{char}}) {
1054 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1055 wakaba 1.1 } else {
1056 wakaba 1.76 $self->{set_next_char}->($self);
1057 wakaba 1.1 }
1058    
1059     redo A;
1060     }
1061 wakaba 1.59 } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {
1062 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
1063     $self->{next_char} == 0x000A or # LF
1064     $self->{next_char} == 0x000B or # VT
1065     $self->{next_char} == 0x000C or # FF
1066     $self->{next_char} == 0x0020) { # SP
1067 wakaba 1.77
1068     $Whatpm::HTML::Debug::cp_pass->(45) if $Whatpm::HTML::Debug::cp_pass;
1069     BEGIN {
1070     $Whatpm::HTML::Debug::cp->{45} = 1;
1071     }
1072    
1073 wakaba 1.1 ## Stay in the state
1074    
1075     if (@{$self->{char}}) {
1076 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1077 wakaba 1.1 } else {
1078 wakaba 1.76 $self->{set_next_char}->($self);
1079 wakaba 1.1 }
1080    
1081     redo A;
1082 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
1083 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1084 wakaba 1.77
1085     $Whatpm::HTML::Debug::cp_pass->(46) if $Whatpm::HTML::Debug::cp_pass;
1086     BEGIN {
1087     $Whatpm::HTML::Debug::cp->{46} = 1;
1088     }
1089    
1090 wakaba 1.28 $self->{current_token}->{first_start_tag}
1091     = not defined $self->{last_emitted_start_tag_name};
1092 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1093 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1094 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1095 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1096 wakaba 1.77
1097     $Whatpm::HTML::Debug::cp_pass->(47) if $Whatpm::HTML::Debug::cp_pass;
1098     BEGIN {
1099     $Whatpm::HTML::Debug::cp->{47} = 1;
1100     }
1101    
1102 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1103 wakaba 1.77 } else {
1104    
1105     $Whatpm::HTML::Debug::cp_pass->(48) if $Whatpm::HTML::Debug::cp_pass;
1106     BEGIN {
1107     $Whatpm::HTML::Debug::cp->{48} = 1;
1108     }
1109    
1110 wakaba 1.1 }
1111     } else {
1112     die "$0: $self->{current_token}->{type}: Unknown token type";
1113     }
1114 wakaba 1.59 $self->{state} = DATA_STATE;
1115 wakaba 1.1
1116     if (@{$self->{char}}) {
1117 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1118 wakaba 1.1 } else {
1119 wakaba 1.76 $self->{set_next_char}->($self);
1120 wakaba 1.1 }
1121    
1122    
1123     return ($self->{current_token}); # start tag or end tag
1124    
1125     redo A;
1126 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
1127     $self->{next_char} <= 0x005A) { # A..Z
1128 wakaba 1.77
1129     $Whatpm::HTML::Debug::cp_pass->(49) if $Whatpm::HTML::Debug::cp_pass;
1130     BEGIN {
1131     $Whatpm::HTML::Debug::cp->{49} = 1;
1132     }
1133    
1134 wakaba 1.76 $self->{current_attribute} = {name => chr ($self->{next_char} + 0x0020),
1135 wakaba 1.1 value => ''};
1136 wakaba 1.59 $self->{state} = ATTRIBUTE_NAME_STATE;
1137 wakaba 1.1
1138     if (@{$self->{char}}) {
1139 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1140 wakaba 1.1 } else {
1141 wakaba 1.76 $self->{set_next_char}->($self);
1142 wakaba 1.1 }
1143    
1144     redo A;
1145 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
1146 wakaba 1.1
1147     if (@{$self->{char}}) {
1148 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1149 wakaba 1.1 } else {
1150 wakaba 1.76 $self->{set_next_char}->($self);
1151 wakaba 1.1 }
1152    
1153 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
1154 wakaba 1.57 $self->{current_token}->{type} == START_TAG_TOKEN and
1155 wakaba 1.1 $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
1156     # permitted slash
1157 wakaba 1.77
1158     $Whatpm::HTML::Debug::cp_pass->(50) if $Whatpm::HTML::Debug::cp_pass;
1159     BEGIN {
1160     $Whatpm::HTML::Debug::cp->{50} = 1;
1161     }
1162    
1163 wakaba 1.1 #
1164     } else {
1165 wakaba 1.77
1166     $Whatpm::HTML::Debug::cp_pass->(51) if $Whatpm::HTML::Debug::cp_pass;
1167     BEGIN {
1168     $Whatpm::HTML::Debug::cp->{51} = 1;
1169     }
1170    
1171 wakaba 1.3 $self->{parse_error}-> (type => 'nestc');
1172 wakaba 1.1 }
1173     ## Stay in the state
1174     # next-input-character is already done
1175     redo A;
1176 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1177 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
1178 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1179 wakaba 1.77
1180     $Whatpm::HTML::Debug::cp_pass->(52) if $Whatpm::HTML::Debug::cp_pass;
1181     BEGIN {
1182     $Whatpm::HTML::Debug::cp->{52} = 1;
1183     }
1184    
1185 wakaba 1.28 $self->{current_token}->{first_start_tag}
1186     = not defined $self->{last_emitted_start_tag_name};
1187 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1188 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1189 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1190 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1191 wakaba 1.77
1192     $Whatpm::HTML::Debug::cp_pass->(53) if $Whatpm::HTML::Debug::cp_pass;
1193     BEGIN {
1194     $Whatpm::HTML::Debug::cp->{53} = 1;
1195     }
1196    
1197 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1198 wakaba 1.77 } else {
1199    
1200     $Whatpm::HTML::Debug::cp_pass->(54) if $Whatpm::HTML::Debug::cp_pass;
1201     BEGIN {
1202     $Whatpm::HTML::Debug::cp->{54} = 1;
1203     }
1204    
1205 wakaba 1.1 }
1206     } else {
1207     die "$0: $self->{current_token}->{type}: Unknown token type";
1208     }
1209 wakaba 1.59 $self->{state} = DATA_STATE;
1210 wakaba 1.1 # reconsume
1211    
1212     return ($self->{current_token}); # start tag or end tag
1213    
1214     redo A;
1215     } else {
1216 wakaba 1.72 if ({
1217     0x0022 => 1, # "
1218     0x0027 => 1, # '
1219     0x003D => 1, # =
1220 wakaba 1.76 }->{$self->{next_char}}) {
1221 wakaba 1.77
1222     $Whatpm::HTML::Debug::cp_pass->(55) if $Whatpm::HTML::Debug::cp_pass;
1223     BEGIN {
1224     $Whatpm::HTML::Debug::cp->{55} = 1;
1225     }
1226    
1227 wakaba 1.72 $self->{parse_error}-> (type => 'bad attribute name');
1228 wakaba 1.77 } else {
1229    
1230     $Whatpm::HTML::Debug::cp_pass->(56) if $Whatpm::HTML::Debug::cp_pass;
1231     BEGIN {
1232     $Whatpm::HTML::Debug::cp->{56} = 1;
1233     }
1234    
1235 wakaba 1.72 }
1236 wakaba 1.76 $self->{current_attribute} = {name => chr ($self->{next_char}),
1237 wakaba 1.1 value => ''};
1238 wakaba 1.59 $self->{state} = ATTRIBUTE_NAME_STATE;
1239 wakaba 1.1
1240     if (@{$self->{char}}) {
1241 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1242 wakaba 1.1 } else {
1243 wakaba 1.76 $self->{set_next_char}->($self);
1244 wakaba 1.1 }
1245    
1246     redo A;
1247     }
1248 wakaba 1.59 } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {
1249 wakaba 1.1 my $before_leave = sub {
1250     if (exists $self->{current_token}->{attributes} # start tag or end tag
1251     ->{$self->{current_attribute}->{name}}) { # MUST
1252 wakaba 1.77
1253     $Whatpm::HTML::Debug::cp_pass->(57) if $Whatpm::HTML::Debug::cp_pass;
1254     BEGIN {
1255     $Whatpm::HTML::Debug::cp->{57} = 1;
1256     }
1257    
1258 wakaba 1.40 $self->{parse_error}-> (type => 'duplicate attribute:'.$self->{current_attribute}->{name});
1259 wakaba 1.1 ## Discard $self->{current_attribute} # MUST
1260     } else {
1261 wakaba 1.77
1262     $Whatpm::HTML::Debug::cp_pass->(58) if $Whatpm::HTML::Debug::cp_pass;
1263     BEGIN {
1264     $Whatpm::HTML::Debug::cp->{58} = 1;
1265     }
1266    
1267 wakaba 1.1 $self->{current_token}->{attributes}->{$self->{current_attribute}->{name}}
1268     = $self->{current_attribute};
1269     }
1270     }; # $before_leave
1271    
1272 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
1273     $self->{next_char} == 0x000A or # LF
1274     $self->{next_char} == 0x000B or # VT
1275     $self->{next_char} == 0x000C or # FF
1276     $self->{next_char} == 0x0020) { # SP
1277 wakaba 1.77
1278     $Whatpm::HTML::Debug::cp_pass->(59) if $Whatpm::HTML::Debug::cp_pass;
1279     BEGIN {
1280     $Whatpm::HTML::Debug::cp->{59} = 1;
1281     }
1282    
1283 wakaba 1.1 $before_leave->();
1284 wakaba 1.59 $self->{state} = AFTER_ATTRIBUTE_NAME_STATE;
1285 wakaba 1.1
1286     if (@{$self->{char}}) {
1287 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1288 wakaba 1.1 } else {
1289 wakaba 1.76 $self->{set_next_char}->($self);
1290 wakaba 1.1 }
1291    
1292     redo A;
1293 wakaba 1.76 } elsif ($self->{next_char} == 0x003D) { # =
1294 wakaba 1.77
1295     $Whatpm::HTML::Debug::cp_pass->(60) if $Whatpm::HTML::Debug::cp_pass;
1296     BEGIN {
1297     $Whatpm::HTML::Debug::cp->{60} = 1;
1298     }
1299    
1300 wakaba 1.1 $before_leave->();
1301 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;
1302 wakaba 1.1
1303     if (@{$self->{char}}) {
1304 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1305 wakaba 1.1 } else {
1306 wakaba 1.76 $self->{set_next_char}->($self);
1307 wakaba 1.1 }
1308    
1309     redo A;
1310 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
1311 wakaba 1.1 $before_leave->();
1312 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1313 wakaba 1.77
1314     $Whatpm::HTML::Debug::cp_pass->(61) if $Whatpm::HTML::Debug::cp_pass;
1315     BEGIN {
1316     $Whatpm::HTML::Debug::cp->{61} = 1;
1317     }
1318    
1319 wakaba 1.28 $self->{current_token}->{first_start_tag}
1320     = not defined $self->{last_emitted_start_tag_name};
1321 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1322 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1323 wakaba 1.77
1324     $Whatpm::HTML::Debug::cp_pass->(62) if $Whatpm::HTML::Debug::cp_pass;
1325     BEGIN {
1326     $Whatpm::HTML::Debug::cp->{62} = 1;
1327     }
1328    
1329 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1330 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1331 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1332 wakaba 1.1 }
1333     } else {
1334     die "$0: $self->{current_token}->{type}: Unknown token type";
1335     }
1336 wakaba 1.59 $self->{state} = DATA_STATE;
1337 wakaba 1.1
1338     if (@{$self->{char}}) {
1339 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1340 wakaba 1.1 } else {
1341 wakaba 1.76 $self->{set_next_char}->($self);
1342 wakaba 1.1 }
1343    
1344    
1345     return ($self->{current_token}); # start tag or end tag
1346    
1347     redo A;
1348 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
1349     $self->{next_char} <= 0x005A) { # A..Z
1350 wakaba 1.77
1351     $Whatpm::HTML::Debug::cp_pass->(63) if $Whatpm::HTML::Debug::cp_pass;
1352     BEGIN {
1353     $Whatpm::HTML::Debug::cp->{63} = 1;
1354     }
1355    
1356 wakaba 1.76 $self->{current_attribute}->{name} .= chr ($self->{next_char} + 0x0020);
1357 wakaba 1.1 ## Stay in the state
1358    
1359     if (@{$self->{char}}) {
1360 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1361 wakaba 1.1 } else {
1362 wakaba 1.76 $self->{set_next_char}->($self);
1363 wakaba 1.1 }
1364    
1365     redo A;
1366 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
1367 wakaba 1.1 $before_leave->();
1368    
1369     if (@{$self->{char}}) {
1370 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1371 wakaba 1.1 } else {
1372 wakaba 1.76 $self->{set_next_char}->($self);
1373 wakaba 1.1 }
1374    
1375 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
1376 wakaba 1.57 $self->{current_token}->{type} == START_TAG_TOKEN and
1377 wakaba 1.1 $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
1378     # permitted slash
1379 wakaba 1.77
1380     $Whatpm::HTML::Debug::cp_pass->(64) if $Whatpm::HTML::Debug::cp_pass;
1381     BEGIN {
1382     $Whatpm::HTML::Debug::cp->{64} = 1;
1383     }
1384    
1385 wakaba 1.1 #
1386     } else {
1387 wakaba 1.77
1388     $Whatpm::HTML::Debug::cp_pass->(65) if $Whatpm::HTML::Debug::cp_pass;
1389     BEGIN {
1390     $Whatpm::HTML::Debug::cp->{65} = 1;
1391     }
1392    
1393 wakaba 1.3 $self->{parse_error}-> (type => 'nestc');
1394 wakaba 1.1 }
1395 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1396 wakaba 1.1 # next-input-character is already done
1397     redo A;
1398 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1399 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
1400 wakaba 1.1 $before_leave->();
1401 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1402 wakaba 1.77
1403     $Whatpm::HTML::Debug::cp_pass->(66) if $Whatpm::HTML::Debug::cp_pass;
1404     BEGIN {
1405     $Whatpm::HTML::Debug::cp->{66} = 1;
1406     }
1407    
1408 wakaba 1.28 $self->{current_token}->{first_start_tag}
1409     = not defined $self->{last_emitted_start_tag_name};
1410 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1411 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1412 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1413 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1414 wakaba 1.77
1415     $Whatpm::HTML::Debug::cp_pass->(67) if $Whatpm::HTML::Debug::cp_pass;
1416     BEGIN {
1417     $Whatpm::HTML::Debug::cp->{67} = 1;
1418     }
1419    
1420 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1421 wakaba 1.77 } else {
1422 wakaba 1.78 ## NOTE: This state should never be reached.
1423 wakaba 1.77
1424     $Whatpm::HTML::Debug::cp_pass->(68) if $Whatpm::HTML::Debug::cp_pass;
1425     BEGIN {
1426     $Whatpm::HTML::Debug::cp->{68} = 1;
1427     }
1428    
1429 wakaba 1.1 }
1430     } else {
1431     die "$0: $self->{current_token}->{type}: Unknown token type";
1432     }
1433 wakaba 1.59 $self->{state} = DATA_STATE;
1434 wakaba 1.1 # reconsume
1435    
1436     return ($self->{current_token}); # start tag or end tag
1437    
1438     redo A;
1439     } else {
1440 wakaba 1.76 if ($self->{next_char} == 0x0022 or # "
1441     $self->{next_char} == 0x0027) { # '
1442 wakaba 1.77
1443     $Whatpm::HTML::Debug::cp_pass->(69) if $Whatpm::HTML::Debug::cp_pass;
1444     BEGIN {
1445     $Whatpm::HTML::Debug::cp->{69} = 1;
1446     }
1447    
1448 wakaba 1.72 $self->{parse_error}-> (type => 'bad attribute name');
1449 wakaba 1.77 } else {
1450    
1451     $Whatpm::HTML::Debug::cp_pass->(70) if $Whatpm::HTML::Debug::cp_pass;
1452     BEGIN {
1453     $Whatpm::HTML::Debug::cp->{70} = 1;
1454     }
1455    
1456 wakaba 1.72 }
1457 wakaba 1.76 $self->{current_attribute}->{name} .= chr ($self->{next_char});
1458 wakaba 1.1 ## Stay in the state
1459    
1460     if (@{$self->{char}}) {
1461 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1462 wakaba 1.1 } else {
1463 wakaba 1.76 $self->{set_next_char}->($self);
1464 wakaba 1.1 }
1465    
1466     redo A;
1467     }
1468 wakaba 1.59 } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {
1469 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
1470     $self->{next_char} == 0x000A or # LF
1471     $self->{next_char} == 0x000B or # VT
1472     $self->{next_char} == 0x000C or # FF
1473     $self->{next_char} == 0x0020) { # SP
1474 wakaba 1.77
1475     $Whatpm::HTML::Debug::cp_pass->(71) if $Whatpm::HTML::Debug::cp_pass;
1476     BEGIN {
1477     $Whatpm::HTML::Debug::cp->{71} = 1;
1478     }
1479    
1480 wakaba 1.1 ## Stay in the state
1481    
1482     if (@{$self->{char}}) {
1483 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1484 wakaba 1.1 } else {
1485 wakaba 1.76 $self->{set_next_char}->($self);
1486 wakaba 1.1 }
1487    
1488     redo A;
1489 wakaba 1.76 } elsif ($self->{next_char} == 0x003D) { # =
1490 wakaba 1.77
1491     $Whatpm::HTML::Debug::cp_pass->(72) if $Whatpm::HTML::Debug::cp_pass;
1492     BEGIN {
1493     $Whatpm::HTML::Debug::cp->{72} = 1;
1494     }
1495    
1496 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;
1497 wakaba 1.1
1498     if (@{$self->{char}}) {
1499 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1500 wakaba 1.1 } else {
1501 wakaba 1.76 $self->{set_next_char}->($self);
1502 wakaba 1.1 }
1503    
1504     redo A;
1505 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
1506 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1507 wakaba 1.77
1508     $Whatpm::HTML::Debug::cp_pass->(73) if $Whatpm::HTML::Debug::cp_pass;
1509     BEGIN {
1510     $Whatpm::HTML::Debug::cp->{73} = 1;
1511     }
1512    
1513 wakaba 1.28 $self->{current_token}->{first_start_tag}
1514     = not defined $self->{last_emitted_start_tag_name};
1515 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1516 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1517 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1518 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1519 wakaba 1.77
1520     $Whatpm::HTML::Debug::cp_pass->(74) if $Whatpm::HTML::Debug::cp_pass;
1521     BEGIN {
1522     $Whatpm::HTML::Debug::cp->{74} = 1;
1523     }
1524    
1525 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1526 wakaba 1.77 } else {
1527 wakaba 1.78 ## NOTE: This state should never be reached.
1528 wakaba 1.77
1529     $Whatpm::HTML::Debug::cp_pass->(75) if $Whatpm::HTML::Debug::cp_pass;
1530     BEGIN {
1531     $Whatpm::HTML::Debug::cp->{75} = 1;
1532     }
1533    
1534 wakaba 1.1 }
1535     } else {
1536     die "$0: $self->{current_token}->{type}: Unknown token type";
1537     }
1538 wakaba 1.59 $self->{state} = DATA_STATE;
1539 wakaba 1.1
1540     if (@{$self->{char}}) {
1541 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1542 wakaba 1.1 } else {
1543 wakaba 1.76 $self->{set_next_char}->($self);
1544 wakaba 1.1 }
1545    
1546    
1547     return ($self->{current_token}); # start tag or end tag
1548    
1549     redo A;
1550 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
1551     $self->{next_char} <= 0x005A) { # A..Z
1552 wakaba 1.77
1553     $Whatpm::HTML::Debug::cp_pass->(76) if $Whatpm::HTML::Debug::cp_pass;
1554     BEGIN {
1555     $Whatpm::HTML::Debug::cp->{76} = 1;
1556     }
1557    
1558 wakaba 1.76 $self->{current_attribute} = {name => chr ($self->{next_char} + 0x0020),
1559 wakaba 1.1 value => ''};
1560 wakaba 1.59 $self->{state} = ATTRIBUTE_NAME_STATE;
1561 wakaba 1.1
1562     if (@{$self->{char}}) {
1563 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1564 wakaba 1.1 } else {
1565 wakaba 1.76 $self->{set_next_char}->($self);
1566 wakaba 1.1 }
1567    
1568     redo A;
1569 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
1570 wakaba 1.1
1571     if (@{$self->{char}}) {
1572 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1573 wakaba 1.1 } else {
1574 wakaba 1.76 $self->{set_next_char}->($self);
1575 wakaba 1.1 }
1576    
1577 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
1578 wakaba 1.57 $self->{current_token}->{type} == START_TAG_TOKEN and
1579 wakaba 1.1 $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
1580     # permitted slash
1581 wakaba 1.77
1582     $Whatpm::HTML::Debug::cp_pass->(77) if $Whatpm::HTML::Debug::cp_pass;
1583     BEGIN {
1584     $Whatpm::HTML::Debug::cp->{77} = 1;
1585     }
1586    
1587 wakaba 1.1 #
1588     } else {
1589 wakaba 1.77
1590     $Whatpm::HTML::Debug::cp_pass->(78) if $Whatpm::HTML::Debug::cp_pass;
1591     BEGIN {
1592     $Whatpm::HTML::Debug::cp->{78} = 1;
1593     }
1594    
1595 wakaba 1.3 $self->{parse_error}-> (type => 'nestc');
1596 wakaba 1.33 ## TODO: Different error type for <aa / bb> than <aa/>
1597 wakaba 1.1 }
1598 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1599 wakaba 1.1 # next-input-character is already done
1600     redo A;
1601 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1602 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
1603 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1604 wakaba 1.77
1605     $Whatpm::HTML::Debug::cp_pass->(79) if $Whatpm::HTML::Debug::cp_pass;
1606     BEGIN {
1607     $Whatpm::HTML::Debug::cp->{79} = 1;
1608     }
1609    
1610 wakaba 1.28 $self->{current_token}->{first_start_tag}
1611     = not defined $self->{last_emitted_start_tag_name};
1612 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1613 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1614 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1615 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1616 wakaba 1.77
1617     $Whatpm::HTML::Debug::cp_pass->(80) if $Whatpm::HTML::Debug::cp_pass;
1618     BEGIN {
1619     $Whatpm::HTML::Debug::cp->{80} = 1;
1620     }
1621    
1622 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1623 wakaba 1.77 } else {
1624 wakaba 1.78 ## NOTE: This state should never be reached.
1625 wakaba 1.77
1626     $Whatpm::HTML::Debug::cp_pass->(81) if $Whatpm::HTML::Debug::cp_pass;
1627     BEGIN {
1628     $Whatpm::HTML::Debug::cp->{81} = 1;
1629     }
1630    
1631 wakaba 1.1 }
1632     } else {
1633     die "$0: $self->{current_token}->{type}: Unknown token type";
1634     }
1635 wakaba 1.59 $self->{state} = DATA_STATE;
1636 wakaba 1.1 # reconsume
1637    
1638     return ($self->{current_token}); # start tag or end tag
1639    
1640     redo A;
1641     } else {
1642 wakaba 1.77
1643     $Whatpm::HTML::Debug::cp_pass->(82) if $Whatpm::HTML::Debug::cp_pass;
1644     BEGIN {
1645     $Whatpm::HTML::Debug::cp->{82} = 1;
1646     }
1647    
1648 wakaba 1.76 $self->{current_attribute} = {name => chr ($self->{next_char}),
1649 wakaba 1.1 value => ''};
1650 wakaba 1.59 $self->{state} = ATTRIBUTE_NAME_STATE;
1651 wakaba 1.1
1652     if (@{$self->{char}}) {
1653 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1654 wakaba 1.1 } else {
1655 wakaba 1.76 $self->{set_next_char}->($self);
1656 wakaba 1.1 }
1657    
1658     redo A;
1659     }
1660 wakaba 1.59 } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {
1661 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
1662     $self->{next_char} == 0x000A or # LF
1663     $self->{next_char} == 0x000B or # VT
1664     $self->{next_char} == 0x000C or # FF
1665     $self->{next_char} == 0x0020) { # SP
1666 wakaba 1.77
1667     $Whatpm::HTML::Debug::cp_pass->(83) if $Whatpm::HTML::Debug::cp_pass;
1668     BEGIN {
1669     $Whatpm::HTML::Debug::cp->{83} = 1;
1670     }
1671    
1672 wakaba 1.1 ## Stay in the state
1673    
1674     if (@{$self->{char}}) {
1675 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1676 wakaba 1.1 } else {
1677 wakaba 1.76 $self->{set_next_char}->($self);
1678 wakaba 1.1 }
1679    
1680     redo A;
1681 wakaba 1.76 } elsif ($self->{next_char} == 0x0022) { # "
1682 wakaba 1.77
1683     $Whatpm::HTML::Debug::cp_pass->(84) if $Whatpm::HTML::Debug::cp_pass;
1684     BEGIN {
1685     $Whatpm::HTML::Debug::cp->{84} = 1;
1686     }
1687    
1688 wakaba 1.59 $self->{state} = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;
1689 wakaba 1.1
1690     if (@{$self->{char}}) {
1691 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1692 wakaba 1.1 } else {
1693 wakaba 1.76 $self->{set_next_char}->($self);
1694 wakaba 1.1 }
1695    
1696     redo A;
1697 wakaba 1.76 } elsif ($self->{next_char} == 0x0026) { # &
1698 wakaba 1.77
1699     $Whatpm::HTML::Debug::cp_pass->(85) if $Whatpm::HTML::Debug::cp_pass;
1700     BEGIN {
1701     $Whatpm::HTML::Debug::cp->{85} = 1;
1702     }
1703    
1704 wakaba 1.59 $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;
1705 wakaba 1.1 ## reconsume
1706     redo A;
1707 wakaba 1.76 } elsif ($self->{next_char} == 0x0027) { # '
1708 wakaba 1.77
1709     $Whatpm::HTML::Debug::cp_pass->(86) if $Whatpm::HTML::Debug::cp_pass;
1710     BEGIN {
1711     $Whatpm::HTML::Debug::cp->{86} = 1;
1712     }
1713    
1714 wakaba 1.59 $self->{state} = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;
1715 wakaba 1.1
1716     if (@{$self->{char}}) {
1717 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1718 wakaba 1.1 } else {
1719 wakaba 1.76 $self->{set_next_char}->($self);
1720 wakaba 1.1 }
1721    
1722     redo A;
1723 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
1724 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1725 wakaba 1.77
1726     $Whatpm::HTML::Debug::cp_pass->(87) if $Whatpm::HTML::Debug::cp_pass;
1727     BEGIN {
1728     $Whatpm::HTML::Debug::cp->{87} = 1;
1729     }
1730    
1731 wakaba 1.28 $self->{current_token}->{first_start_tag}
1732     = not defined $self->{last_emitted_start_tag_name};
1733 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1734 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1735 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1736 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1737 wakaba 1.77
1738     $Whatpm::HTML::Debug::cp_pass->(88) if $Whatpm::HTML::Debug::cp_pass;
1739     BEGIN {
1740     $Whatpm::HTML::Debug::cp->{88} = 1;
1741     }
1742    
1743 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1744 wakaba 1.77 } else {
1745 wakaba 1.78 ## NOTE: This state should never be reached.
1746 wakaba 1.77
1747     $Whatpm::HTML::Debug::cp_pass->(89) if $Whatpm::HTML::Debug::cp_pass;
1748     BEGIN {
1749     $Whatpm::HTML::Debug::cp->{89} = 1;
1750     }
1751    
1752 wakaba 1.1 }
1753     } else {
1754     die "$0: $self->{current_token}->{type}: Unknown token type";
1755     }
1756 wakaba 1.59 $self->{state} = DATA_STATE;
1757 wakaba 1.1
1758     if (@{$self->{char}}) {
1759 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1760 wakaba 1.1 } else {
1761 wakaba 1.76 $self->{set_next_char}->($self);
1762 wakaba 1.1 }
1763    
1764    
1765     return ($self->{current_token}); # start tag or end tag
1766    
1767     redo A;
1768 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1769 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
1770 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1771 wakaba 1.77
1772     $Whatpm::HTML::Debug::cp_pass->(90) if $Whatpm::HTML::Debug::cp_pass;
1773     BEGIN {
1774     $Whatpm::HTML::Debug::cp->{90} = 1;
1775     }
1776    
1777 wakaba 1.28 $self->{current_token}->{first_start_tag}
1778     = not defined $self->{last_emitted_start_tag_name};
1779 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1780 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1781 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1782 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1783 wakaba 1.77
1784     $Whatpm::HTML::Debug::cp_pass->(91) if $Whatpm::HTML::Debug::cp_pass;
1785     BEGIN {
1786     $Whatpm::HTML::Debug::cp->{91} = 1;
1787     }
1788    
1789 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1790 wakaba 1.77 } else {
1791 wakaba 1.78 ## NOTE: This state should never be reached.
1792 wakaba 1.77
1793     $Whatpm::HTML::Debug::cp_pass->(92) if $Whatpm::HTML::Debug::cp_pass;
1794     BEGIN {
1795     $Whatpm::HTML::Debug::cp->{92} = 1;
1796     }
1797    
1798 wakaba 1.1 }
1799     } else {
1800     die "$0: $self->{current_token}->{type}: Unknown token type";
1801     }
1802 wakaba 1.59 $self->{state} = DATA_STATE;
1803 wakaba 1.1 ## reconsume
1804    
1805     return ($self->{current_token}); # start tag or end tag
1806    
1807     redo A;
1808     } else {
1809 wakaba 1.76 if ($self->{next_char} == 0x003D) { # =
1810 wakaba 1.77
1811     $Whatpm::HTML::Debug::cp_pass->(93) if $Whatpm::HTML::Debug::cp_pass;
1812     BEGIN {
1813     $Whatpm::HTML::Debug::cp->{93} = 1;
1814     }
1815    
1816 wakaba 1.72 $self->{parse_error}-> (type => 'bad attribute value');
1817 wakaba 1.77 } else {
1818    
1819     $Whatpm::HTML::Debug::cp_pass->(94) if $Whatpm::HTML::Debug::cp_pass;
1820     BEGIN {
1821     $Whatpm::HTML::Debug::cp->{94} = 1;
1822     }
1823    
1824 wakaba 1.72 }
1825 wakaba 1.76 $self->{current_attribute}->{value} .= chr ($self->{next_char});
1826 wakaba 1.59 $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;
1827 wakaba 1.1
1828     if (@{$self->{char}}) {
1829 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1830 wakaba 1.1 } else {
1831 wakaba 1.76 $self->{set_next_char}->($self);
1832 wakaba 1.1 }
1833    
1834     redo A;
1835     }
1836 wakaba 1.59 } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {
1837 wakaba 1.76 if ($self->{next_char} == 0x0022) { # "
1838 wakaba 1.77
1839     $Whatpm::HTML::Debug::cp_pass->(95) if $Whatpm::HTML::Debug::cp_pass;
1840     BEGIN {
1841     $Whatpm::HTML::Debug::cp->{95} = 1;
1842     }
1843    
1844 wakaba 1.72 $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1845 wakaba 1.1
1846     if (@{$self->{char}}) {
1847 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1848 wakaba 1.1 } else {
1849 wakaba 1.76 $self->{set_next_char}->($self);
1850 wakaba 1.1 }
1851    
1852     redo A;
1853 wakaba 1.76 } elsif ($self->{next_char} == 0x0026) { # &
1854 wakaba 1.77
1855     $Whatpm::HTML::Debug::cp_pass->(96) if $Whatpm::HTML::Debug::cp_pass;
1856     BEGIN {
1857     $Whatpm::HTML::Debug::cp->{96} = 1;
1858     }
1859    
1860 wakaba 1.59 $self->{last_attribute_value_state} = $self->{state};
1861     $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
1862 wakaba 1.1
1863     if (@{$self->{char}}) {
1864 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1865 wakaba 1.1 } else {
1866 wakaba 1.76 $self->{set_next_char}->($self);
1867 wakaba 1.1 }
1868    
1869     redo A;
1870 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1871 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed attribute value');
1872 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1873 wakaba 1.77
1874     $Whatpm::HTML::Debug::cp_pass->(97) if $Whatpm::HTML::Debug::cp_pass;
1875     BEGIN {
1876     $Whatpm::HTML::Debug::cp->{97} = 1;
1877     }
1878    
1879 wakaba 1.28 $self->{current_token}->{first_start_tag}
1880     = not defined $self->{last_emitted_start_tag_name};
1881 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1882 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1883 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1884 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1885 wakaba 1.77
1886     $Whatpm::HTML::Debug::cp_pass->(98) if $Whatpm::HTML::Debug::cp_pass;
1887     BEGIN {
1888     $Whatpm::HTML::Debug::cp->{98} = 1;
1889     }
1890    
1891 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1892 wakaba 1.77 } else {
1893 wakaba 1.78 ## NOTE: This state should never be reached.
1894 wakaba 1.77
1895     $Whatpm::HTML::Debug::cp_pass->(99) if $Whatpm::HTML::Debug::cp_pass;
1896     BEGIN {
1897     $Whatpm::HTML::Debug::cp->{99} = 1;
1898     }
1899    
1900 wakaba 1.1 }
1901     } else {
1902     die "$0: $self->{current_token}->{type}: Unknown token type";
1903     }
1904 wakaba 1.59 $self->{state} = DATA_STATE;
1905 wakaba 1.1 ## reconsume
1906    
1907     return ($self->{current_token}); # start tag or end tag
1908    
1909     redo A;
1910     } else {
1911 wakaba 1.77
1912     $Whatpm::HTML::Debug::cp_pass->(100) if $Whatpm::HTML::Debug::cp_pass;
1913     BEGIN {
1914     $Whatpm::HTML::Debug::cp->{100} = 1;
1915     }
1916    
1917 wakaba 1.76 $self->{current_attribute}->{value} .= chr ($self->{next_char});
1918 wakaba 1.1 ## Stay in the state
1919    
1920     if (@{$self->{char}}) {
1921 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1922 wakaba 1.1 } else {
1923 wakaba 1.76 $self->{set_next_char}->($self);
1924 wakaba 1.1 }
1925    
1926     redo A;
1927     }
1928 wakaba 1.59 } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {
1929 wakaba 1.76 if ($self->{next_char} == 0x0027) { # '
1930 wakaba 1.77
1931     $Whatpm::HTML::Debug::cp_pass->(101) if $Whatpm::HTML::Debug::cp_pass;
1932     BEGIN {
1933     $Whatpm::HTML::Debug::cp->{101} = 1;
1934     }
1935    
1936 wakaba 1.72 $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1937 wakaba 1.1
1938     if (@{$self->{char}}) {
1939 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1940 wakaba 1.1 } else {
1941 wakaba 1.76 $self->{set_next_char}->($self);
1942 wakaba 1.1 }
1943    
1944     redo A;
1945 wakaba 1.76 } elsif ($self->{next_char} == 0x0026) { # &
1946 wakaba 1.77
1947     $Whatpm::HTML::Debug::cp_pass->(102) if $Whatpm::HTML::Debug::cp_pass;
1948     BEGIN {
1949     $Whatpm::HTML::Debug::cp->{102} = 1;
1950     }
1951    
1952 wakaba 1.59 $self->{last_attribute_value_state} = $self->{state};
1953     $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
1954 wakaba 1.1
1955     if (@{$self->{char}}) {
1956 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1957 wakaba 1.1 } else {
1958 wakaba 1.76 $self->{set_next_char}->($self);
1959 wakaba 1.1 }
1960    
1961     redo A;
1962 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1963 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed attribute value');
1964 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1965 wakaba 1.77
1966     $Whatpm::HTML::Debug::cp_pass->(103) if $Whatpm::HTML::Debug::cp_pass;
1967     BEGIN {
1968     $Whatpm::HTML::Debug::cp->{103} = 1;
1969     }
1970    
1971 wakaba 1.28 $self->{current_token}->{first_start_tag}
1972     = not defined $self->{last_emitted_start_tag_name};
1973 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1974 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1975 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1976 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1977 wakaba 1.77
1978     $Whatpm::HTML::Debug::cp_pass->(104) if $Whatpm::HTML::Debug::cp_pass;
1979     BEGIN {
1980     $Whatpm::HTML::Debug::cp->{104} = 1;
1981     }
1982    
1983 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1984 wakaba 1.77 } else {
1985 wakaba 1.78 ## NOTE: This state should never be reached.
1986 wakaba 1.77
1987     $Whatpm::HTML::Debug::cp_pass->(105) if $Whatpm::HTML::Debug::cp_pass;
1988     BEGIN {
1989     $Whatpm::HTML::Debug::cp->{105} = 1;
1990     }
1991    
1992 wakaba 1.1 }
1993     } else {
1994     die "$0: $self->{current_token}->{type}: Unknown token type";
1995     }
1996 wakaba 1.59 $self->{state} = DATA_STATE;
1997 wakaba 1.1 ## reconsume
1998    
1999     return ($self->{current_token}); # start tag or end tag
2000    
2001     redo A;
2002     } else {
2003 wakaba 1.77
2004     $Whatpm::HTML::Debug::cp_pass->(106) if $Whatpm::HTML::Debug::cp_pass;
2005     BEGIN {
2006     $Whatpm::HTML::Debug::cp->{106} = 1;
2007     }
2008    
2009 wakaba 1.76 $self->{current_attribute}->{value} .= chr ($self->{next_char});
2010 wakaba 1.1 ## Stay in the state
2011    
2012     if (@{$self->{char}}) {
2013 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2014 wakaba 1.1 } else {
2015 wakaba 1.76 $self->{set_next_char}->($self);
2016 wakaba 1.1 }
2017    
2018     redo A;
2019     }
2020 wakaba 1.59 } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {
2021 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2022     $self->{next_char} == 0x000A or # LF
2023     $self->{next_char} == 0x000B or # HT
2024     $self->{next_char} == 0x000C or # FF
2025     $self->{next_char} == 0x0020) { # SP
2026 wakaba 1.77
2027     $Whatpm::HTML::Debug::cp_pass->(107) if $Whatpm::HTML::Debug::cp_pass;
2028     BEGIN {
2029     $Whatpm::HTML::Debug::cp->{107} = 1;
2030     }
2031    
2032 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
2033 wakaba 1.1
2034     if (@{$self->{char}}) {
2035 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2036 wakaba 1.1 } else {
2037 wakaba 1.76 $self->{set_next_char}->($self);
2038 wakaba 1.1 }
2039    
2040     redo A;
2041 wakaba 1.76 } elsif ($self->{next_char} == 0x0026) { # &
2042 wakaba 1.77
2043     $Whatpm::HTML::Debug::cp_pass->(108) if $Whatpm::HTML::Debug::cp_pass;
2044     BEGIN {
2045     $Whatpm::HTML::Debug::cp->{108} = 1;
2046     }
2047    
2048 wakaba 1.59 $self->{last_attribute_value_state} = $self->{state};
2049     $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
2050 wakaba 1.1
2051     if (@{$self->{char}}) {
2052 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2053 wakaba 1.1 } else {
2054 wakaba 1.76 $self->{set_next_char}->($self);
2055 wakaba 1.1 }
2056    
2057     redo A;
2058 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2059 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
2060 wakaba 1.77
2061     $Whatpm::HTML::Debug::cp_pass->(109) if $Whatpm::HTML::Debug::cp_pass;
2062     BEGIN {
2063     $Whatpm::HTML::Debug::cp->{109} = 1;
2064     }
2065    
2066 wakaba 1.28 $self->{current_token}->{first_start_tag}
2067     = not defined $self->{last_emitted_start_tag_name};
2068 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
2069 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
2070 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
2071 wakaba 1.1 if ($self->{current_token}->{attributes}) {
2072 wakaba 1.77
2073     $Whatpm::HTML::Debug::cp_pass->(110) if $Whatpm::HTML::Debug::cp_pass;
2074     BEGIN {
2075     $Whatpm::HTML::Debug::cp->{110} = 1;
2076     }
2077    
2078 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
2079 wakaba 1.77 } else {
2080 wakaba 1.78 ## NOTE: This state should never be reached.
2081 wakaba 1.77
2082     $Whatpm::HTML::Debug::cp_pass->(111) if $Whatpm::HTML::Debug::cp_pass;
2083     BEGIN {
2084     $Whatpm::HTML::Debug::cp->{111} = 1;
2085     }
2086    
2087 wakaba 1.1 }
2088     } else {
2089     die "$0: $self->{current_token}->{type}: Unknown token type";
2090     }
2091 wakaba 1.59 $self->{state} = DATA_STATE;
2092 wakaba 1.1
2093     if (@{$self->{char}}) {
2094 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2095 wakaba 1.1 } else {
2096 wakaba 1.76 $self->{set_next_char}->($self);
2097 wakaba 1.1 }
2098    
2099    
2100     return ($self->{current_token}); # start tag or end tag
2101    
2102     redo A;
2103 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2104 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
2105 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
2106 wakaba 1.77
2107     $Whatpm::HTML::Debug::cp_pass->(112) if $Whatpm::HTML::Debug::cp_pass;
2108     BEGIN {
2109     $Whatpm::HTML::Debug::cp->{112} = 1;
2110     }
2111    
2112 wakaba 1.28 $self->{current_token}->{first_start_tag}
2113     = not defined $self->{last_emitted_start_tag_name};
2114 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
2115 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
2116 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
2117 wakaba 1.1 if ($self->{current_token}->{attributes}) {
2118 wakaba 1.77
2119     $Whatpm::HTML::Debug::cp_pass->(113) if $Whatpm::HTML::Debug::cp_pass;
2120     BEGIN {
2121     $Whatpm::HTML::Debug::cp->{113} = 1;
2122     }
2123    
2124 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
2125 wakaba 1.77 } else {
2126 wakaba 1.78 ## NOTE: This state should never be reached.
2127 wakaba 1.77
2128     $Whatpm::HTML::Debug::cp_pass->(114) if $Whatpm::HTML::Debug::cp_pass;
2129     BEGIN {
2130     $Whatpm::HTML::Debug::cp->{114} = 1;
2131     }
2132    
2133 wakaba 1.1 }
2134     } else {
2135     die "$0: $self->{current_token}->{type}: Unknown token type";
2136     }
2137 wakaba 1.59 $self->{state} = DATA_STATE;
2138 wakaba 1.1 ## reconsume
2139    
2140     return ($self->{current_token}); # start tag or end tag
2141    
2142     redo A;
2143     } else {
2144 wakaba 1.72 if ({
2145     0x0022 => 1, # "
2146     0x0027 => 1, # '
2147     0x003D => 1, # =
2148 wakaba 1.76 }->{$self->{next_char}}) {
2149 wakaba 1.77
2150     $Whatpm::HTML::Debug::cp_pass->(115) if $Whatpm::HTML::Debug::cp_pass;
2151     BEGIN {
2152     $Whatpm::HTML::Debug::cp->{115} = 1;
2153     }
2154    
2155 wakaba 1.72 $self->{parse_error}-> (type => 'bad attribute value');
2156 wakaba 1.77 } else {
2157    
2158     $Whatpm::HTML::Debug::cp_pass->(116) if $Whatpm::HTML::Debug::cp_pass;
2159     BEGIN {
2160     $Whatpm::HTML::Debug::cp->{116} = 1;
2161     }
2162    
2163 wakaba 1.72 }
2164 wakaba 1.76 $self->{current_attribute}->{value} .= chr ($self->{next_char});
2165 wakaba 1.1 ## Stay in the state
2166    
2167     if (@{$self->{char}}) {
2168 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2169 wakaba 1.1 } else {
2170 wakaba 1.76 $self->{set_next_char}->($self);
2171 wakaba 1.1 }
2172    
2173     redo A;
2174     }
2175 wakaba 1.59 } elsif ($self->{state} == ENTITY_IN_ATTRIBUTE_VALUE_STATE) {
2176 wakaba 1.72 my $token = $self->_tokenize_attempt_to_consume_an_entity
2177     (1,
2178     $self->{last_attribute_value_state}
2179     == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE ? 0x0022 : # "
2180     $self->{last_attribute_value_state}
2181     == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE ? 0x0027 : # '
2182     -1);
2183 wakaba 1.1
2184     unless (defined $token) {
2185 wakaba 1.77
2186     $Whatpm::HTML::Debug::cp_pass->(117) if $Whatpm::HTML::Debug::cp_pass;
2187     BEGIN {
2188     $Whatpm::HTML::Debug::cp->{117} = 1;
2189     }
2190    
2191 wakaba 1.1 $self->{current_attribute}->{value} .= '&';
2192     } else {
2193 wakaba 1.77
2194     $Whatpm::HTML::Debug::cp_pass->(118) if $Whatpm::HTML::Debug::cp_pass;
2195     BEGIN {
2196     $Whatpm::HTML::Debug::cp->{118} = 1;
2197     }
2198    
2199 wakaba 1.1 $self->{current_attribute}->{value} .= $token->{data};
2200 wakaba 1.68 $self->{current_attribute}->{has_reference} = $token->{has_reference};
2201 wakaba 1.1 ## ISSUE: spec says "append the returned character token to the current attribute's value"
2202     }
2203    
2204     $self->{state} = $self->{last_attribute_value_state};
2205     # next-input-character is already done
2206     redo A;
2207 wakaba 1.72 } elsif ($self->{state} == AFTER_ATTRIBUTE_VALUE_QUOTED_STATE) {
2208 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2209     $self->{next_char} == 0x000A or # LF
2210     $self->{next_char} == 0x000B or # VT
2211     $self->{next_char} == 0x000C or # FF
2212     $self->{next_char} == 0x0020) { # SP
2213 wakaba 1.77
2214     $Whatpm::HTML::Debug::cp_pass->(118) if $Whatpm::HTML::Debug::cp_pass;
2215     BEGIN {
2216     $Whatpm::HTML::Debug::cp->{118} = 1;
2217     }
2218    
2219 wakaba 1.72 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
2220    
2221     if (@{$self->{char}}) {
2222 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2223 wakaba 1.72 } else {
2224 wakaba 1.76 $self->{set_next_char}->($self);
2225 wakaba 1.72 }
2226    
2227     redo A;
2228 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2229 wakaba 1.72 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
2230 wakaba 1.77
2231     $Whatpm::HTML::Debug::cp_pass->(119) if $Whatpm::HTML::Debug::cp_pass;
2232     BEGIN {
2233     $Whatpm::HTML::Debug::cp->{119} = 1;
2234     }
2235    
2236 wakaba 1.72 $self->{current_token}->{first_start_tag}
2237     = not defined $self->{last_emitted_start_tag_name};
2238     $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
2239     } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
2240     $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
2241     if ($self->{current_token}->{attributes}) {
2242 wakaba 1.77
2243     $Whatpm::HTML::Debug::cp_pass->(120) if $Whatpm::HTML::Debug::cp_pass;
2244     BEGIN {
2245     $Whatpm::HTML::Debug::cp->{120} = 1;
2246     }
2247    
2248 wakaba 1.72 $self->{parse_error}-> (type => 'end tag attribute');
2249 wakaba 1.77 } else {
2250 wakaba 1.78 ## NOTE: This state should never be reached.
2251 wakaba 1.77
2252     $Whatpm::HTML::Debug::cp_pass->(121) if $Whatpm::HTML::Debug::cp_pass;
2253     BEGIN {
2254     $Whatpm::HTML::Debug::cp->{121} = 1;
2255     }
2256    
2257 wakaba 1.72 }
2258     } else {
2259     die "$0: $self->{current_token}->{type}: Unknown token type";
2260     }
2261     $self->{state} = DATA_STATE;
2262    
2263     if (@{$self->{char}}) {
2264 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2265 wakaba 1.72 } else {
2266 wakaba 1.76 $self->{set_next_char}->($self);
2267 wakaba 1.72 }
2268    
2269    
2270     return ($self->{current_token}); # start tag or end tag
2271    
2272     redo A;
2273 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
2274 wakaba 1.72
2275     if (@{$self->{char}}) {
2276 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2277 wakaba 1.72 } else {
2278 wakaba 1.76 $self->{set_next_char}->($self);
2279 wakaba 1.72 }
2280    
2281 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
2282 wakaba 1.72 $self->{current_token}->{type} == START_TAG_TOKEN and
2283     $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
2284     # permitted slash
2285 wakaba 1.77
2286     $Whatpm::HTML::Debug::cp_pass->(122) if $Whatpm::HTML::Debug::cp_pass;
2287     BEGIN {
2288     $Whatpm::HTML::Debug::cp->{122} = 1;
2289     }
2290    
2291 wakaba 1.72 #
2292     } else {
2293 wakaba 1.77
2294     $Whatpm::HTML::Debug::cp_pass->(123) if $Whatpm::HTML::Debug::cp_pass;
2295     BEGIN {
2296     $Whatpm::HTML::Debug::cp->{123} = 1;
2297     }
2298    
2299 wakaba 1.72 $self->{parse_error}-> (type => 'nestc');
2300     }
2301     $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
2302     # next-input-character is already done
2303     redo A;
2304     } else {
2305 wakaba 1.77
2306     $Whatpm::HTML::Debug::cp_pass->(124) if $Whatpm::HTML::Debug::cp_pass;
2307     BEGIN {
2308     $Whatpm::HTML::Debug::cp->{124} = 1;
2309     }
2310    
2311 wakaba 1.72 $self->{parse_error}-> (type => 'no space between attributes');
2312     $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
2313     ## reconsume
2314     redo A;
2315     }
2316 wakaba 1.59 } elsif ($self->{state} == BOGUS_COMMENT_STATE) {
2317 wakaba 1.1 ## (only happen if PCDATA state)
2318    
2319 wakaba 1.57 my $token = {type => COMMENT_TOKEN, data => ''};
2320 wakaba 1.1
2321     BC: {
2322 wakaba 1.76 if ($self->{next_char} == 0x003E) { # >
2323 wakaba 1.77
2324     $Whatpm::HTML::Debug::cp_pass->(124) if $Whatpm::HTML::Debug::cp_pass;
2325     BEGIN {
2326     $Whatpm::HTML::Debug::cp->{124} = 1;
2327     }
2328    
2329 wakaba 1.59 $self->{state} = DATA_STATE;
2330 wakaba 1.1
2331     if (@{$self->{char}}) {
2332 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2333 wakaba 1.1 } else {
2334 wakaba 1.76 $self->{set_next_char}->($self);
2335 wakaba 1.1 }
2336    
2337    
2338     return ($token);
2339    
2340     redo A;
2341 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2342 wakaba 1.77
2343     $Whatpm::HTML::Debug::cp_pass->(125) if $Whatpm::HTML::Debug::cp_pass;
2344     BEGIN {
2345     $Whatpm::HTML::Debug::cp->{125} = 1;
2346     }
2347    
2348 wakaba 1.59 $self->{state} = DATA_STATE;
2349 wakaba 1.1 ## reconsume
2350    
2351     return ($token);
2352    
2353     redo A;
2354     } else {
2355 wakaba 1.77
2356     $Whatpm::HTML::Debug::cp_pass->(126) if $Whatpm::HTML::Debug::cp_pass;
2357     BEGIN {
2358     $Whatpm::HTML::Debug::cp->{126} = 1;
2359     }
2360    
2361 wakaba 1.76 $token->{data} .= chr ($self->{next_char});
2362 wakaba 1.1
2363     if (@{$self->{char}}) {
2364 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2365 wakaba 1.1 } else {
2366 wakaba 1.76 $self->{set_next_char}->($self);
2367 wakaba 1.1 }
2368    
2369     redo BC;
2370     }
2371     } # BC
2372 wakaba 1.77
2373     die "$0: _get_next_token: unexpected case [BC]";
2374 wakaba 1.59 } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {
2375 wakaba 1.1 ## (only happen if PCDATA state)
2376    
2377     my @next_char;
2378 wakaba 1.76 push @next_char, $self->{next_char};
2379 wakaba 1.1
2380 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2381 wakaba 1.1
2382     if (@{$self->{char}}) {
2383 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2384 wakaba 1.1 } else {
2385 wakaba 1.76 $self->{set_next_char}->($self);
2386 wakaba 1.1 }
2387    
2388 wakaba 1.76 push @next_char, $self->{next_char};
2389     if ($self->{next_char} == 0x002D) { # -
2390 wakaba 1.77
2391     $Whatpm::HTML::Debug::cp_pass->(127) if $Whatpm::HTML::Debug::cp_pass;
2392     BEGIN {
2393     $Whatpm::HTML::Debug::cp->{127} = 1;
2394     }
2395    
2396 wakaba 1.57 $self->{current_token} = {type => COMMENT_TOKEN, data => ''};
2397 wakaba 1.59 $self->{state} = COMMENT_START_STATE;
2398 wakaba 1.1
2399     if (@{$self->{char}}) {
2400 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2401 wakaba 1.1 } else {
2402 wakaba 1.76 $self->{set_next_char}->($self);
2403 wakaba 1.1 }
2404    
2405     redo A;
2406 wakaba 1.77 } else {
2407    
2408     $Whatpm::HTML::Debug::cp_pass->(128) if $Whatpm::HTML::Debug::cp_pass;
2409     BEGIN {
2410     $Whatpm::HTML::Debug::cp->{128} = 1;
2411     }
2412    
2413 wakaba 1.1 }
2414 wakaba 1.76 } elsif ($self->{next_char} == 0x0044 or # D
2415     $self->{next_char} == 0x0064) { # d
2416 wakaba 1.1
2417     if (@{$self->{char}}) {
2418 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2419 wakaba 1.1 } else {
2420 wakaba 1.76 $self->{set_next_char}->($self);
2421 wakaba 1.1 }
2422    
2423 wakaba 1.76 push @next_char, $self->{next_char};
2424     if ($self->{next_char} == 0x004F or # O
2425     $self->{next_char} == 0x006F) { # o
2426 wakaba 1.1
2427     if (@{$self->{char}}) {
2428 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2429 wakaba 1.1 } else {
2430 wakaba 1.76 $self->{set_next_char}->($self);
2431 wakaba 1.1 }
2432    
2433 wakaba 1.76 push @next_char, $self->{next_char};
2434     if ($self->{next_char} == 0x0043 or # C
2435     $self->{next_char} == 0x0063) { # c
2436 wakaba 1.1
2437     if (@{$self->{char}}) {
2438 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2439 wakaba 1.1 } else {
2440 wakaba 1.76 $self->{set_next_char}->($self);
2441 wakaba 1.1 }
2442    
2443 wakaba 1.76 push @next_char, $self->{next_char};
2444     if ($self->{next_char} == 0x0054 or # T
2445     $self->{next_char} == 0x0074) { # t
2446 wakaba 1.1
2447     if (@{$self->{char}}) {
2448 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2449 wakaba 1.1 } else {
2450 wakaba 1.76 $self->{set_next_char}->($self);
2451 wakaba 1.1 }
2452    
2453 wakaba 1.76 push @next_char, $self->{next_char};
2454     if ($self->{next_char} == 0x0059 or # Y
2455     $self->{next_char} == 0x0079) { # y
2456 wakaba 1.1
2457     if (@{$self->{char}}) {
2458 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2459 wakaba 1.1 } else {
2460 wakaba 1.76 $self->{set_next_char}->($self);
2461 wakaba 1.1 }
2462    
2463 wakaba 1.76 push @next_char, $self->{next_char};
2464     if ($self->{next_char} == 0x0050 or # P
2465     $self->{next_char} == 0x0070) { # p
2466 wakaba 1.1
2467     if (@{$self->{char}}) {
2468 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2469 wakaba 1.1 } else {
2470 wakaba 1.76 $self->{set_next_char}->($self);
2471 wakaba 1.1 }
2472    
2473 wakaba 1.76 push @next_char, $self->{next_char};
2474     if ($self->{next_char} == 0x0045 or # E
2475     $self->{next_char} == 0x0065) { # e
2476 wakaba 1.77
2477     $Whatpm::HTML::Debug::cp_pass->(129) if $Whatpm::HTML::Debug::cp_pass;
2478     BEGIN {
2479     $Whatpm::HTML::Debug::cp->{129} = 1;
2480     }
2481    
2482     ## TODO: What a stupid code this is!
2483 wakaba 1.59 $self->{state} = DOCTYPE_STATE;
2484 wakaba 1.1
2485     if (@{$self->{char}}) {
2486 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2487 wakaba 1.1 } else {
2488 wakaba 1.76 $self->{set_next_char}->($self);
2489 wakaba 1.1 }
2490    
2491     redo A;
2492 wakaba 1.77 } else {
2493    
2494     $Whatpm::HTML::Debug::cp_pass->(130) if $Whatpm::HTML::Debug::cp_pass;
2495     BEGIN {
2496     $Whatpm::HTML::Debug::cp->{130} = 1;
2497     }
2498    
2499 wakaba 1.1 }
2500 wakaba 1.77 } else {
2501    
2502     $Whatpm::HTML::Debug::cp_pass->(131) if $Whatpm::HTML::Debug::cp_pass;
2503     BEGIN {
2504     $Whatpm::HTML::Debug::cp->{131} = 1;
2505     }
2506    
2507 wakaba 1.1 }
2508 wakaba 1.77 } else {
2509    
2510     $Whatpm::HTML::Debug::cp_pass->(132) if $Whatpm::HTML::Debug::cp_pass;
2511     BEGIN {
2512     $Whatpm::HTML::Debug::cp->{132} = 1;
2513     }
2514    
2515 wakaba 1.1 }
2516 wakaba 1.77 } else {
2517    
2518     $Whatpm::HTML::Debug::cp_pass->(133) if $Whatpm::HTML::Debug::cp_pass;
2519     BEGIN {
2520     $Whatpm::HTML::Debug::cp->{133} = 1;
2521     }
2522    
2523 wakaba 1.1 }
2524 wakaba 1.77 } else {
2525    
2526     $Whatpm::HTML::Debug::cp_pass->(134) if $Whatpm::HTML::Debug::cp_pass;
2527     BEGIN {
2528     $Whatpm::HTML::Debug::cp->{134} = 1;
2529     }
2530    
2531 wakaba 1.1 }
2532 wakaba 1.77 } else {
2533    
2534     $Whatpm::HTML::Debug::cp_pass->(135) if $Whatpm::HTML::Debug::cp_pass;
2535     BEGIN {
2536     $Whatpm::HTML::Debug::cp->{135} = 1;
2537     }
2538    
2539 wakaba 1.1 }
2540 wakaba 1.77 } else {
2541    
2542     $Whatpm::HTML::Debug::cp_pass->(136) if $Whatpm::HTML::Debug::cp_pass;
2543     BEGIN {
2544     $Whatpm::HTML::Debug::cp->{136} = 1;
2545     }
2546    
2547 wakaba 1.1 }
2548    
2549 wakaba 1.30 $self->{parse_error}-> (type => 'bogus comment');
2550 wakaba 1.76 $self->{next_char} = shift @next_char;
2551 wakaba 1.1 unshift @{$self->{char}}, (@next_char);
2552 wakaba 1.59 $self->{state} = BOGUS_COMMENT_STATE;
2553 wakaba 1.1 redo A;
2554    
2555     ## ISSUE: typos in spec: chacacters, is is a parse error
2556     ## ISSUE: spec is somewhat unclear on "is the first character that will be in the comment"; what is "that will be in the comment" is what the algorithm defines, isn't it?
2557 wakaba 1.59 } elsif ($self->{state} == COMMENT_START_STATE) {
2558 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2559 wakaba 1.77
2560     $Whatpm::HTML::Debug::cp_pass->(137) if $Whatpm::HTML::Debug::cp_pass;
2561     BEGIN {
2562     $Whatpm::HTML::Debug::cp->{137} = 1;
2563     }
2564    
2565 wakaba 1.59 $self->{state} = COMMENT_START_DASH_STATE;
2566 wakaba 1.23
2567     if (@{$self->{char}}) {
2568 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2569 wakaba 1.23 } else {
2570 wakaba 1.76 $self->{set_next_char}->($self);
2571 wakaba 1.23 }
2572    
2573     redo A;
2574 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2575 wakaba 1.77
2576     $Whatpm::HTML::Debug::cp_pass->(138) if $Whatpm::HTML::Debug::cp_pass;
2577     BEGIN {
2578     $Whatpm::HTML::Debug::cp->{138} = 1;
2579     }
2580    
2581 wakaba 1.23 $self->{parse_error}-> (type => 'bogus comment');
2582 wakaba 1.59 $self->{state} = DATA_STATE;
2583 wakaba 1.23
2584     if (@{$self->{char}}) {
2585 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2586 wakaba 1.23 } else {
2587 wakaba 1.76 $self->{set_next_char}->($self);
2588 wakaba 1.23 }
2589    
2590    
2591     return ($self->{current_token}); # comment
2592    
2593     redo A;
2594 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2595 wakaba 1.77
2596     $Whatpm::HTML::Debug::cp_pass->(139) if $Whatpm::HTML::Debug::cp_pass;
2597     BEGIN {
2598     $Whatpm::HTML::Debug::cp->{139} = 1;
2599     }
2600    
2601 wakaba 1.23 $self->{parse_error}-> (type => 'unclosed comment');
2602 wakaba 1.59 $self->{state} = DATA_STATE;
2603 wakaba 1.23 ## reconsume
2604    
2605     return ($self->{current_token}); # comment
2606    
2607 wakaba 1.77 redo A;
2608     } else {
2609    
2610     $Whatpm::HTML::Debug::cp_pass->(140) if $Whatpm::HTML::Debug::cp_pass;
2611     BEGIN {
2612     $Whatpm::HTML::Debug::cp->{140} = 1;
2613     }
2614    
2615 wakaba 1.23 $self->{current_token}->{data} # comment
2616 wakaba 1.76 .= chr ($self->{next_char});
2617 wakaba 1.59 $self->{state} = COMMENT_STATE;
2618 wakaba 1.23
2619     if (@{$self->{char}}) {
2620 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2621 wakaba 1.23 } else {
2622 wakaba 1.76 $self->{set_next_char}->($self);
2623 wakaba 1.23 }
2624    
2625     redo A;
2626     }
2627 wakaba 1.59 } elsif ($self->{state} == COMMENT_START_DASH_STATE) {
2628 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2629 wakaba 1.77
2630     $Whatpm::HTML::Debug::cp_pass->(141) if $Whatpm::HTML::Debug::cp_pass;
2631     BEGIN {
2632     $Whatpm::HTML::Debug::cp->{141} = 1;
2633     }
2634    
2635 wakaba 1.59 $self->{state} = COMMENT_END_STATE;
2636 wakaba 1.23
2637     if (@{$self->{char}}) {
2638 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2639 wakaba 1.23 } else {
2640 wakaba 1.76 $self->{set_next_char}->($self);
2641 wakaba 1.23 }
2642    
2643     redo A;
2644 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2645 wakaba 1.77
2646     $Whatpm::HTML::Debug::cp_pass->(142) if $Whatpm::HTML::Debug::cp_pass;
2647     BEGIN {
2648     $Whatpm::HTML::Debug::cp->{142} = 1;
2649     }
2650    
2651 wakaba 1.23 $self->{parse_error}-> (type => 'bogus comment');
2652 wakaba 1.59 $self->{state} = DATA_STATE;
2653 wakaba 1.23
2654     if (@{$self->{char}}) {
2655 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2656 wakaba 1.23 } else {
2657 wakaba 1.76 $self->{set_next_char}->($self);
2658 wakaba 1.23 }
2659    
2660    
2661     return ($self->{current_token}); # comment
2662    
2663     redo A;
2664 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2665 wakaba 1.77
2666     $Whatpm::HTML::Debug::cp_pass->(143) if $Whatpm::HTML::Debug::cp_pass;
2667     BEGIN {
2668     $Whatpm::HTML::Debug::cp->{143} = 1;
2669     }
2670    
2671 wakaba 1.23 $self->{parse_error}-> (type => 'unclosed comment');
2672 wakaba 1.59 $self->{state} = DATA_STATE;
2673 wakaba 1.23 ## reconsume
2674    
2675     return ($self->{current_token}); # comment
2676    
2677     redo A;
2678     } else {
2679 wakaba 1.77
2680     $Whatpm::HTML::Debug::cp_pass->(144) if $Whatpm::HTML::Debug::cp_pass;
2681     BEGIN {
2682     $Whatpm::HTML::Debug::cp->{144} = 1;
2683     }
2684    
2685 wakaba 1.23 $self->{current_token}->{data} # comment
2686 wakaba 1.76 .= '-' . chr ($self->{next_char});
2687 wakaba 1.59 $self->{state} = COMMENT_STATE;
2688 wakaba 1.23
2689     if (@{$self->{char}}) {
2690 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2691 wakaba 1.23 } else {
2692 wakaba 1.76 $self->{set_next_char}->($self);
2693 wakaba 1.23 }
2694    
2695     redo A;
2696     }
2697 wakaba 1.59 } elsif ($self->{state} == COMMENT_STATE) {
2698 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2699 wakaba 1.77
2700     $Whatpm::HTML::Debug::cp_pass->(145) if $Whatpm::HTML::Debug::cp_pass;
2701     BEGIN {
2702     $Whatpm::HTML::Debug::cp->{145} = 1;
2703     }
2704    
2705 wakaba 1.59 $self->{state} = COMMENT_END_DASH_STATE;
2706 wakaba 1.1
2707     if (@{$self->{char}}) {
2708 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2709 wakaba 1.1 } else {
2710 wakaba 1.76 $self->{set_next_char}->($self);
2711 wakaba 1.1 }
2712    
2713     redo A;
2714 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2715 wakaba 1.77
2716     $Whatpm::HTML::Debug::cp_pass->(146) if $Whatpm::HTML::Debug::cp_pass;
2717     BEGIN {
2718     $Whatpm::HTML::Debug::cp->{146} = 1;
2719     }
2720    
2721 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed comment');
2722 wakaba 1.59 $self->{state} = DATA_STATE;
2723 wakaba 1.1 ## reconsume
2724    
2725     return ($self->{current_token}); # comment
2726    
2727     redo A;
2728     } else {
2729 wakaba 1.77
2730     $Whatpm::HTML::Debug::cp_pass->(147) if $Whatpm::HTML::Debug::cp_pass;
2731     BEGIN {
2732     $Whatpm::HTML::Debug::cp->{147} = 1;
2733     }
2734    
2735 wakaba 1.76 $self->{current_token}->{data} .= chr ($self->{next_char}); # comment
2736 wakaba 1.1 ## Stay in the state
2737    
2738     if (@{$self->{char}}) {
2739 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2740 wakaba 1.1 } else {
2741 wakaba 1.76 $self->{set_next_char}->($self);
2742 wakaba 1.1 }
2743    
2744     redo A;
2745     }
2746 wakaba 1.59 } elsif ($self->{state} == COMMENT_END_DASH_STATE) {
2747 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2748 wakaba 1.77
2749     $Whatpm::HTML::Debug::cp_pass->(148) if $Whatpm::HTML::Debug::cp_pass;
2750     BEGIN {
2751     $Whatpm::HTML::Debug::cp->{148} = 1;
2752     }
2753    
2754 wakaba 1.59 $self->{state} = COMMENT_END_STATE;
2755 wakaba 1.1
2756     if (@{$self->{char}}) {
2757 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2758 wakaba 1.1 } else {
2759 wakaba 1.76 $self->{set_next_char}->($self);
2760 wakaba 1.1 }
2761    
2762     redo A;
2763 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2764 wakaba 1.77
2765     $Whatpm::HTML::Debug::cp_pass->(149) if $Whatpm::HTML::Debug::cp_pass;
2766     BEGIN {
2767     $Whatpm::HTML::Debug::cp->{149} = 1;
2768     }
2769    
2770 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed comment');
2771 wakaba 1.59 $self->{state} = DATA_STATE;
2772 wakaba 1.1 ## reconsume
2773    
2774     return ($self->{current_token}); # comment
2775    
2776     redo A;
2777     } else {
2778 wakaba 1.77
2779     $Whatpm::HTML::Debug::cp_pass->(150) if $Whatpm::HTML::Debug::cp_pass;
2780     BEGIN {
2781     $Whatpm::HTML::Debug::cp->{150} = 1;
2782     }
2783    
2784 wakaba 1.76 $self->{current_token}->{data} .= '-' . chr ($self->{next_char}); # comment
2785 wakaba 1.59 $self->{state} = COMMENT_STATE;
2786 wakaba 1.1
2787     if (@{$self->{char}}) {
2788 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2789 wakaba 1.1 } else {
2790 wakaba 1.76 $self->{set_next_char}->($self);
2791 wakaba 1.1 }
2792    
2793     redo A;
2794     }
2795 wakaba 1.59 } elsif ($self->{state} == COMMENT_END_STATE) {
2796 wakaba 1.76 if ($self->{next_char} == 0x003E) { # >
2797 wakaba 1.77
2798     $Whatpm::HTML::Debug::cp_pass->(151) if $Whatpm::HTML::Debug::cp_pass;
2799     BEGIN {
2800     $Whatpm::HTML::Debug::cp->{151} = 1;
2801     }
2802    
2803 wakaba 1.59 $self->{state} = DATA_STATE;
2804 wakaba 1.1
2805     if (@{$self->{char}}) {
2806 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2807 wakaba 1.1 } else {
2808 wakaba 1.76 $self->{set_next_char}->($self);
2809 wakaba 1.1 }
2810    
2811    
2812     return ($self->{current_token}); # comment
2813    
2814     redo A;
2815 wakaba 1.76 } elsif ($self->{next_char} == 0x002D) { # -
2816 wakaba 1.77
2817     $Whatpm::HTML::Debug::cp_pass->(152) if $Whatpm::HTML::Debug::cp_pass;
2818     BEGIN {
2819     $Whatpm::HTML::Debug::cp->{152} = 1;
2820     }
2821    
2822 wakaba 1.3 $self->{parse_error}-> (type => 'dash in comment');
2823 wakaba 1.1 $self->{current_token}->{data} .= '-'; # comment
2824     ## Stay in the state
2825    
2826     if (@{$self->{char}}) {
2827 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2828 wakaba 1.1 } else {
2829 wakaba 1.76 $self->{set_next_char}->($self);
2830 wakaba 1.1 }
2831    
2832     redo A;
2833 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2834 wakaba 1.77
2835     $Whatpm::HTML::Debug::cp_pass->(153) if $Whatpm::HTML::Debug::cp_pass;
2836     BEGIN {
2837     $Whatpm::HTML::Debug::cp->{153} = 1;
2838     }
2839    
2840 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed comment');
2841 wakaba 1.59 $self->{state} = DATA_STATE;
2842 wakaba 1.1 ## reconsume
2843    
2844     return ($self->{current_token}); # comment
2845    
2846     redo A;
2847     } else {
2848 wakaba 1.77
2849     $Whatpm::HTML::Debug::cp_pass->(154) if $Whatpm::HTML::Debug::cp_pass;
2850     BEGIN {
2851     $Whatpm::HTML::Debug::cp->{154} = 1;
2852     }
2853    
2854 wakaba 1.3 $self->{parse_error}-> (type => 'dash in comment');
2855 wakaba 1.76 $self->{current_token}->{data} .= '--' . chr ($self->{next_char}); # comment
2856 wakaba 1.59 $self->{state} = COMMENT_STATE;
2857 wakaba 1.1
2858     if (@{$self->{char}}) {
2859 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2860 wakaba 1.1 } else {
2861 wakaba 1.76 $self->{set_next_char}->($self);
2862 wakaba 1.1 }
2863    
2864     redo A;
2865     }
2866 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_STATE) {
2867 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2868     $self->{next_char} == 0x000A or # LF
2869     $self->{next_char} == 0x000B or # VT
2870     $self->{next_char} == 0x000C or # FF
2871     $self->{next_char} == 0x0020) { # SP
2872 wakaba 1.77
2873     $Whatpm::HTML::Debug::cp_pass->(155) if $Whatpm::HTML::Debug::cp_pass;
2874     BEGIN {
2875     $Whatpm::HTML::Debug::cp->{155} = 1;
2876     }
2877    
2878 wakaba 1.59 $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
2879 wakaba 1.1
2880     if (@{$self->{char}}) {
2881 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2882 wakaba 1.1 } else {
2883 wakaba 1.76 $self->{set_next_char}->($self);
2884 wakaba 1.1 }
2885    
2886     redo A;
2887     } else {
2888 wakaba 1.77
2889     $Whatpm::HTML::Debug::cp_pass->(156) if $Whatpm::HTML::Debug::cp_pass;
2890     BEGIN {
2891     $Whatpm::HTML::Debug::cp->{156} = 1;
2892     }
2893    
2894 wakaba 1.3 $self->{parse_error}-> (type => 'no space before DOCTYPE name');
2895 wakaba 1.59 $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
2896 wakaba 1.1 ## reconsume
2897     redo A;
2898     }
2899 wakaba 1.59 } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {
2900 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2901     $self->{next_char} == 0x000A or # LF
2902     $self->{next_char} == 0x000B or # VT
2903     $self->{next_char} == 0x000C or # FF
2904     $self->{next_char} == 0x0020) { # SP
2905 wakaba 1.77
2906     $Whatpm::HTML::Debug::cp_pass->(157) if $Whatpm::HTML::Debug::cp_pass;
2907     BEGIN {
2908     $Whatpm::HTML::Debug::cp->{157} = 1;
2909     }
2910    
2911 wakaba 1.1 ## Stay in the state
2912    
2913     if (@{$self->{char}}) {
2914 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2915 wakaba 1.1 } else {
2916 wakaba 1.76 $self->{set_next_char}->($self);
2917 wakaba 1.1 }
2918    
2919     redo A;
2920 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2921 wakaba 1.77
2922     $Whatpm::HTML::Debug::cp_pass->(158) if $Whatpm::HTML::Debug::cp_pass;
2923     BEGIN {
2924     $Whatpm::HTML::Debug::cp->{158} = 1;
2925     }
2926    
2927 wakaba 1.18 $self->{parse_error}-> (type => 'no DOCTYPE name');
2928 wakaba 1.59 $self->{state} = DATA_STATE;
2929 wakaba 1.18
2930     if (@{$self->{char}}) {
2931 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2932 wakaba 1.18 } else {
2933 wakaba 1.76 $self->{set_next_char}->($self);
2934 wakaba 1.18 }
2935    
2936    
2937 wakaba 1.75 return ({type => DOCTYPE_TOKEN, quirks => 1});
2938 wakaba 1.18
2939     redo A;
2940 wakaba 1.77 } elsif ($self->{next_char} == -1) {
2941    
2942     $Whatpm::HTML::Debug::cp_pass->(159) if $Whatpm::HTML::Debug::cp_pass;
2943     BEGIN {
2944     $Whatpm::HTML::Debug::cp->{159} = 1;
2945     }
2946    
2947 wakaba 1.18 $self->{parse_error}-> (type => 'no DOCTYPE name');
2948 wakaba 1.59 $self->{state} = DATA_STATE;
2949 wakaba 1.18 ## reconsume
2950    
2951 wakaba 1.75 return ({type => DOCTYPE_TOKEN, quirks => 1});
2952 wakaba 1.18
2953     redo A;
2954     } else {
2955 wakaba 1.77
2956     $Whatpm::HTML::Debug::cp_pass->(160) if $Whatpm::HTML::Debug::cp_pass;
2957     BEGIN {
2958     $Whatpm::HTML::Debug::cp->{160} = 1;
2959     }
2960    
2961 wakaba 1.18 $self->{current_token}
2962 wakaba 1.57 = {type => DOCTYPE_TOKEN,
2963 wakaba 1.76 name => chr ($self->{next_char}),
2964 wakaba 1.75 #quirks => 0,
2965     };
2966 wakaba 1.4 ## ISSUE: "Set the token's name name to the" in the spec
2967 wakaba 1.59 $self->{state} = DOCTYPE_NAME_STATE;
2968 wakaba 1.1
2969     if (@{$self->{char}}) {
2970 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2971 wakaba 1.1 } else {
2972 wakaba 1.76 $self->{set_next_char}->($self);
2973 wakaba 1.1 }
2974    
2975     redo A;
2976 wakaba 1.18 }
2977 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_NAME_STATE) {
2978 wakaba 1.18 ## ISSUE: Redundant "First," in the spec.
2979 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2980     $self->{next_char} == 0x000A or # LF
2981     $self->{next_char} == 0x000B or # VT
2982     $self->{next_char} == 0x000C or # FF
2983     $self->{next_char} == 0x0020) { # SP
2984 wakaba 1.77
2985     $Whatpm::HTML::Debug::cp_pass->(161) if $Whatpm::HTML::Debug::cp_pass;
2986     BEGIN {
2987     $Whatpm::HTML::Debug::cp->{161} = 1;
2988     }
2989    
2990 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_NAME_STATE;
2991 wakaba 1.18
2992     if (@{$self->{char}}) {
2993 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2994 wakaba 1.18 } else {
2995 wakaba 1.76 $self->{set_next_char}->($self);
2996 wakaba 1.18 }
2997    
2998     redo A;
2999 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3000 wakaba 1.77
3001     $Whatpm::HTML::Debug::cp_pass->(162) if $Whatpm::HTML::Debug::cp_pass;
3002     BEGIN {
3003     $Whatpm::HTML::Debug::cp->{162} = 1;
3004     }
3005    
3006 wakaba 1.59 $self->{state} = DATA_STATE;
3007 wakaba 1.1
3008     if (@{$self->{char}}) {
3009 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3010 wakaba 1.1 } else {
3011 wakaba 1.76 $self->{set_next_char}->($self);
3012 wakaba 1.1 }
3013    
3014    
3015 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3016 wakaba 1.1
3017     redo A;
3018 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3019 wakaba 1.77
3020     $Whatpm::HTML::Debug::cp_pass->(163) if $Whatpm::HTML::Debug::cp_pass;
3021     BEGIN {
3022     $Whatpm::HTML::Debug::cp->{163} = 1;
3023     }
3024    
3025 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3026 wakaba 1.59 $self->{state} = DATA_STATE;
3027 wakaba 1.1 ## reconsume
3028    
3029 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3030 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3031 wakaba 1.1
3032     redo A;
3033     } else {
3034 wakaba 1.77
3035     $Whatpm::HTML::Debug::cp_pass->(164) if $Whatpm::HTML::Debug::cp_pass;
3036     BEGIN {
3037     $Whatpm::HTML::Debug::cp->{164} = 1;
3038     }
3039    
3040 wakaba 1.18 $self->{current_token}->{name}
3041 wakaba 1.76 .= chr ($self->{next_char}); # DOCTYPE
3042 wakaba 1.18 ## Stay in the state
3043 wakaba 1.1
3044     if (@{$self->{char}}) {
3045 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3046 wakaba 1.1 } else {
3047 wakaba 1.76 $self->{set_next_char}->($self);
3048 wakaba 1.1 }
3049    
3050     redo A;
3051     }
3052 wakaba 1.59 } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {
3053 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
3054     $self->{next_char} == 0x000A or # LF
3055     $self->{next_char} == 0x000B or # VT
3056     $self->{next_char} == 0x000C or # FF
3057     $self->{next_char} == 0x0020) { # SP
3058 wakaba 1.77
3059     $Whatpm::HTML::Debug::cp_pass->(165) if $Whatpm::HTML::Debug::cp_pass;
3060     BEGIN {
3061     $Whatpm::HTML::Debug::cp->{165} = 1;
3062     }
3063    
3064 wakaba 1.18 ## Stay in the state
3065 wakaba 1.1
3066     if (@{$self->{char}}) {
3067 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3068 wakaba 1.1 } else {
3069 wakaba 1.76 $self->{set_next_char}->($self);
3070 wakaba 1.1 }
3071    
3072     redo A;
3073 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3074 wakaba 1.77
3075     $Whatpm::HTML::Debug::cp_pass->(166) if $Whatpm::HTML::Debug::cp_pass;
3076     BEGIN {
3077     $Whatpm::HTML::Debug::cp->{166} = 1;
3078     }
3079    
3080 wakaba 1.59 $self->{state} = DATA_STATE;
3081 wakaba 1.1
3082     if (@{$self->{char}}) {
3083 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3084 wakaba 1.1 } else {
3085 wakaba 1.76 $self->{set_next_char}->($self);
3086 wakaba 1.1 }
3087    
3088    
3089     return ($self->{current_token}); # DOCTYPE
3090    
3091     redo A;
3092 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3093 wakaba 1.77
3094     $Whatpm::HTML::Debug::cp_pass->(167) if $Whatpm::HTML::Debug::cp_pass;
3095     BEGIN {
3096     $Whatpm::HTML::Debug::cp->{167} = 1;
3097     }
3098    
3099 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3100 wakaba 1.59 $self->{state} = DATA_STATE;
3101 wakaba 1.18 ## reconsume
3102    
3103 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3104 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3105    
3106     redo A;
3107 wakaba 1.76 } elsif ($self->{next_char} == 0x0050 or # P
3108     $self->{next_char} == 0x0070) { # p
3109 wakaba 1.18
3110     if (@{$self->{char}}) {
3111 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3112 wakaba 1.18 } else {
3113 wakaba 1.76 $self->{set_next_char}->($self);
3114 wakaba 1.18 }
3115    
3116 wakaba 1.76 if ($self->{next_char} == 0x0055 or # U
3117     $self->{next_char} == 0x0075) { # u
3118 wakaba 1.18
3119     if (@{$self->{char}}) {
3120 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3121 wakaba 1.18 } else {
3122 wakaba 1.76 $self->{set_next_char}->($self);
3123 wakaba 1.18 }
3124    
3125 wakaba 1.76 if ($self->{next_char} == 0x0042 or # B
3126     $self->{next_char} == 0x0062) { # b
3127 wakaba 1.18
3128     if (@{$self->{char}}) {
3129 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3130 wakaba 1.18 } else {
3131 wakaba 1.76 $self->{set_next_char}->($self);
3132 wakaba 1.18 }
3133    
3134 wakaba 1.76 if ($self->{next_char} == 0x004C or # L
3135     $self->{next_char} == 0x006C) { # l
3136 wakaba 1.18
3137     if (@{$self->{char}}) {
3138 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3139 wakaba 1.18 } else {
3140 wakaba 1.76 $self->{set_next_char}->($self);
3141 wakaba 1.18 }
3142    
3143 wakaba 1.76 if ($self->{next_char} == 0x0049 or # I
3144     $self->{next_char} == 0x0069) { # i
3145 wakaba 1.18
3146     if (@{$self->{char}}) {
3147 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3148 wakaba 1.18 } else {
3149 wakaba 1.76 $self->{set_next_char}->($self);
3150 wakaba 1.18 }
3151    
3152 wakaba 1.76 if ($self->{next_char} == 0x0043 or # C
3153     $self->{next_char} == 0x0063) { # c
3154 wakaba 1.77
3155     $Whatpm::HTML::Debug::cp_pass->(168) if $Whatpm::HTML::Debug::cp_pass;
3156     BEGIN {
3157     $Whatpm::HTML::Debug::cp->{168} = 1;
3158     }
3159    
3160 wakaba 1.59 $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
3161 wakaba 1.18
3162     if (@{$self->{char}}) {
3163 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3164 wakaba 1.18 } else {
3165 wakaba 1.76 $self->{set_next_char}->($self);
3166 wakaba 1.18 }
3167    
3168     redo A;
3169 wakaba 1.77 } else {
3170    
3171     $Whatpm::HTML::Debug::cp_pass->(169) if $Whatpm::HTML::Debug::cp_pass;
3172     BEGIN {
3173     $Whatpm::HTML::Debug::cp->{169} = 1;
3174     }
3175    
3176 wakaba 1.18 }
3177 wakaba 1.77 } else {
3178    
3179     $Whatpm::HTML::Debug::cp_pass->(170) if $Whatpm::HTML::Debug::cp_pass;
3180     BEGIN {
3181     $Whatpm::HTML::Debug::cp->{170} = 1;
3182     }
3183    
3184 wakaba 1.18 }
3185 wakaba 1.77 } else {
3186    
3187     $Whatpm::HTML::Debug::cp_pass->(171) if $Whatpm::HTML::Debug::cp_pass;
3188     BEGIN {
3189     $Whatpm::HTML::Debug::cp->{171} = 1;
3190     }
3191    
3192 wakaba 1.18 }
3193 wakaba 1.77 } else {
3194    
3195     $Whatpm::HTML::Debug::cp_pass->(172) if $Whatpm::HTML::Debug::cp_pass;
3196     BEGIN {
3197     $Whatpm::HTML::Debug::cp->{172} = 1;
3198     }
3199    
3200 wakaba 1.18 }
3201 wakaba 1.77 } else {
3202    
3203     $Whatpm::HTML::Debug::cp_pass->(173) if $Whatpm::HTML::Debug::cp_pass;
3204     BEGIN {
3205     $Whatpm::HTML::Debug::cp->{173} = 1;
3206     }
3207    
3208 wakaba 1.18 }
3209    
3210     #
3211 wakaba 1.76 } elsif ($self->{next_char} == 0x0053 or # S
3212     $self->{next_char} == 0x0073) { # s
3213 wakaba 1.18
3214     if (@{$self->{char}}) {
3215 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3216 wakaba 1.18 } else {
3217 wakaba 1.76 $self->{set_next_char}->($self);
3218 wakaba 1.18 }
3219    
3220 wakaba 1.76 if ($self->{next_char} == 0x0059 or # Y
3221     $self->{next_char} == 0x0079) { # y
3222 wakaba 1.18
3223     if (@{$self->{char}}) {
3224 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3225 wakaba 1.18 } else {
3226 wakaba 1.76 $self->{set_next_char}->($self);
3227 wakaba 1.18 }
3228    
3229 wakaba 1.76 if ($self->{next_char} == 0x0053 or # S
3230     $self->{next_char} == 0x0073) { # s
3231 wakaba 1.18
3232     if (@{$self->{char}}) {
3233 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3234 wakaba 1.18 } else {
3235 wakaba 1.76 $self->{set_next_char}->($self);
3236 wakaba 1.18 }
3237    
3238 wakaba 1.76 if ($self->{next_char} == 0x0054 or # T
3239     $self->{next_char} == 0x0074) { # t
3240 wakaba 1.18
3241     if (@{$self->{char}}) {
3242 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3243 wakaba 1.18 } else {
3244 wakaba 1.76 $self->{set_next_char}->($self);
3245 wakaba 1.18 }
3246    
3247 wakaba 1.76 if ($self->{next_char} == 0x0045 or # E
3248     $self->{next_char} == 0x0065) { # e
3249 wakaba 1.18
3250     if (@{$self->{char}}) {
3251 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3252 wakaba 1.18 } else {
3253 wakaba 1.76 $self->{set_next_char}->($self);
3254 wakaba 1.18 }
3255    
3256 wakaba 1.76 if ($self->{next_char} == 0x004D or # M
3257     $self->{next_char} == 0x006D) { # m
3258 wakaba 1.77
3259     $Whatpm::HTML::Debug::cp_pass->(174) if $Whatpm::HTML::Debug::cp_pass;
3260     BEGIN {
3261     $Whatpm::HTML::Debug::cp->{174} = 1;
3262     }
3263    
3264 wakaba 1.59 $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
3265 wakaba 1.18
3266     if (@{$self->{char}}) {
3267 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3268 wakaba 1.18 } else {
3269 wakaba 1.76 $self->{set_next_char}->($self);
3270 wakaba 1.18 }
3271    
3272     redo A;
3273 wakaba 1.77 } else {
3274    
3275     $Whatpm::HTML::Debug::cp_pass->(175) if $Whatpm::HTML::Debug::cp_pass;
3276     BEGIN {
3277     $Whatpm::HTML::Debug::cp->{175} = 1;
3278     }
3279    
3280 wakaba 1.18 }
3281 wakaba 1.77 } else {
3282    
3283     $Whatpm::HTML::Debug::cp_pass->(176) if $Whatpm::HTML::Debug::cp_pass;
3284     BEGIN {
3285     $Whatpm::HTML::Debug::cp->{176} = 1;
3286     }
3287    
3288 wakaba 1.18 }
3289 wakaba 1.77 } else {
3290    
3291     $Whatpm::HTML::Debug::cp_pass->(177) if $Whatpm::HTML::Debug::cp_pass;
3292     BEGIN {
3293     $Whatpm::HTML::Debug::cp->{177} = 1;
3294     }
3295    
3296 wakaba 1.18 }
3297 wakaba 1.77 } else {
3298    
3299     $Whatpm::HTML::Debug::cp_pass->(178) if $Whatpm::HTML::Debug::cp_pass;
3300     BEGIN {
3301     $Whatpm::HTML::Debug::cp->{178} = 1;
3302     }
3303    
3304 wakaba 1.18 }
3305 wakaba 1.77 } else {
3306    
3307     $Whatpm::HTML::Debug::cp_pass->(179) if $Whatpm::HTML::Debug::cp_pass;
3308     BEGIN {
3309     $Whatpm::HTML::Debug::cp->{179} = 1;
3310     }
3311    
3312 wakaba 1.18 }
3313    
3314     #
3315     } else {
3316    
3317 wakaba 1.77 $Whatpm::HTML::Debug::cp_pass->(180) if $Whatpm::HTML::Debug::cp_pass;
3318     BEGIN {
3319     $Whatpm::HTML::Debug::cp->{180} = 1;
3320     }
3321    
3322    
3323 wakaba 1.18 if (@{$self->{char}}) {
3324 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3325 wakaba 1.18 } else {
3326 wakaba 1.76 $self->{set_next_char}->($self);
3327 wakaba 1.18 }
3328    
3329     #
3330     }
3331    
3332     $self->{parse_error}-> (type => 'string after DOCTYPE name');
3333 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3334 wakaba 1.73
3335 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
3336 wakaba 1.18 # next-input-character is already done
3337     redo A;
3338 wakaba 1.59 } elsif ($self->{state} == BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {
3339 wakaba 1.18 if ({
3340     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
3341     #0x000D => 1, # HT, LF, VT, FF, SP, CR
3342 wakaba 1.76 }->{$self->{next_char}}) {
3343 wakaba 1.77
3344     $Whatpm::HTML::Debug::cp_pass->(181) if $Whatpm::HTML::Debug::cp_pass;
3345     BEGIN {
3346     $Whatpm::HTML::Debug::cp->{181} = 1;
3347     }
3348    
3349 wakaba 1.1 ## Stay in the state
3350    
3351     if (@{$self->{char}}) {
3352 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3353 wakaba 1.1 } else {
3354 wakaba 1.76 $self->{set_next_char}->($self);
3355 wakaba 1.1 }
3356    
3357     redo A;
3358 wakaba 1.76 } elsif ($self->{next_char} eq 0x0022) { # "
3359 wakaba 1.77
3360     $Whatpm::HTML::Debug::cp_pass->(182) if $Whatpm::HTML::Debug::cp_pass;
3361     BEGIN {
3362     $Whatpm::HTML::Debug::cp->{182} = 1;
3363     }
3364    
3365 wakaba 1.18 $self->{current_token}->{public_identifier} = ''; # DOCTYPE
3366 wakaba 1.59 $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;
3367 wakaba 1.18
3368     if (@{$self->{char}}) {
3369 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3370 wakaba 1.18 } else {
3371 wakaba 1.76 $self->{set_next_char}->($self);
3372 wakaba 1.18 }
3373    
3374     redo A;
3375 wakaba 1.76 } elsif ($self->{next_char} eq 0x0027) { # '
3376 wakaba 1.77
3377     $Whatpm::HTML::Debug::cp_pass->(183) if $Whatpm::HTML::Debug::cp_pass;
3378     BEGIN {
3379     $Whatpm::HTML::Debug::cp->{183} = 1;
3380     }
3381    
3382 wakaba 1.18 $self->{current_token}->{public_identifier} = ''; # DOCTYPE
3383 wakaba 1.59 $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;
3384 wakaba 1.18
3385     if (@{$self->{char}}) {
3386 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3387 wakaba 1.18 } else {
3388 wakaba 1.76 $self->{set_next_char}->($self);
3389 wakaba 1.18 }
3390    
3391     redo A;
3392 wakaba 1.76 } elsif ($self->{next_char} eq 0x003E) { # >
3393 wakaba 1.77
3394     $Whatpm::HTML::Debug::cp_pass->(184) if $Whatpm::HTML::Debug::cp_pass;
3395     BEGIN {
3396     $Whatpm::HTML::Debug::cp->{184} = 1;
3397     }
3398    
3399 wakaba 1.18 $self->{parse_error}-> (type => 'no PUBLIC literal');
3400    
3401 wakaba 1.59 $self->{state} = DATA_STATE;
3402 wakaba 1.18
3403     if (@{$self->{char}}) {
3404 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3405 wakaba 1.18 } else {
3406 wakaba 1.76 $self->{set_next_char}->($self);
3407 wakaba 1.18 }
3408    
3409    
3410 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3411 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3412    
3413     redo A;
3414 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3415 wakaba 1.77
3416     $Whatpm::HTML::Debug::cp_pass->(185) if $Whatpm::HTML::Debug::cp_pass;
3417     BEGIN {
3418     $Whatpm::HTML::Debug::cp->{185} = 1;
3419     }
3420    
3421 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3422 wakaba 1.18
3423 wakaba 1.59 $self->{state} = DATA_STATE;
3424 wakaba 1.1 ## reconsume
3425    
3426 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3427 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3428 wakaba 1.1
3429     redo A;
3430     } else {
3431 wakaba 1.77
3432     $Whatpm::HTML::Debug::cp_pass->(186) if $Whatpm::HTML::Debug::cp_pass;
3433     BEGIN {
3434     $Whatpm::HTML::Debug::cp->{186} = 1;
3435     }
3436    
3437 wakaba 1.18 $self->{parse_error}-> (type => 'string after PUBLIC');
3438 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3439 wakaba 1.73
3440 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
3441 wakaba 1.18
3442     if (@{$self->{char}}) {
3443 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3444 wakaba 1.18 } else {
3445 wakaba 1.76 $self->{set_next_char}->($self);
3446 wakaba 1.18 }
3447    
3448     redo A;
3449     }
3450 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE) {
3451 wakaba 1.76 if ($self->{next_char} == 0x0022) { # "
3452 wakaba 1.77
3453     $Whatpm::HTML::Debug::cp_pass->(187) if $Whatpm::HTML::Debug::cp_pass;
3454     BEGIN {
3455     $Whatpm::HTML::Debug::cp->{187} = 1;
3456     }
3457    
3458 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
3459 wakaba 1.18
3460     if (@{$self->{char}}) {
3461 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3462 wakaba 1.18 } else {
3463 wakaba 1.76 $self->{set_next_char}->($self);
3464 wakaba 1.18 }
3465    
3466     redo A;
3467 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3468 wakaba 1.77
3469     $Whatpm::HTML::Debug::cp_pass->(188) if $Whatpm::HTML::Debug::cp_pass;
3470     BEGIN {
3471     $Whatpm::HTML::Debug::cp->{188} = 1;
3472     }
3473    
3474 wakaba 1.70 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3475    
3476     $self->{state} = DATA_STATE;
3477    
3478     if (@{$self->{char}}) {
3479 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3480 wakaba 1.70 } else {
3481 wakaba 1.76 $self->{set_next_char}->($self);
3482 wakaba 1.70 }
3483    
3484    
3485 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3486 wakaba 1.70 return ($self->{current_token}); # DOCTYPE
3487    
3488     redo A;
3489 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3490 wakaba 1.77
3491     $Whatpm::HTML::Debug::cp_pass->(189) if $Whatpm::HTML::Debug::cp_pass;
3492     BEGIN {
3493     $Whatpm::HTML::Debug::cp->{189} = 1;
3494     }
3495    
3496 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3497    
3498 wakaba 1.59 $self->{state} = DATA_STATE;
3499 wakaba 1.18 ## reconsume
3500    
3501 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3502 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3503    
3504     redo A;
3505     } else {
3506 wakaba 1.77
3507     $Whatpm::HTML::Debug::cp_pass->(190) if $Whatpm::HTML::Debug::cp_pass;
3508     BEGIN {
3509     $Whatpm::HTML::Debug::cp->{190} = 1;
3510     }
3511    
3512 wakaba 1.18 $self->{current_token}->{public_identifier} # DOCTYPE
3513 wakaba 1.76 .= chr $self->{next_char};
3514 wakaba 1.18 ## Stay in the state
3515    
3516     if (@{$self->{char}}) {
3517 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3518 wakaba 1.18 } else {
3519 wakaba 1.76 $self->{set_next_char}->($self);
3520 wakaba 1.18 }
3521    
3522     redo A;
3523     }
3524 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE) {
3525 wakaba 1.76 if ($self->{next_char} == 0x0027) { # '
3526 wakaba 1.77
3527     $Whatpm::HTML::Debug::cp_pass->(191) if $Whatpm::HTML::Debug::cp_pass;
3528     BEGIN {
3529     $Whatpm::HTML::Debug::cp->{191} = 1;
3530     }
3531    
3532 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
3533 wakaba 1.18
3534     if (@{$self->{char}}) {
3535 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3536 wakaba 1.18 } else {
3537 wakaba 1.76 $self->{set_next_char}->($self);
3538 wakaba 1.18 }
3539    
3540     redo A;
3541 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3542 wakaba 1.77
3543     $Whatpm::HTML::Debug::cp_pass->(192) if $Whatpm::HTML::Debug::cp_pass;
3544     BEGIN {
3545     $Whatpm::HTML::Debug::cp->{192} = 1;
3546     }
3547    
3548 wakaba 1.70 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3549    
3550     $self->{state} = DATA_STATE;
3551    
3552     if (@{$self->{char}}) {
3553 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3554 wakaba 1.70 } else {
3555 wakaba 1.76 $self->{set_next_char}->($self);
3556 wakaba 1.70 }
3557    
3558    
3559 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3560 wakaba 1.70 return ($self->{current_token}); # DOCTYPE
3561    
3562     redo A;
3563 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3564 wakaba 1.77
3565     $Whatpm::HTML::Debug::cp_pass->(193) if $Whatpm::HTML::Debug::cp_pass;
3566     BEGIN {
3567     $Whatpm::HTML::Debug::cp->{193} = 1;
3568     }
3569    
3570 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3571    
3572 wakaba 1.59 $self->{state} = DATA_STATE;
3573 wakaba 1.18 ## reconsume
3574    
3575 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3576 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3577    
3578     redo A;
3579     } else {
3580 wakaba 1.77
3581     $Whatpm::HTML::Debug::cp_pass->(194) if $Whatpm::HTML::Debug::cp_pass;
3582     BEGIN {
3583     $Whatpm::HTML::Debug::cp->{194} = 1;
3584     }
3585    
3586 wakaba 1.18 $self->{current_token}->{public_identifier} # DOCTYPE
3587 wakaba 1.76 .= chr $self->{next_char};
3588 wakaba 1.18 ## Stay in the state
3589    
3590     if (@{$self->{char}}) {
3591 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3592 wakaba 1.18 } else {
3593 wakaba 1.76 $self->{set_next_char}->($self);
3594 wakaba 1.18 }
3595    
3596     redo A;
3597     }
3598 wakaba 1.59 } elsif ($self->{state} == AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {
3599 wakaba 1.18 if ({
3600     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
3601     #0x000D => 1, # HT, LF, VT, FF, SP, CR
3602 wakaba 1.76 }->{$self->{next_char}}) {
3603 wakaba 1.77
3604     $Whatpm::HTML::Debug::cp_pass->(195) if $Whatpm::HTML::Debug::cp_pass;
3605     BEGIN {
3606     $Whatpm::HTML::Debug::cp->{195} = 1;
3607     }
3608    
3609 wakaba 1.1 ## Stay in the state
3610    
3611     if (@{$self->{char}}) {
3612 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3613 wakaba 1.1 } else {
3614 wakaba 1.76 $self->{set_next_char}->($self);
3615 wakaba 1.1 }
3616    
3617     redo A;
3618 wakaba 1.76 } elsif ($self->{next_char} == 0x0022) { # "
3619 wakaba 1.77
3620     $Whatpm::HTML::Debug::cp_pass->(196) if $Whatpm::HTML::Debug::cp_pass;
3621     BEGIN {
3622     $Whatpm::HTML::Debug::cp->{196} = 1;
3623     }
3624    
3625 wakaba 1.18 $self->{current_token}->{system_identifier} = ''; # DOCTYPE
3626 wakaba 1.59 $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
3627 wakaba 1.18
3628     if (@{$self->{char}}) {
3629 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3630 wakaba 1.18 } else {
3631 wakaba 1.76 $self->{set_next_char}->($self);
3632 wakaba 1.18 }
3633    
3634     redo A;
3635 wakaba 1.76 } elsif ($self->{next_char} == 0x0027) { # '
3636 wakaba 1.77
3637     $Whatpm::HTML::Debug::cp_pass->(197) if $Whatpm::HTML::Debug::cp_pass;
3638     BEGIN {
3639     $Whatpm::HTML::Debug::cp->{197} = 1;
3640     }
3641    
3642 wakaba 1.18 $self->{current_token}->{system_identifier} = ''; # DOCTYPE
3643 wakaba 1.59 $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
3644 wakaba 1.18
3645     if (@{$self->{char}}) {
3646 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3647 wakaba 1.18 } else {
3648 wakaba 1.76 $self->{set_next_char}->($self);
3649 wakaba 1.18 }
3650    
3651     redo A;
3652 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3653 wakaba 1.77
3654     $Whatpm::HTML::Debug::cp_pass->(198) if $Whatpm::HTML::Debug::cp_pass;
3655     BEGIN {
3656     $Whatpm::HTML::Debug::cp->{198} = 1;
3657     }
3658    
3659 wakaba 1.59 $self->{state} = DATA_STATE;
3660 wakaba 1.18
3661     if (@{$self->{char}}) {
3662 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3663 wakaba 1.18 } else {
3664 wakaba 1.76 $self->{set_next_char}->($self);
3665 wakaba 1.18 }
3666    
3667    
3668     return ($self->{current_token}); # DOCTYPE
3669    
3670     redo A;
3671 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3672 wakaba 1.77
3673     $Whatpm::HTML::Debug::cp_pass->(199) if $Whatpm::HTML::Debug::cp_pass;
3674     BEGIN {
3675     $Whatpm::HTML::Debug::cp->{199} = 1;
3676     }
3677    
3678 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3679    
3680 wakaba 1.59 $self->{state} = DATA_STATE;
3681 wakaba 1.26 ## reconsume
3682 wakaba 1.18
3683 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3684 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3685    
3686     redo A;
3687     } else {
3688 wakaba 1.77
3689     $Whatpm::HTML::Debug::cp_pass->(200) if $Whatpm::HTML::Debug::cp_pass;
3690     BEGIN {
3691     $Whatpm::HTML::Debug::cp->{200} = 1;
3692     }
3693    
3694 wakaba 1.18 $self->{parse_error}-> (type => 'string after PUBLIC literal');
3695 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3696 wakaba 1.73
3697 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
3698 wakaba 1.18
3699     if (@{$self->{char}}) {
3700 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3701 wakaba 1.18 } else {
3702 wakaba 1.76 $self->{set_next_char}->($self);
3703 wakaba 1.18 }
3704    
3705     redo A;
3706 wakaba 1.1 }
3707 wakaba 1.59 } elsif ($self->{state} == BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {
3708 wakaba 1.18 if ({
3709     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
3710     #0x000D => 1, # HT, LF, VT, FF, SP, CR
3711 wakaba 1.76 }->{$self->{next_char}}) {
3712 wakaba 1.77
3713     $Whatpm::HTML::Debug::cp_pass->(201) if $Whatpm::HTML::Debug::cp_pass;
3714     BEGIN {
3715     $Whatpm::HTML::Debug::cp->{201} = 1;
3716     }
3717    
3718 wakaba 1.1 ## Stay in the state
3719    
3720     if (@{$self->{char}}) {
3721 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3722 wakaba 1.1 } else {
3723 wakaba 1.76 $self->{set_next_char}->($self);
3724 wakaba 1.1 }
3725    
3726     redo A;
3727 wakaba 1.76 } elsif ($self->{next_char} == 0x0022) { # "
3728 wakaba 1.77
3729     $Whatpm::HTML::Debug::cp_pass->(202) if $Whatpm::HTML::Debug::cp_pass;
3730     BEGIN {
3731     $Whatpm::HTML::Debug::cp->{202} = 1;
3732     }
3733    
3734 wakaba 1.18 $self->{current_token}->{system_identifier} = ''; # DOCTYPE
3735 wakaba 1.59 $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
3736 wakaba 1.18
3737     if (@{$self->{char}}) {
3738 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3739 wakaba 1.18 } else {
3740 wakaba 1.76 $self->{set_next_char}->($self);
3741 wakaba 1.18 }
3742    
3743     redo A;
3744 wakaba 1.76 } elsif ($self->{next_char} == 0x0027) { # '
3745 wakaba 1.77
3746     $Whatpm::HTML::Debug::cp_pass->(203) if $Whatpm::HTML::Debug::cp_pass;
3747     BEGIN {
3748     $Whatpm::HTML::Debug::cp->{203} = 1;
3749     }
3750    
3751 wakaba 1.18 $self->{current_token}->{system_identifier} = ''; # DOCTYPE
3752 wakaba 1.59 $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
3753 wakaba 1.18
3754     if (@{$self->{char}}) {
3755 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3756 wakaba 1.18 } else {
3757 wakaba 1.76 $self->{set_next_char}->($self);
3758 wakaba 1.18 }
3759    
3760     redo A;
3761 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3762 wakaba 1.77
3763     $Whatpm::HTML::Debug::cp_pass->(204) if $Whatpm::HTML::Debug::cp_pass;
3764     BEGIN {
3765     $Whatpm::HTML::Debug::cp->{204} = 1;
3766     }
3767    
3768 wakaba 1.18 $self->{parse_error}-> (type => 'no SYSTEM literal');
3769 wakaba 1.59 $self->{state} = DATA_STATE;
3770 wakaba 1.1
3771     if (@{$self->{char}}) {
3772 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3773 wakaba 1.1 } else {
3774 wakaba 1.76 $self->{set_next_char}->($self);
3775 wakaba 1.1 }
3776    
3777    
3778 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3779 wakaba 1.1 return ($self->{current_token}); # DOCTYPE
3780    
3781     redo A;
3782 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3783 wakaba 1.77
3784     $Whatpm::HTML::Debug::cp_pass->(205) if $Whatpm::HTML::Debug::cp_pass;
3785     BEGIN {
3786     $Whatpm::HTML::Debug::cp->{205} = 1;
3787     }
3788    
3789 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3790 wakaba 1.18
3791 wakaba 1.59 $self->{state} = DATA_STATE;
3792 wakaba 1.26 ## reconsume
3793 wakaba 1.18
3794 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3795 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3796    
3797     redo A;
3798     } else {
3799 wakaba 1.77
3800     $Whatpm::HTML::Debug::cp_pass->(206) if $Whatpm::HTML::Debug::cp_pass;
3801     BEGIN {
3802     $Whatpm::HTML::Debug::cp->{206} = 1;
3803     }
3804    
3805 wakaba 1.30 $self->{parse_error}-> (type => 'string after SYSTEM');
3806 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3807 wakaba 1.73
3808 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
3809 wakaba 1.18
3810     if (@{$self->{char}}) {
3811 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3812 wakaba 1.18 } else {
3813 wakaba 1.76 $self->{set_next_char}->($self);
3814 wakaba 1.18 }
3815    
3816     redo A;
3817     }
3818 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE) {
3819 wakaba 1.76 if ($self->{next_char} == 0x0022) { # "
3820 wakaba 1.77
3821     $Whatpm::HTML::Debug::cp_pass->(207) if $Whatpm::HTML::Debug::cp_pass;
3822     BEGIN {
3823     $Whatpm::HTML::Debug::cp->{207} = 1;
3824     }
3825    
3826 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
3827 wakaba 1.18
3828     if (@{$self->{char}}) {
3829 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3830 wakaba 1.18 } else {
3831 wakaba 1.76 $self->{set_next_char}->($self);
3832 wakaba 1.18 }
3833    
3834     redo A;
3835 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3836 wakaba 1.77
3837     $Whatpm::HTML::Debug::cp_pass->(208) if $Whatpm::HTML::Debug::cp_pass;
3838     BEGIN {
3839     $Whatpm::HTML::Debug::cp->{208} = 1;
3840     }
3841    
3842 wakaba 1.70 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3843    
3844     $self->{state} = DATA_STATE;
3845    
3846     if (@{$self->{char}}) {
3847 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3848 wakaba 1.70 } else {
3849 wakaba 1.76 $self->{set_next_char}->($self);
3850 wakaba 1.70 }
3851    
3852    
3853 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3854 wakaba 1.70 return ($self->{current_token}); # DOCTYPE
3855    
3856     redo A;
3857 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3858 wakaba 1.77
3859     $Whatpm::HTML::Debug::cp_pass->(209) if $Whatpm::HTML::Debug::cp_pass;
3860     BEGIN {
3861     $Whatpm::HTML::Debug::cp->{209} = 1;
3862     }
3863    
3864 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed SYSTEM literal');
3865    
3866 wakaba 1.59 $self->{state} = DATA_STATE;
3867 wakaba 1.1 ## reconsume
3868    
3869 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3870 wakaba 1.1 return ($self->{current_token}); # DOCTYPE
3871    
3872     redo A;
3873     } else {
3874 wakaba 1.77
3875     $Whatpm::HTML::Debug::cp_pass->(210) if $Whatpm::HTML::Debug::cp_pass;
3876     BEGIN {
3877     $Whatpm::HTML::Debug::cp->{210} = 1;
3878     }
3879    
3880 wakaba 1.18 $self->{current_token}->{system_identifier} # DOCTYPE
3881 wakaba 1.76 .= chr $self->{next_char};
3882 wakaba 1.18 ## Stay in the state
3883    
3884     if (@{$self->{char}}) {
3885 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3886 wakaba 1.18 } else {
3887 wakaba 1.76 $self->{set_next_char}->($self);
3888 wakaba 1.18 }
3889    
3890     redo A;
3891     }
3892 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE) {
3893 wakaba 1.76 if ($self->{next_char} == 0x0027) { # '
3894 wakaba 1.77
3895     $Whatpm::HTML::Debug::cp_pass->(211) if $Whatpm::HTML::Debug::cp_pass;
3896     BEGIN {
3897     $Whatpm::HTML::Debug::cp->{211} = 1;
3898     }
3899    
3900 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
3901 wakaba 1.18
3902     if (@{$self->{char}}) {
3903 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3904 wakaba 1.18 } else {
3905 wakaba 1.76 $self->{set_next_char}->($self);
3906 wakaba 1.18 }
3907    
3908     redo A;
3909 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3910 wakaba 1.77
3911     $Whatpm::HTML::Debug::cp_pass->(212) if $Whatpm::HTML::Debug::cp_pass;
3912     BEGIN {
3913     $Whatpm::HTML::Debug::cp->{212} = 1;
3914     }
3915    
3916 wakaba 1.70 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3917    
3918     $self->{state} = DATA_STATE;
3919    
3920     if (@{$self->{char}}) {
3921 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3922 wakaba 1.70 } else {
3923 wakaba 1.76 $self->{set_next_char}->($self);
3924 wakaba 1.70 }
3925    
3926    
3927 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3928 wakaba 1.70 return ($self->{current_token}); # DOCTYPE
3929    
3930     redo A;
3931 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3932 wakaba 1.77
3933     $Whatpm::HTML::Debug::cp_pass->(213) if $Whatpm::HTML::Debug::cp_pass;
3934     BEGIN {
3935     $Whatpm::HTML::Debug::cp->{213} = 1;
3936     }
3937    
3938 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed SYSTEM literal');
3939    
3940 wakaba 1.59 $self->{state} = DATA_STATE;
3941 wakaba 1.18 ## reconsume
3942    
3943 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3944 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3945    
3946     redo A;
3947     } else {
3948 wakaba 1.77
3949     $Whatpm::HTML::Debug::cp_pass->(214) if $Whatpm::HTML::Debug::cp_pass;
3950     BEGIN {
3951     $Whatpm::HTML::Debug::cp->{214} = 1;
3952     }
3953    
3954 wakaba 1.18 $self->{current_token}->{system_identifier} # DOCTYPE
3955 wakaba 1.76 .= chr $self->{next_char};
3956 wakaba 1.18 ## Stay in the state
3957    
3958     if (@{$self->{char}}) {
3959 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3960 wakaba 1.18 } else {
3961 wakaba 1.76 $self->{set_next_char}->($self);
3962 wakaba 1.18 }
3963    
3964     redo A;
3965     }
3966 wakaba 1.59 } elsif ($self->{state} == AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {
3967 wakaba 1.18 if ({
3968     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
3969     #0x000D => 1, # HT, LF, VT, FF, SP, CR
3970 wakaba 1.76 }->{$self->{next_char}}) {
3971 wakaba 1.77
3972     $Whatpm::HTML::Debug::cp_pass->(215) if $Whatpm::HTML::Debug::cp_pass;
3973     BEGIN {
3974     $Whatpm::HTML::Debug::cp->{215} = 1;
3975     }
3976    
3977 wakaba 1.18 ## Stay in the state
3978    
3979     if (@{$self->{char}}) {
3980 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3981 wakaba 1.18 } else {
3982 wakaba 1.76 $self->{set_next_char}->($self);
3983 wakaba 1.18 }
3984    
3985     redo A;
3986 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3987 wakaba 1.77
3988     $Whatpm::HTML::Debug::cp_pass->(216) if $Whatpm::HTML::Debug::cp_pass;
3989     BEGIN {
3990     $Whatpm::HTML::Debug::cp->{216} = 1;
3991     }
3992    
3993 wakaba 1.59 $self->{state} = DATA_STATE;
3994 wakaba 1.18
3995     if (@{$self->{char}}) {
3996 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3997 wakaba 1.18 } else {
3998 wakaba 1.76 $self->{set_next_char}->($self);
3999 wakaba 1.18 }
4000    
4001    
4002     return ($self->{current_token}); # DOCTYPE
4003    
4004     redo A;
4005 wakaba 1.76 } elsif ($self->{next_char} == -1) {
4006 wakaba 1.77
4007     $Whatpm::HTML::Debug::cp_pass->(217) if $Whatpm::HTML::Debug::cp_pass;
4008     BEGIN {
4009     $Whatpm::HTML::Debug::cp->{217} = 1;
4010     }
4011    
4012 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
4013    
4014 wakaba 1.59 $self->{state} = DATA_STATE;
4015 wakaba 1.26 ## reconsume
4016 wakaba 1.18
4017 wakaba 1.75 $self->{current_token}->{quirks} = 1;
4018 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
4019    
4020     redo A;
4021     } else {
4022 wakaba 1.77
4023     $Whatpm::HTML::Debug::cp_pass->(218) if $Whatpm::HTML::Debug::cp_pass;
4024     BEGIN {
4025     $Whatpm::HTML::Debug::cp->{218} = 1;
4026     }
4027    
4028 wakaba 1.18 $self->{parse_error}-> (type => 'string after SYSTEM literal');
4029 wakaba 1.75 #$self->{current_token}->{quirks} = 1;
4030 wakaba 1.73
4031 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
4032 wakaba 1.1
4033     if (@{$self->{char}}) {
4034 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4035 wakaba 1.1 } else {
4036 wakaba 1.76 $self->{set_next_char}->($self);
4037 wakaba 1.1 }
4038    
4039     redo A;
4040     }
4041 wakaba 1.59 } elsif ($self->{state} == BOGUS_DOCTYPE_STATE) {
4042 wakaba 1.76 if ($self->{next_char} == 0x003E) { # >
4043 wakaba 1.77
4044     $Whatpm::HTML::Debug::cp_pass->(219) if $Whatpm::HTML::Debug::cp_pass;
4045     BEGIN {
4046     $Whatpm::HTML::Debug::cp->{219} = 1;
4047     }
4048    
4049 wakaba 1.59 $self->{state} = DATA_STATE;
4050 wakaba 1.1
4051     if (@{$self->{char}}) {
4052 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4053 wakaba 1.1 } else {
4054 wakaba 1.76 $self->{set_next_char}->($self);
4055 wakaba 1.1 }
4056    
4057    
4058     return ($self->{current_token}); # DOCTYPE
4059    
4060     redo A;
4061 wakaba 1.76 } elsif ($self->{next_char} == -1) {
4062 wakaba 1.77
4063     $Whatpm::HTML::Debug::cp_pass->(220) if $Whatpm::HTML::Debug::cp_pass;
4064     BEGIN {
4065     $Whatpm::HTML::Debug::cp->{220} = 1;
4066     }
4067    
4068 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
4069 wakaba 1.59 $self->{state} = DATA_STATE;
4070 wakaba 1.1 ## reconsume
4071    
4072     return ($self->{current_token}); # DOCTYPE
4073    
4074     redo A;
4075     } else {
4076 wakaba 1.77
4077     $Whatpm::HTML::Debug::cp_pass->(221) if $Whatpm::HTML::Debug::cp_pass;
4078     BEGIN {
4079     $Whatpm::HTML::Debug::cp->{221} = 1;
4080     }
4081    
4082 wakaba 1.1 ## Stay in the state
4083    
4084     if (@{$self->{char}}) {
4085 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4086 wakaba 1.1 } else {
4087 wakaba 1.76 $self->{set_next_char}->($self);
4088 wakaba 1.1 }
4089    
4090     redo A;
4091     }
4092     } else {
4093     die "$0: $self->{state}: Unknown state";
4094     }
4095     } # A
4096    
4097     die "$0: _get_next_token: unexpected case";
4098     } # _get_next_token
4099    
4100 wakaba 1.72 sub _tokenize_attempt_to_consume_an_entity ($$$) {
4101     my ($self, $in_attr, $additional) = @_;
4102 wakaba 1.20
4103     if ({
4104     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, # HT, LF, VT, FF,
4105     0x0020 => 1, 0x003C => 1, 0x0026 => 1, -1 => 1, # SP, <, & # 0x000D # CR
4106 wakaba 1.72 $additional => 1,
4107 wakaba 1.76 }->{$self->{next_char}}) {
4108 wakaba 1.78
4109     $Whatpm::HTML::Debug::cp_pass->(1001) if $Whatpm::HTML::Debug::cp_pass;
4110     BEGIN {
4111     $Whatpm::HTML::Debug::cp->{1001} = 1;
4112     }
4113    
4114 wakaba 1.20 ## Don't consume
4115     ## No error
4116     return undef;
4117 wakaba 1.76 } elsif ($self->{next_char} == 0x0023) { # #
4118 wakaba 1.1
4119     if (@{$self->{char}}) {
4120 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4121 wakaba 1.1 } else {
4122 wakaba 1.76 $self->{set_next_char}->($self);
4123 wakaba 1.1 }
4124    
4125 wakaba 1.76 if ($self->{next_char} == 0x0078 or # x
4126     $self->{next_char} == 0x0058) { # X
4127 wakaba 1.26 my $code;
4128 wakaba 1.1 X: {
4129 wakaba 1.76 my $x_char = $self->{next_char};
4130 wakaba 1.1
4131     if (@{$self->{char}}) {
4132 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4133 wakaba 1.1 } else {
4134 wakaba 1.76 $self->{set_next_char}->($self);
4135 wakaba 1.1 }
4136    
4137 wakaba 1.76 if (0x0030 <= $self->{next_char} and
4138     $self->{next_char} <= 0x0039) { # 0..9
4139 wakaba 1.78
4140     $Whatpm::HTML::Debug::cp_pass->(1002) if $Whatpm::HTML::Debug::cp_pass;
4141     BEGIN {
4142     $Whatpm::HTML::Debug::cp->{1002} = 1;
4143     }
4144    
4145 wakaba 1.26 $code ||= 0;
4146     $code *= 0x10;
4147 wakaba 1.76 $code += $self->{next_char} - 0x0030;
4148 wakaba 1.1 redo X;
4149 wakaba 1.76 } elsif (0x0061 <= $self->{next_char} and
4150     $self->{next_char} <= 0x0066) { # a..f
4151 wakaba 1.78
4152     $Whatpm::HTML::Debug::cp_pass->(1003) if $Whatpm::HTML::Debug::cp_pass;
4153     BEGIN {
4154     $Whatpm::HTML::Debug::cp->{1003} = 1;
4155     }
4156    
4157 wakaba 1.26 $code ||= 0;
4158     $code *= 0x10;
4159 wakaba 1.76 $code += $self->{next_char} - 0x0060 + 9;
4160 wakaba 1.1 redo X;
4161 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
4162     $self->{next_char} <= 0x0046) { # A..F
4163 wakaba 1.78
4164     $Whatpm::HTML::Debug::cp_pass->(1004) if $Whatpm::HTML::Debug::cp_pass;
4165     BEGIN {
4166     $Whatpm::HTML::Debug::cp->{1004} = 1;
4167     }
4168    
4169 wakaba 1.26 $code ||= 0;
4170     $code *= 0x10;
4171 wakaba 1.76 $code += $self->{next_char} - 0x0040 + 9;
4172 wakaba 1.1 redo X;
4173 wakaba 1.26 } elsif (not defined $code) { # no hexadecimal digit
4174 wakaba 1.78
4175     $Whatpm::HTML::Debug::cp_pass->(1005) if $Whatpm::HTML::Debug::cp_pass;
4176     BEGIN {
4177     $Whatpm::HTML::Debug::cp->{1005} = 1;
4178     }
4179    
4180 wakaba 1.3 $self->{parse_error}-> (type => 'bare hcro');
4181 wakaba 1.76 unshift @{$self->{char}}, ($x_char, $self->{next_char});
4182     $self->{next_char} = 0x0023; # #
4183 wakaba 1.1 return undef;
4184 wakaba 1.76 } elsif ($self->{next_char} == 0x003B) { # ;
4185 wakaba 1.1
4186 wakaba 1.78 $Whatpm::HTML::Debug::cp_pass->(1006) if $Whatpm::HTML::Debug::cp_pass;
4187     BEGIN {
4188     $Whatpm::HTML::Debug::cp->{1006} = 1;
4189     }
4190    
4191    
4192 wakaba 1.1 if (@{$self->{char}}) {
4193 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4194 wakaba 1.1 } else {
4195 wakaba 1.76 $self->{set_next_char}->($self);
4196 wakaba 1.1 }
4197    
4198     } else {
4199 wakaba 1.78
4200     $Whatpm::HTML::Debug::cp_pass->(1007) if $Whatpm::HTML::Debug::cp_pass;
4201     BEGIN {
4202     $Whatpm::HTML::Debug::cp->{1007} = 1;
4203     }
4204    
4205 wakaba 1.3 $self->{parse_error}-> (type => 'no refc');
4206 wakaba 1.1 }
4207    
4208 wakaba 1.26 if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {
4209 wakaba 1.78
4210     $Whatpm::HTML::Debug::cp_pass->(1008) if $Whatpm::HTML::Debug::cp_pass;
4211     BEGIN {
4212     $Whatpm::HTML::Debug::cp->{1008} = 1;
4213     }
4214    
4215 wakaba 1.26 $self->{parse_error}-> (type => sprintf 'invalid character reference:U+%04X', $code);
4216     $code = 0xFFFD;
4217     } elsif ($code > 0x10FFFF) {
4218 wakaba 1.78
4219     $Whatpm::HTML::Debug::cp_pass->(1009) if $Whatpm::HTML::Debug::cp_pass;
4220     BEGIN {
4221     $Whatpm::HTML::Debug::cp->{1009} = 1;
4222     }
4223    
4224 wakaba 1.26 $self->{parse_error}-> (type => sprintf 'invalid character reference:U-%08X', $code);
4225     $code = 0xFFFD;
4226     } elsif ($code == 0x000D) {
4227 wakaba 1.78
4228     $Whatpm::HTML::Debug::cp_pass->(1010) if $Whatpm::HTML::Debug::cp_pass;
4229     BEGIN {
4230     $Whatpm::HTML::Debug::cp->{1010} = 1;
4231     }
4232    
4233 wakaba 1.26 $self->{parse_error}-> (type => 'CR character reference');
4234     $code = 0x000A;
4235     } elsif (0x80 <= $code and $code <= 0x9F) {
4236 wakaba 1.78
4237     $Whatpm::HTML::Debug::cp_pass->(1011) if $Whatpm::HTML::Debug::cp_pass;
4238     BEGIN {
4239     $Whatpm::HTML::Debug::cp->{1011} = 1;
4240     }
4241    
4242 wakaba 1.30 $self->{parse_error}-> (type => sprintf 'C1 character reference:U+%04X', $code);
4243 wakaba 1.26 $code = $c1_entity_char->{$code};
4244 wakaba 1.1 }
4245    
4246 wakaba 1.68 return {type => CHARACTER_TOKEN, data => chr $code,
4247     has_reference => 1};
4248 wakaba 1.1 } # X
4249 wakaba 1.76 } elsif (0x0030 <= $self->{next_char} and
4250     $self->{next_char} <= 0x0039) { # 0..9
4251     my $code = $self->{next_char} - 0x0030;
4252 wakaba 1.1
4253     if (@{$self->{char}}) {
4254 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4255 wakaba 1.1 } else {
4256 wakaba 1.76 $self->{set_next_char}->($self);
4257 wakaba 1.1 }
4258    
4259    
4260 wakaba 1.76 while (0x0030 <= $self->{next_char} and
4261     $self->{next_char} <= 0x0039) { # 0..9
4262 wakaba 1.78
4263     $Whatpm::HTML::Debug::cp_pass->(1012) if $Whatpm::HTML::Debug::cp_pass;
4264     BEGIN {
4265     $Whatpm::HTML::Debug::cp->{1012} = 1;
4266     }
4267    
4268 wakaba 1.1 $code *= 10;
4269 wakaba 1.76 $code += $self->{next_char} - 0x0030;
4270 wakaba 1.1
4271    
4272     if (@{$self->{char}}) {
4273 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4274 wakaba 1.1 } else {
4275 wakaba 1.76 $self->{set_next_char}->($self);
4276 wakaba 1.1 }
4277    
4278     }
4279    
4280 wakaba 1.76 if ($self->{next_char} == 0x003B) { # ;
4281 wakaba 1.1
4282 wakaba 1.78 $Whatpm::HTML::Debug::cp_pass->(1013) if $Whatpm::HTML::Debug::cp_pass;
4283     BEGIN {
4284     $Whatpm::HTML::Debug::cp->{1013} = 1;
4285     }
4286    
4287    
4288 wakaba 1.1 if (@{$self->{char}}) {
4289 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4290 wakaba 1.1 } else {
4291 wakaba 1.76 $self->{set_next_char}->($self);
4292 wakaba 1.1 }
4293    
4294     } else {
4295 wakaba 1.78
4296     $Whatpm::HTML::Debug::cp_pass->(1014) if $Whatpm::HTML::Debug::cp_pass;
4297     BEGIN {
4298     $Whatpm::HTML::Debug::cp->{1014} = 1;
4299     }
4300    
4301 wakaba 1.3 $self->{parse_error}-> (type => 'no refc');
4302 wakaba 1.1 }
4303    
4304 wakaba 1.26 if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {
4305 wakaba 1.78
4306     $Whatpm::HTML::Debug::cp_pass->(1015) if $Whatpm::HTML::Debug::cp_pass;
4307     BEGIN {
4308     $Whatpm::HTML::Debug::cp->{1015} = 1;
4309     }
4310    
4311 wakaba 1.26 $self->{parse_error}-> (type => sprintf 'invalid character reference:U+%04X', $code);
4312     $code = 0xFFFD;
4313     } elsif ($code > 0x10FFFF) {
4314 wakaba 1.78
4315     $Whatpm::HTML::Debug::cp_pass->(1016) if $Whatpm::HTML::Debug::cp_pass;
4316     BEGIN {
4317     $Whatpm::HTML::Debug::cp->{1016} = 1;
4318     }
4319    
4320 wakaba 1.26 $self->{parse_error}-> (type => sprintf 'invalid character reference:U-%08X', $code);
4321     $code = 0xFFFD;
4322     } elsif ($code == 0x000D) {
4323 wakaba 1.78
4324     $Whatpm::HTML::Debug::cp_pass->(1017) if $Whatpm::HTML::Debug::cp_pass;
4325     BEGIN {
4326     $Whatpm::HTML::Debug::cp->{1017} = 1;
4327     }
4328    
4329 wakaba 1.26 $self->{parse_error}-> (type => 'CR character reference');
4330     $code = 0x000A;
4331 wakaba 1.4 } elsif (0x80 <= $code and $code <= 0x9F) {
4332 wakaba 1.78
4333     $Whatpm::HTML::Debug::cp_pass->(1018) if $Whatpm::HTML::Debug::cp_pass;
4334     BEGIN {
4335     $Whatpm::HTML::Debug::cp->{1018} = 1;
4336     }
4337    
4338 wakaba 1.30 $self->{parse_error}-> (type => sprintf 'C1 character reference:U+%04X', $code);
4339 wakaba 1.4 $code = $c1_entity_char->{$code};
4340 wakaba 1.1 }
4341    
4342 wakaba 1.68 return {type => CHARACTER_TOKEN, data => chr $code, has_reference => 1};
4343 wakaba 1.1 } else {
4344 wakaba 1.78
4345     $Whatpm::HTML::Debug::cp_pass->(1019) if $Whatpm::HTML::Debug::cp_pass;
4346     BEGIN {
4347     $Whatpm::HTML::Debug::cp->{1019} = 1;
4348     }
4349    
4350 wakaba 1.3 $self->{parse_error}-> (type => 'bare nero');
4351 wakaba 1.76 unshift @{$self->{char}}, ($self->{next_char});
4352     $self->{next_char} = 0x0023; # #
4353 wakaba 1.1 return undef;
4354     }
4355 wakaba 1.76 } elsif ((0x0041 <= $self->{next_char} and
4356     $self->{next_char} <= 0x005A) or
4357     (0x0061 <= $self->{next_char} and
4358     $self->{next_char} <= 0x007A)) {
4359     my $entity_name = chr $self->{next_char};
4360 wakaba 1.1
4361     if (@{$self->{char}}) {
4362 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4363 wakaba 1.1 } else {
4364 wakaba 1.76 $self->{set_next_char}->($self);
4365 wakaba 1.1 }
4366    
4367    
4368     my $value = $entity_name;
4369 wakaba 1.37 my $match = 0;
4370 wakaba 1.16 require Whatpm::_NamedEntityList;
4371     our $EntityChar;
4372 wakaba 1.1
4373     while (length $entity_name < 10 and
4374     ## NOTE: Some number greater than the maximum length of entity name
4375 wakaba 1.76 ((0x0041 <= $self->{next_char} and # a
4376     $self->{next_char} <= 0x005A) or # x
4377     (0x0061 <= $self->{next_char} and # a
4378     $self->{next_char} <= 0x007A) or # z
4379     (0x0030 <= $self->{next_char} and # 0
4380     $self->{next_char} <= 0x0039) or # 9
4381     $self->{next_char} == 0x003B)) { # ;
4382     $entity_name .= chr $self->{next_char};
4383 wakaba 1.16 if (defined $EntityChar->{$entity_name}) {
4384 wakaba 1.76 if ($self->{next_char} == 0x003B) { # ;
4385 wakaba 1.78
4386     $Whatpm::HTML::Debug::cp_pass->(1020) if $Whatpm::HTML::Debug::cp_pass;
4387     BEGIN {
4388     $Whatpm::HTML::Debug::cp->{1020} = 1;
4389     }
4390    
4391 wakaba 1.26 $value = $EntityChar->{$entity_name};
4392 wakaba 1.16 $match = 1;
4393    
4394     if (@{$self->{char}}) {
4395 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4396 wakaba 1.16 } else {
4397 wakaba 1.76 $self->{set_next_char}->($self);
4398 wakaba 1.16 }
4399    
4400     last;
4401 wakaba 1.37 } else {
4402 wakaba 1.78
4403     $Whatpm::HTML::Debug::cp_pass->(1021) if $Whatpm::HTML::Debug::cp_pass;
4404     BEGIN {
4405     $Whatpm::HTML::Debug::cp->{1021} = 1;
4406     }
4407    
4408 wakaba 1.26 $value = $EntityChar->{$entity_name};
4409     $match = -1;
4410 wakaba 1.37
4411     if (@{$self->{char}}) {
4412 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4413 wakaba 1.37 } else {
4414 wakaba 1.76 $self->{set_next_char}->($self);
4415 wakaba 1.37 }
4416    
4417 wakaba 1.16 }
4418 wakaba 1.1 } else {
4419 wakaba 1.78
4420     $Whatpm::HTML::Debug::cp_pass->(1022) if $Whatpm::HTML::Debug::cp_pass;
4421     BEGIN {
4422     $Whatpm::HTML::Debug::cp->{1022} = 1;
4423     }
4424    
4425 wakaba 1.76 $value .= chr $self->{next_char};
4426 wakaba 1.37 $match *= 2;
4427    
4428 wakaba 1.1 if (@{$self->{char}}) {
4429 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4430 wakaba 1.1 } else {
4431 wakaba 1.76 $self->{set_next_char}->($self);
4432 wakaba 1.1 }
4433    
4434 wakaba 1.37 }
4435 wakaba 1.1 }
4436    
4437 wakaba 1.16 if ($match > 0) {
4438 wakaba 1.78
4439     $Whatpm::HTML::Debug::cp_pass->(1023) if $Whatpm::HTML::Debug::cp_pass;
4440     BEGIN {
4441     $Whatpm::HTML::Debug::cp->{1023} = 1;
4442     }
4443    
4444 wakaba 1.68 return {type => CHARACTER_TOKEN, data => $value, has_reference => 1};
4445 wakaba 1.16 } elsif ($match < 0) {
4446 wakaba 1.30 $self->{parse_error}-> (type => 'no refc');
4447 wakaba 1.37 if ($in_attr and $match < -1) {
4448 wakaba 1.78
4449     $Whatpm::HTML::Debug::cp_pass->(1024) if $Whatpm::HTML::Debug::cp_pass;
4450     BEGIN {
4451     $Whatpm::HTML::Debug::cp->{1024} = 1;
4452     }
4453    
4454 wakaba 1.57 return {type => CHARACTER_TOKEN, data => '&'.$entity_name};
4455 wakaba 1.37 } else {
4456 wakaba 1.78
4457     $Whatpm::HTML::Debug::cp_pass->(1025) if $Whatpm::HTML::Debug::cp_pass;
4458     BEGIN {
4459     $Whatpm::HTML::Debug::cp->{1025} = 1;
4460     }
4461    
4462 wakaba 1.68 return {type => CHARACTER_TOKEN, data => $value, has_reference => 1};
4463 wakaba 1.37 }
4464 wakaba 1.1 } else {
4465 wakaba 1.78
4466     $Whatpm::HTML::Debug::cp_pass->(1026) if $Whatpm::HTML::Debug::cp_pass;
4467     BEGIN {
4468     $Whatpm::HTML::Debug::cp->{1026} = 1;
4469     }
4470    
4471 wakaba 1.3 $self->{parse_error}-> (type => 'bare ero');
4472 wakaba 1.68 ## NOTE: "No characters are consumed" in the spec.
4473 wakaba 1.57 return {type => CHARACTER_TOKEN, data => '&'.$value};
4474 wakaba 1.1 }
4475     } else {
4476 wakaba 1.78
4477     $Whatpm::HTML::Debug::cp_pass->(1027) if $Whatpm::HTML::Debug::cp_pass;
4478     BEGIN {
4479     $Whatpm::HTML::Debug::cp->{1027} = 1;
4480     }
4481    
4482 wakaba 1.1 ## no characters are consumed
4483 wakaba 1.3 $self->{parse_error}-> (type => 'bare ero');
4484 wakaba 1.1 return undef;
4485     }
4486     } # _tokenize_attempt_to_consume_an_entity
4487    
4488     sub _initialize_tree_constructor ($) {
4489     my $self = shift;
4490     ## NOTE: $self->{document} MUST be specified before this method is called
4491     $self->{document}->strict_error_checking (0);
4492     ## TODO: Turn mutation events off # MUST
4493     ## TODO: Turn loose Document option (manakai extension) on
4494 wakaba 1.18 $self->{document}->manakai_is_html (1); # MUST
4495 wakaba 1.1 } # _initialize_tree_constructor
4496    
4497     sub _terminate_tree_constructor ($) {
4498     my $self = shift;
4499     $self->{document}->strict_error_checking (1);
4500     ## TODO: Turn mutation events on
4501     } # _terminate_tree_constructor
4502    
4503     ## ISSUE: Should append_child (for example) in script executed in tree construction stage fire mutation events?
4504    
4505 wakaba 1.3 { # tree construction stage
4506     my $token;
4507    
4508 wakaba 1.1 sub _construct_tree ($) {
4509     my ($self) = @_;
4510    
4511     ## When an interactive UA render the $self->{document} available
4512     ## to the user, or when it begin accepting user input, are
4513     ## not defined.
4514    
4515     ## Append a character: collect it and all subsequent consecutive
4516     ## characters and insert one Text node whose data is concatenation
4517     ## of all those characters. # MUST
4518    
4519     $token = $self->_get_next_token;
4520    
4521 wakaba 1.3 undef $self->{form_element};
4522     undef $self->{head_element};
4523     $self->{open_elements} = [];
4524     undef $self->{inner_html_node};
4525    
4526 wakaba 1.84 ## NOTE: The "initial" insertion mode.
4527 wakaba 1.3 $self->_tree_construction_initial; # MUST
4528 wakaba 1.84
4529 wakaba 1.85 ## NOTE: The "before html" insertion mode.
4530 wakaba 1.3 $self->_tree_construction_root_element;
4531 wakaba 1.84 $self->{insertion_mode} = BEFORE_HEAD_IM;
4532    
4533     ## NOTE: The "before head" insertion mode and so on.
4534 wakaba 1.3 $self->_tree_construction_main;
4535     } # _construct_tree
4536    
4537     sub _tree_construction_initial ($) {
4538     my $self = shift;
4539 wakaba 1.84
4540     ## NOTE: "initial" insertion mode
4541    
4542 wakaba 1.18 INITIAL: {
4543 wakaba 1.57 if ($token->{type} == DOCTYPE_TOKEN) {
4544 wakaba 1.18 ## NOTE: Conformance checkers MAY, instead of reporting "not HTML5"
4545     ## error, switch to a conformance checking mode for another
4546     ## language.
4547     my $doctype_name = $token->{name};
4548     $doctype_name = '' unless defined $doctype_name;
4549     $doctype_name =~ tr/a-z/A-Z/;
4550     if (not defined $token->{name} or # <!DOCTYPE>
4551     defined $token->{public_identifier} or
4552     defined $token->{system_identifier}) {
4553 wakaba 1.79
4554     $Whatpm::HTML::Debug::cp_pass->('t1') if $Whatpm::HTML::Debug::cp_pass;
4555     BEGIN {
4556     $Whatpm::HTML::Debug::cp->{'t1'} = 1;
4557     }
4558    
4559 wakaba 1.18 $self->{parse_error}-> (type => 'not HTML5');
4560     } elsif ($doctype_name ne 'HTML') {
4561 wakaba 1.79
4562     $Whatpm::HTML::Debug::cp_pass->('t2') if $Whatpm::HTML::Debug::cp_pass;
4563     BEGIN {
4564     $Whatpm::HTML::Debug::cp->{'t2'} = 1;
4565     }
4566    
4567 wakaba 1.18 ## ISSUE: ASCII case-insensitive? (in fact it does not matter)
4568     $self->{parse_error}-> (type => 'not HTML5');
4569 wakaba 1.79 } else {
4570    
4571     $Whatpm::HTML::Debug::cp_pass->('t3') if $Whatpm::HTML::Debug::cp_pass;
4572     BEGIN {
4573     $Whatpm::HTML::Debug::cp->{'t3'} = 1;
4574     }
4575    
4576 wakaba 1.18 }
4577    
4578     my $doctype = $self->{document}->create_document_type_definition
4579     ($token->{name}); ## ISSUE: If name is missing (e.g. <!DOCTYPE>)?
4580     $doctype->public_id ($token->{public_identifier})
4581     if defined $token->{public_identifier};
4582     $doctype->system_id ($token->{system_identifier})
4583     if defined $token->{system_identifier};
4584     ## NOTE: Other DocumentType attributes are null or empty lists.
4585     ## ISSUE: internalSubset = null??
4586     $self->{document}->append_child ($doctype);
4587    
4588 wakaba 1.75 if ($token->{quirks} or $doctype_name ne 'HTML') {
4589 wakaba 1.79
4590     $Whatpm::HTML::Debug::cp_pass->('t4') if $Whatpm::HTML::Debug::cp_pass;
4591     BEGIN {
4592     $Whatpm::HTML::Debug::cp->{'t4'} = 1;
4593     }
4594    
4595 wakaba 1.18 $self->{document}->manakai_compat_mode ('quirks');
4596     } elsif (defined $token->{public_identifier}) {
4597     my $pubid = $token->{public_identifier};
4598     $pubid =~ tr/a-z/A-z/;
4599     if ({
4600     "+//SILMARIL//DTD HTML PRO V0R11 19970101//EN" => 1,
4601     "-//ADVASOFT LTD//DTD HTML 3.0 ASWEDIT + EXTENSIONS//EN" => 1,
4602     "-//AS//DTD HTML 3.0 ASWEDIT + EXTENSIONS//EN" => 1,
4603     "-//IETF//DTD HTML 2.0 LEVEL 1//EN" => 1,
4604     "-//IETF//DTD HTML 2.0 LEVEL 2//EN" => 1,
4605     "-//IETF//DTD HTML 2.0 STRICT LEVEL 1//EN" => 1,
4606     "-//IETF//DTD HTML 2.0 STRICT LEVEL 2//EN" => 1,
4607     "-//IETF//DTD HTML 2.0 STRICT//EN" => 1,
4608     "-//IETF//DTD HTML 2.0//EN" => 1,
4609     "-//IETF//DTD HTML 2.1E//EN" => 1,
4610     "-//IETF//DTD HTML 3.0//EN" => 1,
4611     "-//IETF//DTD HTML 3.0//EN//" => 1,
4612     "-//IETF//DTD HTML 3.2 FINAL//EN" => 1,
4613     "-//IETF//DTD HTML 3.2//EN" => 1,
4614     "-//IETF//DTD HTML 3//EN" => 1,
4615     "-//IETF//DTD HTML LEVEL 0//EN" => 1,
4616     "-//IETF//DTD HTML LEVEL 0//EN//2.0" => 1,
4617     "-//IETF//DTD HTML LEVEL 1//EN" => 1,
4618     "-//IETF//DTD HTML LEVEL 1//EN//2.0" => 1,
4619     "-//IETF//DTD HTML LEVEL 2//EN" => 1,
4620     "-//IETF//DTD HTML LEVEL 2//EN//2.0" => 1,
4621     "-//IETF//DTD HTML LEVEL 3//EN" => 1,
4622     "-//IETF//DTD HTML LEVEL 3//EN//3.0" => 1,
4623     "-//IETF//DTD HTML STRICT LEVEL 0//EN" => 1,
4624     "-//IETF//DTD HTML STRICT LEVEL 0//EN//2.0" => 1,
4625     "-//IETF//DTD HTML STRICT LEVEL 1//EN" => 1,
4626     "-//IETF//DTD HTML STRICT LEVEL 1//EN//2.0" => 1,
4627     "-//IETF//DTD HTML STRICT LEVEL 2//EN" => 1,
4628     "-//IETF//DTD HTML STRICT LEVEL 2//EN//2.0" => 1,
4629     "-//IETF//DTD HTML STRICT LEVEL 3//EN" => 1,
4630     "-//IETF//DTD HTML STRICT LEVEL 3//EN//3.0" => 1,
4631     "-//IETF//DTD HTML STRICT//EN" => 1,
4632     "-//IETF//DTD HTML STRICT//EN//2.0" => 1,
4633     "-//IETF//DTD HTML STRICT//EN//3.0" => 1,
4634     "-//IETF//DTD HTML//EN" => 1,
4635     "-//IETF//DTD HTML//EN//2.0" => 1,
4636     "-//IETF//DTD HTML//EN//3.0" => 1,
4637     "-//METRIUS//DTD METRIUS PRESENTATIONAL//EN" => 1,
4638     "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 HTML STRICT//EN" => 1,
4639     "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 HTML//EN" => 1,
4640     "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 TABLES//EN" => 1,
4641     "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 HTML STRICT//EN" => 1,
4642     "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 HTML//EN" => 1,
4643     "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 TABLES//EN" => 1,
4644     "-//NETSCAPE COMM. CORP.//DTD HTML//EN" => 1,
4645     "-//NETSCAPE COMM. CORP.//DTD STRICT HTML//EN" => 1,
4646     "-//O'REILLY AND ASSOCIATES//DTD HTML 2.0//EN" => 1,
4647     "-//O'REILLY AND ASSOCIATES//DTD HTML EXTENDED 1.0//EN" => 1,
4648 wakaba 1.72 "-//O'REILLY AND ASSOCIATES//DTD HTML EXTENDED RELAXED 1.0//EN" => 1,
4649     "-//SOFTQUAD SOFTWARE//DTD HOTMETAL PRO 6.0::19990601::EXTENSIONS TO HTML 4.0//EN" => 1,
4650     "-//SOFTQUAD//DTD HOTMETAL PRO 4.0::19971010::EXTENSIONS TO HTML 4.0//EN" => 1,
4651 wakaba 1.18 "-//SPYGLASS//DTD HTML 2.0 EXTENDED//EN" => 1,
4652     "-//SQ//DTD HTML 2.0 HOTMETAL + EXTENSIONS//EN" => 1,
4653     "-//SUN MICROSYSTEMS CORP.//DTD HOTJAVA HTML//EN" => 1,
4654     "-//SUN MICROSYSTEMS CORP.//DTD HOTJAVA STRICT HTML//EN" => 1,
4655     "-//W3C//DTD HTML 3 1995-03-24//EN" => 1,
4656     "-//W3C//DTD HTML 3.2 DRAFT//EN" => 1,
4657     "-//W3C//DTD HTML 3.2 FINAL//EN" => 1,
4658     "-//W3C//DTD HTML 3.2//EN" => 1,
4659     "-//W3C//DTD HTML 3.2S DRAFT//EN" => 1,
4660     "-//W3C//DTD HTML 4.0 FRAMESET//EN" => 1,
4661     "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN" => 1,
4662     "-//W3C//DTD HTML EXPERIMETNAL 19960712//EN" => 1,
4663     "-//W3C//DTD HTML EXPERIMENTAL 970421//EN" => 1,
4664     "-//W3C//DTD W3 HTML//EN" => 1,
4665     "-//W3O//DTD W3 HTML 3.0//EN" => 1,
4666     "-//W3O//DTD W3 HTML 3.0//EN//" => 1,
4667     "-//W3O//DTD W3 HTML STRICT 3.0//EN//" => 1,
4668     "-//WEBTECHS//DTD MOZILLA HTML 2.0//EN" => 1,
4669     "-//WEBTECHS//DTD MOZILLA HTML//EN" => 1,
4670     "-/W3C/DTD HTML 4.0 TRANSITIONAL/EN" => 1,
4671     "HTML" => 1,
4672     }->{$pubid}) {
4673 wakaba 1.79
4674     $Whatpm::HTML::Debug::cp_pass->('t5') if $Whatpm::HTML::Debug::cp_pass;
4675     BEGIN {
4676     $Whatpm::HTML::Debug::cp->{'t5'} = 1;
4677     }
4678    
4679 wakaba 1.18 $self->{document}->manakai_compat_mode ('quirks');
4680     } elsif ($pubid eq "-//W3C//DTD HTML 4.01 FRAMESET//EN" or
4681     $pubid eq "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN") {
4682     if (defined $token->{system_identifier}) {
4683 wakaba 1.79
4684     $Whatpm::HTML::Debug::cp_pass->('t6') if $Whatpm::HTML::Debug::cp_pass;
4685     BEGIN {
4686     $Whatpm::HTML::Debug::cp->{'t6'} = 1;
4687     }
4688    
4689 wakaba 1.18 $self->{document}->manakai_compat_mode ('quirks');
4690     } else {
4691 wakaba 1.79
4692     $Whatpm::HTML::Debug::cp_pass->('t7') if $Whatpm::HTML::Debug::cp_pass;
4693     BEGIN {
4694     $Whatpm::HTML::Debug::cp->{'t7'} = 1;
4695     }
4696    
4697 wakaba 1.18 $self->{document}->manakai_compat_mode ('limited quirks');
4698 wakaba 1.3 }
4699 wakaba 1.80 } elsif ($pubid eq "-//W3C//DTD XHTML 1.0 FRAMESET//EN" or
4700     $pubid eq "-//W3C//DTD XHTML 1.0 TRANSITIONAL//EN") {
4701 wakaba 1.79
4702     $Whatpm::HTML::Debug::cp_pass->('t8') if $Whatpm::HTML::Debug::cp_pass;
4703     BEGIN {
4704     $Whatpm::HTML::Debug::cp->{'t8'} = 1;
4705     }
4706    
4707 wakaba 1.18 $self->{document}->manakai_compat_mode ('limited quirks');
4708 wakaba 1.79 } else {
4709    
4710     $Whatpm::HTML::Debug::cp_pass->('t9') if $Whatpm::HTML::Debug::cp_pass;
4711     BEGIN {
4712     $Whatpm::HTML::Debug::cp->{'t9'} = 1;
4713     }
4714    
4715 wakaba 1.18 }
4716 wakaba 1.79 } else {
4717    
4718     $Whatpm::HTML::Debug::cp_pass->('t10') if $Whatpm::HTML::Debug::cp_pass;
4719     BEGIN {
4720     $Whatpm::HTML::Debug::cp->{'t10'} = 1;
4721     }
4722    
4723 wakaba 1.18 }
4724     if (defined $token->{system_identifier}) {
4725     my $sysid = $token->{system_identifier};
4726     $sysid =~ tr/A-Z/a-z/;
4727     if ($sysid eq "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
4728 wakaba 1.80 ## TODO: Check the spec: PUBLIC "(limited quirks)" "(quirks)"
4729 wakaba 1.18 $self->{document}->manakai_compat_mode ('quirks');
4730 wakaba 1.79
4731     $Whatpm::HTML::Debug::cp_pass->('t11') if $Whatpm::HTML::Debug::cp_pass;
4732     BEGIN {
4733     $Whatpm::HTML::Debug::cp->{'t11'} = 1;
4734     }
4735    
4736     } else {
4737    
4738     $Whatpm::HTML::Debug::cp_pass->('t12') if $Whatpm::HTML::Debug::cp_pass;
4739     BEGIN {
4740     $Whatpm::HTML::Debug::cp->{'t12'} = 1;
4741     }
4742    
4743 wakaba 1.18 }
4744 wakaba 1.79 } else {
4745    
4746     $Whatpm::HTML::Debug::cp_pass->('t13') if $Whatpm::HTML::Debug::cp_pass;
4747     BEGIN {
4748     $Whatpm::HTML::Debug::cp->{'t13'} = 1;
4749     }
4750    
4751 wakaba 1.18 }
4752    
4753 wakaba 1.85 ## Go to the "before html" insertion mode.
4754 wakaba 1.18 $token = $self->_get_next_token;
4755     return;
4756     } elsif ({
4757 wakaba 1.57 START_TAG_TOKEN, 1,
4758     END_TAG_TOKEN, 1,
4759     END_OF_FILE_TOKEN, 1,
4760 wakaba 1.18 }->{$token->{type}}) {
4761 wakaba 1.79
4762     $Whatpm::HTML::Debug::cp_pass->('t14') if $Whatpm::HTML::Debug::cp_pass;
4763     BEGIN {
4764     $Whatpm::HTML::Debug::cp->{'t14'} = 1;
4765     }
4766    
4767 wakaba 1.18 $self->{parse_error}-> (type => 'no DOCTYPE');
4768     $self->{document}->manakai_compat_mode ('quirks');
4769 wakaba 1.85 ## Go to the "before html" insertion mode.
4770 wakaba 1.18 ## reprocess
4771     return;
4772 wakaba 1.57 } elsif ($token->{type} == CHARACTER_TOKEN) {
4773 wakaba 1.18 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) { # \x0D
4774     ## Ignore the token
4775 wakaba 1.26
4776 wakaba 1.18 unless (length $token->{data}) {
4777 wakaba 1.79
4778     $Whatpm::HTML::Debug::cp_pass->('t15') if $Whatpm::HTML::Debug::cp_pass;
4779     BEGIN {
4780     $Whatpm::HTML::Debug::cp->{'t15'} = 1;
4781     }
4782    
4783 wakaba 1.84 ## Stay in the insertion mode.
4784 wakaba 1.18 $token = $self->_get_next_token;
4785     redo INITIAL;
4786 wakaba 1.79 } else {
4787    
4788     $Whatpm::HTML::Debug::cp_pass->('t16') if $Whatpm::HTML::Debug::cp_pass;
4789     BEGIN {
4790     $Whatpm::HTML::Debug::cp->{'t16'} = 1;
4791     }
4792    
4793 wakaba 1.3 }
4794 wakaba 1.79 } else {
4795    
4796     $Whatpm::HTML::Debug::cp_pass->('t17') if $Whatpm::HTML::Debug::cp_pass;
4797     BEGIN {
4798     $Whatpm::HTML::Debug::cp->{'t17'} = 1;
4799     }
4800    
4801 wakaba 1.3 }
4802 wakaba 1.18
4803     $self->{parse_error}-> (type => 'no DOCTYPE');
4804     $self->{document}->manakai_compat_mode ('quirks');
4805 wakaba 1.85 ## Go to the "before html" insertion mode.
4806 wakaba 1.18 ## reprocess
4807     return;
4808 wakaba 1.57 } elsif ($token->{type} == COMMENT_TOKEN) {
4809 wakaba 1.79
4810     $Whatpm::HTML::Debug::cp_pass->('t18') if $Whatpm::HTML::Debug::cp_pass;
4811     BEGIN {
4812     $Whatpm::HTML::Debug::cp->{'t18'} = 1;
4813     }
4814    
4815 wakaba 1.18 my $comment = $self->{document}->create_comment ($token->{data});
4816     $self->{document}->append_child ($comment);
4817    
4818 wakaba 1.84 ## Stay in the insertion mode.
4819 wakaba 1.18 $token = $self->_get_next_token;
4820     redo INITIAL;
4821     } else {
4822 wakaba 1.57 die "$0: $token->{type}: Unknown token type";
4823 wakaba 1.18 }
4824     } # INITIAL
4825 wakaba 1.79
4826     die "$0: _tree_construction_initial: This should be never reached";
4827 wakaba 1.3 } # _tree_construction_initial
4828    
4829     sub _tree_construction_root_element ($) {
4830     my $self = shift;
4831 wakaba 1.84
4832 wakaba 1.85 ## NOTE: "before html" insertion mode.
4833 wakaba 1.3
4834     B: {
4835 wakaba 1.57 if ($token->{type} == DOCTYPE_TOKEN) {
4836 wakaba 1.79
4837     $Whatpm::HTML::Debug::cp_pass->('t19') if $Whatpm::HTML::Debug::cp_pass;
4838     BEGIN {
4839     $Whatpm::HTML::Debug::cp->{'t19'} = 1;
4840     }
4841    
4842 wakaba 1.3 $self->{parse_error}-> (type => 'in html:#DOCTYPE');
4843     ## Ignore the token
4844 wakaba 1.84 ## Stay in the insertion mode.
4845 wakaba 1.3 $token = $self->_get_next_token;
4846     redo B;
4847 wakaba 1.57 } elsif ($token->{type} == COMMENT_TOKEN) {
4848 wakaba 1.79
4849     $Whatpm::HTML::Debug::cp_pass->('t20') if $Whatpm::HTML::Debug::cp_pass;
4850     BEGIN {
4851     $Whatpm::HTML::Debug::cp->{'t20'} = 1;
4852     }
4853    
4854 wakaba 1.3 my $comment = $self->{document}->create_comment ($token->{data});
4855     $self->{document}->append_child ($comment);
4856 wakaba 1.84 ## Stay in the insertion mode.
4857 wakaba 1.3 $token = $self->_get_next_token;
4858     redo B;
4859 wakaba 1.57 } elsif ($token->{type} == CHARACTER_TOKEN) {
4860 wakaba 1.26 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) { # \x0D
4861     ## Ignore the token.
4862    
4863 wakaba 1.3 unless (length $token->{data}) {
4864 wakaba 1.79
4865     $Whatpm::HTML::Debug::cp_pass->('t21') if $Whatpm::HTML::Debug::cp_pass;
4866     BEGIN {
4867     $Whatpm::HTML::Debug::cp->{'t21'} = 1;
4868     }
4869    
4870 wakaba 1.84 ## Stay in the insertion mode.
4871 wakaba 1.3 $token = $self->_get_next_token;
4872     redo B;
4873 wakaba 1.79 } else {
4874    
4875     $Whatpm::HTML::Debug::cp_pass->('t22') if $Whatpm::HTML::Debug::cp_pass;
4876     BEGIN {
4877     $Whatpm::HTML::Debug::cp->{'t22'} = 1;
4878     }
4879    
4880 wakaba 1.3 }
4881 wakaba 1.79 } else {
4882    
4883     $Whatpm::HTML::Debug::cp_pass->('t23') if $Whatpm::HTML::Debug::cp_pass;
4884     BEGIN {
4885     $Whatpm::HTML::Debug::cp->{'t23'} = 1;
4886     }
4887    
4888 wakaba 1.3 }
4889 wakaba 1.63
4890     $self->{application_cache_selection}->(undef);
4891    
4892     #
4893     } elsif ($token->{type} == START_TAG_TOKEN) {
4894 wakaba 1.84 if ($token->{tag_name} eq 'html') {
4895     my $root_element;
4896 wakaba 1.79
4897 wakaba 1.84 $root_element = $self->{document}->create_element_ns
4898     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
4899    
4900     for my $attr_name (keys %{ $token->{attributes}}) {
4901     $root_element->set_attribute_ns (undef, [undef, $attr_name],
4902     $token->{attributes} ->{$attr_name}->{value});
4903     }
4904    
4905     $self->{document}->append_child ($root_element);
4906     push @{$self->{open_elements}}, [$root_element, 'html'];
4907    
4908     if ($token->{attributes}->{manifest}) {
4909    
4910 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t24') if $Whatpm::HTML::Debug::cp_pass;
4911     BEGIN {
4912     $Whatpm::HTML::Debug::cp->{'t24'} = 1;
4913     }
4914    
4915 wakaba 1.84 $self->{application_cache_selection}
4916     ->($token->{attributes}->{manifest}->{value});
4917     ## ISSUE: No relative reference resolution?
4918     } else {
4919    
4920     $Whatpm::HTML::Debug::cp_pass->('t25') if $Whatpm::HTML::Debug::cp_pass;
4921     BEGIN {
4922     $Whatpm::HTML::Debug::cp->{'t25'} = 1;
4923     }
4924    
4925     $self->{application_cache_selection}->(undef);
4926     }
4927    
4928     $token = $self->_get_next_token;
4929     return; ## Go to the "before head" insertion mode.
4930 wakaba 1.63 } else {
4931 wakaba 1.79
4932 wakaba 1.84 $Whatpm::HTML::Debug::cp_pass->('t25.1') if $Whatpm::HTML::Debug::cp_pass;
4933 wakaba 1.79 BEGIN {
4934 wakaba 1.84 $Whatpm::HTML::Debug::cp->{'t25.1'} = 1;
4935 wakaba 1.79 }
4936    
4937 wakaba 1.84 #
4938 wakaba 1.63 }
4939 wakaba 1.3 } elsif ({
4940 wakaba 1.57 END_TAG_TOKEN, 1,
4941     END_OF_FILE_TOKEN, 1,
4942 wakaba 1.3 }->{$token->{type}}) {
4943 wakaba 1.79
4944     $Whatpm::HTML::Debug::cp_pass->('t26') if $Whatpm::HTML::Debug::cp_pass;
4945     BEGIN {
4946     $Whatpm::HTML::Debug::cp->{'t26'} = 1;
4947     }
4948    
4949 wakaba 1.3 #
4950     } else {
4951 wakaba 1.57 die "$0: $token->{type}: Unknown token type";
4952 wakaba 1.3 }
4953 wakaba 1.63
4954 wakaba 1.84 my $root_element;
4955 wakaba 1.3 $root_element = $self->{document}->create_element_ns
4956     (q<http://www.w3.org/1999/xhtml>, [undef, 'html']);
4957    
4958 wakaba 1.84 $self->{document}->append_child ($root_element);
4959     push @{$self->{open_elements}}, [$root_element, 'html'];
4960    
4961     $self->{application_cache_selection}->(undef);
4962    
4963     ## NOTE: Reprocess the token.
4964     return; ## Go to the "before head" insertion mode.
4965    
4966     ## ISSUE: There is an issue in the spec
4967 wakaba 1.3 } # B
4968 wakaba 1.79
4969     die "$0: _tree_construction_root_element: This should never be reached";
4970 wakaba 1.3 } # _tree_construction_root_element
4971    
4972     sub _reset_insertion_mode ($) {
4973     my $self = shift;
4974    
4975     ## Step 1
4976     my $last;
4977    
4978     ## Step 2
4979     my $i = -1;
4980     my $node = $self->{open_elements}->[$i];
4981    
4982     ## Step 3
4983     S3: {
4984 wakaba 1.29 ## ISSUE: Oops! "If node is the first node in the stack of open
4985     ## elements, then set last to true. If the context element of the
4986     ## HTML fragment parsing algorithm is neither a td element nor a
4987     ## th element, then set node to the context element. (fragment case)":
4988     ## The second "if" is in the scope of the first "if"!?
4989     if ($self->{open_elements}->[0]->[0] eq $node->[0]) {
4990     $last = 1;
4991     if (defined $self->{inner_html_node}) {
4992     if ($self->{inner_html_node}->[1] eq 'td' or
4993     $self->{inner_html_node}->[1] eq 'th') {
4994 wakaba 1.79
4995     $Whatpm::HTML::Debug::cp_pass->('t27') if $Whatpm::HTML::Debug::cp_pass;
4996     BEGIN {
4997     $Whatpm::HTML::Debug::cp->{'t27'} = 1;
4998     }
4999    
5000 wakaba 1.29 #
5001     } else {
5002 wakaba 1.79
5003     $Whatpm::HTML::Debug::cp_pass->('t28') if $Whatpm::HTML::Debug::cp_pass;
5004     BEGIN {
5005     $Whatpm::HTML::Debug::cp->{'t28'} = 1;
5006     }
5007    
5008 wakaba 1.29 $node = $self->{inner_html_node};
5009     }
5010 wakaba 1.3 }
5011     }
5012    
5013     ## Step 4..13
5014     my $new_mode = {
5015 wakaba 1.56 select => IN_SELECT_IM,
5016 wakaba 1.83 ## NOTE: |option| and |optgroup| do not set
5017     ## insertion mode to "in select" by themselves.
5018 wakaba 1.56 td => IN_CELL_IM,
5019     th => IN_CELL_IM,
5020     tr => IN_ROW_IM,
5021     tbody => IN_TABLE_BODY_IM,
5022     thead => IN_TABLE_BODY_IM,
5023     tfoot => IN_TABLE_BODY_IM,
5024     caption => IN_CAPTION_IM,
5025     colgroup => IN_COLUMN_GROUP_IM,
5026     table => IN_TABLE_IM,
5027     head => IN_BODY_IM, # not in head!
5028     body => IN_BODY_IM,
5029     frameset => IN_FRAMESET_IM,
5030 wakaba 1.3 }->{$node->[1]};
5031     $self->{insertion_mode} = $new_mode and return if defined $new_mode;
5032    
5033     ## Step 14
5034     if ($node->[1] eq 'html') {
5035     unless (defined $self->{head_element}) {
5036 wakaba 1.79
5037     $Whatpm::HTML::Debug::cp_pass->('t29') if $Whatpm::HTML::Debug::cp_pass;
5038     BEGIN {
5039     $Whatpm::HTML::Debug::cp->{'t29'} = 1;
5040     }
5041    
5042 wakaba 1.56 $self->{insertion_mode} = BEFORE_HEAD_IM;
5043 wakaba 1.3 } else {
5044 wakaba 1.81 ## ISSUE: Can this state be reached?
5045 wakaba 1.79
5046     $Whatpm::HTML::Debug::cp_pass->('t30') if $Whatpm::HTML::Debug::cp_pass;
5047     BEGIN {
5048     $Whatpm::HTML::Debug::cp->{'t30'} = 1;
5049     }
5050    
5051 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
5052 wakaba 1.3 }
5053     return;
5054 wakaba 1.79 } else {
5055    
5056     $Whatpm::HTML::Debug::cp_pass->('t31') if $Whatpm::HTML::Debug::cp_pass;
5057     BEGIN {
5058     $Whatpm::HTML::Debug::cp->{'t31'} = 1;
5059     }
5060    
5061 wakaba 1.3 }
5062    
5063     ## Step 15
5064 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM and return if $last;
5065 wakaba 1.3
5066     ## Step 16
5067     $i--;
5068     $node = $self->{open_elements}->[$i];
5069    
5070     ## Step 17
5071     redo S3;
5072     } # S3
5073 wakaba 1.79
5074     die "$0: _reset_insertion_mode: This line should never be reached";
5075 wakaba 1.3 } # _reset_insertion_mode
5076    
5077     sub _tree_construction_main ($) {
5078     my $self = shift;
5079    
5080 wakaba 1.1 my $active_formatting_elements = [];
5081    
5082     my $reconstruct_active_formatting_elements = sub { # MUST
5083     my $insert = shift;
5084    
5085     ## Step 1
5086     return unless @$active_formatting_elements;
5087    
5088     ## Step 3
5089     my $i = -1;
5090     my $entry = $active_formatting_elements->[$i];
5091    
5092     ## Step 2
5093     return if $entry->[0] eq '#marker';
5094 wakaba 1.3 for (@{$self->{open_elements}}) {
5095 wakaba 1.1 if ($entry->[0] eq $_->[0]) {
5096 wakaba 1.79
5097     $Whatpm::HTML::Debug::cp_pass->('t32') if $Whatpm::HTML::Debug::cp_pass;
5098     BEGIN {
5099     $Whatpm::HTML::Debug::cp->{'t32'} = 1;
5100     }
5101    
5102 wakaba 1.1 return;
5103     }
5104     }
5105    
5106     S4: {
5107     ## Step 4
5108     last S4 if $active_formatting_elements->[0]->[0] eq $entry->[0];
5109    
5110     ## Step 5
5111     $i--;
5112     $entry = $active_formatting_elements->[$i];
5113    
5114     ## Step 6
5115     if ($entry->[0] eq '#marker') {
5116 wakaba 1.79
5117 wakaba 1.81 $Whatpm::HTML::Debug::cp_pass->('t33_1') if $Whatpm::HTML::Debug::cp_pass;
5118 wakaba 1.79 BEGIN {
5119 wakaba 1.81 $Whatpm::HTML::Debug::cp->{'t33_1'} = 1;
5120 wakaba 1.79 }
5121    
5122 wakaba 1.1 #
5123     } else {
5124     my $in_open_elements;
5125 wakaba 1.3 OE: for (@{$self->{open_elements}}) {
5126 wakaba 1.1 if ($entry->[0] eq $_->[0]) {
5127 wakaba 1.79
5128     $Whatpm::HTML::Debug::cp_pass->('t33') if $Whatpm::HTML::Debug::cp_pass;
5129     BEGIN {
5130     $Whatpm::HTML::Debug::cp->{'t33'} = 1;
5131     }
5132    
5133 wakaba 1.1 $in_open_elements = 1;
5134     last OE;
5135     }
5136     }
5137     if ($in_open_elements) {
5138 wakaba 1.79
5139     $Whatpm::HTML::Debug::cp_pass->('t34') if $Whatpm::HTML::Debug::cp_pass;
5140     BEGIN {
5141     $Whatpm::HTML::Debug::cp->{'t34'} = 1;
5142     }
5143    
5144 wakaba 1.1 #
5145     } else {
5146 wakaba 1.81 ## NOTE: <!DOCTYPE HTML><p><b><i><u></p> <p>X
5147 wakaba 1.79
5148     $Whatpm::HTML::Debug::cp_pass->('t35') if $Whatpm::HTML::Debug::cp_pass;
5149     BEGIN {
5150     $Whatpm::HTML::Debug::cp->{'t35'} = 1;
5151     }
5152    
5153 wakaba 1.1 redo S4;
5154     }
5155     }
5156    
5157     ## Step 7
5158     $i++;
5159     $entry = $active_formatting_elements->[$i];
5160     } # S4
5161    
5162     S7: {
5163     ## Step 8
5164     my $clone = [$entry->[0]->clone_node (0), $entry->[1]];
5165    
5166     ## Step 9
5167     $insert->($clone->[0]);
5168 wakaba 1.3 push @{$self->{open_elements}}, $clone;
5169 wakaba 1.1
5170     ## Step 10
5171 wakaba 1.3 $active_formatting_elements->[$i] = $self->{open_elements}->[-1];
5172 wakaba 1.1
5173     ## Step 11
5174     unless ($clone->[0] eq $active_formatting_elements->[-1]->[0]) {
5175 wakaba 1.79
5176     $Whatpm::HTML::Debug::cp_pass->('t36') if $Whatpm::HTML::Debug::cp_pass;
5177     BEGIN {
5178     $Whatpm::HTML::Debug::cp->{'t36'} = 1;
5179     }
5180    
5181 wakaba 1.1 ## Step 7'
5182     $i++;
5183     $entry = $active_formatting_elements->[$i];
5184    
5185     redo S7;
5186     }
5187 wakaba 1.79
5188    
5189     $Whatpm::HTML::Debug::cp_pass->('t37') if $Whatpm::HTML::Debug::cp_pass;
5190     BEGIN {
5191     $Whatpm::HTML::Debug::cp->{'t37'} = 1;
5192     }
5193    
5194 wakaba 1.1 } # S7
5195     }; # $reconstruct_active_formatting_elements
5196    
5197     my $clear_up_to_marker = sub {
5198     for (reverse 0..$#$active_formatting_elements) {
5199     if ($active_formatting_elements->[$_]->[0] eq '#marker') {
5200 wakaba 1.79
5201     $Whatpm::HTML::Debug::cp_pass->('t38') if $Whatpm::HTML::Debug::cp_pass;
5202     BEGIN {
5203     $Whatpm::HTML::Debug::cp->{'t38'} = 1;
5204     }
5205    
5206 wakaba 1.1 splice @$active_formatting_elements, $_;
5207     return;
5208     }
5209     }
5210 wakaba 1.79
5211    
5212     $Whatpm::HTML::Debug::cp_pass->('t39') if $Whatpm::HTML::Debug::cp_pass;
5213     BEGIN {
5214     $Whatpm::HTML::Debug::cp->{'t39'} = 1;
5215     }
5216    
5217 wakaba 1.1 }; # $clear_up_to_marker
5218    
5219 wakaba 1.25 my $parse_rcdata = sub ($$) {
5220     my ($content_model_flag, $insert) = @_;
5221    
5222     ## Step 1
5223     my $start_tag_name = $token->{tag_name};
5224     my $el;
5225    
5226     $el = $self->{document}->create_element_ns
5227     (q<http://www.w3.org/1999/xhtml>, [undef, $start_tag_name]);
5228 wakaba 1.1
5229 wakaba 1.6 for my $attr_name (keys %{ $token->{attributes}}) {
5230 wakaba 1.25 $el->set_attribute_ns (undef, [undef, $attr_name],
5231 wakaba 1.6 $token->{attributes} ->{$attr_name}->{value});
5232     }
5233    
5234 wakaba 1.25
5235     ## Step 2
5236     $insert->($el); # /context node/->append_child ($el)
5237    
5238     ## Step 3
5239 wakaba 1.41 $self->{content_model} = $content_model_flag; # CDATA or RCDATA
5240 wakaba 1.13 delete $self->{escape}; # MUST
5241 wakaba 1.25
5242     ## Step 4
5243 wakaba 1.1 my $text = '';
5244     $token = $self->_get_next_token;
5245 wakaba 1.57 while ($token->{type} == CHARACTER_TOKEN) { # or until stop tokenizing
5246 wakaba 1.79
5247     $Whatpm::HTML::Debug::cp_pass->('t40') if $Whatpm::HTML::Debug::cp_pass;
5248     BEGIN {
5249     $Whatpm::HTML::Debug::cp->{'t40'} = 1;
5250     }
5251    
5252 wakaba 1.1 $text .= $token->{data};
5253     $token = $self->_get_next_token;
5254 wakaba 1.25 }
5255    
5256     ## Step 5
5257 wakaba 1.1 if (length $text) {
5258 wakaba 1.79
5259     $Whatpm::HTML::Debug::cp_pass->('t41') if $Whatpm::HTML::Debug::cp_pass;
5260     BEGIN {
5261     $Whatpm::HTML::Debug::cp->{'t41'} = 1;
5262     }
5263    
5264 wakaba 1.25 my $text = $self->{document}->create_text_node ($text);
5265     $el->append_child ($text);
5266 wakaba 1.1 }
5267 wakaba 1.25
5268     ## Step 6
5269 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL;
5270 wakaba 1.25
5271     ## Step 7
5272 wakaba 1.79 if ($token->{type} == END_TAG_TOKEN and
5273     $token->{tag_name} eq $start_tag_name) {
5274    
5275     $Whatpm::HTML::Debug::cp_pass->('t42') if $Whatpm::HTML::Debug::cp_pass;
5276     BEGIN {
5277     $Whatpm::HTML::Debug::cp->{'t42'} = 1;
5278     }
5279    
5280 wakaba 1.1 ## Ignore the token
5281 wakaba 1.41 } elsif ($content_model_flag == CDATA_CONTENT_MODEL) {
5282 wakaba 1.79
5283     $Whatpm::HTML::Debug::cp_pass->('t43') if $Whatpm::HTML::Debug::cp_pass;
5284     BEGIN {
5285     $Whatpm::HTML::Debug::cp->{'t43'} = 1;
5286     }
5287    
5288 wakaba 1.41 $self->{parse_error}-> (type => 'in CDATA:#'.$token->{type});
5289     } elsif ($content_model_flag == RCDATA_CONTENT_MODEL) {
5290 wakaba 1.79
5291     $Whatpm::HTML::Debug::cp_pass->('t44') if $Whatpm::HTML::Debug::cp_pass;
5292     BEGIN {
5293     $Whatpm::HTML::Debug::cp->{'t44'} = 1;
5294     }
5295    
5296 wakaba 1.41 $self->{parse_error}-> (type => 'in RCDATA:#'.$token->{type});
5297 wakaba 1.1 } else {
5298 wakaba 1.41 die "$0: $content_model_flag in parse_rcdata";
5299 wakaba 1.1 }
5300     $token = $self->_get_next_token;
5301 wakaba 1.25 }; # $parse_rcdata
5302 wakaba 1.1
5303 wakaba 1.25 my $script_start_tag = sub ($) {
5304     my $insert = $_[0];
5305 wakaba 1.1 my $script_el;
5306    
5307     $script_el = $self->{document}->create_element_ns
5308     (q<http://www.w3.org/1999/xhtml>, [undef, 'script']);
5309    
5310     for my $attr_name (keys %{ $token->{attributes}}) {
5311     $script_el->set_attribute_ns (undef, [undef, $attr_name],
5312     $token->{attributes} ->{$attr_name}->{value});
5313     }
5314    
5315     ## TODO: mark as "parser-inserted"
5316    
5317 wakaba 1.41 $self->{content_model} = CDATA_CONTENT_MODEL;
5318 wakaba 1.13 delete $self->{escape}; # MUST
5319 wakaba 1.1
5320     my $text = '';
5321     $token = $self->_get_next_token;
5322 wakaba 1.57 while ($token->{type} == CHARACTER_TOKEN) {
5323 wakaba 1.79
5324     $Whatpm::HTML::Debug::cp_pass->('t45') if $Whatpm::HTML::Debug::cp_pass;
5325     BEGIN {
5326     $Whatpm::HTML::Debug::cp->{'t45'} = 1;
5327     }
5328    
5329 wakaba 1.1 $text .= $token->{data};
5330     $token = $self->_get_next_token;
5331     } # stop if non-character token or tokenizer stops tokenising
5332     if (length $text) {
5333 wakaba 1.79
5334     $Whatpm::HTML::Debug::cp_pass->('t46') if $Whatpm::HTML::Debug::cp_pass;
5335     BEGIN {
5336     $Whatpm::HTML::Debug::cp->{'t46'} = 1;
5337     }
5338    
5339 wakaba 1.1 $script_el->manakai_append_text ($text);
5340     }
5341    
5342 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL;
5343 wakaba 1.1
5344 wakaba 1.57 if ($token->{type} == END_TAG_TOKEN and
5345 wakaba 1.1 $token->{tag_name} eq 'script') {
5346 wakaba 1.79
5347     $Whatpm::HTML::Debug::cp_pass->('t47') if $Whatpm::HTML::Debug::cp_pass;
5348     BEGIN {
5349     $Whatpm::HTML::Debug::cp->{'t47'} = 1;
5350     }
5351    
5352 wakaba 1.1 ## Ignore the token
5353     } else {
5354 wakaba 1.79
5355     $Whatpm::HTML::Debug::cp_pass->('t48') if $Whatpm::HTML::Debug::cp_pass;
5356     BEGIN {
5357     $Whatpm::HTML::Debug::cp->{'t48'} = 1;
5358     }
5359    
5360 wakaba 1.3 $self->{parse_error}-> (type => 'in CDATA:#'.$token->{type});
5361 wakaba 1.1 ## ISSUE: And ignore?
5362     ## TODO: mark as "already executed"
5363     }
5364    
5365 wakaba 1.3 if (defined $self->{inner_html_node}) {
5366 wakaba 1.79
5367     $Whatpm::HTML::Debug::cp_pass->('t49') if $Whatpm::HTML::Debug::cp_pass;
5368     BEGIN {
5369     $Whatpm::HTML::Debug::cp->{'t49'} = 1;
5370     }
5371    
5372 wakaba 1.3 ## TODO: mark as "already executed"
5373     } else {
5374 wakaba 1.79
5375     $Whatpm::HTML::Debug::cp_pass->('t50') if $Whatpm::HTML::Debug::cp_pass;
5376     BEGIN {
5377     $Whatpm::HTML::Debug::cp->{'t50'} = 1;
5378     }
5379    
5380 wakaba 1.1 ## TODO: $old_insertion_point = current insertion point
5381     ## TODO: insertion point = just before the next input character
5382 wakaba 1.25
5383     $insert->($script_el);
5384 wakaba 1.1
5385     ## TODO: insertion point = $old_insertion_point (might be "undefined")
5386    
5387     ## TODO: if there is a script that will execute as soon as the parser resume, then...
5388     }
5389    
5390     $token = $self->_get_next_token;
5391     }; # $script_start_tag
5392    
5393     my $formatting_end_tag = sub {
5394     my $tag_name = shift;
5395    
5396     FET: {
5397     ## Step 1
5398     my $formatting_element;
5399     my $formatting_element_i_in_active;
5400     AFE: for (reverse 0..$#$active_formatting_elements) {
5401     if ($active_formatting_elements->[$_]->[1] eq $tag_name) {
5402 wakaba 1.79
5403     $Whatpm::HTML::Debug::cp_pass->('t51') if $Whatpm::HTML::Debug::cp_pass;
5404     BEGIN {
5405     $Whatpm::HTML::Debug::cp->{'t51'} = 1;
5406     }
5407    
5408 wakaba 1.1 $formatting_element = $active_formatting_elements->[$_];
5409     $formatting_element_i_in_active = $_;
5410     last AFE;
5411     } elsif ($active_formatting_elements->[$_]->[0] eq '#marker') {
5412 wakaba 1.79
5413     $Whatpm::HTML::Debug::cp_pass->('t52') if $Whatpm::HTML::Debug::cp_pass;
5414     BEGIN {
5415     $Whatpm::HTML::Debug::cp->{'t52'} = 1;
5416     }
5417    
5418 wakaba 1.1 last AFE;
5419     }
5420     } # AFE
5421     unless (defined $formatting_element) {
5422 wakaba 1.79
5423     $Whatpm::HTML::Debug::cp_pass->('t53') if $Whatpm::HTML::Debug::cp_pass;
5424     BEGIN {
5425     $Whatpm::HTML::Debug::cp->{'t53'} = 1;
5426     }
5427    
5428 wakaba 1.3 $self->{parse_error}-> (type => 'unmatched end tag:'.$tag_name);
5429 wakaba 1.1 ## Ignore the token
5430     $token = $self->_get_next_token;
5431     return;
5432     }
5433     ## has an element in scope
5434     my $in_scope = 1;
5435     my $formatting_element_i_in_open;
5436 wakaba 1.3 INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5437     my $node = $self->{open_elements}->[$_];
5438 wakaba 1.1 if ($node->[0] eq $formatting_element->[0]) {
5439     if ($in_scope) {
5440 wakaba 1.79
5441     $Whatpm::HTML::Debug::cp_pass->('t54') if $Whatpm::HTML::Debug::cp_pass;
5442     BEGIN {
5443     $Whatpm::HTML::Debug::cp->{'t54'} = 1;
5444     }
5445    
5446 wakaba 1.1 $formatting_element_i_in_open = $_;
5447     last INSCOPE;
5448     } else { # in open elements but not in scope
5449 wakaba 1.79
5450     $Whatpm::HTML::Debug::cp_pass->('t55') if $Whatpm::HTML::Debug::cp_pass;
5451     BEGIN {
5452     $Whatpm::HTML::Debug::cp->{'t55'} = 1;
5453     }
5454    
5455 wakaba 1.4 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
5456 wakaba 1.1 ## Ignore the token
5457     $token = $self->_get_next_token;
5458     return;
5459     }
5460     } elsif ({
5461     table => 1, caption => 1, td => 1, th => 1,
5462     button => 1, marquee => 1, object => 1, html => 1,
5463     }->{$node->[1]}) {
5464 wakaba 1.79
5465     $Whatpm::HTML::Debug::cp_pass->('t56') if $Whatpm::HTML::Debug::cp_pass;
5466     BEGIN {
5467     $Whatpm::HTML::Debug::cp->{'t56'} = 1;
5468     }
5469    
5470 wakaba 1.1 $in_scope = 0;
5471     }
5472     } # INSCOPE
5473     unless (defined $formatting_element_i_in_open) {
5474 wakaba 1.79
5475     $Whatpm::HTML::Debug::cp_pass->('t57') if $Whatpm::HTML::Debug::cp_pass;
5476     BEGIN {
5477     $Whatpm::HTML::Debug::cp->{'t57'} = 1;
5478     }
5479    
5480 wakaba 1.4 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
5481 wakaba 1.1 pop @$active_formatting_elements; # $formatting_element
5482     $token = $self->_get_next_token; ## TODO: ok?
5483     return;
5484     }
5485 wakaba 1.3 if (not $self->{open_elements}->[-1]->[0] eq $formatting_element->[0]) {
5486 wakaba 1.79
5487     $Whatpm::HTML::Debug::cp_pass->('t58') if $Whatpm::HTML::Debug::cp_pass;
5488     BEGIN {
5489     $Whatpm::HTML::Debug::cp->{'t58'} = 1;
5490     }
5491    
5492 wakaba 1.4 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5493 wakaba 1.1 }
5494    
5495     ## Step 2
5496     my $furthest_block;
5497     my $furthest_block_i_in_open;
5498 wakaba 1.3 OE: for (reverse 0..$#{$self->{open_elements}}) {
5499     my $node = $self->{open_elements}->[$_];
5500 wakaba 1.1 if (not $formatting_category->{$node->[1]} and
5501     #not $phrasing_category->{$node->[1]} and
5502     ($special_category->{$node->[1]} or
5503     $scoping_category->{$node->[1]})) {
5504 wakaba 1.79
5505     $Whatpm::HTML::Debug::cp_pass->('t59') if $Whatpm::HTML::Debug::cp_pass;
5506     BEGIN {
5507     $Whatpm::HTML::Debug::cp->{'t59'} = 1;
5508     }
5509    
5510 wakaba 1.1 $furthest_block = $node;
5511     $furthest_block_i_in_open = $_;
5512     } elsif ($node->[0] eq $formatting_element->[0]) {
5513 wakaba 1.79
5514     $Whatpm::HTML::Debug::cp_pass->('t60') if $Whatpm::HTML::Debug::cp_pass;
5515     BEGIN {
5516     $Whatpm::HTML::Debug::cp->{'t60'} = 1;
5517     }
5518    
5519 wakaba 1.1 last OE;
5520     }
5521     } # OE
5522    
5523     ## Step 3
5524     unless (defined $furthest_block) { # MUST
5525 wakaba 1.79
5526     $Whatpm::HTML::Debug::cp_pass->('t61') if $Whatpm::HTML::Debug::cp_pass;
5527     BEGIN {
5528     $Whatpm::HTML::Debug::cp->{'t61'} = 1;
5529     }
5530    
5531 wakaba 1.3 splice @{$self->{open_elements}}, $formatting_element_i_in_open;
5532 wakaba 1.1 splice @$active_formatting_elements, $formatting_element_i_in_active, 1;
5533     $token = $self->_get_next_token;
5534     return;
5535     }
5536    
5537     ## Step 4
5538 wakaba 1.3 my $common_ancestor_node = $self->{open_elements}->[$formatting_element_i_in_open - 1];
5539 wakaba 1.1
5540     ## Step 5
5541     my $furthest_block_parent = $furthest_block->[0]->parent_node;
5542     if (defined $furthest_block_parent) {
5543 wakaba 1.79
5544     $Whatpm::HTML::Debug::cp_pass->('t62') if $Whatpm::HTML::Debug::cp_pass;
5545     BEGIN {
5546     $Whatpm::HTML::Debug::cp->{'t62'} = 1;
5547     }
5548    
5549 wakaba 1.1 $furthest_block_parent->remove_child ($furthest_block->[0]);
5550     }
5551    
5552     ## Step 6
5553     my $bookmark_prev_el
5554     = $active_formatting_elements->[$formatting_element_i_in_active - 1]
5555     ->[0];
5556    
5557     ## Step 7
5558     my $node = $furthest_block;
5559     my $node_i_in_open = $furthest_block_i_in_open;
5560     my $last_node = $furthest_block;
5561     S7: {
5562     ## Step 1
5563     $node_i_in_open--;
5564 wakaba 1.3 $node = $self->{open_elements}->[$node_i_in_open];
5565 wakaba 1.1
5566     ## Step 2
5567     my $node_i_in_active;
5568     S7S2: {
5569     for (reverse 0..$#$active_formatting_elements) {
5570     if ($active_formatting_elements->[$_]->[0] eq $node->[0]) {
5571 wakaba 1.79
5572     $Whatpm::HTML::Debug::cp_pass->('t63') if $Whatpm::HTML::Debug::cp_pass;
5573     BEGIN {
5574     $Whatpm::HTML::Debug::cp->{'t63'} = 1;
5575     }
5576    
5577 wakaba 1.1 $node_i_in_active = $_;
5578     last S7S2;
5579     }
5580     }
5581 wakaba 1.3 splice @{$self->{open_elements}}, $node_i_in_open, 1;
5582 wakaba 1.1 redo S7;
5583     } # S7S2
5584    
5585     ## Step 3
5586     last S7 if $node->[0] eq $formatting_element->[0];
5587    
5588     ## Step 4
5589     if ($last_node->[0] eq $furthest_block->[0]) {
5590 wakaba 1.79
5591     $Whatpm::HTML::Debug::cp_pass->('t64') if $Whatpm::HTML::Debug::cp_pass;
5592     BEGIN {
5593     $Whatpm::HTML::Debug::cp->{'t64'} = 1;
5594     }
5595    
5596 wakaba 1.1 $bookmark_prev_el = $node->[0];
5597     }
5598    
5599     ## Step 5
5600     if ($node->[0]->has_child_nodes ()) {
5601 wakaba 1.79
5602     $Whatpm::HTML::Debug::cp_pass->('t65') if $Whatpm::HTML::Debug::cp_pass;
5603     BEGIN {
5604     $Whatpm::HTML::Debug::cp->{'t65'} = 1;
5605     }
5606    
5607 wakaba 1.1 my $clone = [$node->[0]->clone_node (0), $node->[1]];
5608     $active_formatting_elements->[$node_i_in_active] = $clone;
5609 wakaba 1.3 $self->{open_elements}->[$node_i_in_open] = $clone;
5610 wakaba 1.1 $node = $clone;
5611     }
5612    
5613     ## Step 6
5614     $node->[0]->append_child ($last_node->[0]);
5615    
5616     ## Step 7
5617     $last_node = $node;
5618    
5619     ## Step 8
5620     redo S7;
5621     } # S7
5622    
5623     ## Step 8
5624     $common_ancestor_node->[0]->append_child ($last_node->[0]);
5625    
5626     ## Step 9
5627     my $clone = [$formatting_element->[0]->clone_node (0),
5628     $formatting_element->[1]];
5629    
5630     ## Step 10
5631     my @cn = @{$furthest_block->[0]->child_nodes};
5632     $clone->[0]->append_child ($_) for @cn;
5633    
5634     ## Step 11
5635     $furthest_block->[0]->append_child ($clone->[0]);
5636    
5637     ## Step 12
5638     my $i;
5639     AFE: for (reverse 0..$#$active_formatting_elements) {
5640     if ($active_formatting_elements->[$_]->[0] eq $formatting_element->[0]) {
5641 wakaba 1.79
5642     $Whatpm::HTML::Debug::cp_pass->('t66') if $Whatpm::HTML::Debug::cp_pass;
5643     BEGIN {
5644     $Whatpm::HTML::Debug::cp->{'t66'} = 1;
5645     }
5646    
5647 wakaba 1.1 splice @$active_formatting_elements, $_, 1;
5648     $i-- and last AFE if defined $i;
5649     } elsif ($active_formatting_elements->[$_]->[0] eq $bookmark_prev_el) {
5650 wakaba 1.79
5651     $Whatpm::HTML::Debug::cp_pass->('t67') if $Whatpm::HTML::Debug::cp_pass;
5652     BEGIN {
5653     $Whatpm::HTML::Debug::cp->{'t67'} = 1;
5654     }
5655    
5656 wakaba 1.1 $i = $_;
5657     }
5658     } # AFE
5659     splice @$active_formatting_elements, $i + 1, 0, $clone;
5660    
5661     ## Step 13
5662     undef $i;
5663 wakaba 1.3 OE: for (reverse 0..$#{$self->{open_elements}}) {
5664     if ($self->{open_elements}->[$_]->[0] eq $formatting_element->[0]) {
5665 wakaba 1.79
5666     $Whatpm::HTML::Debug::cp_pass->('t68') if $Whatpm::HTML::Debug::cp_pass;
5667     BEGIN {
5668     $Whatpm::HTML::Debug::cp->{'t68'} = 1;
5669     }
5670    
5671 wakaba 1.3 splice @{$self->{open_elements}}, $_, 1;
5672 wakaba 1.1 $i-- and last OE if defined $i;
5673 wakaba 1.3 } elsif ($self->{open_elements}->[$_]->[0] eq $furthest_block->[0]) {
5674 wakaba 1.79
5675     $Whatpm::HTML::Debug::cp_pass->('t69') if $Whatpm::HTML::Debug::cp_pass;
5676     BEGIN {
5677     $Whatpm::HTML::Debug::cp->{'t69'} = 1;
5678     }
5679    
5680 wakaba 1.1 $i = $_;
5681     }
5682     } # OE
5683 wakaba 1.3 splice @{$self->{open_elements}}, $i + 1, 1, $clone;
5684 wakaba 1.1
5685     ## Step 14
5686     redo FET;
5687     } # FET
5688     }; # $formatting_end_tag
5689    
5690     my $insert_to_current = sub {
5691 wakaba 1.25 $self->{open_elements}->[-1]->[0]->append_child ($_[0]);
5692 wakaba 1.1 }; # $insert_to_current
5693    
5694     my $insert_to_foster = sub {
5695     my $child = shift;
5696     if ({
5697     table => 1, tbody => 1, tfoot => 1,
5698     thead => 1, tr => 1,
5699 wakaba 1.3 }->{$self->{open_elements}->[-1]->[1]}) {
5700 wakaba 1.1 # MUST
5701     my $foster_parent_element;
5702     my $next_sibling;
5703 wakaba 1.3 OE: for (reverse 0..$#{$self->{open_elements}}) {
5704     if ($self->{open_elements}->[$_]->[1] eq 'table') {
5705     my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
5706 wakaba 1.1 if (defined $parent and $parent->node_type == 1) {
5707 wakaba 1.79
5708     $Whatpm::HTML::Debug::cp_pass->('t70') if $Whatpm::HTML::Debug::cp_pass;
5709     BEGIN {
5710     $Whatpm::HTML::Debug::cp->{'t70'} = 1;
5711     }
5712    
5713 wakaba 1.1 $foster_parent_element = $parent;
5714 wakaba 1.3 $next_sibling = $self->{open_elements}->[$_]->[0];
5715 wakaba 1.1 } else {
5716 wakaba 1.79
5717     $Whatpm::HTML::Debug::cp_pass->('t71') if $Whatpm::HTML::Debug::cp_pass;
5718     BEGIN {
5719     $Whatpm::HTML::Debug::cp->{'t71'} = 1;
5720     }
5721    
5722 wakaba 1.1 $foster_parent_element
5723 wakaba 1.3 = $self->{open_elements}->[$_ - 1]->[0];
5724 wakaba 1.1 }
5725     last OE;
5726     }
5727     } # OE
5728 wakaba 1.3 $foster_parent_element = $self->{open_elements}->[0]->[0]
5729 wakaba 1.1 unless defined $foster_parent_element;
5730     $foster_parent_element->insert_before
5731     ($child, $next_sibling);
5732     } else {
5733 wakaba 1.79
5734     $Whatpm::HTML::Debug::cp_pass->('t72') if $Whatpm::HTML::Debug::cp_pass;
5735     BEGIN {
5736     $Whatpm::HTML::Debug::cp->{'t72'} = 1;
5737     }
5738    
5739 wakaba 1.3 $self->{open_elements}->[-1]->[0]->append_child ($child);
5740 wakaba 1.1 }
5741     }; # $insert_to_foster
5742    
5743 wakaba 1.54 my $insert;
5744    
5745     B: {
5746 wakaba 1.57 if ($token->{type} == DOCTYPE_TOKEN) {
5747 wakaba 1.79
5748     $Whatpm::HTML::Debug::cp_pass->('t73') if $Whatpm::HTML::Debug::cp_pass;
5749     BEGIN {
5750     $Whatpm::HTML::Debug::cp->{'t73'} = 1;
5751     }
5752    
5753 wakaba 1.54 $self->{parse_error}-> (type => 'DOCTYPE in the middle');
5754     ## Ignore the token
5755     ## Stay in the phase
5756     $token = $self->_get_next_token;
5757     redo B;
5758 wakaba 1.57 } elsif ($token->{type} == END_OF_FILE_TOKEN) {
5759 wakaba 1.58 if ($self->{insertion_mode} & AFTER_HTML_IMS) {
5760 wakaba 1.79
5761     $Whatpm::HTML::Debug::cp_pass->('t74') if $Whatpm::HTML::Debug::cp_pass;
5762     BEGIN {
5763     $Whatpm::HTML::Debug::cp->{'t74'} = 1;
5764     }
5765    
5766 wakaba 1.54 #
5767     } else {
5768     ## Generate implied end tags
5769     if ({
5770     dd => 1, dt => 1, li => 1, p => 1, td => 1, th => 1, tr => 1,
5771     tbody => 1, tfoot=> 1, thead => 1,
5772     }->{$self->{open_elements}->[-1]->[1]}) {
5773 wakaba 1.79
5774     $Whatpm::HTML::Debug::cp_pass->('t75') if $Whatpm::HTML::Debug::cp_pass;
5775     BEGIN {
5776     $Whatpm::HTML::Debug::cp->{'t75'} = 1;
5777     }
5778    
5779 wakaba 1.54 unshift @{$self->{token}}, $token;
5780 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => $self->{open_elements}->[-1]->[1]};
5781 wakaba 1.54 redo B;
5782     }
5783 wakaba 1.1
5784 wakaba 1.54 if (@{$self->{open_elements}} > 2 or
5785     (@{$self->{open_elements}} == 2 and $self->{open_elements}->[1]->[1] ne 'body')) {
5786 wakaba 1.79
5787     $Whatpm::HTML::Debug::cp_pass->('t76') if $Whatpm::HTML::Debug::cp_pass;
5788     BEGIN {
5789     $Whatpm::HTML::Debug::cp->{'t76'} = 1;
5790     }
5791    
5792 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5793     } elsif (defined $self->{inner_html_node} and
5794     @{$self->{open_elements}} > 1 and
5795     $self->{open_elements}->[1]->[1] ne 'body') {
5796 wakaba 1.81 ## ISSUE: This case is never reached.
5797 wakaba 1.79
5798     $Whatpm::HTML::Debug::cp_pass->('t77') if $Whatpm::HTML::Debug::cp_pass;
5799     BEGIN {
5800     $Whatpm::HTML::Debug::cp->{'t77'} = 1;
5801     }
5802    
5803 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5804 wakaba 1.79 } else {
5805    
5806     $Whatpm::HTML::Debug::cp_pass->('t78') if $Whatpm::HTML::Debug::cp_pass;
5807     BEGIN {
5808     $Whatpm::HTML::Debug::cp->{'t78'} = 1;
5809     }
5810    
5811 wakaba 1.54 }
5812    
5813     ## ISSUE: There is an issue in the spec.
5814     }
5815    
5816     ## Stop parsing
5817     last B;
5818 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN and
5819 wakaba 1.54 $token->{tag_name} eq 'html') {
5820 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
5821 wakaba 1.79
5822     $Whatpm::HTML::Debug::cp_pass->('t79') if $Whatpm::HTML::Debug::cp_pass;
5823     BEGIN {
5824     $Whatpm::HTML::Debug::cp->{'t79'} = 1;
5825     }
5826    
5827 wakaba 1.54 $self->{parse_error}-> (type => 'after html:html');
5828 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
5829     } elsif ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
5830 wakaba 1.79
5831     $Whatpm::HTML::Debug::cp_pass->('t80') if $Whatpm::HTML::Debug::cp_pass;
5832     BEGIN {
5833     $Whatpm::HTML::Debug::cp->{'t80'} = 1;
5834     }
5835    
5836 wakaba 1.54 $self->{parse_error}-> (type => 'after html:html');
5837 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
5838 wakaba 1.79 } else {
5839    
5840     $Whatpm::HTML::Debug::cp_pass->('t81') if $Whatpm::HTML::Debug::cp_pass;
5841     BEGIN {
5842     $Whatpm::HTML::Debug::cp->{'t81'} = 1;
5843     }
5844    
5845 wakaba 1.54 }
5846    
5847 wakaba 1.84
5848 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t82') if $Whatpm::HTML::Debug::cp_pass;
5849     BEGIN {
5850     $Whatpm::HTML::Debug::cp->{'t82'} = 1;
5851     }
5852    
5853 wakaba 1.84 $self->{parse_error}-> (type => 'not first start tag');
5854 wakaba 1.54 my $top_el = $self->{open_elements}->[0]->[0];
5855     for my $attr_name (keys %{$token->{attributes}}) {
5856     unless ($top_el->has_attribute_ns (undef, $attr_name)) {
5857 wakaba 1.79
5858     $Whatpm::HTML::Debug::cp_pass->('t84') if $Whatpm::HTML::Debug::cp_pass;
5859     BEGIN {
5860     $Whatpm::HTML::Debug::cp->{'t84'} = 1;
5861     }
5862    
5863 wakaba 1.54 $top_el->set_attribute_ns
5864     (undef, [undef, $attr_name],
5865     $token->{attributes}->{$attr_name}->{value});
5866     }
5867     }
5868     $token = $self->_get_next_token;
5869     redo B;
5870 wakaba 1.57 } elsif ($token->{type} == COMMENT_TOKEN) {
5871 wakaba 1.54 my $comment = $self->{document}->create_comment ($token->{data});
5872 wakaba 1.58 if ($self->{insertion_mode} & AFTER_HTML_IMS) {
5873 wakaba 1.79
5874     $Whatpm::HTML::Debug::cp_pass->('t85') if $Whatpm::HTML::Debug::cp_pass;
5875     BEGIN {
5876     $Whatpm::HTML::Debug::cp->{'t85'} = 1;
5877     }
5878    
5879 wakaba 1.54 $self->{document}->append_child ($comment);
5880 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_BODY_IM) {
5881 wakaba 1.79
5882     $Whatpm::HTML::Debug::cp_pass->('t86') if $Whatpm::HTML::Debug::cp_pass;
5883     BEGIN {
5884     $Whatpm::HTML::Debug::cp->{'t86'} = 1;
5885     }
5886    
5887 wakaba 1.54 $self->{open_elements}->[0]->[0]->append_child ($comment);
5888     } else {
5889 wakaba 1.79
5890     $Whatpm::HTML::Debug::cp_pass->('t87') if $Whatpm::HTML::Debug::cp_pass;
5891     BEGIN {
5892     $Whatpm::HTML::Debug::cp->{'t87'} = 1;
5893     }
5894    
5895 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($comment);
5896     }
5897     $token = $self->_get_next_token;
5898     redo B;
5899 wakaba 1.58 } elsif ($self->{insertion_mode} & HEAD_IMS) {
5900 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
5901 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
5902     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
5903     unless (length $token->{data}) {
5904 wakaba 1.79
5905     $Whatpm::HTML::Debug::cp_pass->('t88') if $Whatpm::HTML::Debug::cp_pass;
5906     BEGIN {
5907     $Whatpm::HTML::Debug::cp->{'t88'} = 1;
5908     }
5909    
5910 wakaba 1.54 $token = $self->_get_next_token;
5911     redo B;
5912     }
5913     }
5914    
5915 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
5916 wakaba 1.79
5917     $Whatpm::HTML::Debug::cp_pass->('t89') if $Whatpm::HTML::Debug::cp_pass;
5918     BEGIN {
5919     $Whatpm::HTML::Debug::cp->{'t89'} = 1;
5920     }
5921    
5922 wakaba 1.54 ## As if <head>
5923    
5924     $self->{head_element} = $self->{document}->create_element_ns
5925     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
5926    
5927     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
5928     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
5929    
5930     ## Reprocess in the "in head" insertion mode...
5931     pop @{$self->{open_elements}};
5932    
5933     ## Reprocess in the "after head" insertion mode...
5934 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
5935 wakaba 1.79
5936     $Whatpm::HTML::Debug::cp_pass->('t90') if $Whatpm::HTML::Debug::cp_pass;
5937     BEGIN {
5938     $Whatpm::HTML::Debug::cp->{'t90'} = 1;
5939     }
5940    
5941 wakaba 1.54 ## As if </noscript>
5942     pop @{$self->{open_elements}};
5943     $self->{parse_error}-> (type => 'in noscript:#character');
5944    
5945     ## Reprocess in the "in head" insertion mode...
5946     ## As if </head>
5947     pop @{$self->{open_elements}};
5948    
5949     ## Reprocess in the "after head" insertion mode...
5950 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
5951 wakaba 1.79
5952     $Whatpm::HTML::Debug::cp_pass->('t91') if $Whatpm::HTML::Debug::cp_pass;
5953     BEGIN {
5954     $Whatpm::HTML::Debug::cp->{'t91'} = 1;
5955     }
5956    
5957 wakaba 1.54 pop @{$self->{open_elements}};
5958    
5959     ## Reprocess in the "after head" insertion mode...
5960 wakaba 1.79 } else {
5961    
5962     $Whatpm::HTML::Debug::cp_pass->('t92') if $Whatpm::HTML::Debug::cp_pass;
5963     BEGIN {
5964     $Whatpm::HTML::Debug::cp->{'t92'} = 1;
5965     }
5966    
5967 wakaba 1.54 }
5968    
5969     ## "after head" insertion mode
5970     ## As if <body>
5971    
5972     {
5973     my $el;
5974    
5975     $el = $self->{document}->create_element_ns
5976     (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
5977    
5978     $self->{open_elements}->[-1]->[0]->append_child ($el);
5979     push @{$self->{open_elements}}, [$el, 'body'];
5980     }
5981    
5982 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
5983 wakaba 1.54 ## reprocess
5984     redo B;
5985 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
5986 wakaba 1.54 if ($token->{tag_name} eq 'head') {
5987 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
5988 wakaba 1.54
5989 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t93') if $Whatpm::HTML::Debug::cp_pass;
5990     BEGIN {
5991     $Whatpm::HTML::Debug::cp->{'t93'} = 1;
5992     }
5993    
5994    
5995 wakaba 1.54 $self->{head_element} = $self->{document}->create_element_ns
5996     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
5997    
5998     for my $attr_name (keys %{ $token->{attributes}}) {
5999     $self->{head_element}->set_attribute_ns (undef, [undef, $attr_name],
6000     $token->{attributes} ->{$attr_name}->{value});
6001     }
6002    
6003     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6004     push @{$self->{open_elements}}, [$self->{head_element}, $token->{tag_name}];
6005 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6006 wakaba 1.54 $token = $self->_get_next_token;
6007     redo B;
6008 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
6009 wakaba 1.79
6010     $Whatpm::HTML::Debug::cp_pass->('t94') if $Whatpm::HTML::Debug::cp_pass;
6011     BEGIN {
6012     $Whatpm::HTML::Debug::cp->{'t94'} = 1;
6013     }
6014    
6015 wakaba 1.56 #
6016     } else {
6017 wakaba 1.79
6018     $Whatpm::HTML::Debug::cp_pass->('t95') if $Whatpm::HTML::Debug::cp_pass;
6019     BEGIN {
6020     $Whatpm::HTML::Debug::cp->{'t95'} = 1;
6021     }
6022    
6023 wakaba 1.54 $self->{parse_error}-> (type => 'in head:head'); # or in head noscript
6024     ## Ignore the token
6025     $token = $self->_get_next_token;
6026     redo B;
6027     }
6028 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6029 wakaba 1.79
6030     $Whatpm::HTML::Debug::cp_pass->('t96') if $Whatpm::HTML::Debug::cp_pass;
6031     BEGIN {
6032     $Whatpm::HTML::Debug::cp->{'t96'} = 1;
6033     }
6034    
6035 wakaba 1.54 ## As if <head>
6036    
6037     $self->{head_element} = $self->{document}->create_element_ns
6038     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6039    
6040     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6041     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6042    
6043 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6044 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6045 wakaba 1.79 } else {
6046    
6047     $Whatpm::HTML::Debug::cp_pass->('t97') if $Whatpm::HTML::Debug::cp_pass;
6048     BEGIN {
6049     $Whatpm::HTML::Debug::cp->{'t97'} = 1;
6050     }
6051    
6052 wakaba 1.54 }
6053    
6054     if ($token->{tag_name} eq 'base') {
6055 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6056 wakaba 1.79
6057     $Whatpm::HTML::Debug::cp_pass->('t98') if $Whatpm::HTML::Debug::cp_pass;
6058     BEGIN {
6059     $Whatpm::HTML::Debug::cp->{'t98'} = 1;
6060     }
6061    
6062 wakaba 1.54 ## As if </noscript>
6063     pop @{$self->{open_elements}};
6064     $self->{parse_error}-> (type => 'in noscript:base');
6065    
6066 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6067 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6068 wakaba 1.79 } else {
6069    
6070     $Whatpm::HTML::Debug::cp_pass->('t99') if $Whatpm::HTML::Debug::cp_pass;
6071     BEGIN {
6072     $Whatpm::HTML::Debug::cp->{'t99'} = 1;
6073     }
6074    
6075 wakaba 1.54 }
6076    
6077     ## NOTE: There is a "as if in head" code clone.
6078 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6079 wakaba 1.79
6080     $Whatpm::HTML::Debug::cp_pass->('t100') if $Whatpm::HTML::Debug::cp_pass;
6081     BEGIN {
6082     $Whatpm::HTML::Debug::cp->{'t100'} = 1;
6083     }
6084    
6085 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6086     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6087 wakaba 1.79 } else {
6088    
6089     $Whatpm::HTML::Debug::cp_pass->('t101') if $Whatpm::HTML::Debug::cp_pass;
6090     BEGIN {
6091     $Whatpm::HTML::Debug::cp->{'t101'} = 1;
6092     }
6093    
6094 wakaba 1.54 }
6095    
6096     {
6097     my $el;
6098    
6099     $el = $self->{document}->create_element_ns
6100     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6101    
6102     for my $attr_name (keys %{ $token->{attributes}}) {
6103     $el->set_attribute_ns (undef, [undef, $attr_name],
6104     $token->{attributes} ->{$attr_name}->{value});
6105     }
6106    
6107     $self->{open_elements}->[-1]->[0]->append_child ($el);
6108     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6109     }
6110    
6111     pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6112     pop @{$self->{open_elements}}
6113 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6114 wakaba 1.54 $token = $self->_get_next_token;
6115     redo B;
6116     } elsif ($token->{tag_name} eq 'link') {
6117     ## NOTE: There is a "as if in head" code clone.
6118 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6119 wakaba 1.79
6120     $Whatpm::HTML::Debug::cp_pass->('t102') if $Whatpm::HTML::Debug::cp_pass;
6121     BEGIN {
6122     $Whatpm::HTML::Debug::cp->{'t102'} = 1;
6123     }
6124    
6125 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6126     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6127 wakaba 1.79 } else {
6128    
6129     $Whatpm::HTML::Debug::cp_pass->('t103') if $Whatpm::HTML::Debug::cp_pass;
6130     BEGIN {
6131     $Whatpm::HTML::Debug::cp->{'t103'} = 1;
6132     }
6133    
6134 wakaba 1.54 }
6135    
6136 wakaba 1.25 {
6137     my $el;
6138    
6139 wakaba 1.1 $el = $self->{document}->create_element_ns
6140     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6141    
6142 wakaba 1.25 for my $attr_name (keys %{ $token->{attributes}}) {
6143 wakaba 1.1 $el->set_attribute_ns (undef, [undef, $attr_name],
6144 wakaba 1.25 $token->{attributes} ->{$attr_name}->{value});
6145 wakaba 1.1 }
6146    
6147 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6148 wakaba 1.25 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6149     }
6150    
6151 wakaba 1.54 pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6152     pop @{$self->{open_elements}}
6153 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6154 wakaba 1.54 $token = $self->_get_next_token;
6155     redo B;
6156     } elsif ($token->{tag_name} eq 'meta') {
6157     ## NOTE: There is a "as if in head" code clone.
6158 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6159 wakaba 1.79
6160     $Whatpm::HTML::Debug::cp_pass->('t104') if $Whatpm::HTML::Debug::cp_pass;
6161     BEGIN {
6162     $Whatpm::HTML::Debug::cp->{'t104'} = 1;
6163     }
6164    
6165 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6166     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6167 wakaba 1.79 } else {
6168    
6169     $Whatpm::HTML::Debug::cp_pass->('t105') if $Whatpm::HTML::Debug::cp_pass;
6170     BEGIN {
6171     $Whatpm::HTML::Debug::cp->{'t105'} = 1;
6172     }
6173    
6174 wakaba 1.54 }
6175    
6176 wakaba 1.34 {
6177     my $el;
6178    
6179     $el = $self->{document}->create_element_ns
6180     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6181    
6182     for my $attr_name (keys %{ $token->{attributes}}) {
6183     $el->set_attribute_ns (undef, [undef, $attr_name],
6184     $token->{attributes} ->{$attr_name}->{value});
6185     }
6186    
6187 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6188 wakaba 1.34 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6189     }
6190    
6191 wakaba 1.68 my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6192 wakaba 1.34
6193 wakaba 1.54 unless ($self->{confident}) {
6194     if ($token->{attributes}->{charset}) { ## TODO: And if supported
6195 wakaba 1.79
6196     $Whatpm::HTML::Debug::cp_pass->('t106') if $Whatpm::HTML::Debug::cp_pass;
6197     BEGIN {
6198     $Whatpm::HTML::Debug::cp->{'t106'} = 1;
6199     }
6200    
6201 wakaba 1.65 $self->{change_encoding}
6202     ->($self, $token->{attributes}->{charset}->{value});
6203 wakaba 1.68
6204     $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
6205     ->set_user_data (manakai_has_reference =>
6206     $token->{attributes}->{charset}
6207     ->{has_reference});
6208 wakaba 1.65 } elsif ($token->{attributes}->{content}) {
6209 wakaba 1.54 ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.
6210 wakaba 1.65 if ($token->{attributes}->{content}->{value}
6211 wakaba 1.71 =~ /\A[^;]*;[\x09-\x0D\x20]*[Cc][Hh][Aa][Rr][Ss][Ee][Tt]
6212     [\x09-\x0D\x20]*=
6213 wakaba 1.54 [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
6214     ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
6215 wakaba 1.79
6216     $Whatpm::HTML::Debug::cp_pass->('t107') if $Whatpm::HTML::Debug::cp_pass;
6217     BEGIN {
6218     $Whatpm::HTML::Debug::cp->{'t107'} = 1;
6219     }
6220    
6221 wakaba 1.65 $self->{change_encoding}
6222     ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);
6223 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
6224     ->set_user_data (manakai_has_reference =>
6225     $token->{attributes}->{content}
6226     ->{has_reference});
6227 wakaba 1.79 } else {
6228    
6229     $Whatpm::HTML::Debug::cp_pass->('t108') if $Whatpm::HTML::Debug::cp_pass;
6230     BEGIN {
6231     $Whatpm::HTML::Debug::cp->{'t108'} = 1;
6232     }
6233    
6234 wakaba 1.65 }
6235 wakaba 1.54 }
6236 wakaba 1.68 } else {
6237     if ($token->{attributes}->{charset}) {
6238 wakaba 1.79
6239     $Whatpm::HTML::Debug::cp_pass->('t109') if $Whatpm::HTML::Debug::cp_pass;
6240     BEGIN {
6241     $Whatpm::HTML::Debug::cp->{'t109'} = 1;
6242     }
6243    
6244 wakaba 1.68 $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
6245     ->set_user_data (manakai_has_reference =>
6246     $token->{attributes}->{charset}
6247     ->{has_reference});
6248     }
6249 wakaba 1.69 if ($token->{attributes}->{content}) {
6250 wakaba 1.79
6251     $Whatpm::HTML::Debug::cp_pass->('t110') if $Whatpm::HTML::Debug::cp_pass;
6252     BEGIN {
6253     $Whatpm::HTML::Debug::cp->{'t110'} = 1;
6254     }
6255    
6256 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
6257     ->set_user_data (manakai_has_reference =>
6258     $token->{attributes}->{content}
6259     ->{has_reference});
6260     }
6261 wakaba 1.54 }
6262 wakaba 1.34
6263 wakaba 1.54 pop @{$self->{open_elements}}
6264 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6265 wakaba 1.54 $token = $self->_get_next_token;
6266     redo B;
6267     } elsif ($token->{tag_name} eq 'title') {
6268 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6269 wakaba 1.79
6270     $Whatpm::HTML::Debug::cp_pass->('t111') if $Whatpm::HTML::Debug::cp_pass;
6271     BEGIN {
6272     $Whatpm::HTML::Debug::cp->{'t111'} = 1;
6273     }
6274    
6275 wakaba 1.54 ## As if </noscript>
6276     pop @{$self->{open_elements}};
6277     $self->{parse_error}-> (type => 'in noscript:title');
6278 wakaba 1.1
6279 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6280 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6281 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
6282 wakaba 1.79
6283     $Whatpm::HTML::Debug::cp_pass->('t112') if $Whatpm::HTML::Debug::cp_pass;
6284     BEGIN {
6285     $Whatpm::HTML::Debug::cp->{'t112'} = 1;
6286     }
6287    
6288 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6289     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6290 wakaba 1.79 } else {
6291    
6292     $Whatpm::HTML::Debug::cp_pass->('t113') if $Whatpm::HTML::Debug::cp_pass;
6293     BEGIN {
6294     $Whatpm::HTML::Debug::cp->{'t113'} = 1;
6295     }
6296    
6297 wakaba 1.54 }
6298    
6299     ## NOTE: There is a "as if in head" code clone.
6300     my $parent = defined $self->{head_element} ? $self->{head_element}
6301     : $self->{open_elements}->[-1]->[0];
6302     $parse_rcdata->(RCDATA_CONTENT_MODEL,
6303     sub { $parent->append_child ($_[0]) });
6304     pop @{$self->{open_elements}}
6305 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6306 wakaba 1.54 redo B;
6307     } elsif ($token->{tag_name} eq 'style') {
6308     ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and
6309 wakaba 1.56 ## insertion mode IN_HEAD_IM)
6310 wakaba 1.54 ## NOTE: There is a "as if in head" code clone.
6311 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6312 wakaba 1.79
6313     $Whatpm::HTML::Debug::cp_pass->('t114') if $Whatpm::HTML::Debug::cp_pass;
6314     BEGIN {
6315     $Whatpm::HTML::Debug::cp->{'t114'} = 1;
6316     }
6317    
6318 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6319     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6320 wakaba 1.79 } else {
6321    
6322     $Whatpm::HTML::Debug::cp_pass->('t115') if $Whatpm::HTML::Debug::cp_pass;
6323     BEGIN {
6324     $Whatpm::HTML::Debug::cp->{'t115'} = 1;
6325     }
6326    
6327 wakaba 1.54 }
6328     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert_to_current);
6329     pop @{$self->{open_elements}}
6330 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6331 wakaba 1.54 redo B;
6332     } elsif ($token->{tag_name} eq 'noscript') {
6333 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_IM) {
6334 wakaba 1.79
6335     $Whatpm::HTML::Debug::cp_pass->('t116') if $Whatpm::HTML::Debug::cp_pass;
6336     BEGIN {
6337     $Whatpm::HTML::Debug::cp->{'t116'} = 1;
6338     }
6339    
6340 wakaba 1.54 ## NOTE: and scripting is disalbed
6341    
6342 wakaba 1.1 {
6343     my $el;
6344    
6345     $el = $self->{document}->create_element_ns
6346     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6347    
6348     for my $attr_name (keys %{ $token->{attributes}}) {
6349     $el->set_attribute_ns (undef, [undef, $attr_name],
6350     $token->{attributes} ->{$attr_name}->{value});
6351     }
6352    
6353 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6354 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6355 wakaba 1.1 }
6356    
6357 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_NOSCRIPT_IM;
6358 wakaba 1.54 $token = $self->_get_next_token;
6359     redo B;
6360 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6361 wakaba 1.79
6362     $Whatpm::HTML::Debug::cp_pass->('t117') if $Whatpm::HTML::Debug::cp_pass;
6363     BEGIN {
6364     $Whatpm::HTML::Debug::cp->{'t117'} = 1;
6365     }
6366    
6367 wakaba 1.54 $self->{parse_error}-> (type => 'in noscript:noscript');
6368     ## Ignore the token
6369     $token = $self->_get_next_token;
6370     redo B;
6371     } else {
6372 wakaba 1.79
6373     $Whatpm::HTML::Debug::cp_pass->('t118') if $Whatpm::HTML::Debug::cp_pass;
6374     BEGIN {
6375     $Whatpm::HTML::Debug::cp->{'t118'} = 1;
6376     }
6377    
6378 wakaba 1.54 #
6379     }
6380     } elsif ($token->{tag_name} eq 'script') {
6381 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6382 wakaba 1.79
6383     $Whatpm::HTML::Debug::cp_pass->('t119') if $Whatpm::HTML::Debug::cp_pass;
6384     BEGIN {
6385     $Whatpm::HTML::Debug::cp->{'t119'} = 1;
6386     }
6387    
6388 wakaba 1.54 ## As if </noscript>
6389     pop @{$self->{open_elements}};
6390     $self->{parse_error}-> (type => 'in noscript:script');
6391    
6392 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6393 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6394 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
6395 wakaba 1.79
6396     $Whatpm::HTML::Debug::cp_pass->('t120') if $Whatpm::HTML::Debug::cp_pass;
6397     BEGIN {
6398     $Whatpm::HTML::Debug::cp->{'t120'} = 1;
6399     }
6400    
6401 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6402     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6403 wakaba 1.79 } else {
6404    
6405     $Whatpm::HTML::Debug::cp_pass->('t121') if $Whatpm::HTML::Debug::cp_pass;
6406     BEGIN {
6407     $Whatpm::HTML::Debug::cp->{'t121'} = 1;
6408     }
6409    
6410 wakaba 1.54 }
6411    
6412     ## NOTE: There is a "as if in head" code clone.
6413     $script_start_tag->($insert_to_current);
6414     pop @{$self->{open_elements}}
6415 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6416 wakaba 1.54 redo B;
6417     } elsif ($token->{tag_name} eq 'body' or
6418     $token->{tag_name} eq 'frameset') {
6419 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6420 wakaba 1.79
6421     $Whatpm::HTML::Debug::cp_pass->('t122') if $Whatpm::HTML::Debug::cp_pass;
6422     BEGIN {
6423     $Whatpm::HTML::Debug::cp->{'t122'} = 1;
6424     }
6425    
6426 wakaba 1.54 ## As if </noscript>
6427     pop @{$self->{open_elements}};
6428     $self->{parse_error}-> (type => 'in noscript:'.$token->{tag_name});
6429    
6430     ## Reprocess in the "in head" insertion mode...
6431     ## As if </head>
6432     pop @{$self->{open_elements}};
6433    
6434     ## Reprocess in the "after head" insertion mode...
6435 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6436 wakaba 1.79
6437     $Whatpm::HTML::Debug::cp_pass->('t124') if $Whatpm::HTML::Debug::cp_pass;
6438     BEGIN {
6439     $Whatpm::HTML::Debug::cp->{'t124'} = 1;
6440     }
6441    
6442 wakaba 1.54 pop @{$self->{open_elements}};
6443    
6444     ## Reprocess in the "after head" insertion mode...
6445 wakaba 1.79 } else {
6446    
6447     $Whatpm::HTML::Debug::cp_pass->('t125') if $Whatpm::HTML::Debug::cp_pass;
6448     BEGIN {
6449     $Whatpm::HTML::Debug::cp->{'t125'} = 1;
6450     }
6451    
6452 wakaba 1.54 }
6453    
6454     ## "after head" insertion mode
6455    
6456 wakaba 1.1 {
6457     my $el;
6458    
6459     $el = $self->{document}->create_element_ns
6460     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6461    
6462     for my $attr_name (keys %{ $token->{attributes}}) {
6463     $el->set_attribute_ns (undef, [undef, $attr_name],
6464     $token->{attributes} ->{$attr_name}->{value});
6465     }
6466    
6467 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6468 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6469 wakaba 1.1 }
6470    
6471 wakaba 1.56 if ($token->{tag_name} eq 'body') {
6472 wakaba 1.79
6473     $Whatpm::HTML::Debug::cp_pass->('t126') if $Whatpm::HTML::Debug::cp_pass;
6474     BEGIN {
6475     $Whatpm::HTML::Debug::cp->{'t126'} = 1;
6476     }
6477    
6478 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6479     } elsif ($token->{tag_name} eq 'frameset') {
6480 wakaba 1.79
6481     $Whatpm::HTML::Debug::cp_pass->('t127') if $Whatpm::HTML::Debug::cp_pass;
6482     BEGIN {
6483     $Whatpm::HTML::Debug::cp->{'t127'} = 1;
6484     }
6485    
6486 wakaba 1.56 $self->{insertion_mode} = IN_FRAMESET_IM;
6487     } else {
6488     die "$0: tag name: $self->{tag_name}";
6489     }
6490 wakaba 1.54 $token = $self->_get_next_token;
6491     redo B;
6492     } else {
6493 wakaba 1.79
6494     $Whatpm::HTML::Debug::cp_pass->('t128') if $Whatpm::HTML::Debug::cp_pass;
6495     BEGIN {
6496     $Whatpm::HTML::Debug::cp->{'t128'} = 1;
6497     }
6498    
6499 wakaba 1.54 #
6500 wakaba 1.8 }
6501 wakaba 1.54
6502 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6503 wakaba 1.79
6504     $Whatpm::HTML::Debug::cp_pass->('t129') if $Whatpm::HTML::Debug::cp_pass;
6505     BEGIN {
6506     $Whatpm::HTML::Debug::cp->{'t129'} = 1;
6507     }
6508    
6509 wakaba 1.54 ## As if </noscript>
6510     pop @{$self->{open_elements}};
6511     $self->{parse_error}-> (type => 'in noscript:/'.$token->{tag_name});
6512    
6513     ## Reprocess in the "in head" insertion mode...
6514     ## As if </head>
6515     pop @{$self->{open_elements}};
6516    
6517     ## Reprocess in the "after head" insertion mode...
6518 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6519 wakaba 1.79
6520     $Whatpm::HTML::Debug::cp_pass->('t130') if $Whatpm::HTML::Debug::cp_pass;
6521     BEGIN {
6522     $Whatpm::HTML::Debug::cp->{'t130'} = 1;
6523     }
6524    
6525 wakaba 1.54 ## As if </head>
6526     pop @{$self->{open_elements}};
6527    
6528     ## Reprocess in the "after head" insertion mode...
6529 wakaba 1.79 } else {
6530    
6531     $Whatpm::HTML::Debug::cp_pass->('t131') if $Whatpm::HTML::Debug::cp_pass;
6532     BEGIN {
6533     $Whatpm::HTML::Debug::cp->{'t131'} = 1;
6534     }
6535    
6536 wakaba 1.54 }
6537    
6538     ## "after head" insertion mode
6539     ## As if <body>
6540    
6541 wakaba 1.1 {
6542     my $el;
6543    
6544     $el = $self->{document}->create_element_ns
6545 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
6546 wakaba 1.1
6547 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6548     push @{$self->{open_elements}}, [$el, 'body'];
6549 wakaba 1.1 }
6550    
6551 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6552 wakaba 1.54 ## reprocess
6553     redo B;
6554 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
6555 wakaba 1.54 if ($token->{tag_name} eq 'head') {
6556 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6557 wakaba 1.79
6558     $Whatpm::HTML::Debug::cp_pass->('t132') if $Whatpm::HTML::Debug::cp_pass;
6559     BEGIN {
6560     $Whatpm::HTML::Debug::cp->{'t132'} = 1;
6561     }
6562    
6563 wakaba 1.54 ## As if <head>
6564    
6565     $self->{head_element} = $self->{document}->create_element_ns
6566     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6567    
6568     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6569     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6570    
6571     ## Reprocess in the "in head" insertion mode...
6572     pop @{$self->{open_elements}};
6573 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6574 wakaba 1.54 $token = $self->_get_next_token;
6575     redo B;
6576 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6577 wakaba 1.79
6578     $Whatpm::HTML::Debug::cp_pass->('t133') if $Whatpm::HTML::Debug::cp_pass;
6579     BEGIN {
6580     $Whatpm::HTML::Debug::cp->{'t133'} = 1;
6581     }
6582    
6583 wakaba 1.54 ## As if </noscript>
6584     pop @{$self->{open_elements}};
6585 wakaba 1.82 $self->{parse_error}-> (type => 'in noscript:/head');
6586 wakaba 1.54
6587     ## Reprocess in the "in head" insertion mode...
6588     pop @{$self->{open_elements}};
6589 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6590 wakaba 1.54 $token = $self->_get_next_token;
6591     redo B;
6592 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6593 wakaba 1.79
6594     $Whatpm::HTML::Debug::cp_pass->('t134') if $Whatpm::HTML::Debug::cp_pass;
6595     BEGIN {
6596     $Whatpm::HTML::Debug::cp->{'t134'} = 1;
6597     }
6598    
6599 wakaba 1.54 pop @{$self->{open_elements}};
6600 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6601 wakaba 1.54 $token = $self->_get_next_token;
6602     redo B;
6603     } else {
6604 wakaba 1.79
6605     $Whatpm::HTML::Debug::cp_pass->('t135') if $Whatpm::HTML::Debug::cp_pass;
6606     BEGIN {
6607     $Whatpm::HTML::Debug::cp->{'t135'} = 1;
6608     }
6609    
6610 wakaba 1.54 #
6611     }
6612     } elsif ($token->{tag_name} eq 'noscript') {
6613 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6614 wakaba 1.79
6615     $Whatpm::HTML::Debug::cp_pass->('t136') if $Whatpm::HTML::Debug::cp_pass;
6616     BEGIN {
6617     $Whatpm::HTML::Debug::cp->{'t136'} = 1;
6618     }
6619    
6620 wakaba 1.54 pop @{$self->{open_elements}};
6621 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6622 wakaba 1.54 $token = $self->_get_next_token;
6623     redo B;
6624 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6625 wakaba 1.79
6626     $Whatpm::HTML::Debug::cp_pass->('t137') if $Whatpm::HTML::Debug::cp_pass;
6627     BEGIN {
6628     $Whatpm::HTML::Debug::cp->{'t137'} = 1;
6629     }
6630    
6631 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:noscript');
6632     ## Ignore the token ## ISSUE: An issue in the spec.
6633     $token = $self->_get_next_token;
6634     redo B;
6635     } else {
6636 wakaba 1.79
6637     $Whatpm::HTML::Debug::cp_pass->('t138') if $Whatpm::HTML::Debug::cp_pass;
6638     BEGIN {
6639     $Whatpm::HTML::Debug::cp->{'t138'} = 1;
6640     }
6641    
6642 wakaba 1.54 #
6643     }
6644     } elsif ({
6645     body => 1, html => 1,
6646     }->{$token->{tag_name}}) {
6647 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6648 wakaba 1.79
6649     $Whatpm::HTML::Debug::cp_pass->('t139') if $Whatpm::HTML::Debug::cp_pass;
6650     BEGIN {
6651     $Whatpm::HTML::Debug::cp->{'t139'} = 1;
6652     }
6653    
6654 wakaba 1.54 ## As if <head>
6655    
6656     $self->{head_element} = $self->{document}->create_element_ns
6657     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6658    
6659     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6660     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6661    
6662 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6663 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6664 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6665 wakaba 1.79
6666     $Whatpm::HTML::Debug::cp_pass->('t140') if $Whatpm::HTML::Debug::cp_pass;
6667     BEGIN {
6668     $Whatpm::HTML::Debug::cp->{'t140'} = 1;
6669     }
6670    
6671 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6672     ## Ignore the token
6673     $token = $self->_get_next_token;
6674     redo B;
6675 wakaba 1.79 } else {
6676    
6677     $Whatpm::HTML::Debug::cp_pass->('t141') if $Whatpm::HTML::Debug::cp_pass;
6678     BEGIN {
6679     $Whatpm::HTML::Debug::cp->{'t141'} = 1;
6680     }
6681    
6682 wakaba 1.54 }
6683    
6684     #
6685     } elsif ({
6686     p => 1, br => 1,
6687     }->{$token->{tag_name}}) {
6688 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6689 wakaba 1.79
6690     $Whatpm::HTML::Debug::cp_pass->('t142') if $Whatpm::HTML::Debug::cp_pass;
6691     BEGIN {
6692     $Whatpm::HTML::Debug::cp->{'t142'} = 1;
6693     }
6694    
6695 wakaba 1.54 ## As if <head>
6696    
6697     $self->{head_element} = $self->{document}->create_element_ns
6698     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6699    
6700     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6701     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6702    
6703 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6704 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6705 wakaba 1.79 } else {
6706    
6707     $Whatpm::HTML::Debug::cp_pass->('t143') if $Whatpm::HTML::Debug::cp_pass;
6708     BEGIN {
6709     $Whatpm::HTML::Debug::cp->{'t143'} = 1;
6710     }
6711    
6712 wakaba 1.54 }
6713    
6714     #
6715     } else {
6716 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6717 wakaba 1.79
6718     $Whatpm::HTML::Debug::cp_pass->('t144') if $Whatpm::HTML::Debug::cp_pass;
6719     BEGIN {
6720     $Whatpm::HTML::Debug::cp->{'t144'} = 1;
6721     }
6722    
6723 wakaba 1.56 #
6724     } else {
6725 wakaba 1.79
6726     $Whatpm::HTML::Debug::cp_pass->('t145') if $Whatpm::HTML::Debug::cp_pass;
6727     BEGIN {
6728     $Whatpm::HTML::Debug::cp->{'t145'} = 1;
6729     }
6730    
6731 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6732     ## Ignore the token
6733     $token = $self->_get_next_token;
6734     redo B;
6735     }
6736     }
6737    
6738 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6739 wakaba 1.79
6740     $Whatpm::HTML::Debug::cp_pass->('t146') if $Whatpm::HTML::Debug::cp_pass;
6741     BEGIN {
6742     $Whatpm::HTML::Debug::cp->{'t146'} = 1;
6743     }
6744    
6745 wakaba 1.54 ## As if </noscript>
6746     pop @{$self->{open_elements}};
6747     $self->{parse_error}-> (type => 'in noscript:/'.$token->{tag_name});
6748    
6749     ## Reprocess in the "in head" insertion mode...
6750     ## As if </head>
6751     pop @{$self->{open_elements}};
6752    
6753     ## Reprocess in the "after head" insertion mode...
6754 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6755 wakaba 1.79
6756     $Whatpm::HTML::Debug::cp_pass->('t147') if $Whatpm::HTML::Debug::cp_pass;
6757     BEGIN {
6758     $Whatpm::HTML::Debug::cp->{'t147'} = 1;
6759     }
6760    
6761 wakaba 1.54 ## As if </head>
6762     pop @{$self->{open_elements}};
6763    
6764     ## Reprocess in the "after head" insertion mode...
6765 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6766 wakaba 1.82 ## ISSUE: This case cannot be reached?
6767 wakaba 1.79
6768     $Whatpm::HTML::Debug::cp_pass->('t148') if $Whatpm::HTML::Debug::cp_pass;
6769     BEGIN {
6770     $Whatpm::HTML::Debug::cp->{'t148'} = 1;
6771     }
6772    
6773 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6774     ## Ignore the token ## ISSUE: An issue in the spec.
6775     $token = $self->_get_next_token;
6776     redo B;
6777 wakaba 1.79 } else {
6778    
6779     $Whatpm::HTML::Debug::cp_pass->('t149') if $Whatpm::HTML::Debug::cp_pass;
6780     BEGIN {
6781     $Whatpm::HTML::Debug::cp->{'t149'} = 1;
6782     }
6783    
6784 wakaba 1.8 }
6785 wakaba 1.54
6786     ## "after head" insertion mode
6787     ## As if <body>
6788    
6789 wakaba 1.1 {
6790     my $el;
6791    
6792     $el = $self->{document}->create_element_ns
6793 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
6794 wakaba 1.1
6795 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6796     push @{$self->{open_elements}}, [$el, 'body'];
6797 wakaba 1.1 }
6798    
6799 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6800 wakaba 1.54 ## reprocess
6801     redo B;
6802     } else {
6803     die "$0: $token->{type}: Unknown token type";
6804 wakaba 1.1 }
6805 wakaba 1.54
6806     ## ISSUE: An issue in the spec.
6807 wakaba 1.58 } elsif ($self->{insertion_mode} & BODY_IMS) {
6808 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
6809 wakaba 1.79
6810     $Whatpm::HTML::Debug::cp_pass->('t150') if $Whatpm::HTML::Debug::cp_pass;
6811     BEGIN {
6812     $Whatpm::HTML::Debug::cp->{'t150'} = 1;
6813     }
6814    
6815 wakaba 1.54 ## NOTE: There is a code clone of "character in body".
6816     $reconstruct_active_formatting_elements->($insert_to_current);
6817    
6818     $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
6819    
6820     $token = $self->_get_next_token;
6821     redo B;
6822 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
6823 wakaba 1.54 if ({
6824     caption => 1, col => 1, colgroup => 1, tbody => 1,
6825     td => 1, tfoot => 1, th => 1, thead => 1, tr => 1,
6826     }->{$token->{tag_name}}) {
6827 wakaba 1.56 if ($self->{insertion_mode} == IN_CELL_IM) {
6828 wakaba 1.54 ## have an element in table scope
6829     my $tn;
6830     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6831     my $node = $self->{open_elements}->[$_];
6832     if ($node->[1] eq 'td' or $node->[1] eq 'th') {
6833 wakaba 1.79
6834     $Whatpm::HTML::Debug::cp_pass->('t151') if $Whatpm::HTML::Debug::cp_pass;
6835     BEGIN {
6836     $Whatpm::HTML::Debug::cp->{'t151'} = 1;
6837     }
6838    
6839 wakaba 1.54 $tn = $node->[1];
6840     last INSCOPE;
6841     } elsif ({
6842     table => 1, html => 1,
6843     }->{$node->[1]}) {
6844 wakaba 1.79
6845     $Whatpm::HTML::Debug::cp_pass->('t152') if $Whatpm::HTML::Debug::cp_pass;
6846     BEGIN {
6847     $Whatpm::HTML::Debug::cp->{'t152'} = 1;
6848     }
6849    
6850 wakaba 1.54 last INSCOPE;
6851     }
6852     } # INSCOPE
6853     unless (defined $tn) {
6854 wakaba 1.79
6855     $Whatpm::HTML::Debug::cp_pass->('t153') if $Whatpm::HTML::Debug::cp_pass;
6856     BEGIN {
6857     $Whatpm::HTML::Debug::cp->{'t153'} = 1;
6858     }
6859    
6860 wakaba 1.82 ## TODO: This error type is wrong.
6861 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6862     ## Ignore the token
6863     $token = $self->_get_next_token;
6864     redo B;
6865     }
6866    
6867 wakaba 1.79
6868     $Whatpm::HTML::Debug::cp_pass->('t154') if $Whatpm::HTML::Debug::cp_pass;
6869     BEGIN {
6870     $Whatpm::HTML::Debug::cp->{'t154'} = 1;
6871     }
6872    
6873 wakaba 1.54 ## Close the cell
6874     unshift @{$self->{token}}, $token; # <?>
6875 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => $tn};
6876 wakaba 1.54 redo B;
6877 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {
6878 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:caption');
6879    
6880     ## As if </caption>
6881     ## have a table element in table scope
6882     my $i;
6883     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6884     my $node = $self->{open_elements}->[$_];
6885     if ($node->[1] eq 'caption') {
6886 wakaba 1.79
6887     $Whatpm::HTML::Debug::cp_pass->('t155') if $Whatpm::HTML::Debug::cp_pass;
6888     BEGIN {
6889     $Whatpm::HTML::Debug::cp->{'t155'} = 1;
6890     }
6891    
6892 wakaba 1.54 $i = $_;
6893     last INSCOPE;
6894     } elsif ({
6895     table => 1, html => 1,
6896     }->{$node->[1]}) {
6897 wakaba 1.79
6898     $Whatpm::HTML::Debug::cp_pass->('t156') if $Whatpm::HTML::Debug::cp_pass;
6899     BEGIN {
6900     $Whatpm::HTML::Debug::cp->{'t156'} = 1;
6901     }
6902    
6903 wakaba 1.54 last INSCOPE;
6904     }
6905     } # INSCOPE
6906     unless (defined $i) {
6907 wakaba 1.79
6908     $Whatpm::HTML::Debug::cp_pass->('t157') if $Whatpm::HTML::Debug::cp_pass;
6909     BEGIN {
6910     $Whatpm::HTML::Debug::cp->{'t157'} = 1;
6911     }
6912    
6913 wakaba 1.83 ## TODO: this type is wrong.
6914 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:caption');
6915     ## Ignore the token
6916     $token = $self->_get_next_token;
6917     redo B;
6918     }
6919    
6920     ## generate implied end tags
6921     if ({
6922     dd => 1, dt => 1, li => 1, p => 1,
6923 wakaba 1.83
6924     ## NOTE: Maybe the following elements never appear here.
6925 wakaba 1.54 td => 1, th => 1, tr => 1,
6926 wakaba 1.83 tbody => 1, tfoot => 1, thead => 1,
6927 wakaba 1.54 }->{$self->{open_elements}->[-1]->[1]}) {
6928 wakaba 1.79
6929     $Whatpm::HTML::Debug::cp_pass->('t158') if $Whatpm::HTML::Debug::cp_pass;
6930     BEGIN {
6931     $Whatpm::HTML::Debug::cp->{'t158'} = 1;
6932     }
6933    
6934 wakaba 1.54 unshift @{$self->{token}}, $token; # <?>
6935 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'caption'};
6936 wakaba 1.54 unshift @{$self->{token}}, $token;
6937 wakaba 1.57 $token = {type => END_TAG_TOKEN,
6938 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
6939     redo B;
6940     }
6941    
6942     if ($self->{open_elements}->[-1]->[1] ne 'caption') {
6943 wakaba 1.79
6944     $Whatpm::HTML::Debug::cp_pass->('t159') if $Whatpm::HTML::Debug::cp_pass;
6945     BEGIN {
6946     $Whatpm::HTML::Debug::cp->{'t159'} = 1;
6947     }
6948    
6949 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
6950 wakaba 1.79 } else {
6951    
6952     $Whatpm::HTML::Debug::cp_pass->('t160') if $Whatpm::HTML::Debug::cp_pass;
6953     BEGIN {
6954     $Whatpm::HTML::Debug::cp->{'t160'} = 1;
6955     }
6956    
6957 wakaba 1.54 }
6958    
6959     splice @{$self->{open_elements}}, $i;
6960    
6961     $clear_up_to_marker->();
6962    
6963 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
6964 wakaba 1.54
6965     ## reprocess
6966     redo B;
6967     } else {
6968 wakaba 1.79
6969     $Whatpm::HTML::Debug::cp_pass->('t161') if $Whatpm::HTML::Debug::cp_pass;
6970     BEGIN {
6971     $Whatpm::HTML::Debug::cp->{'t161'} = 1;
6972     }
6973    
6974 wakaba 1.54 #
6975     }
6976     } else {
6977 wakaba 1.79
6978     $Whatpm::HTML::Debug::cp_pass->('t162') if $Whatpm::HTML::Debug::cp_pass;
6979     BEGIN {
6980     $Whatpm::HTML::Debug::cp->{'t162'} = 1;
6981     }
6982    
6983 wakaba 1.54 #
6984     }
6985 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
6986 wakaba 1.54 if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') {
6987 wakaba 1.56 if ($self->{insertion_mode} == IN_CELL_IM) {
6988 wakaba 1.54 ## have an element in table scope
6989     my $i;
6990     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6991     my $node = $self->{open_elements}->[$_];
6992     if ($node->[1] eq $token->{tag_name}) {
6993 wakaba 1.79
6994     $Whatpm::HTML::Debug::cp_pass->('t163') if $Whatpm::HTML::Debug::cp_pass;
6995     BEGIN {
6996     $Whatpm::HTML::Debug::cp->{'t163'} = 1;
6997     }
6998    
6999 wakaba 1.54 $i = $_;
7000     last INSCOPE;
7001     } elsif ({
7002     table => 1, html => 1,
7003     }->{$node->[1]}) {
7004 wakaba 1.79
7005     $Whatpm::HTML::Debug::cp_pass->('t164') if $Whatpm::HTML::Debug::cp_pass;
7006     BEGIN {
7007     $Whatpm::HTML::Debug::cp->{'t164'} = 1;
7008     }
7009    
7010 wakaba 1.54 last INSCOPE;
7011     }
7012     } # INSCOPE
7013     unless (defined $i) {
7014 wakaba 1.79
7015     $Whatpm::HTML::Debug::cp_pass->('t165') if $Whatpm::HTML::Debug::cp_pass;
7016     BEGIN {
7017     $Whatpm::HTML::Debug::cp->{'t165'} = 1;
7018     }
7019    
7020 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7021     ## Ignore the token
7022     $token = $self->_get_next_token;
7023     redo B;
7024     }
7025    
7026     ## generate implied end tags
7027     if ({
7028     dd => 1, dt => 1, li => 1, p => 1,
7029     td => ($token->{tag_name} eq 'th'),
7030     th => ($token->{tag_name} eq 'td'),
7031 wakaba 1.83
7032     ## NOTE: Maybe the following elements never appear here.
7033 wakaba 1.54 tr => 1,
7034 wakaba 1.83 tbody => 1, tfoot => 1, thead => 1,
7035 wakaba 1.54 }->{$self->{open_elements}->[-1]->[1]}) {
7036 wakaba 1.79
7037     $Whatpm::HTML::Debug::cp_pass->('t166') if $Whatpm::HTML::Debug::cp_pass;
7038     BEGIN {
7039     $Whatpm::HTML::Debug::cp->{'t166'} = 1;
7040     }
7041    
7042 wakaba 1.54 unshift @{$self->{token}}, $token;
7043 wakaba 1.57 $token = {type => END_TAG_TOKEN,
7044 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
7045     redo B;
7046     }
7047    
7048     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
7049 wakaba 1.79
7050     $Whatpm::HTML::Debug::cp_pass->('t167') if $Whatpm::HTML::Debug::cp_pass;
7051     BEGIN {
7052     $Whatpm::HTML::Debug::cp->{'t167'} = 1;
7053     }
7054    
7055 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7056 wakaba 1.79 } else {
7057    
7058     $Whatpm::HTML::Debug::cp_pass->('t168') if $Whatpm::HTML::Debug::cp_pass;
7059     BEGIN {
7060     $Whatpm::HTML::Debug::cp->{'t168'} = 1;
7061     }
7062    
7063 wakaba 1.54 }
7064    
7065     splice @{$self->{open_elements}}, $i;
7066    
7067     $clear_up_to_marker->();
7068    
7069 wakaba 1.56 $self->{insertion_mode} = IN_ROW_IM;
7070 wakaba 1.54
7071     $token = $self->_get_next_token;
7072     redo B;
7073 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {
7074 wakaba 1.79
7075     $Whatpm::HTML::Debug::cp_pass->('t169') if $Whatpm::HTML::Debug::cp_pass;
7076     BEGIN {
7077     $Whatpm::HTML::Debug::cp->{'t169'} = 1;
7078     }
7079    
7080 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7081     ## Ignore the token
7082     $token = $self->_get_next_token;
7083     redo B;
7084     } else {
7085 wakaba 1.79
7086     $Whatpm::HTML::Debug::cp_pass->('t170') if $Whatpm::HTML::Debug::cp_pass;
7087     BEGIN {
7088     $Whatpm::HTML::Debug::cp->{'t170'} = 1;
7089     }
7090    
7091 wakaba 1.54 #
7092     }
7093     } elsif ($token->{tag_name} eq 'caption') {
7094 wakaba 1.56 if ($self->{insertion_mode} == IN_CAPTION_IM) {
7095 wakaba 1.54 ## have a table element in table scope
7096     my $i;
7097     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7098     my $node = $self->{open_elements}->[$_];
7099     if ($node->[1] eq $token->{tag_name}) {
7100 wakaba 1.79
7101     $Whatpm::HTML::Debug::cp_pass->('t171') if $Whatpm::HTML::Debug::cp_pass;
7102     BEGIN {
7103     $Whatpm::HTML::Debug::cp->{'t171'} = 1;
7104     }
7105    
7106 wakaba 1.54 $i = $_;
7107     last INSCOPE;
7108     } elsif ({
7109     table => 1, html => 1,
7110     }->{$node->[1]}) {
7111 wakaba 1.79
7112     $Whatpm::HTML::Debug::cp_pass->('t172') if $Whatpm::HTML::Debug::cp_pass;
7113     BEGIN {
7114     $Whatpm::HTML::Debug::cp->{'t172'} = 1;
7115     }
7116    
7117 wakaba 1.54 last INSCOPE;
7118     }
7119     } # INSCOPE
7120     unless (defined $i) {
7121 wakaba 1.79
7122     $Whatpm::HTML::Debug::cp_pass->('t173') if $Whatpm::HTML::Debug::cp_pass;
7123     BEGIN {
7124     $Whatpm::HTML::Debug::cp->{'t173'} = 1;
7125     }
7126    
7127 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7128     ## Ignore the token
7129     $token = $self->_get_next_token;
7130     redo B;
7131     }
7132    
7133     ## generate implied end tags
7134     if ({
7135     dd => 1, dt => 1, li => 1, p => 1,
7136 wakaba 1.83
7137     ## NOTE: The following elements never appear here, maybe.
7138 wakaba 1.54 td => 1, th => 1, tr => 1,
7139 wakaba 1.83 tbody => 1, tfoot => 1, thead => 1,
7140 wakaba 1.54 }->{$self->{open_elements}->[-1]->[1]}) {
7141 wakaba 1.79
7142     $Whatpm::HTML::Debug::cp_pass->('t174') if $Whatpm::HTML::Debug::cp_pass;
7143     BEGIN {
7144     $Whatpm::HTML::Debug::cp->{'t174'} = 1;
7145     }
7146    
7147 wakaba 1.54 unshift @{$self->{token}}, $token;
7148 wakaba 1.57 $token = {type => END_TAG_TOKEN,
7149 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
7150     redo B;
7151     }
7152    
7153     if ($self->{open_elements}->[-1]->[1] ne 'caption') {
7154 wakaba 1.79
7155     $Whatpm::HTML::Debug::cp_pass->('t175') if $Whatpm::HTML::Debug::cp_pass;
7156     BEGIN {
7157     $Whatpm::HTML::Debug::cp->{'t175'} = 1;
7158     }
7159    
7160 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7161 wakaba 1.79 } else {
7162    
7163     $Whatpm::HTML::Debug::cp_pass->('t176') if $Whatpm::HTML::Debug::cp_pass;
7164     BEGIN {
7165     $Whatpm::HTML::Debug::cp->{'t176'} = 1;
7166     }
7167    
7168 wakaba 1.54 }
7169    
7170     splice @{$self->{open_elements}}, $i;
7171    
7172     $clear_up_to_marker->();
7173    
7174 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7175 wakaba 1.54
7176     $token = $self->_get_next_token;
7177     redo B;
7178 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CELL_IM) {
7179 wakaba 1.79
7180     $Whatpm::HTML::Debug::cp_pass->('t177') if $Whatpm::HTML::Debug::cp_pass;
7181     BEGIN {
7182     $Whatpm::HTML::Debug::cp->{'t177'} = 1;
7183     }
7184    
7185 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7186     ## Ignore the token
7187     $token = $self->_get_next_token;
7188     redo B;
7189     } else {
7190 wakaba 1.79
7191     $Whatpm::HTML::Debug::cp_pass->('t178') if $Whatpm::HTML::Debug::cp_pass;
7192     BEGIN {
7193     $Whatpm::HTML::Debug::cp->{'t178'} = 1;
7194     }
7195    
7196 wakaba 1.54 #
7197 wakaba 1.1 }
7198 wakaba 1.54 } elsif ({
7199     table => 1, tbody => 1, tfoot => 1,
7200     thead => 1, tr => 1,
7201     }->{$token->{tag_name}} and
7202 wakaba 1.56 $self->{insertion_mode} == IN_CELL_IM) {
7203 wakaba 1.54 ## have an element in table scope
7204     my $i;
7205     my $tn;
7206     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7207     my $node = $self->{open_elements}->[$_];
7208     if ($node->[1] eq $token->{tag_name}) {
7209 wakaba 1.79
7210     $Whatpm::HTML::Debug::cp_pass->('t179') if $Whatpm::HTML::Debug::cp_pass;
7211     BEGIN {
7212     $Whatpm::HTML::Debug::cp->{'t179'} = 1;
7213     }
7214    
7215 wakaba 1.54 $i = $_;
7216     last INSCOPE;
7217     } elsif ($node->[1] eq 'td' or $node->[1] eq 'th') {
7218 wakaba 1.79
7219     $Whatpm::HTML::Debug::cp_pass->('t180') if $Whatpm::HTML::Debug::cp_pass;
7220     BEGIN {
7221     $Whatpm::HTML::Debug::cp->{'t180'} = 1;
7222     }
7223    
7224 wakaba 1.54 $tn = $node->[1];
7225     ## NOTE: There is exactly one |td| or |th| element
7226     ## in scope in the stack of open elements by definition.
7227     } elsif ({
7228     table => 1, html => 1,
7229     }->{$node->[1]}) {
7230 wakaba 1.79
7231     $Whatpm::HTML::Debug::cp_pass->('t181') if $Whatpm::HTML::Debug::cp_pass;
7232     BEGIN {
7233     $Whatpm::HTML::Debug::cp->{'t181'} = 1;
7234     }
7235    
7236 wakaba 1.54 last INSCOPE;
7237     }
7238     } # INSCOPE
7239     unless (defined $i) {
7240 wakaba 1.79
7241     $Whatpm::HTML::Debug::cp_pass->('t182') if $Whatpm::HTML::Debug::cp_pass;
7242     BEGIN {
7243     $Whatpm::HTML::Debug::cp->{'t182'} = 1;
7244     }
7245    
7246 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7247     ## Ignore the token
7248     $token = $self->_get_next_token;
7249     redo B;
7250 wakaba 1.79 } else {
7251    
7252     $Whatpm::HTML::Debug::cp_pass->('t183') if $Whatpm::HTML::Debug::cp_pass;
7253     BEGIN {
7254     $Whatpm::HTML::Debug::cp->{'t183'} = 1;
7255     }
7256    
7257 wakaba 1.1 }
7258    
7259 wakaba 1.54 ## Close the cell
7260     unshift @{$self->{token}}, $token; # </?>
7261 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => $tn};
7262 wakaba 1.54 redo B;
7263     } elsif ($token->{tag_name} eq 'table' and
7264 wakaba 1.56 $self->{insertion_mode} == IN_CAPTION_IM) {
7265 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:caption');
7266 wakaba 1.31
7267 wakaba 1.54 ## As if </caption>
7268     ## have a table element in table scope
7269     my $i;
7270     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7271     my $node = $self->{open_elements}->[$_];
7272     if ($node->[1] eq 'caption') {
7273 wakaba 1.79
7274     $Whatpm::HTML::Debug::cp_pass->('t184') if $Whatpm::HTML::Debug::cp_pass;
7275     BEGIN {
7276     $Whatpm::HTML::Debug::cp->{'t184'} = 1;
7277     }
7278    
7279 wakaba 1.54 $i = $_;
7280     last INSCOPE;
7281     } elsif ({
7282     table => 1, html => 1,
7283     }->{$node->[1]}) {
7284 wakaba 1.79
7285     $Whatpm::HTML::Debug::cp_pass->('t185') if $Whatpm::HTML::Debug::cp_pass;
7286     BEGIN {
7287     $Whatpm::HTML::Debug::cp->{'t185'} = 1;
7288     }
7289    
7290 wakaba 1.54 last INSCOPE;
7291     }
7292     } # INSCOPE
7293     unless (defined $i) {
7294 wakaba 1.79
7295     $Whatpm::HTML::Debug::cp_pass->('t186') if $Whatpm::HTML::Debug::cp_pass;
7296     BEGIN {
7297     $Whatpm::HTML::Debug::cp->{'t186'} = 1;
7298     }
7299    
7300 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:caption');
7301     ## Ignore the token
7302     $token = $self->_get_next_token;
7303     redo B;
7304     }
7305    
7306     ## generate implied end tags
7307     if ({
7308     dd => 1, dt => 1, li => 1, p => 1,
7309 wakaba 1.83
7310     ## NOTE: The following elements never appear, maybe.
7311 wakaba 1.54 td => 1, th => 1, tr => 1,
7312 wakaba 1.83 tbody => 1, tfoot => 1, thead => 1,
7313 wakaba 1.54 }->{$self->{open_elements}->[-1]->[1]}) {
7314 wakaba 1.79
7315     $Whatpm::HTML::Debug::cp_pass->('t187') if $Whatpm::HTML::Debug::cp_pass;
7316     BEGIN {
7317     $Whatpm::HTML::Debug::cp->{'t187'} = 1;
7318     }
7319    
7320 wakaba 1.54 unshift @{$self->{token}}, $token; # </table>
7321 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'caption'};
7322 wakaba 1.54 unshift @{$self->{token}}, $token;
7323 wakaba 1.57 $token = {type => END_TAG_TOKEN,
7324 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
7325     redo B;
7326     }
7327 wakaba 1.20
7328 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] ne 'caption') {
7329 wakaba 1.79
7330     $Whatpm::HTML::Debug::cp_pass->('t188') if $Whatpm::HTML::Debug::cp_pass;
7331     BEGIN {
7332     $Whatpm::HTML::Debug::cp->{'t188'} = 1;
7333     }
7334    
7335 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7336 wakaba 1.79 } else {
7337    
7338     $Whatpm::HTML::Debug::cp_pass->('t189') if $Whatpm::HTML::Debug::cp_pass;
7339     BEGIN {
7340     $Whatpm::HTML::Debug::cp->{'t189'} = 1;
7341     }
7342    
7343 wakaba 1.54 }
7344 wakaba 1.12
7345 wakaba 1.54 splice @{$self->{open_elements}}, $i;
7346 wakaba 1.31
7347 wakaba 1.54 $clear_up_to_marker->();
7348 wakaba 1.1
7349 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7350 wakaba 1.3
7351 wakaba 1.54 ## reprocess
7352     redo B;
7353     } elsif ({
7354     body => 1, col => 1, colgroup => 1, html => 1,
7355     }->{$token->{tag_name}}) {
7356 wakaba 1.58 if ($self->{insertion_mode} & BODY_TABLE_IMS) {
7357 wakaba 1.79
7358     $Whatpm::HTML::Debug::cp_pass->('t190') if $Whatpm::HTML::Debug::cp_pass;
7359     BEGIN {
7360     $Whatpm::HTML::Debug::cp->{'t190'} = 1;
7361     }
7362    
7363 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7364     ## Ignore the token
7365     $token = $self->_get_next_token;
7366     redo B;
7367     } else {
7368 wakaba 1.79
7369     $Whatpm::HTML::Debug::cp_pass->('t191') if $Whatpm::HTML::Debug::cp_pass;
7370     BEGIN {
7371     $Whatpm::HTML::Debug::cp->{'t191'} = 1;
7372     }
7373    
7374 wakaba 1.54 #
7375     }
7376     } elsif ({
7377     tbody => 1, tfoot => 1,
7378     thead => 1, tr => 1,
7379     }->{$token->{tag_name}} and
7380 wakaba 1.56 $self->{insertion_mode} == IN_CAPTION_IM) {
7381 wakaba 1.79
7382     $Whatpm::HTML::Debug::cp_pass->('t192') if $Whatpm::HTML::Debug::cp_pass;
7383     BEGIN {
7384     $Whatpm::HTML::Debug::cp->{'t192'} = 1;
7385     }
7386    
7387 wakaba 1.25 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7388 wakaba 1.1 ## Ignore the token
7389     $token = $self->_get_next_token;
7390 wakaba 1.54 redo B;
7391     } else {
7392 wakaba 1.79
7393     $Whatpm::HTML::Debug::cp_pass->('t193') if $Whatpm::HTML::Debug::cp_pass;
7394     BEGIN {
7395     $Whatpm::HTML::Debug::cp->{'t193'} = 1;
7396     }
7397    
7398 wakaba 1.54 #
7399 wakaba 1.1 }
7400 wakaba 1.54 } else {
7401     die "$0: $token->{type}: Unknown token type";
7402 wakaba 1.1 }
7403    
7404 wakaba 1.54 $insert = $insert_to_current;
7405     #
7406 wakaba 1.58 } elsif ($self->{insertion_mode} & TABLE_IMS) {
7407 wakaba 1.60 if ($token->{type} == CHARACTER_TOKEN) {
7408 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
7409     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
7410    
7411     unless (length $token->{data}) {
7412 wakaba 1.79
7413     $Whatpm::HTML::Debug::cp_pass->('t194') if $Whatpm::HTML::Debug::cp_pass;
7414     BEGIN {
7415     $Whatpm::HTML::Debug::cp->{'t194'} = 1;
7416     }
7417    
7418 wakaba 1.54 $token = $self->_get_next_token;
7419     redo B;
7420 wakaba 1.79 } else {
7421    
7422     $Whatpm::HTML::Debug::cp_pass->('t195') if $Whatpm::HTML::Debug::cp_pass;
7423     BEGIN {
7424     $Whatpm::HTML::Debug::cp->{'t195'} = 1;
7425     }
7426    
7427 wakaba 1.54 }
7428     }
7429 wakaba 1.1
7430 wakaba 1.54 $self->{parse_error}-> (type => 'in table:#character');
7431 wakaba 1.1
7432 wakaba 1.54 ## As if in body, but insert into foster parent element
7433     ## ISSUE: Spec says that "whenever a node would be inserted
7434     ## into the current node" while characters might not be
7435     ## result in a new Text node.
7436     $reconstruct_active_formatting_elements->($insert_to_foster);
7437    
7438     if ({
7439     table => 1, tbody => 1, tfoot => 1,
7440     thead => 1, tr => 1,
7441     }->{$self->{open_elements}->[-1]->[1]}) {
7442     # MUST
7443     my $foster_parent_element;
7444     my $next_sibling;
7445     my $prev_sibling;
7446     OE: for (reverse 0..$#{$self->{open_elements}}) {
7447     if ($self->{open_elements}->[$_]->[1] eq 'table') {
7448     my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
7449     if (defined $parent and $parent->node_type == 1) {
7450 wakaba 1.79
7451     $Whatpm::HTML::Debug::cp_pass->('t196') if $Whatpm::HTML::Debug::cp_pass;
7452     BEGIN {
7453     $Whatpm::HTML::Debug::cp->{'t196'} = 1;
7454     }
7455    
7456 wakaba 1.54 $foster_parent_element = $parent;
7457     $next_sibling = $self->{open_elements}->[$_]->[0];
7458     $prev_sibling = $next_sibling->previous_sibling;
7459     } else {
7460 wakaba 1.79
7461     $Whatpm::HTML::Debug::cp_pass->('t197') if $Whatpm::HTML::Debug::cp_pass;
7462     BEGIN {
7463     $Whatpm::HTML::Debug::cp->{'t197'} = 1;
7464     }
7465    
7466 wakaba 1.54 $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
7467     $prev_sibling = $foster_parent_element->last_child;
7468     }
7469     last OE;
7470     }
7471     } # OE
7472     $foster_parent_element = $self->{open_elements}->[0]->[0] and
7473     $prev_sibling = $foster_parent_element->last_child
7474     unless defined $foster_parent_element;
7475     if (defined $prev_sibling and
7476     $prev_sibling->node_type == 3) {
7477 wakaba 1.79
7478     $Whatpm::HTML::Debug::cp_pass->('t198') if $Whatpm::HTML::Debug::cp_pass;
7479     BEGIN {
7480     $Whatpm::HTML::Debug::cp->{'t198'} = 1;
7481     }
7482    
7483 wakaba 1.54 $prev_sibling->manakai_append_text ($token->{data});
7484     } else {
7485 wakaba 1.79
7486     $Whatpm::HTML::Debug::cp_pass->('t199') if $Whatpm::HTML::Debug::cp_pass;
7487     BEGIN {
7488     $Whatpm::HTML::Debug::cp->{'t199'} = 1;
7489     }
7490    
7491 wakaba 1.54 $foster_parent_element->insert_before
7492     ($self->{document}->create_text_node ($token->{data}),
7493     $next_sibling);
7494     }
7495     } else {
7496 wakaba 1.79
7497     $Whatpm::HTML::Debug::cp_pass->('t200') if $Whatpm::HTML::Debug::cp_pass;
7498     BEGIN {
7499     $Whatpm::HTML::Debug::cp->{'t200'} = 1;
7500     }
7501    
7502 wakaba 1.54 $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
7503     }
7504    
7505 wakaba 1.52 $token = $self->_get_next_token;
7506 wakaba 1.1 redo B;
7507 wakaba 1.60 } elsif ($token->{type} == START_TAG_TOKEN) {
7508 wakaba 1.54 if ({
7509 wakaba 1.56 tr => ($self->{insertion_mode} != IN_ROW_IM),
7510 wakaba 1.54 th => 1, td => 1,
7511     }->{$token->{tag_name}}) {
7512 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_IM) {
7513 wakaba 1.54 ## Clear back to table context
7514     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7515     $self->{open_elements}->[-1]->[1] ne 'html') {
7516 wakaba 1.79
7517     $Whatpm::HTML::Debug::cp_pass->('t201') if $Whatpm::HTML::Debug::cp_pass;
7518     BEGIN {
7519     $Whatpm::HTML::Debug::cp->{'t201'} = 1;
7520     }
7521    
7522 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7523     pop @{$self->{open_elements}};
7524     }
7525    
7526    
7527     {
7528     my $el;
7529    
7530     $el = $self->{document}->create_element_ns
7531     (q<http://www.w3.org/1999/xhtml>, [undef, 'tbody']);
7532    
7533     $self->{open_elements}->[-1]->[0]->append_child ($el);
7534     push @{$self->{open_elements}}, [$el, 'tbody'];
7535     }
7536    
7537 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
7538 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
7539     }
7540    
7541 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
7542 wakaba 1.54 unless ($token->{tag_name} eq 'tr') {
7543 wakaba 1.79
7544     $Whatpm::HTML::Debug::cp_pass->('t202') if $Whatpm::HTML::Debug::cp_pass;
7545     BEGIN {
7546     $Whatpm::HTML::Debug::cp->{'t202'} = 1;
7547     }
7548    
7549 wakaba 1.54 $self->{parse_error}-> (type => 'missing start tag:tr');
7550     }
7551    
7552     ## Clear back to table body context
7553     while (not {
7554     tbody => 1, tfoot => 1, thead => 1, html => 1,
7555     }->{$self->{open_elements}->[-1]->[1]}) {
7556 wakaba 1.79
7557     $Whatpm::HTML::Debug::cp_pass->('t203') if $Whatpm::HTML::Debug::cp_pass;
7558     BEGIN {
7559     $Whatpm::HTML::Debug::cp->{'t203'} = 1;
7560     }
7561    
7562 wakaba 1.83 ## ISSUE: Can this case be reached?
7563 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7564     pop @{$self->{open_elements}};
7565     }
7566    
7567 wakaba 1.56 $self->{insertion_mode} = IN_ROW_IM;
7568 wakaba 1.54 if ($token->{tag_name} eq 'tr') {
7569    
7570 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t204') if $Whatpm::HTML::Debug::cp_pass;
7571     BEGIN {
7572     $Whatpm::HTML::Debug::cp->{'t204'} = 1;
7573     }
7574    
7575    
7576 wakaba 1.54 {
7577     my $el;
7578    
7579     $el = $self->{document}->create_element_ns
7580     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7581    
7582     for my $attr_name (keys %{ $token->{attributes}}) {
7583     $el->set_attribute_ns (undef, [undef, $attr_name],
7584     $token->{attributes} ->{$attr_name}->{value});
7585 wakaba 1.1 }
7586 wakaba 1.54
7587     $self->{open_elements}->[-1]->[0]->append_child ($el);
7588     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7589     }
7590    
7591     $token = $self->_get_next_token;
7592     redo B;
7593     } else {
7594    
7595 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t205') if $Whatpm::HTML::Debug::cp_pass;
7596     BEGIN {
7597     $Whatpm::HTML::Debug::cp->{'t205'} = 1;
7598     }
7599    
7600    
7601 wakaba 1.54 {
7602     my $el;
7603    
7604     $el = $self->{document}->create_element_ns
7605     (q<http://www.w3.org/1999/xhtml>, [undef, 'tr']);
7606    
7607     $self->{open_elements}->[-1]->[0]->append_child ($el);
7608     push @{$self->{open_elements}}, [$el, 'tr'];
7609     }
7610    
7611     ## reprocess in the "in row" insertion mode
7612     }
7613 wakaba 1.79 } else {
7614    
7615     $Whatpm::HTML::Debug::cp_pass->('t206') if $Whatpm::HTML::Debug::cp_pass;
7616     BEGIN {
7617     $Whatpm::HTML::Debug::cp->{'t206'} = 1;
7618     }
7619    
7620 wakaba 1.54 }
7621 wakaba 1.52
7622 wakaba 1.54 ## Clear back to table row context
7623     while (not {
7624     tr => 1, html => 1,
7625     }->{$self->{open_elements}->[-1]->[1]}) {
7626 wakaba 1.79
7627     $Whatpm::HTML::Debug::cp_pass->('t207') if $Whatpm::HTML::Debug::cp_pass;
7628     BEGIN {
7629     $Whatpm::HTML::Debug::cp->{'t207'} = 1;
7630     }
7631    
7632 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7633     pop @{$self->{open_elements}};
7634     }
7635    
7636    
7637     {
7638     my $el;
7639    
7640     $el = $self->{document}->create_element_ns
7641     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7642 wakaba 1.1
7643 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
7644     $el->set_attribute_ns (undef, [undef, $attr_name],
7645     $token->{attributes} ->{$attr_name}->{value});
7646     }
7647    
7648     $self->{open_elements}->[-1]->[0]->append_child ($el);
7649     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7650     }
7651    
7652 wakaba 1.56 $self->{insertion_mode} = IN_CELL_IM;
7653 wakaba 1.54
7654     push @$active_formatting_elements, ['#marker', ''];
7655    
7656     $token = $self->_get_next_token;
7657     redo B;
7658     } elsif ({
7659     caption => 1, col => 1, colgroup => 1,
7660     tbody => 1, tfoot => 1, thead => 1,
7661 wakaba 1.56 tr => 1, # $self->{insertion_mode} == IN_ROW_IM
7662 wakaba 1.54 }->{$token->{tag_name}}) {
7663 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
7664 wakaba 1.54 ## As if </tr>
7665     ## have an element in table scope
7666     my $i;
7667     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7668     my $node = $self->{open_elements}->[$_];
7669     if ($node->[1] eq 'tr') {
7670 wakaba 1.79
7671     $Whatpm::HTML::Debug::cp_pass->('t208') if $Whatpm::HTML::Debug::cp_pass;
7672     BEGIN {
7673     $Whatpm::HTML::Debug::cp->{'t208'} = 1;
7674     }
7675    
7676 wakaba 1.54 $i = $_;
7677     last INSCOPE;
7678     } elsif ({
7679 wakaba 1.83 html => 1,
7680    
7681     ## NOTE: This element does not appear here, maybe.
7682     table => 1,
7683 wakaba 1.54 }->{$node->[1]}) {
7684 wakaba 1.79
7685     $Whatpm::HTML::Debug::cp_pass->('t209') if $Whatpm::HTML::Debug::cp_pass;
7686     BEGIN {
7687     $Whatpm::HTML::Debug::cp->{'t209'} = 1;
7688     }
7689    
7690 wakaba 1.54 last INSCOPE;
7691     }
7692     } # INSCOPE
7693 wakaba 1.79 unless (defined $i) {
7694    
7695     $Whatpm::HTML::Debug::cp_pass->('t210') if $Whatpm::HTML::Debug::cp_pass;
7696     BEGIN {
7697     $Whatpm::HTML::Debug::cp->{'t210'} = 1;
7698     }
7699    
7700 wakaba 1.83 ## TODO: This type is wrong.
7701 wakaba 1.79 $self->{parse_error}-> (type => 'unmacthed end tag:'.$token->{tag_name});
7702 wakaba 1.54 ## Ignore the token
7703     $token = $self->_get_next_token;
7704     redo B;
7705     }
7706    
7707     ## Clear back to table row context
7708     while (not {
7709     tr => 1, html => 1,
7710     }->{$self->{open_elements}->[-1]->[1]}) {
7711 wakaba 1.79
7712     $Whatpm::HTML::Debug::cp_pass->('t211') if $Whatpm::HTML::Debug::cp_pass;
7713     BEGIN {
7714     $Whatpm::HTML::Debug::cp->{'t211'} = 1;
7715     }
7716    
7717 wakaba 1.83 ## ISSUE: Can this case be reached?
7718 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7719     pop @{$self->{open_elements}};
7720     }
7721    
7722     pop @{$self->{open_elements}}; # tr
7723 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
7724 wakaba 1.54 if ($token->{tag_name} eq 'tr') {
7725 wakaba 1.79
7726     $Whatpm::HTML::Debug::cp_pass->('t212') if $Whatpm::HTML::Debug::cp_pass;
7727     BEGIN {
7728     $Whatpm::HTML::Debug::cp->{'t212'} = 1;
7729     }
7730    
7731 wakaba 1.54 ## reprocess
7732     redo B;
7733     } else {
7734 wakaba 1.79
7735     $Whatpm::HTML::Debug::cp_pass->('t213') if $Whatpm::HTML::Debug::cp_pass;
7736     BEGIN {
7737     $Whatpm::HTML::Debug::cp->{'t213'} = 1;
7738     }
7739    
7740 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
7741     }
7742     }
7743 wakaba 1.52
7744 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
7745 wakaba 1.54 ## have an element in table scope
7746     my $i;
7747     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7748     my $node = $self->{open_elements}->[$_];
7749     if ({
7750     tbody => 1, thead => 1, tfoot => 1,
7751     }->{$node->[1]}) {
7752 wakaba 1.79
7753     $Whatpm::HTML::Debug::cp_pass->('t214') if $Whatpm::HTML::Debug::cp_pass;
7754     BEGIN {
7755     $Whatpm::HTML::Debug::cp->{'t214'} = 1;
7756     }
7757    
7758 wakaba 1.54 $i = $_;
7759     last INSCOPE;
7760     } elsif ({
7761     table => 1, html => 1,
7762     }->{$node->[1]}) {
7763 wakaba 1.79
7764     $Whatpm::HTML::Debug::cp_pass->('t215') if $Whatpm::HTML::Debug::cp_pass;
7765     BEGIN {
7766     $Whatpm::HTML::Debug::cp->{'t215'} = 1;
7767     }
7768    
7769 wakaba 1.54 last INSCOPE;
7770     }
7771     } # INSCOPE
7772     unless (defined $i) {
7773 wakaba 1.79
7774     $Whatpm::HTML::Debug::cp_pass->('t216') if $Whatpm::HTML::Debug::cp_pass;
7775     BEGIN {
7776     $Whatpm::HTML::Debug::cp->{'t216'} = 1;
7777     }
7778    
7779 wakaba 1.83 ## TODO: This erorr type ios wrong.
7780     $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7781 wakaba 1.54 ## Ignore the token
7782     $token = $self->_get_next_token;
7783     redo B;
7784     }
7785 wakaba 1.52
7786 wakaba 1.54 ## Clear back to table body context
7787     while (not {
7788     tbody => 1, tfoot => 1, thead => 1, html => 1,
7789     }->{$self->{open_elements}->[-1]->[1]}) {
7790 wakaba 1.79
7791     $Whatpm::HTML::Debug::cp_pass->('t217') if $Whatpm::HTML::Debug::cp_pass;
7792     BEGIN {
7793     $Whatpm::HTML::Debug::cp->{'t217'} = 1;
7794     }
7795    
7796 wakaba 1.83 ## ISSUE: Can this state be reached?
7797 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7798     pop @{$self->{open_elements}};
7799     }
7800    
7801     ## As if <{current node}>
7802     ## have an element in table scope
7803     ## true by definition
7804    
7805     ## Clear back to table body context
7806     ## nop by definition
7807    
7808     pop @{$self->{open_elements}};
7809 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7810 wakaba 1.54 ## reprocess in "in table" insertion mode...
7811 wakaba 1.79 } else {
7812    
7813     $Whatpm::HTML::Debug::cp_pass->('t218') if $Whatpm::HTML::Debug::cp_pass;
7814     BEGIN {
7815     $Whatpm::HTML::Debug::cp->{'t218'} = 1;
7816     }
7817    
7818 wakaba 1.54 }
7819 wakaba 1.51
7820 wakaba 1.54 if ($token->{tag_name} eq 'col') {
7821     ## Clear back to table context
7822     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7823     $self->{open_elements}->[-1]->[1] ne 'html') {
7824 wakaba 1.79
7825     $Whatpm::HTML::Debug::cp_pass->('t219') if $Whatpm::HTML::Debug::cp_pass;
7826     BEGIN {
7827     $Whatpm::HTML::Debug::cp->{'t219'} = 1;
7828     }
7829    
7830 wakaba 1.83 ## ISSUE: Can this state be reached?
7831 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7832     pop @{$self->{open_elements}};
7833     }
7834    
7835    
7836 wakaba 1.51 {
7837     my $el;
7838    
7839     $el = $self->{document}->create_element_ns
7840 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'colgroup']);
7841 wakaba 1.51
7842     $self->{open_elements}->[-1]->[0]->append_child ($el);
7843 wakaba 1.54 push @{$self->{open_elements}}, [$el, 'colgroup'];
7844 wakaba 1.51 }
7845    
7846 wakaba 1.56 $self->{insertion_mode} = IN_COLUMN_GROUP_IM;
7847 wakaba 1.54 ## reprocess
7848     redo B;
7849     } elsif ({
7850     caption => 1,
7851     colgroup => 1,
7852     tbody => 1, tfoot => 1, thead => 1,
7853     }->{$token->{tag_name}}) {
7854     ## Clear back to table context
7855     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7856     $self->{open_elements}->[-1]->[1] ne 'html') {
7857 wakaba 1.79
7858     $Whatpm::HTML::Debug::cp_pass->('t220') if $Whatpm::HTML::Debug::cp_pass;
7859     BEGIN {
7860     $Whatpm::HTML::Debug::cp->{'t220'} = 1;
7861     }
7862    
7863 wakaba 1.83 ## ISSUE: Can this state be reached?
7864 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7865     pop @{$self->{open_elements}};
7866     }
7867    
7868     push @$active_formatting_elements, ['#marker', '']
7869     if $token->{tag_name} eq 'caption';
7870    
7871 wakaba 1.52
7872 wakaba 1.54 {
7873     my $el;
7874    
7875     $el = $self->{document}->create_element_ns
7876 wakaba 1.52 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7877    
7878 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
7879     $el->set_attribute_ns (undef, [undef, $attr_name],
7880     $token->{attributes} ->{$attr_name}->{value});
7881 wakaba 1.52 }
7882    
7883 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
7884     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7885     }
7886    
7887     $self->{insertion_mode} = {
7888 wakaba 1.56 caption => IN_CAPTION_IM,
7889     colgroup => IN_COLUMN_GROUP_IM,
7890     tbody => IN_TABLE_BODY_IM,
7891     tfoot => IN_TABLE_BODY_IM,
7892     thead => IN_TABLE_BODY_IM,
7893 wakaba 1.54 }->{$token->{tag_name}};
7894 wakaba 1.52 $token = $self->_get_next_token;
7895     redo B;
7896 wakaba 1.54 } else {
7897     die "$0: in table: <>: $token->{tag_name}";
7898     }
7899     } elsif ($token->{tag_name} eq 'table') {
7900     $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7901    
7902     ## As if </table>
7903     ## have a table element in table scope
7904     my $i;
7905     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7906     my $node = $self->{open_elements}->[$_];
7907     if ($node->[1] eq 'table') {
7908 wakaba 1.79
7909     $Whatpm::HTML::Debug::cp_pass->('t221') if $Whatpm::HTML::Debug::cp_pass;
7910     BEGIN {
7911     $Whatpm::HTML::Debug::cp->{'t221'} = 1;
7912     }
7913    
7914 wakaba 1.54 $i = $_;
7915     last INSCOPE;
7916     } elsif ({
7917 wakaba 1.83 #table => 1,
7918     html => 1,
7919 wakaba 1.54 }->{$node->[1]}) {
7920 wakaba 1.79
7921     $Whatpm::HTML::Debug::cp_pass->('t222') if $Whatpm::HTML::Debug::cp_pass;
7922     BEGIN {
7923     $Whatpm::HTML::Debug::cp->{'t222'} = 1;
7924     }
7925    
7926 wakaba 1.54 last INSCOPE;
7927     }
7928     } # INSCOPE
7929     unless (defined $i) {
7930 wakaba 1.79
7931     $Whatpm::HTML::Debug::cp_pass->('t223') if $Whatpm::HTML::Debug::cp_pass;
7932     BEGIN {
7933     $Whatpm::HTML::Debug::cp->{'t223'} = 1;
7934     }
7935    
7936 wakaba 1.83 ## TODO: The following is wrong, maybe.
7937 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:table');
7938     ## Ignore tokens </table><table>
7939 wakaba 1.52 $token = $self->_get_next_token;
7940     redo B;
7941     }
7942    
7943 wakaba 1.54 ## generate implied end tags
7944     if ({
7945     dd => 1, dt => 1, li => 1, p => 1,
7946     td => 1, th => 1, tr => 1,
7947     tbody => 1, tfoot=> 1, thead => 1,
7948     }->{$self->{open_elements}->[-1]->[1]}) {
7949 wakaba 1.79
7950     $Whatpm::HTML::Debug::cp_pass->('t224') if $Whatpm::HTML::Debug::cp_pass;
7951     BEGIN {
7952     $Whatpm::HTML::Debug::cp->{'t224'} = 1;
7953     }
7954    
7955 wakaba 1.54 unshift @{$self->{token}}, $token; # <table>
7956 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'table'};
7957 wakaba 1.54 unshift @{$self->{token}}, $token;
7958 wakaba 1.57 $token = {type => END_TAG_TOKEN,
7959 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
7960     redo B;
7961     }
7962    
7963     if ($self->{open_elements}->[-1]->[1] ne 'table') {
7964 wakaba 1.79
7965     $Whatpm::HTML::Debug::cp_pass->('t225') if $Whatpm::HTML::Debug::cp_pass;
7966     BEGIN {
7967     $Whatpm::HTML::Debug::cp->{'t225'} = 1;
7968     }
7969    
7970 wakaba 1.83 ## ISSUE: Can this case be reached?
7971 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7972 wakaba 1.79 } else {
7973    
7974     $Whatpm::HTML::Debug::cp_pass->('t226') if $Whatpm::HTML::Debug::cp_pass;
7975     BEGIN {
7976     $Whatpm::HTML::Debug::cp->{'t226'} = 1;
7977     }
7978    
7979 wakaba 1.54 }
7980    
7981     splice @{$self->{open_elements}}, $i;
7982    
7983     $self->_reset_insertion_mode;
7984 wakaba 1.52
7985 wakaba 1.54 ## reprocess
7986     redo B;
7987 wakaba 1.60 } else {
7988 wakaba 1.79
7989     $Whatpm::HTML::Debug::cp_pass->('t227') if $Whatpm::HTML::Debug::cp_pass;
7990     BEGIN {
7991     $Whatpm::HTML::Debug::cp->{'t227'} = 1;
7992     }
7993    
7994 wakaba 1.60 $self->{parse_error}-> (type => 'in table:'.$token->{tag_name});
7995    
7996     $insert = $insert_to_foster;
7997     #
7998     }
7999     } elsif ($token->{type} == END_TAG_TOKEN) {
8000 wakaba 1.54 if ($token->{tag_name} eq 'tr' and
8001 wakaba 1.56 $self->{insertion_mode} == IN_ROW_IM) {
8002 wakaba 1.54 ## have an element in table scope
8003     my $i;
8004     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8005     my $node = $self->{open_elements}->[$_];
8006     if ($node->[1] eq $token->{tag_name}) {
8007 wakaba 1.79
8008     $Whatpm::HTML::Debug::cp_pass->('t228') if $Whatpm::HTML::Debug::cp_pass;
8009     BEGIN {
8010     $Whatpm::HTML::Debug::cp->{'t228'} = 1;
8011     }
8012    
8013 wakaba 1.54 $i = $_;
8014     last INSCOPE;
8015     } elsif ({
8016     table => 1, html => 1,
8017     }->{$node->[1]}) {
8018 wakaba 1.79
8019     $Whatpm::HTML::Debug::cp_pass->('t229') if $Whatpm::HTML::Debug::cp_pass;
8020     BEGIN {
8021     $Whatpm::HTML::Debug::cp->{'t229'} = 1;
8022     }
8023    
8024 wakaba 1.54 last INSCOPE;
8025     }
8026     } # INSCOPE
8027     unless (defined $i) {
8028 wakaba 1.79
8029     $Whatpm::HTML::Debug::cp_pass->('t230') if $Whatpm::HTML::Debug::cp_pass;
8030     BEGIN {
8031     $Whatpm::HTML::Debug::cp->{'t230'} = 1;
8032     }
8033    
8034 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8035     ## Ignore the token
8036     $token = $self->_get_next_token;
8037     redo B;
8038 wakaba 1.79 } else {
8039    
8040     $Whatpm::HTML::Debug::cp_pass->('t232') if $Whatpm::HTML::Debug::cp_pass;
8041     BEGIN {
8042     $Whatpm::HTML::Debug::cp->{'t232'} = 1;
8043     }
8044    
8045 wakaba 1.54 }
8046    
8047     ## Clear back to table row context
8048     while (not {
8049     tr => 1, html => 1,
8050     }->{$self->{open_elements}->[-1]->[1]}) {
8051 wakaba 1.79
8052     $Whatpm::HTML::Debug::cp_pass->('t231') if $Whatpm::HTML::Debug::cp_pass;
8053     BEGIN {
8054     $Whatpm::HTML::Debug::cp->{'t231'} = 1;
8055     }
8056    
8057 wakaba 1.83 ## ISSUE: Can this state be reached?
8058 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8059     pop @{$self->{open_elements}};
8060     }
8061    
8062     pop @{$self->{open_elements}}; # tr
8063 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8064 wakaba 1.54 $token = $self->_get_next_token;
8065     redo B;
8066     } elsif ($token->{tag_name} eq 'table') {
8067 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
8068 wakaba 1.54 ## As if </tr>
8069     ## have an element in table scope
8070     my $i;
8071     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8072     my $node = $self->{open_elements}->[$_];
8073     if ($node->[1] eq 'tr') {
8074 wakaba 1.79
8075     $Whatpm::HTML::Debug::cp_pass->('t233') if $Whatpm::HTML::Debug::cp_pass;
8076     BEGIN {
8077     $Whatpm::HTML::Debug::cp->{'t233'} = 1;
8078     }
8079    
8080 wakaba 1.54 $i = $_;
8081     last INSCOPE;
8082     } elsif ({
8083     table => 1, html => 1,
8084     }->{$node->[1]}) {
8085 wakaba 1.79
8086     $Whatpm::HTML::Debug::cp_pass->('t234') if $Whatpm::HTML::Debug::cp_pass;
8087     BEGIN {
8088     $Whatpm::HTML::Debug::cp->{'t234'} = 1;
8089     }
8090    
8091 wakaba 1.54 last INSCOPE;
8092     }
8093     } # INSCOPE
8094     unless (defined $i) {
8095 wakaba 1.79
8096     $Whatpm::HTML::Debug::cp_pass->('t235') if $Whatpm::HTML::Debug::cp_pass;
8097     BEGIN {
8098     $Whatpm::HTML::Debug::cp->{'t235'} = 1;
8099     }
8100    
8101 wakaba 1.83 ## TODO: The following is wrong.
8102 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{type});
8103     ## Ignore the token
8104     $token = $self->_get_next_token;
8105     redo B;
8106     }
8107    
8108     ## Clear back to table row context
8109     while (not {
8110     tr => 1, html => 1,
8111     }->{$self->{open_elements}->[-1]->[1]}) {
8112 wakaba 1.79
8113     $Whatpm::HTML::Debug::cp_pass->('t236') if $Whatpm::HTML::Debug::cp_pass;
8114     BEGIN {
8115     $Whatpm::HTML::Debug::cp->{'t236'} = 1;
8116     }
8117    
8118 wakaba 1.83 ## ISSUE: Can this state be reached?
8119 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8120     pop @{$self->{open_elements}};
8121     }
8122    
8123     pop @{$self->{open_elements}}; # tr
8124 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8125 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
8126     }
8127    
8128 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
8129 wakaba 1.54 ## have an element in table scope
8130     my $i;
8131     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8132     my $node = $self->{open_elements}->[$_];
8133     if ({
8134     tbody => 1, thead => 1, tfoot => 1,
8135     }->{$node->[1]}) {
8136 wakaba 1.79
8137     $Whatpm::HTML::Debug::cp_pass->('t237') if $Whatpm::HTML::Debug::cp_pass;
8138     BEGIN {
8139     $Whatpm::HTML::Debug::cp->{'t237'} = 1;
8140     }
8141    
8142 wakaba 1.54 $i = $_;
8143     last INSCOPE;
8144     } elsif ({
8145     table => 1, html => 1,
8146     }->{$node->[1]}) {
8147 wakaba 1.79
8148     $Whatpm::HTML::Debug::cp_pass->('t238') if $Whatpm::HTML::Debug::cp_pass;
8149     BEGIN {
8150     $Whatpm::HTML::Debug::cp->{'t238'} = 1;
8151     }
8152    
8153 wakaba 1.54 last INSCOPE;
8154     }
8155     } # INSCOPE
8156     unless (defined $i) {
8157 wakaba 1.79
8158     $Whatpm::HTML::Debug::cp_pass->('t239') if $Whatpm::HTML::Debug::cp_pass;
8159     BEGIN {
8160     $Whatpm::HTML::Debug::cp->{'t239'} = 1;
8161     }
8162    
8163 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8164     ## Ignore the token
8165     $token = $self->_get_next_token;
8166     redo B;
8167     }
8168    
8169     ## Clear back to table body context
8170     while (not {
8171     tbody => 1, tfoot => 1, thead => 1, html => 1,
8172     }->{$self->{open_elements}->[-1]->[1]}) {
8173 wakaba 1.79
8174     $Whatpm::HTML::Debug::cp_pass->('t240') if $Whatpm::HTML::Debug::cp_pass;
8175     BEGIN {
8176     $Whatpm::HTML::Debug::cp->{'t240'} = 1;
8177     }
8178    
8179 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8180     pop @{$self->{open_elements}};
8181     }
8182    
8183     ## As if <{current node}>
8184     ## have an element in table scope
8185     ## true by definition
8186    
8187     ## Clear back to table body context
8188     ## nop by definition
8189    
8190     pop @{$self->{open_elements}};
8191 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8192 wakaba 1.54 ## reprocess in the "in table" insertion mode...
8193     }
8194 wakaba 1.52
8195 wakaba 1.54 ## have a table element in table scope
8196     my $i;
8197     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8198     my $node = $self->{open_elements}->[$_];
8199     if ($node->[1] eq $token->{tag_name}) {
8200 wakaba 1.79
8201     $Whatpm::HTML::Debug::cp_pass->('t241') if $Whatpm::HTML::Debug::cp_pass;
8202     BEGIN {
8203     $Whatpm::HTML::Debug::cp->{'t241'} = 1;
8204     }
8205    
8206 wakaba 1.54 $i = $_;
8207     last INSCOPE;
8208     } elsif ({
8209     table => 1, html => 1,
8210     }->{$node->[1]}) {
8211 wakaba 1.79
8212     $Whatpm::HTML::Debug::cp_pass->('t242') if $Whatpm::HTML::Debug::cp_pass;
8213     BEGIN {
8214     $Whatpm::HTML::Debug::cp->{'t242'} = 1;
8215     }
8216    
8217 wakaba 1.54 last INSCOPE;
8218     }
8219     } # INSCOPE
8220     unless (defined $i) {
8221 wakaba 1.79
8222     $Whatpm::HTML::Debug::cp_pass->('t243') if $Whatpm::HTML::Debug::cp_pass;
8223     BEGIN {
8224     $Whatpm::HTML::Debug::cp->{'t243'} = 1;
8225     }
8226    
8227 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8228     ## Ignore the token
8229     $token = $self->_get_next_token;
8230     redo B;
8231 wakaba 1.51 }
8232    
8233 wakaba 1.54 ## generate implied end tags
8234     if ({
8235     dd => 1, dt => 1, li => 1, p => 1,
8236     td => 1, th => 1, tr => 1,
8237     tbody => 1, tfoot=> 1, thead => 1,
8238     }->{$self->{open_elements}->[-1]->[1]}) {
8239 wakaba 1.79
8240     $Whatpm::HTML::Debug::cp_pass->('t244') if $Whatpm::HTML::Debug::cp_pass;
8241     BEGIN {
8242     $Whatpm::HTML::Debug::cp->{'t244'} = 1;
8243     }
8244    
8245 wakaba 1.83 ## ISSUE: Can this case be reached?
8246 wakaba 1.54 unshift @{$self->{token}}, $token;
8247 wakaba 1.57 $token = {type => END_TAG_TOKEN,
8248 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
8249     redo B;
8250 wakaba 1.51 }
8251    
8252 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] ne 'table') {
8253 wakaba 1.79
8254     $Whatpm::HTML::Debug::cp_pass->('t245') if $Whatpm::HTML::Debug::cp_pass;
8255     BEGIN {
8256     $Whatpm::HTML::Debug::cp->{'t245'} = 1;
8257     }
8258    
8259 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8260 wakaba 1.79 } else {
8261    
8262     $Whatpm::HTML::Debug::cp_pass->('t246') if $Whatpm::HTML::Debug::cp_pass;
8263     BEGIN {
8264     $Whatpm::HTML::Debug::cp->{'t246'} = 1;
8265     }
8266    
8267     }
8268 wakaba 1.54
8269     splice @{$self->{open_elements}}, $i;
8270    
8271     $self->_reset_insertion_mode;
8272 wakaba 1.1
8273     $token = $self->_get_next_token;
8274 wakaba 1.25 redo B;
8275 wakaba 1.54 } elsif ({
8276     tbody => 1, tfoot => 1, thead => 1,
8277     }->{$token->{tag_name}} and
8278 wakaba 1.58 $self->{insertion_mode} & ROW_IMS) {
8279 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
8280 wakaba 1.54 ## have an element in table scope
8281     my $i;
8282     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8283     my $node = $self->{open_elements}->[$_];
8284     if ($node->[1] eq $token->{tag_name}) {
8285 wakaba 1.79
8286     $Whatpm::HTML::Debug::cp_pass->('t247') if $Whatpm::HTML::Debug::cp_pass;
8287     BEGIN {
8288     $Whatpm::HTML::Debug::cp->{'t247'} = 1;
8289     }
8290    
8291 wakaba 1.54 $i = $_;
8292     last INSCOPE;
8293     } elsif ({
8294     table => 1, html => 1,
8295     }->{$node->[1]}) {
8296 wakaba 1.79
8297     $Whatpm::HTML::Debug::cp_pass->('t248') if $Whatpm::HTML::Debug::cp_pass;
8298     BEGIN {
8299     $Whatpm::HTML::Debug::cp->{'t248'} = 1;
8300     }
8301    
8302 wakaba 1.54 last INSCOPE;
8303     }
8304     } # INSCOPE
8305     unless (defined $i) {
8306 wakaba 1.79
8307     $Whatpm::HTML::Debug::cp_pass->('t249') if $Whatpm::HTML::Debug::cp_pass;
8308     BEGIN {
8309     $Whatpm::HTML::Debug::cp->{'t249'} = 1;
8310     }
8311    
8312 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8313     ## Ignore the token
8314     $token = $self->_get_next_token;
8315     redo B;
8316     }
8317    
8318     ## As if </tr>
8319     ## have an element in table scope
8320     my $i;
8321     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8322     my $node = $self->{open_elements}->[$_];
8323     if ($node->[1] eq 'tr') {
8324 wakaba 1.79
8325     $Whatpm::HTML::Debug::cp_pass->('t250') if $Whatpm::HTML::Debug::cp_pass;
8326     BEGIN {
8327     $Whatpm::HTML::Debug::cp->{'t250'} = 1;
8328     }
8329    
8330 wakaba 1.54 $i = $_;
8331     last INSCOPE;
8332     } elsif ({
8333     table => 1, html => 1,
8334     }->{$node->[1]}) {
8335 wakaba 1.79
8336     $Whatpm::HTML::Debug::cp_pass->('t251') if $Whatpm::HTML::Debug::cp_pass;
8337     BEGIN {
8338     $Whatpm::HTML::Debug::cp->{'t251'} = 1;
8339     }
8340    
8341 wakaba 1.54 last INSCOPE;
8342     }
8343     } # INSCOPE
8344     unless (defined $i) {
8345 wakaba 1.79
8346     $Whatpm::HTML::Debug::cp_pass->('t252') if $Whatpm::HTML::Debug::cp_pass;
8347     BEGIN {
8348     $Whatpm::HTML::Debug::cp->{'t252'} = 1;
8349     }
8350    
8351 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:tr');
8352     ## Ignore the token
8353     $token = $self->_get_next_token;
8354     redo B;
8355     }
8356    
8357     ## Clear back to table row context
8358     while (not {
8359     tr => 1, html => 1,
8360     }->{$self->{open_elements}->[-1]->[1]}) {
8361 wakaba 1.79
8362     $Whatpm::HTML::Debug::cp_pass->('t253') if $Whatpm::HTML::Debug::cp_pass;
8363     BEGIN {
8364     $Whatpm::HTML::Debug::cp->{'t253'} = 1;
8365     }
8366    
8367 wakaba 1.83 ## ISSUE: Can this case be reached?
8368 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8369     pop @{$self->{open_elements}};
8370     }
8371    
8372     pop @{$self->{open_elements}}; # tr
8373 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8374 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
8375 wakaba 1.34 }
8376    
8377 wakaba 1.54 ## have an element in table scope
8378     my $i;
8379     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8380     my $node = $self->{open_elements}->[$_];
8381     if ($node->[1] eq $token->{tag_name}) {
8382 wakaba 1.79
8383     $Whatpm::HTML::Debug::cp_pass->('t254') if $Whatpm::HTML::Debug::cp_pass;
8384     BEGIN {
8385     $Whatpm::HTML::Debug::cp->{'t254'} = 1;
8386     }
8387    
8388 wakaba 1.54 $i = $_;
8389     last INSCOPE;
8390     } elsif ({
8391     table => 1, html => 1,
8392     }->{$node->[1]}) {
8393 wakaba 1.79
8394     $Whatpm::HTML::Debug::cp_pass->('t255') if $Whatpm::HTML::Debug::cp_pass;
8395     BEGIN {
8396     $Whatpm::HTML::Debug::cp->{'t255'} = 1;
8397     }
8398    
8399 wakaba 1.54 last INSCOPE;
8400 wakaba 1.34 }
8401 wakaba 1.54 } # INSCOPE
8402     unless (defined $i) {
8403 wakaba 1.79
8404     $Whatpm::HTML::Debug::cp_pass->('t256') if $Whatpm::HTML::Debug::cp_pass;
8405     BEGIN {
8406     $Whatpm::HTML::Debug::cp->{'t256'} = 1;
8407     }
8408    
8409 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8410     ## Ignore the token
8411     $token = $self->_get_next_token;
8412     redo B;
8413 wakaba 1.34 }
8414    
8415 wakaba 1.54 ## Clear back to table body context
8416     while (not {
8417     tbody => 1, tfoot => 1, thead => 1, html => 1,
8418     }->{$self->{open_elements}->[-1]->[1]}) {
8419 wakaba 1.79
8420     $Whatpm::HTML::Debug::cp_pass->('t257') if $Whatpm::HTML::Debug::cp_pass;
8421     BEGIN {
8422     $Whatpm::HTML::Debug::cp->{'t257'} = 1;
8423     }
8424    
8425 wakaba 1.83 ## ISSUE: Can this case be reached?
8426 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8427 wakaba 1.51 pop @{$self->{open_elements}};
8428 wakaba 1.25 }
8429 wakaba 1.51
8430 wakaba 1.54 pop @{$self->{open_elements}};
8431 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8432 wakaba 1.54 $token = $self->_get_next_token;
8433     redo B;
8434     } elsif ({
8435     body => 1, caption => 1, col => 1, colgroup => 1,
8436     html => 1, td => 1, th => 1,
8437 wakaba 1.56 tr => 1, # $self->{insertion_mode} == IN_ROW_IM
8438     tbody => 1, tfoot => 1, thead => 1, # $self->{insertion_mode} == IN_TABLE_IM
8439 wakaba 1.54 }->{$token->{tag_name}}) {
8440 wakaba 1.79
8441     $Whatpm::HTML::Debug::cp_pass->('t258') if $Whatpm::HTML::Debug::cp_pass;
8442     BEGIN {
8443     $Whatpm::HTML::Debug::cp->{'t258'} = 1;
8444     }
8445    
8446 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8447     ## Ignore the token
8448     $token = $self->_get_next_token;
8449 wakaba 1.1 redo B;
8450 wakaba 1.60 } else {
8451 wakaba 1.79
8452     $Whatpm::HTML::Debug::cp_pass->('t259') if $Whatpm::HTML::Debug::cp_pass;
8453     BEGIN {
8454     $Whatpm::HTML::Debug::cp->{'t259'} = 1;
8455     }
8456    
8457 wakaba 1.60 $self->{parse_error}-> (type => 'in table:/'.$token->{tag_name});
8458 wakaba 1.54
8459 wakaba 1.60 $insert = $insert_to_foster;
8460     #
8461     }
8462     } else {
8463     die "$0: $token->{type}: Unknown token type";
8464     }
8465 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_COLUMN_GROUP_IM) {
8466 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
8467 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
8468     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
8469     unless (length $token->{data}) {
8470 wakaba 1.79
8471     $Whatpm::HTML::Debug::cp_pass->('t260') if $Whatpm::HTML::Debug::cp_pass;
8472     BEGIN {
8473     $Whatpm::HTML::Debug::cp->{'t260'} = 1;
8474     }
8475    
8476 wakaba 1.54 $token = $self->_get_next_token;
8477     redo B;
8478 wakaba 1.25 }
8479 wakaba 1.54 }
8480    
8481 wakaba 1.79
8482     $Whatpm::HTML::Debug::cp_pass->('t261') if $Whatpm::HTML::Debug::cp_pass;
8483     BEGIN {
8484     $Whatpm::HTML::Debug::cp->{'t261'} = 1;
8485     }
8486    
8487 wakaba 1.54 #
8488 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
8489 wakaba 1.54 if ($token->{tag_name} eq 'col') {
8490    
8491 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t262') if $Whatpm::HTML::Debug::cp_pass;
8492     BEGIN {
8493     $Whatpm::HTML::Debug::cp->{'t262'} = 1;
8494     }
8495    
8496    
8497 wakaba 1.25 {
8498     my $el;
8499    
8500 wakaba 1.1 $el = $self->{document}->create_element_ns
8501     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8502    
8503 wakaba 1.25 for my $attr_name (keys %{ $token->{attributes}}) {
8504 wakaba 1.1 $el->set_attribute_ns (undef, [undef, $attr_name],
8505 wakaba 1.25 $token->{attributes} ->{$attr_name}->{value});
8506 wakaba 1.1 }
8507    
8508 wakaba 1.25 $self->{open_elements}->[-1]->[0]->append_child ($el);
8509     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8510     }
8511    
8512 wakaba 1.54 pop @{$self->{open_elements}};
8513     $token = $self->_get_next_token;
8514     redo B;
8515     } else {
8516 wakaba 1.79
8517     $Whatpm::HTML::Debug::cp_pass->('t263') if $Whatpm::HTML::Debug::cp_pass;
8518     BEGIN {
8519     $Whatpm::HTML::Debug::cp->{'t263'} = 1;
8520     }
8521    
8522 wakaba 1.54 #
8523     }
8524 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
8525 wakaba 1.54 if ($token->{tag_name} eq 'colgroup') {
8526     if ($self->{open_elements}->[-1]->[1] eq 'html') {
8527 wakaba 1.79
8528     $Whatpm::HTML::Debug::cp_pass->('t264') if $Whatpm::HTML::Debug::cp_pass;
8529     BEGIN {
8530     $Whatpm::HTML::Debug::cp->{'t264'} = 1;
8531     }
8532    
8533 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:colgroup');
8534 wakaba 1.25 ## Ignore the token
8535 wakaba 1.42 $token = $self->_get_next_token;
8536 wakaba 1.25 redo B;
8537 wakaba 1.24 } else {
8538 wakaba 1.79
8539     $Whatpm::HTML::Debug::cp_pass->('t265') if $Whatpm::HTML::Debug::cp_pass;
8540     BEGIN {
8541     $Whatpm::HTML::Debug::cp->{'t265'} = 1;
8542     }
8543    
8544 wakaba 1.54 pop @{$self->{open_elements}}; # colgroup
8545 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8546 wakaba 1.54 $token = $self->_get_next_token;
8547     redo B;
8548 wakaba 1.25 }
8549 wakaba 1.54 } elsif ($token->{tag_name} eq 'col') {
8550 wakaba 1.79
8551     $Whatpm::HTML::Debug::cp_pass->('t266') if $Whatpm::HTML::Debug::cp_pass;
8552     BEGIN {
8553     $Whatpm::HTML::Debug::cp->{'t266'} = 1;
8554     }
8555    
8556 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:col');
8557     ## Ignore the token
8558     $token = $self->_get_next_token;
8559     redo B;
8560     } else {
8561 wakaba 1.79
8562     $Whatpm::HTML::Debug::cp_pass->('t267') if $Whatpm::HTML::Debug::cp_pass;
8563     BEGIN {
8564     $Whatpm::HTML::Debug::cp->{'t267'} = 1;
8565     }
8566    
8567 wakaba 1.54 #
8568     }
8569     } else {
8570 wakaba 1.83 die "$0: $token->{type}: Unknown token type";
8571 wakaba 1.54 }
8572 wakaba 1.51
8573 wakaba 1.54 ## As if </colgroup>
8574     if ($self->{open_elements}->[-1]->[1] eq 'html') {
8575 wakaba 1.79
8576     $Whatpm::HTML::Debug::cp_pass->('t269') if $Whatpm::HTML::Debug::cp_pass;
8577     BEGIN {
8578     $Whatpm::HTML::Debug::cp->{'t269'} = 1;
8579     }
8580    
8581 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:colgroup');
8582     ## Ignore the token
8583     $token = $self->_get_next_token;
8584     redo B;
8585     } else {
8586 wakaba 1.79
8587     $Whatpm::HTML::Debug::cp_pass->('t270') if $Whatpm::HTML::Debug::cp_pass;
8588     BEGIN {
8589     $Whatpm::HTML::Debug::cp->{'t270'} = 1;
8590     }
8591    
8592 wakaba 1.54 pop @{$self->{open_elements}}; # colgroup
8593 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8594 wakaba 1.54 ## reprocess
8595     redo B;
8596     }
8597 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_SELECT_IM) {
8598 wakaba 1.60 if ($token->{type} == CHARACTER_TOKEN) {
8599 wakaba 1.79
8600     $Whatpm::HTML::Debug::cp_pass->('t271') if $Whatpm::HTML::Debug::cp_pass;
8601     BEGIN {
8602     $Whatpm::HTML::Debug::cp->{'t271'} = 1;
8603     }
8604    
8605 wakaba 1.60 $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
8606     $token = $self->_get_next_token;
8607     redo B;
8608     } elsif ($token->{type} == START_TAG_TOKEN) {
8609 wakaba 1.54 if ($token->{tag_name} eq 'option') {
8610     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8611 wakaba 1.79
8612     $Whatpm::HTML::Debug::cp_pass->('t272') if $Whatpm::HTML::Debug::cp_pass;
8613     BEGIN {
8614     $Whatpm::HTML::Debug::cp->{'t272'} = 1;
8615     }
8616    
8617 wakaba 1.54 ## As if </option>
8618 wakaba 1.51 pop @{$self->{open_elements}};
8619 wakaba 1.79 } else {
8620    
8621     $Whatpm::HTML::Debug::cp_pass->('t273') if $Whatpm::HTML::Debug::cp_pass;
8622     BEGIN {
8623     $Whatpm::HTML::Debug::cp->{'t273'} = 1;
8624     }
8625    
8626 wakaba 1.51 }
8627    
8628 wakaba 1.1
8629     {
8630     my $el;
8631    
8632     $el = $self->{document}->create_element_ns
8633 wakaba 1.51 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8634 wakaba 1.1
8635     for my $attr_name (keys %{ $token->{attributes}}) {
8636     $el->set_attribute_ns (undef, [undef, $attr_name],
8637     $token->{attributes} ->{$attr_name}->{value});
8638     }
8639    
8640 wakaba 1.3 $self->{open_elements}->[-1]->[0]->append_child ($el);
8641 wakaba 1.51 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8642 wakaba 1.1 }
8643    
8644     $token = $self->_get_next_token;
8645     redo B;
8646 wakaba 1.54 } elsif ($token->{tag_name} eq 'optgroup') {
8647     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8648 wakaba 1.79
8649     $Whatpm::HTML::Debug::cp_pass->('t274') if $Whatpm::HTML::Debug::cp_pass;
8650     BEGIN {
8651     $Whatpm::HTML::Debug::cp->{'t274'} = 1;
8652     }
8653    
8654 wakaba 1.54 ## As if </option>
8655 wakaba 1.51 pop @{$self->{open_elements}};
8656 wakaba 1.79 } else {
8657    
8658     $Whatpm::HTML::Debug::cp_pass->('t275') if $Whatpm::HTML::Debug::cp_pass;
8659     BEGIN {
8660     $Whatpm::HTML::Debug::cp->{'t275'} = 1;
8661     }
8662    
8663 wakaba 1.51 }
8664 wakaba 1.54
8665     if ($self->{open_elements}->[-1]->[1] eq 'optgroup') {
8666 wakaba 1.79
8667     $Whatpm::HTML::Debug::cp_pass->('t276') if $Whatpm::HTML::Debug::cp_pass;
8668     BEGIN {
8669     $Whatpm::HTML::Debug::cp->{'t276'} = 1;
8670     }
8671    
8672 wakaba 1.54 ## As if </optgroup>
8673 wakaba 1.51 pop @{$self->{open_elements}};
8674 wakaba 1.79 } else {
8675    
8676     $Whatpm::HTML::Debug::cp_pass->('t277') if $Whatpm::HTML::Debug::cp_pass;
8677     BEGIN {
8678     $Whatpm::HTML::Debug::cp->{'t277'} = 1;
8679     }
8680    
8681 wakaba 1.51 }
8682    
8683    
8684 wakaba 1.1 {
8685     my $el;
8686    
8687     $el = $self->{document}->create_element_ns
8688 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8689 wakaba 1.1
8690 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
8691     $el->set_attribute_ns (undef, [undef, $attr_name],
8692     $token->{attributes} ->{$attr_name}->{value});
8693     }
8694    
8695 wakaba 1.3 $self->{open_elements}->[-1]->[0]->append_child ($el);
8696 wakaba 1.54 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8697 wakaba 1.1 }
8698    
8699 wakaba 1.54 $token = $self->_get_next_token;
8700     redo B;
8701     } elsif ($token->{tag_name} eq 'select') {
8702 wakaba 1.83 ## TODO: The type below is not good - <select> is replaced by </select>
8703 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:select');
8704     ## As if </select> instead
8705     ## have an element in table scope
8706     my $i;
8707     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8708     my $node = $self->{open_elements}->[$_];
8709     if ($node->[1] eq $token->{tag_name}) {
8710 wakaba 1.79
8711     $Whatpm::HTML::Debug::cp_pass->('t278') if $Whatpm::HTML::Debug::cp_pass;
8712     BEGIN {
8713     $Whatpm::HTML::Debug::cp->{'t278'} = 1;
8714     }
8715    
8716 wakaba 1.54 $i = $_;
8717     last INSCOPE;
8718     } elsif ({
8719     table => 1, html => 1,
8720     }->{$node->[1]}) {
8721 wakaba 1.79
8722     $Whatpm::HTML::Debug::cp_pass->('t279') if $Whatpm::HTML::Debug::cp_pass;
8723     BEGIN {
8724     $Whatpm::HTML::Debug::cp->{'t279'} = 1;
8725     }
8726    
8727 wakaba 1.54 last INSCOPE;
8728 wakaba 1.44 }
8729 wakaba 1.54 } # INSCOPE
8730     unless (defined $i) {
8731 wakaba 1.79
8732     $Whatpm::HTML::Debug::cp_pass->('t280') if $Whatpm::HTML::Debug::cp_pass;
8733     BEGIN {
8734     $Whatpm::HTML::Debug::cp->{'t280'} = 1;
8735     }
8736    
8737 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:select');
8738     ## Ignore the token
8739     $token = $self->_get_next_token;
8740 wakaba 1.44 redo B;
8741     }
8742 wakaba 1.54
8743 wakaba 1.79
8744     $Whatpm::HTML::Debug::cp_pass->('t281') if $Whatpm::HTML::Debug::cp_pass;
8745     BEGIN {
8746     $Whatpm::HTML::Debug::cp->{'t281'} = 1;
8747     }
8748    
8749 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8750    
8751     $self->_reset_insertion_mode;
8752    
8753     $token = $self->_get_next_token;
8754     redo B;
8755 wakaba 1.60 } else {
8756 wakaba 1.79
8757     $Whatpm::HTML::Debug::cp_pass->('t282') if $Whatpm::HTML::Debug::cp_pass;
8758     BEGIN {
8759     $Whatpm::HTML::Debug::cp->{'t282'} = 1;
8760     }
8761    
8762 wakaba 1.60 $self->{parse_error}-> (type => 'in select:'.$token->{tag_name});
8763     ## Ignore the token
8764     $token = $self->_get_next_token;
8765     redo B;
8766     }
8767     } elsif ($token->{type} == END_TAG_TOKEN) {
8768 wakaba 1.54 if ($token->{tag_name} eq 'optgroup') {
8769     if ($self->{open_elements}->[-1]->[1] eq 'option' and
8770     $self->{open_elements}->[-2]->[1] eq 'optgroup') {
8771 wakaba 1.79
8772     $Whatpm::HTML::Debug::cp_pass->('t283') if $Whatpm::HTML::Debug::cp_pass;
8773     BEGIN {
8774     $Whatpm::HTML::Debug::cp->{'t283'} = 1;
8775     }
8776    
8777 wakaba 1.54 ## As if </option>
8778     splice @{$self->{open_elements}}, -2;
8779     } elsif ($self->{open_elements}->[-1]->[1] eq 'optgroup') {
8780 wakaba 1.79
8781     $Whatpm::HTML::Debug::cp_pass->('t284') if $Whatpm::HTML::Debug::cp_pass;
8782     BEGIN {
8783     $Whatpm::HTML::Debug::cp->{'t284'} = 1;
8784     }
8785    
8786 wakaba 1.54 pop @{$self->{open_elements}};
8787     } else {
8788 wakaba 1.79
8789     $Whatpm::HTML::Debug::cp_pass->('t285') if $Whatpm::HTML::Debug::cp_pass;
8790     BEGIN {
8791     $Whatpm::HTML::Debug::cp->{'t285'} = 1;
8792     }
8793    
8794 wakaba 1.44 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8795 wakaba 1.43 ## Ignore the token
8796 wakaba 1.54 }
8797     $token = $self->_get_next_token;
8798     redo B;
8799     } elsif ($token->{tag_name} eq 'option') {
8800     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8801 wakaba 1.79
8802     $Whatpm::HTML::Debug::cp_pass->('t286') if $Whatpm::HTML::Debug::cp_pass;
8803     BEGIN {
8804     $Whatpm::HTML::Debug::cp->{'t286'} = 1;
8805     }
8806    
8807 wakaba 1.54 pop @{$self->{open_elements}};
8808 wakaba 1.44 } else {
8809 wakaba 1.79
8810     $Whatpm::HTML::Debug::cp_pass->('t287') if $Whatpm::HTML::Debug::cp_pass;
8811     BEGIN {
8812     $Whatpm::HTML::Debug::cp->{'t287'} = 1;
8813     }
8814    
8815 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8816     ## Ignore the token
8817 wakaba 1.43 }
8818 wakaba 1.54 $token = $self->_get_next_token;
8819     redo B;
8820     } elsif ($token->{tag_name} eq 'select') {
8821     ## have an element in table scope
8822     my $i;
8823     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8824     my $node = $self->{open_elements}->[$_];
8825     if ($node->[1] eq $token->{tag_name}) {
8826 wakaba 1.79
8827     $Whatpm::HTML::Debug::cp_pass->('t288') if $Whatpm::HTML::Debug::cp_pass;
8828     BEGIN {
8829     $Whatpm::HTML::Debug::cp->{'t288'} = 1;
8830     }
8831    
8832 wakaba 1.54 $i = $_;
8833     last INSCOPE;
8834     } elsif ({
8835     table => 1, html => 1,
8836     }->{$node->[1]}) {
8837 wakaba 1.79
8838     $Whatpm::HTML::Debug::cp_pass->('t289') if $Whatpm::HTML::Debug::cp_pass;
8839     BEGIN {
8840     $Whatpm::HTML::Debug::cp->{'t289'} = 1;
8841     }
8842    
8843 wakaba 1.54 last INSCOPE;
8844 wakaba 1.44 }
8845 wakaba 1.54 } # INSCOPE
8846     unless (defined $i) {
8847 wakaba 1.79
8848     $Whatpm::HTML::Debug::cp_pass->('t290') if $Whatpm::HTML::Debug::cp_pass;
8849     BEGIN {
8850     $Whatpm::HTML::Debug::cp->{'t290'} = 1;
8851     }
8852    
8853 wakaba 1.44 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8854     ## Ignore the token
8855     $token = $self->_get_next_token;
8856 wakaba 1.43 redo B;
8857     }
8858 wakaba 1.54
8859 wakaba 1.79
8860     $Whatpm::HTML::Debug::cp_pass->('t291') if $Whatpm::HTML::Debug::cp_pass;
8861     BEGIN {
8862     $Whatpm::HTML::Debug::cp->{'t291'} = 1;
8863     }
8864    
8865 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8866    
8867     $self->_reset_insertion_mode;
8868    
8869     $token = $self->_get_next_token;
8870     redo B;
8871 wakaba 1.44 } elsif ({
8872 wakaba 1.54 caption => 1, table => 1, tbody => 1,
8873     tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,
8874     }->{$token->{tag_name}}) {
8875 wakaba 1.83 ## TODO: The following is wrong?
8876 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8877    
8878 wakaba 1.44 ## have an element in table scope
8879 wakaba 1.43 my $i;
8880     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8881     my $node = $self->{open_elements}->[$_];
8882     if ($node->[1] eq $token->{tag_name}) {
8883 wakaba 1.79
8884     $Whatpm::HTML::Debug::cp_pass->('t292') if $Whatpm::HTML::Debug::cp_pass;
8885     BEGIN {
8886     $Whatpm::HTML::Debug::cp->{'t292'} = 1;
8887     }
8888    
8889 wakaba 1.43 $i = $_;
8890     last INSCOPE;
8891     } elsif ({
8892     table => 1, html => 1,
8893     }->{$node->[1]}) {
8894 wakaba 1.79
8895     $Whatpm::HTML::Debug::cp_pass->('t293') if $Whatpm::HTML::Debug::cp_pass;
8896     BEGIN {
8897     $Whatpm::HTML::Debug::cp->{'t293'} = 1;
8898     }
8899    
8900 wakaba 1.43 last INSCOPE;
8901     }
8902     } # INSCOPE
8903     unless (defined $i) {
8904 wakaba 1.79
8905     $Whatpm::HTML::Debug::cp_pass->('t294') if $Whatpm::HTML::Debug::cp_pass;
8906     BEGIN {
8907     $Whatpm::HTML::Debug::cp->{'t294'} = 1;
8908     }
8909    
8910 wakaba 1.43 ## Ignore the token
8911     $token = $self->_get_next_token;
8912     redo B;
8913     }
8914 wakaba 1.54
8915     ## As if </select>
8916     ## have an element in table scope
8917     undef $i;
8918 wakaba 1.43 INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8919     my $node = $self->{open_elements}->[$_];
8920 wakaba 1.54 if ($node->[1] eq 'select') {
8921 wakaba 1.79
8922     $Whatpm::HTML::Debug::cp_pass->('t295') if $Whatpm::HTML::Debug::cp_pass;
8923     BEGIN {
8924     $Whatpm::HTML::Debug::cp->{'t295'} = 1;
8925     }
8926    
8927 wakaba 1.43 $i = $_;
8928     last INSCOPE;
8929     } elsif ({
8930     table => 1, html => 1,
8931     }->{$node->[1]}) {
8932 wakaba 1.83 ## ISSUE: Can this state be reached?
8933 wakaba 1.79
8934     $Whatpm::HTML::Debug::cp_pass->('t296') if $Whatpm::HTML::Debug::cp_pass;
8935     BEGIN {
8936     $Whatpm::HTML::Debug::cp->{'t296'} = 1;
8937     }
8938    
8939 wakaba 1.43 last INSCOPE;
8940     }
8941     } # INSCOPE
8942     unless (defined $i) {
8943 wakaba 1.79
8944     $Whatpm::HTML::Debug::cp_pass->('t297') if $Whatpm::HTML::Debug::cp_pass;
8945     BEGIN {
8946     $Whatpm::HTML::Debug::cp->{'t297'} = 1;
8947     }
8948    
8949 wakaba 1.83 ## TODO: The following error type is correct?
8950 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:select');
8951     ## Ignore the </select> token
8952     $token = $self->_get_next_token; ## TODO: ok?
8953 wakaba 1.43 redo B;
8954     }
8955 wakaba 1.54
8956 wakaba 1.79
8957     $Whatpm::HTML::Debug::cp_pass->('t298') if $Whatpm::HTML::Debug::cp_pass;
8958     BEGIN {
8959     $Whatpm::HTML::Debug::cp->{'t298'} = 1;
8960     }
8961    
8962 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8963    
8964     $self->_reset_insertion_mode;
8965    
8966     ## reprocess
8967     redo B;
8968 wakaba 1.60 } else {
8969 wakaba 1.79
8970     $Whatpm::HTML::Debug::cp_pass->('t299') if $Whatpm::HTML::Debug::cp_pass;
8971     BEGIN {
8972     $Whatpm::HTML::Debug::cp->{'t299'} = 1;
8973     }
8974    
8975 wakaba 1.60 $self->{parse_error}-> (type => 'in select:/'.$token->{tag_name});
8976 wakaba 1.54 ## Ignore the token
8977     $token = $self->_get_next_token;
8978     redo B;
8979 wakaba 1.60 }
8980     } else {
8981     die "$0: $token->{type}: Unknown token type";
8982     }
8983 wakaba 1.58 } elsif ($self->{insertion_mode} & BODY_AFTER_IMS) {
8984 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
8985 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
8986     my $data = $1;
8987     ## As if in body
8988     $reconstruct_active_formatting_elements->($insert_to_current);
8989    
8990     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
8991    
8992     unless (length $token->{data}) {
8993 wakaba 1.79
8994     $Whatpm::HTML::Debug::cp_pass->('t300') if $Whatpm::HTML::Debug::cp_pass;
8995     BEGIN {
8996     $Whatpm::HTML::Debug::cp->{'t300'} = 1;
8997     }
8998    
8999 wakaba 1.54 $token = $self->_get_next_token;
9000     redo B;
9001     }
9002     }
9003    
9004 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
9005 wakaba 1.79
9006     $Whatpm::HTML::Debug::cp_pass->('t301') if $Whatpm::HTML::Debug::cp_pass;
9007     BEGIN {
9008     $Whatpm::HTML::Debug::cp->{'t301'} = 1;
9009     }
9010    
9011 wakaba 1.54 $self->{parse_error}-> (type => 'after html:#character');
9012    
9013 wakaba 1.85 ## Reprocess in the "after body" insertion mode.
9014 wakaba 1.79 } else {
9015    
9016     $Whatpm::HTML::Debug::cp_pass->('t302') if $Whatpm::HTML::Debug::cp_pass;
9017     BEGIN {
9018     $Whatpm::HTML::Debug::cp->{'t302'} = 1;
9019     }
9020    
9021 wakaba 1.54 }
9022    
9023     ## "after body" insertion mode
9024     $self->{parse_error}-> (type => 'after body:#character');
9025    
9026 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
9027 wakaba 1.54 ## reprocess
9028     redo B;
9029 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
9030 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
9031 wakaba 1.79
9032     $Whatpm::HTML::Debug::cp_pass->('t303') if $Whatpm::HTML::Debug::cp_pass;
9033     BEGIN {
9034     $Whatpm::HTML::Debug::cp->{'t303'} = 1;
9035     }
9036    
9037 wakaba 1.54 $self->{parse_error}-> (type => 'after html:'.$token->{tag_name});
9038    
9039 wakaba 1.85 ## Reprocess in the "after body" insertion mode.
9040 wakaba 1.79 } else {
9041    
9042     $Whatpm::HTML::Debug::cp_pass->('t304') if $Whatpm::HTML::Debug::cp_pass;
9043     BEGIN {
9044     $Whatpm::HTML::Debug::cp->{'t304'} = 1;
9045     }
9046    
9047 wakaba 1.54 }
9048    
9049     ## "after body" insertion mode
9050     $self->{parse_error}-> (type => 'after body:'.$token->{tag_name});
9051    
9052 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
9053 wakaba 1.54 ## reprocess
9054     redo B;
9055 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
9056 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
9057 wakaba 1.79
9058     $Whatpm::HTML::Debug::cp_pass->('t305') if $Whatpm::HTML::Debug::cp_pass;
9059     BEGIN {
9060     $Whatpm::HTML::Debug::cp->{'t305'} = 1;
9061     }
9062    
9063 wakaba 1.54 $self->{parse_error}-> (type => 'after html:/'.$token->{tag_name});
9064    
9065 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
9066 wakaba 1.85 ## Reprocess in the "after body" insertion mode.
9067 wakaba 1.79 } else {
9068    
9069     $Whatpm::HTML::Debug::cp_pass->('t306') if $Whatpm::HTML::Debug::cp_pass;
9070     BEGIN {
9071     $Whatpm::HTML::Debug::cp->{'t306'} = 1;
9072     }
9073    
9074 wakaba 1.54 }
9075    
9076     ## "after body" insertion mode
9077     if ($token->{tag_name} eq 'html') {
9078     if (defined $self->{inner_html_node}) {
9079 wakaba 1.79
9080     $Whatpm::HTML::Debug::cp_pass->('t307') if $Whatpm::HTML::Debug::cp_pass;
9081     BEGIN {
9082     $Whatpm::HTML::Debug::cp->{'t307'} = 1;
9083     }
9084    
9085 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:html');
9086     ## Ignore the token
9087     $token = $self->_get_next_token;
9088     redo B;
9089     } else {
9090 wakaba 1.79
9091     $Whatpm::HTML::Debug::cp_pass->('t308') if $Whatpm::HTML::Debug::cp_pass;
9092     BEGIN {
9093     $Whatpm::HTML::Debug::cp->{'t308'} = 1;
9094     }
9095    
9096 wakaba 1.56 $self->{insertion_mode} = AFTER_HTML_BODY_IM;
9097 wakaba 1.54 $token = $self->_get_next_token;
9098     redo B;
9099     }
9100     } else {
9101 wakaba 1.79
9102     $Whatpm::HTML::Debug::cp_pass->('t309') if $Whatpm::HTML::Debug::cp_pass;
9103     BEGIN {
9104     $Whatpm::HTML::Debug::cp->{'t309'} = 1;
9105     }
9106    
9107 wakaba 1.54 $self->{parse_error}-> (type => 'after body:/'.$token->{tag_name});
9108    
9109 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
9110 wakaba 1.54 ## reprocess
9111     redo B;
9112     }
9113     } else {
9114     die "$0: $token->{type}: Unknown token type";
9115     }
9116 wakaba 1.58 } elsif ($self->{insertion_mode} & FRAME_IMS) {
9117 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
9118 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
9119     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
9120    
9121     unless (length $token->{data}) {
9122 wakaba 1.79
9123     $Whatpm::HTML::Debug::cp_pass->('t310') if $Whatpm::HTML::Debug::cp_pass;
9124     BEGIN {
9125     $Whatpm::HTML::Debug::cp->{'t310'} = 1;
9126     }
9127    
9128 wakaba 1.54 $token = $self->_get_next_token;
9129     redo B;
9130     }
9131     }
9132    
9133     if ($token->{data} =~ s/^[^\x09\x0A\x0B\x0C\x20]+//) {
9134 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9135 wakaba 1.79
9136     $Whatpm::HTML::Debug::cp_pass->('t311') if $Whatpm::HTML::Debug::cp_pass;
9137     BEGIN {
9138     $Whatpm::HTML::Debug::cp->{'t311'} = 1;
9139     }
9140    
9141 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:#character');
9142 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_FRAMESET_IM) {
9143 wakaba 1.79
9144     $Whatpm::HTML::Debug::cp_pass->('t312') if $Whatpm::HTML::Debug::cp_pass;
9145     BEGIN {
9146     $Whatpm::HTML::Debug::cp->{'t312'} = 1;
9147     }
9148    
9149 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:#character');
9150     } else { # "after html frameset"
9151 wakaba 1.79
9152     $Whatpm::HTML::Debug::cp_pass->('t313') if $Whatpm::HTML::Debug::cp_pass;
9153     BEGIN {
9154     $Whatpm::HTML::Debug::cp->{'t313'} = 1;
9155     }
9156    
9157 wakaba 1.54 $self->{parse_error}-> (type => 'after html:#character');
9158    
9159 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9160 wakaba 1.85 ## Reprocess in the "after frameset" insertion mode.
9161 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:#character');
9162     }
9163    
9164     ## Ignore the token.
9165     if (length $token->{data}) {
9166 wakaba 1.79
9167     $Whatpm::HTML::Debug::cp_pass->('t314') if $Whatpm::HTML::Debug::cp_pass;
9168     BEGIN {
9169     $Whatpm::HTML::Debug::cp->{'t314'} = 1;
9170     }
9171    
9172 wakaba 1.54 ## reprocess the rest of characters
9173     } else {
9174 wakaba 1.79
9175     $Whatpm::HTML::Debug::cp_pass->('t315') if $Whatpm::HTML::Debug::cp_pass;
9176     BEGIN {
9177     $Whatpm::HTML::Debug::cp->{'t315'} = 1;
9178     }
9179    
9180 wakaba 1.54 $token = $self->_get_next_token;
9181     }
9182     redo B;
9183     }
9184    
9185     die qq[$0: Character "$token->{data}"];
9186 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
9187 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
9188 wakaba 1.79
9189     $Whatpm::HTML::Debug::cp_pass->('t316') if $Whatpm::HTML::Debug::cp_pass;
9190     BEGIN {
9191     $Whatpm::HTML::Debug::cp->{'t316'} = 1;
9192     }
9193    
9194 wakaba 1.54 $self->{parse_error}-> (type => 'after html:'.$token->{tag_name});
9195    
9196 wakaba 1.79 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9197 wakaba 1.85 ## Process in the "after frameset" insertion mode.
9198 wakaba 1.79 } else {
9199    
9200     $Whatpm::HTML::Debug::cp_pass->('t317') if $Whatpm::HTML::Debug::cp_pass;
9201     BEGIN {
9202     $Whatpm::HTML::Debug::cp->{'t317'} = 1;
9203     }
9204    
9205     }
9206    
9207 wakaba 1.54 if ($token->{tag_name} eq 'frameset' and
9208 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9209 wakaba 1.54
9210 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t318') if $Whatpm::HTML::Debug::cp_pass;
9211     BEGIN {
9212     $Whatpm::HTML::Debug::cp->{'t318'} = 1;
9213     }
9214    
9215    
9216 wakaba 1.54 {
9217     my $el;
9218    
9219     $el = $self->{document}->create_element_ns
9220     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9221    
9222     for my $attr_name (keys %{ $token->{attributes}}) {
9223     $el->set_attribute_ns (undef, [undef, $attr_name],
9224     $token->{attributes} ->{$attr_name}->{value});
9225     }
9226    
9227     $self->{open_elements}->[-1]->[0]->append_child ($el);
9228     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9229     }
9230    
9231     $token = $self->_get_next_token;
9232     redo B;
9233     } elsif ($token->{tag_name} eq 'frame' and
9234 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9235 wakaba 1.54
9236 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t319') if $Whatpm::HTML::Debug::cp_pass;
9237     BEGIN {
9238     $Whatpm::HTML::Debug::cp->{'t319'} = 1;
9239     }
9240    
9241    
9242 wakaba 1.54 {
9243     my $el;
9244    
9245     $el = $self->{document}->create_element_ns
9246     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9247    
9248     for my $attr_name (keys %{ $token->{attributes}}) {
9249     $el->set_attribute_ns (undef, [undef, $attr_name],
9250     $token->{attributes} ->{$attr_name}->{value});
9251     }
9252    
9253     $self->{open_elements}->[-1]->[0]->append_child ($el);
9254     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9255     }
9256    
9257     pop @{$self->{open_elements}};
9258     $token = $self->_get_next_token;
9259     redo B;
9260     } elsif ($token->{tag_name} eq 'noframes') {
9261 wakaba 1.79
9262     $Whatpm::HTML::Debug::cp_pass->('t320') if $Whatpm::HTML::Debug::cp_pass;
9263     BEGIN {
9264     $Whatpm::HTML::Debug::cp->{'t320'} = 1;
9265     }
9266    
9267 wakaba 1.54 ## NOTE: As if in body.
9268     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert_to_current);
9269     redo B;
9270     } else {
9271 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9272 wakaba 1.79
9273     $Whatpm::HTML::Debug::cp_pass->('t321') if $Whatpm::HTML::Debug::cp_pass;
9274     BEGIN {
9275     $Whatpm::HTML::Debug::cp->{'t321'} = 1;
9276     }
9277    
9278 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:'.$token->{tag_name});
9279     } else {
9280 wakaba 1.79
9281     $Whatpm::HTML::Debug::cp_pass->('t322') if $Whatpm::HTML::Debug::cp_pass;
9282     BEGIN {
9283     $Whatpm::HTML::Debug::cp->{'t322'} = 1;
9284     }
9285    
9286 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:'.$token->{tag_name});
9287     }
9288     ## Ignore the token
9289     $token = $self->_get_next_token;
9290     redo B;
9291     }
9292 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
9293 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
9294 wakaba 1.79
9295     $Whatpm::HTML::Debug::cp_pass->('t323') if $Whatpm::HTML::Debug::cp_pass;
9296     BEGIN {
9297     $Whatpm::HTML::Debug::cp->{'t323'} = 1;
9298     }
9299    
9300 wakaba 1.54 $self->{parse_error}-> (type => 'after html:/'.$token->{tag_name});
9301    
9302 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9303 wakaba 1.85 ## Process in the "after frameset" insertion mode.
9304 wakaba 1.79 } else {
9305    
9306     $Whatpm::HTML::Debug::cp_pass->('t324') if $Whatpm::HTML::Debug::cp_pass;
9307     BEGIN {
9308     $Whatpm::HTML::Debug::cp->{'t324'} = 1;
9309     }
9310    
9311 wakaba 1.54 }
9312    
9313     if ($token->{tag_name} eq 'frameset' and
9314 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9315 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] eq 'html' and
9316     @{$self->{open_elements}} == 1) {
9317 wakaba 1.79
9318     $Whatpm::HTML::Debug::cp_pass->('t325') if $Whatpm::HTML::Debug::cp_pass;
9319     BEGIN {
9320     $Whatpm::HTML::Debug::cp->{'t325'} = 1;
9321     }
9322    
9323 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
9324     ## Ignore the token
9325     $token = $self->_get_next_token;
9326     } else {
9327 wakaba 1.79
9328     $Whatpm::HTML::Debug::cp_pass->('t326') if $Whatpm::HTML::Debug::cp_pass;
9329     BEGIN {
9330     $Whatpm::HTML::Debug::cp->{'t326'} = 1;
9331     }
9332    
9333 wakaba 1.54 pop @{$self->{open_elements}};
9334     $token = $self->_get_next_token;
9335     }
9336 wakaba 1.43
9337 wakaba 1.54 if (not defined $self->{inner_html_node} and
9338     $self->{open_elements}->[-1]->[1] ne 'frameset') {
9339 wakaba 1.79
9340     $Whatpm::HTML::Debug::cp_pass->('t327') if $Whatpm::HTML::Debug::cp_pass;
9341     BEGIN {
9342     $Whatpm::HTML::Debug::cp->{'t327'} = 1;
9343     }
9344    
9345 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9346 wakaba 1.79 } else {
9347    
9348     $Whatpm::HTML::Debug::cp_pass->('t328') if $Whatpm::HTML::Debug::cp_pass;
9349     BEGIN {
9350     $Whatpm::HTML::Debug::cp->{'t328'} = 1;
9351     }
9352    
9353 wakaba 1.54 }
9354     redo B;
9355     } elsif ($token->{tag_name} eq 'html' and
9356 wakaba 1.56 $self->{insertion_mode} == AFTER_FRAMESET_IM) {
9357 wakaba 1.79
9358     $Whatpm::HTML::Debug::cp_pass->('t329') if $Whatpm::HTML::Debug::cp_pass;
9359     BEGIN {
9360     $Whatpm::HTML::Debug::cp->{'t329'} = 1;
9361     }
9362    
9363 wakaba 1.56 $self->{insertion_mode} = AFTER_HTML_FRAMESET_IM;
9364 wakaba 1.54 $token = $self->_get_next_token;
9365     redo B;
9366     } else {
9367 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9368 wakaba 1.79
9369     $Whatpm::HTML::Debug::cp_pass->('t330') if $Whatpm::HTML::Debug::cp_pass;
9370     BEGIN {
9371     $Whatpm::HTML::Debug::cp->{'t330'} = 1;
9372     }
9373    
9374 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:/'.$token->{tag_name});
9375     } else {
9376 wakaba 1.79
9377     $Whatpm::HTML::Debug::cp_pass->('t331') if $Whatpm::HTML::Debug::cp_pass;
9378     BEGIN {
9379     $Whatpm::HTML::Debug::cp->{'t331'} = 1;
9380     }
9381    
9382 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:/'.$token->{tag_name});
9383     }
9384     ## Ignore the token
9385     $token = $self->_get_next_token;
9386     redo B;
9387     }
9388     } else {
9389     die "$0: $token->{type}: Unknown token type";
9390     }
9391 wakaba 1.43
9392 wakaba 1.54 ## ISSUE: An issue in spec here
9393     } else {
9394     die "$0: $self->{insertion_mode}: Unknown insertion mode";
9395     }
9396 wakaba 1.43
9397 wakaba 1.54 ## "in body" insertion mode
9398 wakaba 1.57 if ($token->{type} == START_TAG_TOKEN) {
9399 wakaba 1.54 if ($token->{tag_name} eq 'script') {
9400 wakaba 1.79
9401     $Whatpm::HTML::Debug::cp_pass->('t332') if $Whatpm::HTML::Debug::cp_pass;
9402     BEGIN {
9403     $Whatpm::HTML::Debug::cp->{'t332'} = 1;
9404     }
9405    
9406 wakaba 1.54 ## NOTE: This is an "as if in head" code clone
9407     $script_start_tag->($insert);
9408 wakaba 1.55 redo B;
9409 wakaba 1.54 } elsif ($token->{tag_name} eq 'style') {
9410 wakaba 1.79
9411     $Whatpm::HTML::Debug::cp_pass->('t333') if $Whatpm::HTML::Debug::cp_pass;
9412     BEGIN {
9413     $Whatpm::HTML::Debug::cp->{'t333'} = 1;
9414     }
9415    
9416 wakaba 1.54 ## NOTE: This is an "as if in head" code clone
9417     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
9418 wakaba 1.55 redo B;
9419 wakaba 1.54 } elsif ({
9420     base => 1, link => 1,
9421     }->{$token->{tag_name}}) {
9422 wakaba 1.79
9423     $Whatpm::HTML::Debug::cp_pass->('t334') if $Whatpm::HTML::Debug::cp_pass;
9424     BEGIN {
9425     $Whatpm::HTML::Debug::cp->{'t334'} = 1;
9426     }
9427    
9428 wakaba 1.54 ## NOTE: This is an "as if in head" code clone, only "-t" differs
9429    
9430     {
9431     my $el;
9432    
9433     $el = $self->{document}->create_element_ns
9434     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9435    
9436     for my $attr_name (keys %{ $token->{attributes}}) {
9437     $el->set_attribute_ns (undef, [undef, $attr_name],
9438     $token->{attributes} ->{$attr_name}->{value});
9439     }
9440    
9441     $insert->($el);
9442     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9443     }
9444    
9445     pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
9446     $token = $self->_get_next_token;
9447 wakaba 1.55 redo B;
9448 wakaba 1.54 } elsif ($token->{tag_name} eq 'meta') {
9449     ## NOTE: This is an "as if in head" code clone, only "-t" differs
9450    
9451     {
9452     my $el;
9453    
9454     $el = $self->{document}->create_element_ns
9455     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9456    
9457     for my $attr_name (keys %{ $token->{attributes}}) {
9458     $el->set_attribute_ns (undef, [undef, $attr_name],
9459     $token->{attributes} ->{$attr_name}->{value});
9460     }
9461    
9462     $insert->($el);
9463     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9464     }
9465    
9466 wakaba 1.68 my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
9467 wakaba 1.43
9468 wakaba 1.54 unless ($self->{confident}) {
9469     if ($token->{attributes}->{charset}) { ## TODO: And if supported
9470 wakaba 1.79
9471     $Whatpm::HTML::Debug::cp_pass->('t335') if $Whatpm::HTML::Debug::cp_pass;
9472     BEGIN {
9473     $Whatpm::HTML::Debug::cp->{'t335'} = 1;
9474     }
9475    
9476 wakaba 1.65 $self->{change_encoding}
9477     ->($self, $token->{attributes}->{charset}->{value});
9478 wakaba 1.68
9479     $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
9480     ->set_user_data (manakai_has_reference =>
9481     $token->{attributes}->{charset}
9482     ->{has_reference});
9483 wakaba 1.65 } elsif ($token->{attributes}->{content}) {
9484 wakaba 1.54 ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.
9485 wakaba 1.65 if ($token->{attributes}->{content}->{value}
9486 wakaba 1.71 =~ /\A[^;]*;[\x09-\x0D\x20]*[Cc][Hh][Aa][Rr][Ss][Ee][Tt]
9487     [\x09-\x0D\x20]*=
9488 wakaba 1.54 [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
9489     ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
9490 wakaba 1.79
9491     $Whatpm::HTML::Debug::cp_pass->('t336') if $Whatpm::HTML::Debug::cp_pass;
9492     BEGIN {
9493     $Whatpm::HTML::Debug::cp->{'t336'} = 1;
9494     }
9495    
9496 wakaba 1.65 $self->{change_encoding}
9497     ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);
9498 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
9499     ->set_user_data (manakai_has_reference =>
9500     $token->{attributes}->{content}
9501     ->{has_reference});
9502 wakaba 1.65 }
9503 wakaba 1.54 }
9504 wakaba 1.68 } else {
9505     if ($token->{attributes}->{charset}) {
9506 wakaba 1.79
9507     $Whatpm::HTML::Debug::cp_pass->('t337') if $Whatpm::HTML::Debug::cp_pass;
9508     BEGIN {
9509     $Whatpm::HTML::Debug::cp->{'t337'} = 1;
9510     }
9511    
9512 wakaba 1.68 $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
9513     ->set_user_data (manakai_has_reference =>
9514     $token->{attributes}->{charset}
9515     ->{has_reference});
9516     }
9517 wakaba 1.69 if ($token->{attributes}->{content}) {
9518 wakaba 1.79
9519     $Whatpm::HTML::Debug::cp_pass->('t338') if $Whatpm::HTML::Debug::cp_pass;
9520     BEGIN {
9521     $Whatpm::HTML::Debug::cp->{'t338'} = 1;
9522     }
9523    
9524 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
9525     ->set_user_data (manakai_has_reference =>
9526     $token->{attributes}->{content}
9527     ->{has_reference});
9528     }
9529 wakaba 1.54 }
9530 wakaba 1.43
9531 wakaba 1.54 $token = $self->_get_next_token;
9532 wakaba 1.55 redo B;
9533 wakaba 1.54 } elsif ($token->{tag_name} eq 'title') {
9534 wakaba 1.79
9535     $Whatpm::HTML::Debug::cp_pass->('t341') if $Whatpm::HTML::Debug::cp_pass;
9536     BEGIN {
9537     $Whatpm::HTML::Debug::cp->{'t341'} = 1;
9538     }
9539    
9540 wakaba 1.54 $self->{parse_error}-> (type => 'in body:title');
9541     ## NOTE: This is an "as if in head" code clone
9542     $parse_rcdata->(RCDATA_CONTENT_MODEL, sub {
9543     if (defined $self->{head_element}) {
9544 wakaba 1.79
9545     $Whatpm::HTML::Debug::cp_pass->('t339') if $Whatpm::HTML::Debug::cp_pass;
9546     BEGIN {
9547     $Whatpm::HTML::Debug::cp->{'t339'} = 1;
9548     }
9549    
9550 wakaba 1.54 $self->{head_element}->append_child ($_[0]);
9551 wakaba 1.1 } else {
9552 wakaba 1.79
9553     $Whatpm::HTML::Debug::cp_pass->('t340') if $Whatpm::HTML::Debug::cp_pass;
9554     BEGIN {
9555     $Whatpm::HTML::Debug::cp->{'t340'} = 1;
9556     }
9557    
9558 wakaba 1.54 $insert->($_[0]);
9559 wakaba 1.1 }
9560 wakaba 1.54 });
9561 wakaba 1.55 redo B;
9562 wakaba 1.54 } elsif ($token->{tag_name} eq 'body') {
9563     $self->{parse_error}-> (type => 'in body:body');
9564 wakaba 1.1
9565 wakaba 1.54 if (@{$self->{open_elements}} == 1 or
9566     $self->{open_elements}->[1]->[1] ne 'body') {
9567 wakaba 1.79
9568     $Whatpm::HTML::Debug::cp_pass->('t342') if $Whatpm::HTML::Debug::cp_pass;
9569     BEGIN {
9570     $Whatpm::HTML::Debug::cp->{'t342'} = 1;
9571     }
9572    
9573 wakaba 1.54 ## Ignore the token
9574     } else {
9575     my $body_el = $self->{open_elements}->[1]->[0];
9576     for my $attr_name (keys %{$token->{attributes}}) {
9577     unless ($body_el->has_attribute_ns (undef, $attr_name)) {
9578 wakaba 1.79
9579     $Whatpm::HTML::Debug::cp_pass->('t343') if $Whatpm::HTML::Debug::cp_pass;
9580     BEGIN {
9581     $Whatpm::HTML::Debug::cp->{'t343'} = 1;
9582     }
9583    
9584 wakaba 1.54 $body_el->set_attribute_ns
9585     (undef, [undef, $attr_name],
9586     $token->{attributes}->{$attr_name}->{value});
9587 wakaba 1.1 }
9588 wakaba 1.54 }
9589     }
9590     $token = $self->_get_next_token;
9591 wakaba 1.55 redo B;
9592 wakaba 1.54 } elsif ({
9593     address => 1, blockquote => 1, center => 1, dir => 1,
9594 wakaba 1.85 div => 1, dl => 1, fieldset => 1,
9595     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
9596     listing => 1, menu => 1, ol => 1, p => 1, ul => 1,
9597 wakaba 1.54 pre => 1,
9598     }->{$token->{tag_name}}) {
9599     ## has a p element in scope
9600     INSCOPE: for (reverse @{$self->{open_elements}}) {
9601     if ($_->[1] eq 'p') {
9602 wakaba 1.79
9603     $Whatpm::HTML::Debug::cp_pass->('t344') if $Whatpm::HTML::Debug::cp_pass;
9604     BEGIN {
9605     $Whatpm::HTML::Debug::cp->{'t344'} = 1;
9606     }
9607    
9608 wakaba 1.54 unshift @{$self->{token}}, $token;
9609 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9610 wakaba 1.55 redo B;
9611 wakaba 1.54 } elsif ({
9612     table => 1, caption => 1, td => 1, th => 1,
9613     button => 1, marquee => 1, object => 1, html => 1,
9614     }->{$_->[1]}) {
9615 wakaba 1.79
9616     $Whatpm::HTML::Debug::cp_pass->('t345') if $Whatpm::HTML::Debug::cp_pass;
9617     BEGIN {
9618     $Whatpm::HTML::Debug::cp->{'t345'} = 1;
9619     }
9620    
9621 wakaba 1.54 last INSCOPE;
9622     }
9623     } # INSCOPE
9624    
9625    
9626 wakaba 1.48 {
9627     my $el;
9628    
9629     $el = $self->{document}->create_element_ns
9630 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9631 wakaba 1.48
9632 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9633     $el->set_attribute_ns (undef, [undef, $attr_name],
9634     $token->{attributes} ->{$attr_name}->{value});
9635     }
9636    
9637     $insert->($el);
9638     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9639 wakaba 1.48 }
9640    
9641 wakaba 1.54 if ($token->{tag_name} eq 'pre') {
9642     $token = $self->_get_next_token;
9643 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
9644 wakaba 1.54 $token->{data} =~ s/^\x0A//;
9645     unless (length $token->{data}) {
9646 wakaba 1.79
9647     $Whatpm::HTML::Debug::cp_pass->('t346') if $Whatpm::HTML::Debug::cp_pass;
9648     BEGIN {
9649     $Whatpm::HTML::Debug::cp->{'t346'} = 1;
9650     }
9651    
9652 wakaba 1.54 $token = $self->_get_next_token;
9653 wakaba 1.79 } else {
9654    
9655     $Whatpm::HTML::Debug::cp_pass->('t349') if $Whatpm::HTML::Debug::cp_pass;
9656     BEGIN {
9657     $Whatpm::HTML::Debug::cp->{'t349'} = 1;
9658     }
9659    
9660 wakaba 1.54 }
9661 wakaba 1.79 } else {
9662    
9663     $Whatpm::HTML::Debug::cp_pass->('t348') if $Whatpm::HTML::Debug::cp_pass;
9664     BEGIN {
9665     $Whatpm::HTML::Debug::cp->{'t348'} = 1;
9666     }
9667    
9668 wakaba 1.54 }
9669     } else {
9670 wakaba 1.79
9671     $Whatpm::HTML::Debug::cp_pass->('t347') if $Whatpm::HTML::Debug::cp_pass;
9672     BEGIN {
9673     $Whatpm::HTML::Debug::cp->{'t347'} = 1;
9674     }
9675    
9676 wakaba 1.54 $token = $self->_get_next_token;
9677     }
9678 wakaba 1.55 redo B;
9679 wakaba 1.54 } elsif ($token->{tag_name} eq 'form') {
9680     if (defined $self->{form_element}) {
9681 wakaba 1.79
9682     $Whatpm::HTML::Debug::cp_pass->('t350') if $Whatpm::HTML::Debug::cp_pass;
9683     BEGIN {
9684     $Whatpm::HTML::Debug::cp->{'t350'} = 1;
9685     }
9686    
9687 wakaba 1.54 $self->{parse_error}-> (type => 'in form:form');
9688     ## Ignore the token
9689     $token = $self->_get_next_token;
9690 wakaba 1.55 redo B;
9691 wakaba 1.54 } else {
9692     ## has a p element in scope
9693     INSCOPE: for (reverse @{$self->{open_elements}}) {
9694     if ($_->[1] eq 'p') {
9695 wakaba 1.79
9696     $Whatpm::HTML::Debug::cp_pass->('t351') if $Whatpm::HTML::Debug::cp_pass;
9697     BEGIN {
9698     $Whatpm::HTML::Debug::cp->{'t351'} = 1;
9699     }
9700    
9701 wakaba 1.54 unshift @{$self->{token}}, $token;
9702 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9703 wakaba 1.55 redo B;
9704 wakaba 1.54 } elsif ({
9705     table => 1, caption => 1, td => 1, th => 1,
9706     button => 1, marquee => 1, object => 1, html => 1,
9707     }->{$_->[1]}) {
9708 wakaba 1.79
9709     $Whatpm::HTML::Debug::cp_pass->('t352') if $Whatpm::HTML::Debug::cp_pass;
9710     BEGIN {
9711     $Whatpm::HTML::Debug::cp->{'t352'} = 1;
9712     }
9713    
9714 wakaba 1.54 last INSCOPE;
9715     }
9716     } # INSCOPE
9717    
9718    
9719 wakaba 1.1 {
9720     my $el;
9721    
9722     $el = $self->{document}->create_element_ns
9723     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9724    
9725     for my $attr_name (keys %{ $token->{attributes}}) {
9726     $el->set_attribute_ns (undef, [undef, $attr_name],
9727     $token->{attributes} ->{$attr_name}->{value});
9728     }
9729    
9730 wakaba 1.54 $insert->($el);
9731 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9732 wakaba 1.1 }
9733    
9734 wakaba 1.54 $self->{form_element} = $self->{open_elements}->[-1]->[0];
9735     $token = $self->_get_next_token;
9736 wakaba 1.55 redo B;
9737 wakaba 1.54 }
9738     } elsif ($token->{tag_name} eq 'li') {
9739     ## has a p element in scope
9740     INSCOPE: for (reverse @{$self->{open_elements}}) {
9741     if ($_->[1] eq 'p') {
9742 wakaba 1.79
9743     $Whatpm::HTML::Debug::cp_pass->('t353') if $Whatpm::HTML::Debug::cp_pass;
9744     BEGIN {
9745     $Whatpm::HTML::Debug::cp->{'t353'} = 1;
9746     }
9747    
9748 wakaba 1.54 unshift @{$self->{token}}, $token;
9749 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9750 wakaba 1.55 redo B;
9751 wakaba 1.54 } elsif ({
9752     table => 1, caption => 1, td => 1, th => 1,
9753     button => 1, marquee => 1, object => 1, html => 1,
9754     }->{$_->[1]}) {
9755 wakaba 1.79
9756     $Whatpm::HTML::Debug::cp_pass->('t354') if $Whatpm::HTML::Debug::cp_pass;
9757     BEGIN {
9758     $Whatpm::HTML::Debug::cp->{'t354'} = 1;
9759     }
9760    
9761 wakaba 1.54 last INSCOPE;
9762     }
9763     } # INSCOPE
9764    
9765     ## Step 1
9766     my $i = -1;
9767     my $node = $self->{open_elements}->[$i];
9768     LI: {
9769     ## Step 2
9770     if ($node->[1] eq 'li') {
9771     if ($i != -1) {
9772 wakaba 1.79
9773     $Whatpm::HTML::Debug::cp_pass->('t355') if $Whatpm::HTML::Debug::cp_pass;
9774     BEGIN {
9775     $Whatpm::HTML::Debug::cp->{'t355'} = 1;
9776     }
9777    
9778 wakaba 1.54 $self->{parse_error}-> (type => 'end tag missing:'.
9779     $self->{open_elements}->[-1]->[1]);
9780 wakaba 1.79 } else {
9781    
9782     $Whatpm::HTML::Debug::cp_pass->('t356') if $Whatpm::HTML::Debug::cp_pass;
9783     BEGIN {
9784     $Whatpm::HTML::Debug::cp->{'t356'} = 1;
9785     }
9786    
9787 wakaba 1.54 }
9788     splice @{$self->{open_elements}}, $i;
9789     last LI;
9790 wakaba 1.79 } else {
9791    
9792     $Whatpm::HTML::Debug::cp_pass->('t357') if $Whatpm::HTML::Debug::cp_pass;
9793     BEGIN {
9794     $Whatpm::HTML::Debug::cp->{'t357'} = 1;
9795     }
9796    
9797 wakaba 1.54 }
9798    
9799     ## Step 3
9800     if (not $formatting_category->{$node->[1]} and
9801     #not $phrasing_category->{$node->[1]} and
9802     ($special_category->{$node->[1]} or
9803     $scoping_category->{$node->[1]}) and
9804     $node->[1] ne 'address' and $node->[1] ne 'div') {
9805 wakaba 1.79
9806     $Whatpm::HTML::Debug::cp_pass->('t358') if $Whatpm::HTML::Debug::cp_pass;
9807     BEGIN {
9808     $Whatpm::HTML::Debug::cp->{'t358'} = 1;
9809     }
9810    
9811 wakaba 1.54 last LI;
9812     }
9813    
9814 wakaba 1.79
9815     $Whatpm::HTML::Debug::cp_pass->('t359') if $Whatpm::HTML::Debug::cp_pass;
9816     BEGIN {
9817     $Whatpm::HTML::Debug::cp->{'t359'} = 1;
9818     }
9819    
9820 wakaba 1.54 ## Step 4
9821     $i--;
9822     $node = $self->{open_elements}->[$i];
9823     redo LI;
9824     } # LI
9825    
9826    
9827 wakaba 1.48 {
9828     my $el;
9829    
9830     $el = $self->{document}->create_element_ns
9831 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9832 wakaba 1.48
9833 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9834     $el->set_attribute_ns (undef, [undef, $attr_name],
9835     $token->{attributes} ->{$attr_name}->{value});
9836     }
9837    
9838     $insert->($el);
9839     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9840 wakaba 1.48 }
9841    
9842 wakaba 1.54 $token = $self->_get_next_token;
9843 wakaba 1.55 redo B;
9844 wakaba 1.54 } elsif ($token->{tag_name} eq 'dd' or $token->{tag_name} eq 'dt') {
9845     ## has a p element in scope
9846     INSCOPE: for (reverse @{$self->{open_elements}}) {
9847     if ($_->[1] eq 'p') {
9848 wakaba 1.79
9849     $Whatpm::HTML::Debug::cp_pass->('t360') if $Whatpm::HTML::Debug::cp_pass;
9850     BEGIN {
9851     $Whatpm::HTML::Debug::cp->{'t360'} = 1;
9852     }
9853    
9854 wakaba 1.54 unshift @{$self->{token}}, $token;
9855 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9856 wakaba 1.55 redo B;
9857 wakaba 1.54 } elsif ({
9858     table => 1, caption => 1, td => 1, th => 1,
9859     button => 1, marquee => 1, object => 1, html => 1,
9860     }->{$_->[1]}) {
9861 wakaba 1.79
9862     $Whatpm::HTML::Debug::cp_pass->('t361') if $Whatpm::HTML::Debug::cp_pass;
9863     BEGIN {
9864     $Whatpm::HTML::Debug::cp->{'t361'} = 1;
9865     }
9866    
9867 wakaba 1.54 last INSCOPE;
9868     }
9869     } # INSCOPE
9870    
9871     ## Step 1
9872     my $i = -1;
9873     my $node = $self->{open_elements}->[$i];
9874     LI: {
9875     ## Step 2
9876     if ($node->[1] eq 'dt' or $node->[1] eq 'dd') {
9877     if ($i != -1) {
9878 wakaba 1.79
9879     $Whatpm::HTML::Debug::cp_pass->('t362') if $Whatpm::HTML::Debug::cp_pass;
9880     BEGIN {
9881     $Whatpm::HTML::Debug::cp->{'t362'} = 1;
9882     }
9883    
9884 wakaba 1.54 $self->{parse_error}-> (type => 'end tag missing:'.
9885     $self->{open_elements}->[-1]->[1]);
9886 wakaba 1.79 } else {
9887    
9888     $Whatpm::HTML::Debug::cp_pass->('t363') if $Whatpm::HTML::Debug::cp_pass;
9889     BEGIN {
9890     $Whatpm::HTML::Debug::cp->{'t363'} = 1;
9891     }
9892    
9893 wakaba 1.54 }
9894     splice @{$self->{open_elements}}, $i;
9895     last LI;
9896 wakaba 1.79 } else {
9897    
9898     $Whatpm::HTML::Debug::cp_pass->('t364') if $Whatpm::HTML::Debug::cp_pass;
9899     BEGIN {
9900     $Whatpm::HTML::Debug::cp->{'t364'} = 1;
9901     }
9902    
9903 wakaba 1.54 }
9904    
9905     ## Step 3
9906     if (not $formatting_category->{$node->[1]} and
9907     #not $phrasing_category->{$node->[1]} and
9908     ($special_category->{$node->[1]} or
9909     $scoping_category->{$node->[1]}) and
9910     $node->[1] ne 'address' and $node->[1] ne 'div') {
9911 wakaba 1.79
9912     $Whatpm::HTML::Debug::cp_pass->('t365') if $Whatpm::HTML::Debug::cp_pass;
9913     BEGIN {
9914     $Whatpm::HTML::Debug::cp->{'t365'} = 1;
9915     }
9916    
9917 wakaba 1.54 last LI;
9918     }
9919    
9920 wakaba 1.79
9921     $Whatpm::HTML::Debug::cp_pass->('t366') if $Whatpm::HTML::Debug::cp_pass;
9922     BEGIN {
9923     $Whatpm::HTML::Debug::cp->{'t366'} = 1;
9924     }
9925    
9926 wakaba 1.54 ## Step 4
9927     $i--;
9928     $node = $self->{open_elements}->[$i];
9929     redo LI;
9930     } # LI
9931    
9932    
9933 wakaba 1.49 {
9934     my $el;
9935    
9936     $el = $self->{document}->create_element_ns
9937     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9938    
9939     for my $attr_name (keys %{ $token->{attributes}}) {
9940     $el->set_attribute_ns (undef, [undef, $attr_name],
9941     $token->{attributes} ->{$attr_name}->{value});
9942     }
9943    
9944 wakaba 1.54 $insert->($el);
9945 wakaba 1.49 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9946     }
9947    
9948 wakaba 1.54 $token = $self->_get_next_token;
9949 wakaba 1.55 redo B;
9950 wakaba 1.54 } elsif ($token->{tag_name} eq 'plaintext') {
9951     ## has a p element in scope
9952     INSCOPE: for (reverse @{$self->{open_elements}}) {
9953     if ($_->[1] eq 'p') {
9954 wakaba 1.79
9955     $Whatpm::HTML::Debug::cp_pass->('t367') if $Whatpm::HTML::Debug::cp_pass;
9956     BEGIN {
9957     $Whatpm::HTML::Debug::cp->{'t367'} = 1;
9958     }
9959    
9960 wakaba 1.54 unshift @{$self->{token}}, $token;
9961 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9962 wakaba 1.55 redo B;
9963 wakaba 1.54 } elsif ({
9964     table => 1, caption => 1, td => 1, th => 1,
9965     button => 1, marquee => 1, object => 1, html => 1,
9966     }->{$_->[1]}) {
9967 wakaba 1.79
9968     $Whatpm::HTML::Debug::cp_pass->('t368') if $Whatpm::HTML::Debug::cp_pass;
9969     BEGIN {
9970     $Whatpm::HTML::Debug::cp->{'t368'} = 1;
9971     }
9972    
9973 wakaba 1.54 last INSCOPE;
9974     }
9975     } # INSCOPE
9976    
9977    
9978 wakaba 1.1 {
9979     my $el;
9980    
9981     $el = $self->{document}->create_element_ns
9982 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9983 wakaba 1.1
9984 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9985     $el->set_attribute_ns (undef, [undef, $attr_name],
9986     $token->{attributes} ->{$attr_name}->{value});
9987     }
9988    
9989     $insert->($el);
9990     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9991 wakaba 1.1 }
9992    
9993 wakaba 1.54
9994     $self->{content_model} = PLAINTEXT_CONTENT_MODEL;
9995    
9996     $token = $self->_get_next_token;
9997 wakaba 1.55 redo B;
9998 wakaba 1.54 } elsif ($token->{tag_name} eq 'a') {
9999     AFE: for my $i (reverse 0..$#$active_formatting_elements) {
10000     my $node = $active_formatting_elements->[$i];
10001     if ($node->[1] eq 'a') {
10002 wakaba 1.79
10003     $Whatpm::HTML::Debug::cp_pass->('t371') if $Whatpm::HTML::Debug::cp_pass;
10004     BEGIN {
10005     $Whatpm::HTML::Debug::cp->{'t371'} = 1;
10006     }
10007    
10008 wakaba 1.54 $self->{parse_error}-> (type => 'in a:a');
10009    
10010     unshift @{$self->{token}}, $token;
10011 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'a'};
10012 wakaba 1.54 $formatting_end_tag->($token->{tag_name});
10013    
10014     AFE2: for (reverse 0..$#$active_formatting_elements) {
10015     if ($active_formatting_elements->[$_]->[0] eq $node->[0]) {
10016 wakaba 1.79
10017     $Whatpm::HTML::Debug::cp_pass->('t372') if $Whatpm::HTML::Debug::cp_pass;
10018     BEGIN {
10019     $Whatpm::HTML::Debug::cp->{'t372'} = 1;
10020     }
10021    
10022 wakaba 1.54 splice @$active_formatting_elements, $_, 1;
10023     last AFE2;
10024 wakaba 1.49 }
10025 wakaba 1.54 } # AFE2
10026     OE: for (reverse 0..$#{$self->{open_elements}}) {
10027     if ($self->{open_elements}->[$_]->[0] eq $node->[0]) {
10028 wakaba 1.79
10029     $Whatpm::HTML::Debug::cp_pass->('t373') if $Whatpm::HTML::Debug::cp_pass;
10030     BEGIN {
10031     $Whatpm::HTML::Debug::cp->{'t373'} = 1;
10032     }
10033    
10034 wakaba 1.54 splice @{$self->{open_elements}}, $_, 1;
10035     last OE;
10036 wakaba 1.49 }
10037 wakaba 1.54 } # OE
10038     last AFE;
10039     } elsif ($node->[0] eq '#marker') {
10040 wakaba 1.79
10041     $Whatpm::HTML::Debug::cp_pass->('t374') if $Whatpm::HTML::Debug::cp_pass;
10042     BEGIN {
10043     $Whatpm::HTML::Debug::cp->{'t374'} = 1;
10044     }
10045    
10046 wakaba 1.54 last AFE;
10047     }
10048     } # AFE
10049    
10050     $reconstruct_active_formatting_elements->($insert_to_current);
10051 wakaba 1.49
10052 wakaba 1.54
10053     {
10054     my $el;
10055    
10056     $el = $self->{document}->create_element_ns
10057     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10058    
10059     for my $attr_name (keys %{ $token->{attributes}}) {
10060     $el->set_attribute_ns (undef, [undef, $attr_name],
10061     $token->{attributes} ->{$attr_name}->{value});
10062     }
10063    
10064     $insert->($el);
10065     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10066     }
10067    
10068     push @$active_formatting_elements, $self->{open_elements}->[-1];
10069 wakaba 1.48
10070 wakaba 1.54 $token = $self->_get_next_token;
10071 wakaba 1.55 redo B;
10072 wakaba 1.54 } elsif ({
10073     b => 1, big => 1, em => 1, font => 1, i => 1,
10074     s => 1, small => 1, strile => 1,
10075     strong => 1, tt => 1, u => 1,
10076     }->{$token->{tag_name}}) {
10077 wakaba 1.79
10078     $Whatpm::HTML::Debug::cp_pass->('t375') if $Whatpm::HTML::Debug::cp_pass;
10079     BEGIN {
10080     $Whatpm::HTML::Debug::cp->{'t375'} = 1;
10081     }
10082    
10083 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10084    
10085    
10086     {
10087     my $el;
10088    
10089     $el = $self->{document}->create_element_ns
10090     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10091    
10092     for my $attr_name (keys %{ $token->{attributes}}) {
10093     $el->set_attribute_ns (undef, [undef, $attr_name],
10094     $token->{attributes} ->{$attr_name}->{value});
10095     }
10096    
10097     $insert->($el);
10098     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10099     }
10100    
10101     push @$active_formatting_elements, $self->{open_elements}->[-1];
10102    
10103     $token = $self->_get_next_token;
10104 wakaba 1.55 redo B;
10105 wakaba 1.54 } elsif ($token->{tag_name} eq 'nobr') {
10106     $reconstruct_active_formatting_elements->($insert_to_current);
10107 wakaba 1.1
10108 wakaba 1.54 ## has a |nobr| element in scope
10109     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10110     my $node = $self->{open_elements}->[$_];
10111     if ($node->[1] eq 'nobr') {
10112 wakaba 1.79
10113     $Whatpm::HTML::Debug::cp_pass->('t376') if $Whatpm::HTML::Debug::cp_pass;
10114     BEGIN {
10115     $Whatpm::HTML::Debug::cp->{'t376'} = 1;
10116     }
10117    
10118 wakaba 1.60 $self->{parse_error}-> (type => 'in nobr:nobr');
10119 wakaba 1.54 unshift @{$self->{token}}, $token;
10120 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'nobr'};
10121 wakaba 1.55 redo B;
10122 wakaba 1.54 } elsif ({
10123     table => 1, caption => 1, td => 1, th => 1,
10124     button => 1, marquee => 1, object => 1, html => 1,
10125     }->{$node->[1]}) {
10126 wakaba 1.79
10127     $Whatpm::HTML::Debug::cp_pass->('t377') if $Whatpm::HTML::Debug::cp_pass;
10128     BEGIN {
10129     $Whatpm::HTML::Debug::cp->{'t377'} = 1;
10130     }
10131    
10132 wakaba 1.54 last INSCOPE;
10133     }
10134     } # INSCOPE
10135    
10136    
10137     {
10138     my $el;
10139    
10140     $el = $self->{document}->create_element_ns
10141     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10142    
10143     for my $attr_name (keys %{ $token->{attributes}}) {
10144     $el->set_attribute_ns (undef, [undef, $attr_name],
10145     $token->{attributes} ->{$attr_name}->{value});
10146     }
10147    
10148     $insert->($el);
10149     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10150     }
10151    
10152     push @$active_formatting_elements, $self->{open_elements}->[-1];
10153    
10154     $token = $self->_get_next_token;
10155 wakaba 1.55 redo B;
10156 wakaba 1.54 } elsif ($token->{tag_name} eq 'button') {
10157     ## has a button element in scope
10158     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10159     my $node = $self->{open_elements}->[$_];
10160     if ($node->[1] eq 'button') {
10161 wakaba 1.79
10162     $Whatpm::HTML::Debug::cp_pass->('t378') if $Whatpm::HTML::Debug::cp_pass;
10163     BEGIN {
10164     $Whatpm::HTML::Debug::cp->{'t378'} = 1;
10165     }
10166    
10167 wakaba 1.54 $self->{parse_error}-> (type => 'in button:button');
10168     unshift @{$self->{token}}, $token;
10169 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'button'};
10170 wakaba 1.55 redo B;
10171 wakaba 1.54 } elsif ({
10172     table => 1, caption => 1, td => 1, th => 1,
10173     button => 1, marquee => 1, object => 1, html => 1,
10174     }->{$node->[1]}) {
10175 wakaba 1.79
10176     $Whatpm::HTML::Debug::cp_pass->('t379') if $Whatpm::HTML::Debug::cp_pass;
10177     BEGIN {
10178     $Whatpm::HTML::Debug::cp->{'t379'} = 1;
10179     }
10180    
10181 wakaba 1.54 last INSCOPE;
10182 wakaba 1.1 }
10183 wakaba 1.54 } # INSCOPE
10184    
10185     $reconstruct_active_formatting_elements->($insert_to_current);
10186    
10187    
10188     {
10189     my $el;
10190    
10191     $el = $self->{document}->create_element_ns
10192     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10193    
10194     for my $attr_name (keys %{ $token->{attributes}}) {
10195     $el->set_attribute_ns (undef, [undef, $attr_name],
10196     $token->{attributes} ->{$attr_name}->{value});
10197     }
10198    
10199     $insert->($el);
10200     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10201     }
10202    
10203     push @$active_formatting_elements, ['#marker', ''];
10204 wakaba 1.1
10205 wakaba 1.54 $token = $self->_get_next_token;
10206 wakaba 1.55 redo B;
10207 wakaba 1.54 } elsif ($token->{tag_name} eq 'marquee' or
10208     $token->{tag_name} eq 'object') {
10209 wakaba 1.79
10210     $Whatpm::HTML::Debug::cp_pass->('t380') if $Whatpm::HTML::Debug::cp_pass;
10211     BEGIN {
10212     $Whatpm::HTML::Debug::cp->{'t380'} = 1;
10213     }
10214    
10215 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10216    
10217    
10218 wakaba 1.1 {
10219     my $el;
10220    
10221     $el = $self->{document}->create_element_ns
10222     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10223    
10224     for my $attr_name (keys %{ $token->{attributes}}) {
10225     $el->set_attribute_ns (undef, [undef, $attr_name],
10226     $token->{attributes} ->{$attr_name}->{value});
10227     }
10228    
10229 wakaba 1.54 $insert->($el);
10230 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10231 wakaba 1.1 }
10232    
10233 wakaba 1.54 push @$active_formatting_elements, ['#marker', ''];
10234    
10235     $token = $self->_get_next_token;
10236 wakaba 1.55 redo B;
10237 wakaba 1.54 } elsif ($token->{tag_name} eq 'xmp') {
10238 wakaba 1.79
10239     $Whatpm::HTML::Debug::cp_pass->('t381') if $Whatpm::HTML::Debug::cp_pass;
10240     BEGIN {
10241     $Whatpm::HTML::Debug::cp->{'t381'} = 1;
10242     }
10243    
10244 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10245     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
10246 wakaba 1.55 redo B;
10247 wakaba 1.54 } elsif ($token->{tag_name} eq 'table') {
10248     ## has a p element in scope
10249     INSCOPE: for (reverse @{$self->{open_elements}}) {
10250     if ($_->[1] eq 'p') {
10251 wakaba 1.79
10252     $Whatpm::HTML::Debug::cp_pass->('t382') if $Whatpm::HTML::Debug::cp_pass;
10253     BEGIN {
10254     $Whatpm::HTML::Debug::cp->{'t382'} = 1;
10255     }
10256    
10257 wakaba 1.54 unshift @{$self->{token}}, $token;
10258 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
10259 wakaba 1.55 redo B;
10260 wakaba 1.54 } elsif ({
10261     table => 1, caption => 1, td => 1, th => 1,
10262     button => 1, marquee => 1, object => 1, html => 1,
10263     }->{$_->[1]}) {
10264 wakaba 1.79
10265     $Whatpm::HTML::Debug::cp_pass->('t383') if $Whatpm::HTML::Debug::cp_pass;
10266     BEGIN {
10267     $Whatpm::HTML::Debug::cp->{'t383'} = 1;
10268     }
10269    
10270 wakaba 1.54 last INSCOPE;
10271 wakaba 1.1 }
10272 wakaba 1.54 } # INSCOPE
10273    
10274    
10275     {
10276     my $el;
10277    
10278     $el = $self->{document}->create_element_ns
10279     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10280    
10281     for my $attr_name (keys %{ $token->{attributes}}) {
10282     $el->set_attribute_ns (undef, [undef, $attr_name],
10283     $token->{attributes} ->{$attr_name}->{value});
10284     }
10285    
10286     $insert->($el);
10287     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10288     }
10289    
10290    
10291 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
10292 wakaba 1.54
10293     $token = $self->_get_next_token;
10294 wakaba 1.55 redo B;
10295 wakaba 1.54 } elsif ({
10296     area => 1, basefont => 1, bgsound => 1, br => 1,
10297     embed => 1, img => 1, param => 1, spacer => 1, wbr => 1,
10298     image => 1,
10299     }->{$token->{tag_name}}) {
10300     if ($token->{tag_name} eq 'image') {
10301 wakaba 1.79
10302     $Whatpm::HTML::Debug::cp_pass->('t384') if $Whatpm::HTML::Debug::cp_pass;
10303     BEGIN {
10304     $Whatpm::HTML::Debug::cp->{'t384'} = 1;
10305     }
10306    
10307 wakaba 1.54 $self->{parse_error}-> (type => 'image');
10308     $token->{tag_name} = 'img';
10309 wakaba 1.79 } else {
10310    
10311     $Whatpm::HTML::Debug::cp_pass->('t385') if $Whatpm::HTML::Debug::cp_pass;
10312     BEGIN {
10313     $Whatpm::HTML::Debug::cp->{'t385'} = 1;
10314     }
10315    
10316 wakaba 1.54 }
10317 wakaba 1.1
10318 wakaba 1.54 ## NOTE: There is an "as if <br>" code clone.
10319     $reconstruct_active_formatting_elements->($insert_to_current);
10320    
10321    
10322     {
10323     my $el;
10324    
10325     $el = $self->{document}->create_element_ns
10326     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10327    
10328     for my $attr_name (keys %{ $token->{attributes}}) {
10329     $el->set_attribute_ns (undef, [undef, $attr_name],
10330     $token->{attributes} ->{$attr_name}->{value});
10331     }
10332    
10333     $insert->($el);
10334     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10335     }
10336    
10337     pop @{$self->{open_elements}};
10338    
10339     $token = $self->_get_next_token;
10340 wakaba 1.55 redo B;
10341 wakaba 1.54 } elsif ($token->{tag_name} eq 'hr') {
10342     ## has a p element in scope
10343     INSCOPE: for (reverse @{$self->{open_elements}}) {
10344     if ($_->[1] eq 'p') {
10345 wakaba 1.79
10346     $Whatpm::HTML::Debug::cp_pass->('t386') if $Whatpm::HTML::Debug::cp_pass;
10347     BEGIN {
10348     $Whatpm::HTML::Debug::cp->{'t386'} = 1;
10349     }
10350    
10351 wakaba 1.54 unshift @{$self->{token}}, $token;
10352 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
10353 wakaba 1.55 redo B;
10354 wakaba 1.54 } elsif ({
10355     table => 1, caption => 1, td => 1, th => 1,
10356     button => 1, marquee => 1, object => 1, html => 1,
10357     }->{$_->[1]}) {
10358 wakaba 1.79
10359     $Whatpm::HTML::Debug::cp_pass->('t387') if $Whatpm::HTML::Debug::cp_pass;
10360     BEGIN {
10361     $Whatpm::HTML::Debug::cp->{'t387'} = 1;
10362     }
10363    
10364 wakaba 1.54 last INSCOPE;
10365 wakaba 1.1 }
10366 wakaba 1.54 } # INSCOPE
10367    
10368    
10369 wakaba 1.1 {
10370     my $el;
10371    
10372     $el = $self->{document}->create_element_ns
10373     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10374    
10375     for my $attr_name (keys %{ $token->{attributes}}) {
10376     $el->set_attribute_ns (undef, [undef, $attr_name],
10377     $token->{attributes} ->{$attr_name}->{value});
10378     }
10379    
10380 wakaba 1.54 $insert->($el);
10381 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10382 wakaba 1.1 }
10383    
10384 wakaba 1.54 pop @{$self->{open_elements}};
10385    
10386     $token = $self->_get_next_token;
10387 wakaba 1.55 redo B;
10388 wakaba 1.54 } elsif ($token->{tag_name} eq 'input') {
10389 wakaba 1.79
10390     $Whatpm::HTML::Debug::cp_pass->('t388') if $Whatpm::HTML::Debug::cp_pass;
10391     BEGIN {
10392     $Whatpm::HTML::Debug::cp->{'t388'} = 1;
10393     }
10394    
10395 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10396    
10397    
10398 wakaba 1.1 {
10399     my $el;
10400    
10401     $el = $self->{document}->create_element_ns
10402     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10403    
10404     for my $attr_name (keys %{ $token->{attributes}}) {
10405     $el->set_attribute_ns (undef, [undef, $attr_name],
10406     $token->{attributes} ->{$attr_name}->{value});
10407     }
10408    
10409 wakaba 1.54 $insert->($el);
10410 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10411 wakaba 1.1 }
10412    
10413 wakaba 1.54 ## TODO: associate with $self->{form_element} if defined
10414     pop @{$self->{open_elements}};
10415    
10416     $token = $self->_get_next_token;
10417 wakaba 1.55 redo B;
10418 wakaba 1.54 } elsif ($token->{tag_name} eq 'isindex') {
10419     $self->{parse_error}-> (type => 'isindex');
10420    
10421     if (defined $self->{form_element}) {
10422 wakaba 1.79
10423     $Whatpm::HTML::Debug::cp_pass->('t389') if $Whatpm::HTML::Debug::cp_pass;
10424     BEGIN {
10425     $Whatpm::HTML::Debug::cp->{'t389'} = 1;
10426     }
10427    
10428 wakaba 1.54 ## Ignore the token
10429     $token = $self->_get_next_token;
10430 wakaba 1.55 redo B;
10431 wakaba 1.54 } else {
10432     my $at = $token->{attributes};
10433     my $form_attrs;
10434     $form_attrs->{action} = $at->{action} if $at->{action};
10435     my $prompt_attr = $at->{prompt};
10436     $at->{name} = {name => 'name', value => 'isindex'};
10437     delete $at->{action};
10438     delete $at->{prompt};
10439     my @tokens = (
10440 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'form',
10441 wakaba 1.54 attributes => $form_attrs},
10442 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'hr'},
10443     {type => START_TAG_TOKEN, tag_name => 'p'},
10444     {type => START_TAG_TOKEN, tag_name => 'label'},
10445 wakaba 1.54 );
10446     if ($prompt_attr) {
10447 wakaba 1.79
10448     $Whatpm::HTML::Debug::cp_pass->('t390') if $Whatpm::HTML::Debug::cp_pass;
10449     BEGIN {
10450     $Whatpm::HTML::Debug::cp->{'t390'} = 1;
10451     }
10452    
10453 wakaba 1.57 push @tokens, {type => CHARACTER_TOKEN, data => $prompt_attr->{value}};
10454 wakaba 1.1 } else {
10455 wakaba 1.79
10456     $Whatpm::HTML::Debug::cp_pass->('t391') if $Whatpm::HTML::Debug::cp_pass;
10457     BEGIN {
10458     $Whatpm::HTML::Debug::cp->{'t391'} = 1;
10459     }
10460    
10461 wakaba 1.57 push @tokens, {type => CHARACTER_TOKEN,
10462 wakaba 1.54 data => 'This is a searchable index. Insert your search keywords here: '}; # SHOULD
10463     ## TODO: make this configurable
10464 wakaba 1.1 }
10465 wakaba 1.54 push @tokens,
10466 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'input', attributes => $at},
10467     #{type => CHARACTER_TOKEN, data => ''}, # SHOULD
10468     {type => END_TAG_TOKEN, tag_name => 'label'},
10469     {type => END_TAG_TOKEN, tag_name => 'p'},
10470     {type => START_TAG_TOKEN, tag_name => 'hr'},
10471     {type => END_TAG_TOKEN, tag_name => 'form'};
10472 wakaba 1.54 $token = shift @tokens;
10473     unshift @{$self->{token}}, (@tokens);
10474 wakaba 1.55 redo B;
10475 wakaba 1.54 }
10476     } elsif ($token->{tag_name} eq 'textarea') {
10477     my $tag_name = $token->{tag_name};
10478     my $el;
10479    
10480     $el = $self->{document}->create_element_ns
10481     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10482    
10483     for my $attr_name (keys %{ $token->{attributes}}) {
10484     $el->set_attribute_ns (undef, [undef, $attr_name],
10485     $token->{attributes} ->{$attr_name}->{value});
10486     }
10487    
10488    
10489     ## TODO: $self->{form_element} if defined
10490     $self->{content_model} = RCDATA_CONTENT_MODEL;
10491     delete $self->{escape}; # MUST
10492    
10493     $insert->($el);
10494    
10495     my $text = '';
10496     $token = $self->_get_next_token;
10497 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
10498 wakaba 1.54 $token->{data} =~ s/^\x0A//;
10499 wakaba 1.53 unless (length $token->{data}) {
10500 wakaba 1.79
10501     $Whatpm::HTML::Debug::cp_pass->('t392') if $Whatpm::HTML::Debug::cp_pass;
10502     BEGIN {
10503     $Whatpm::HTML::Debug::cp->{'t392'} = 1;
10504     }
10505    
10506 wakaba 1.53 $token = $self->_get_next_token;
10507 wakaba 1.79 } else {
10508    
10509     $Whatpm::HTML::Debug::cp_pass->('t393') if $Whatpm::HTML::Debug::cp_pass;
10510     BEGIN {
10511     $Whatpm::HTML::Debug::cp->{'t393'} = 1;
10512     }
10513    
10514 wakaba 1.53 }
10515 wakaba 1.79 } else {
10516    
10517     $Whatpm::HTML::Debug::cp_pass->('t394') if $Whatpm::HTML::Debug::cp_pass;
10518     BEGIN {
10519     $Whatpm::HTML::Debug::cp->{'t394'} = 1;
10520     }
10521    
10522 wakaba 1.53 }
10523 wakaba 1.57 while ($token->{type} == CHARACTER_TOKEN) {
10524 wakaba 1.79
10525     $Whatpm::HTML::Debug::cp_pass->('t395') if $Whatpm::HTML::Debug::cp_pass;
10526     BEGIN {
10527     $Whatpm::HTML::Debug::cp->{'t395'} = 1;
10528     }
10529    
10530 wakaba 1.54 $text .= $token->{data};
10531     $token = $self->_get_next_token;
10532     }
10533     if (length $text) {
10534 wakaba 1.79
10535     $Whatpm::HTML::Debug::cp_pass->('t396') if $Whatpm::HTML::Debug::cp_pass;
10536     BEGIN {
10537     $Whatpm::HTML::Debug::cp->{'t396'} = 1;
10538     }
10539    
10540 wakaba 1.54 $el->manakai_append_text ($text);
10541     }
10542    
10543     $self->{content_model} = PCDATA_CONTENT_MODEL;
10544    
10545 wakaba 1.57 if ($token->{type} == END_TAG_TOKEN and
10546 wakaba 1.54 $token->{tag_name} eq $tag_name) {
10547 wakaba 1.79
10548     $Whatpm::HTML::Debug::cp_pass->('t397') if $Whatpm::HTML::Debug::cp_pass;
10549     BEGIN {
10550     $Whatpm::HTML::Debug::cp->{'t397'} = 1;
10551     }
10552    
10553 wakaba 1.54 ## Ignore the token
10554     } else {
10555 wakaba 1.79
10556     $Whatpm::HTML::Debug::cp_pass->('t398') if $Whatpm::HTML::Debug::cp_pass;
10557     BEGIN {
10558     $Whatpm::HTML::Debug::cp->{'t398'} = 1;
10559     }
10560    
10561 wakaba 1.54 $self->{parse_error}-> (type => 'in RCDATA:#'.$token->{type});
10562     }
10563     $token = $self->_get_next_token;
10564 wakaba 1.55 redo B;
10565 wakaba 1.54 } elsif ({
10566     iframe => 1,
10567     noembed => 1,
10568     noframes => 1,
10569     noscript => 0, ## TODO: 1 if scripting is enabled
10570     }->{$token->{tag_name}}) {
10571 wakaba 1.79
10572     $Whatpm::HTML::Debug::cp_pass->('t399') if $Whatpm::HTML::Debug::cp_pass;
10573     BEGIN {
10574     $Whatpm::HTML::Debug::cp->{'t399'} = 1;
10575     }
10576    
10577 wakaba 1.60 ## NOTE: There is an "as if in body" code clone.
10578 wakaba 1.54 $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
10579 wakaba 1.55 redo B;
10580 wakaba 1.54 } elsif ($token->{tag_name} eq 'select') {
10581 wakaba 1.79
10582     $Whatpm::HTML::Debug::cp_pass->('t400') if $Whatpm::HTML::Debug::cp_pass;
10583     BEGIN {
10584     $Whatpm::HTML::Debug::cp->{'t400'} = 1;
10585     }
10586    
10587 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10588    
10589    
10590     {
10591     my $el;
10592    
10593     $el = $self->{document}->create_element_ns
10594     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10595    
10596     for my $attr_name (keys %{ $token->{attributes}}) {
10597     $el->set_attribute_ns (undef, [undef, $attr_name],
10598     $token->{attributes} ->{$attr_name}->{value});
10599     }
10600    
10601     $insert->($el);
10602     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10603     }
10604    
10605    
10606 wakaba 1.56 $self->{insertion_mode} = IN_SELECT_IM;
10607 wakaba 1.54 $token = $self->_get_next_token;
10608 wakaba 1.55 redo B;
10609 wakaba 1.54 } elsif ({
10610     caption => 1, col => 1, colgroup => 1, frame => 1,
10611     frameset => 1, head => 1, option => 1, optgroup => 1,
10612     tbody => 1, td => 1, tfoot => 1, th => 1,
10613     thead => 1, tr => 1,
10614     }->{$token->{tag_name}}) {
10615 wakaba 1.79
10616     $Whatpm::HTML::Debug::cp_pass->('t401') if $Whatpm::HTML::Debug::cp_pass;
10617     BEGIN {
10618     $Whatpm::HTML::Debug::cp->{'t401'} = 1;
10619     }
10620    
10621 wakaba 1.54 $self->{parse_error}-> (type => 'in body:'.$token->{tag_name});
10622     ## Ignore the token
10623     $token = $self->_get_next_token;
10624 wakaba 1.55 redo B;
10625 wakaba 1.54
10626     ## ISSUE: An issue on HTML5 new elements in the spec.
10627     } else {
10628 wakaba 1.79
10629     $Whatpm::HTML::Debug::cp_pass->('t402') if $Whatpm::HTML::Debug::cp_pass;
10630     BEGIN {
10631     $Whatpm::HTML::Debug::cp->{'t402'} = 1;
10632     }
10633    
10634 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10635 wakaba 1.53
10636 wakaba 1.54
10637     {
10638     my $el;
10639    
10640     $el = $self->{document}->create_element_ns
10641     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10642    
10643     for my $attr_name (keys %{ $token->{attributes}}) {
10644     $el->set_attribute_ns (undef, [undef, $attr_name],
10645     $token->{attributes} ->{$attr_name}->{value});
10646 wakaba 1.53 }
10647 wakaba 1.54
10648     $insert->($el);
10649     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10650     }
10651    
10652 wakaba 1.53
10653 wakaba 1.54 $token = $self->_get_next_token;
10654 wakaba 1.55 redo B;
10655 wakaba 1.54 }
10656 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
10657 wakaba 1.54 if ($token->{tag_name} eq 'body') {
10658     if (@{$self->{open_elements}} > 1 and
10659     $self->{open_elements}->[1]->[1] eq 'body') {
10660     for (@{$self->{open_elements}}) {
10661     unless ({
10662     dd => 1, dt => 1, li => 1, p => 1, td => 1,
10663     th => 1, tr => 1, body => 1, html => 1,
10664     tbody => 1, tfoot => 1, thead => 1,
10665     }->{$_->[1]}) {
10666 wakaba 1.79
10667     $Whatpm::HTML::Debug::cp_pass->('t403') if $Whatpm::HTML::Debug::cp_pass;
10668     BEGIN {
10669     $Whatpm::HTML::Debug::cp->{'t403'} = 1;
10670     }
10671    
10672 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$_->[1]);
10673 wakaba 1.79 } else {
10674    
10675     $Whatpm::HTML::Debug::cp_pass->('t404') if $Whatpm::HTML::Debug::cp_pass;
10676     BEGIN {
10677     $Whatpm::HTML::Debug::cp->{'t404'} = 1;
10678     }
10679    
10680 wakaba 1.54 }
10681     }
10682 wakaba 1.53
10683 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
10684 wakaba 1.54 $token = $self->_get_next_token;
10685 wakaba 1.55 redo B;
10686 wakaba 1.54 } else {
10687 wakaba 1.79
10688     $Whatpm::HTML::Debug::cp_pass->('t405') if $Whatpm::HTML::Debug::cp_pass;
10689     BEGIN {
10690     $Whatpm::HTML::Debug::cp->{'t405'} = 1;
10691     }
10692    
10693 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10694     ## Ignore the token
10695     $token = $self->_get_next_token;
10696 wakaba 1.55 redo B;
10697 wakaba 1.53 }
10698 wakaba 1.54 } elsif ($token->{tag_name} eq 'html') {
10699     if (@{$self->{open_elements}} > 1 and $self->{open_elements}->[1]->[1] eq 'body') {
10700     ## ISSUE: There is an issue in the spec.
10701     if ($self->{open_elements}->[-1]->[1] ne 'body') {
10702 wakaba 1.79
10703     $Whatpm::HTML::Debug::cp_pass->('t406') if $Whatpm::HTML::Debug::cp_pass;
10704     BEGIN {
10705     $Whatpm::HTML::Debug::cp->{'t406'} = 1;
10706     }
10707    
10708 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[1]->[1]);
10709 wakaba 1.79 } else {
10710    
10711     $Whatpm::HTML::Debug::cp_pass->('t407') if $Whatpm::HTML::Debug::cp_pass;
10712     BEGIN {
10713     $Whatpm::HTML::Debug::cp->{'t407'} = 1;
10714     }
10715    
10716 wakaba 1.54 }
10717 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
10718 wakaba 1.54 ## reprocess
10719 wakaba 1.55 redo B;
10720 wakaba 1.54 } else {
10721 wakaba 1.79
10722     $Whatpm::HTML::Debug::cp_pass->('t408') if $Whatpm::HTML::Debug::cp_pass;
10723     BEGIN {
10724     $Whatpm::HTML::Debug::cp->{'t408'} = 1;
10725     }
10726    
10727 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10728     ## Ignore the token
10729     $token = $self->_get_next_token;
10730 wakaba 1.55 redo B;
10731 wakaba 1.53 }
10732 wakaba 1.54 } elsif ({
10733     address => 1, blockquote => 1, center => 1, dir => 1,
10734     div => 1, dl => 1, fieldset => 1, listing => 1,
10735     menu => 1, ol => 1, pre => 1, ul => 1,
10736     p => 1,
10737     dd => 1, dt => 1, li => 1,
10738     button => 1, marquee => 1, object => 1,
10739     }->{$token->{tag_name}}) {
10740     ## has an element in scope
10741     my $i;
10742     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10743     my $node = $self->{open_elements}->[$_];
10744     if ($node->[1] eq $token->{tag_name}) {
10745     ## generate implied end tags
10746     if ({
10747     dd => ($token->{tag_name} ne 'dd'),
10748     dt => ($token->{tag_name} ne 'dt'),
10749     li => ($token->{tag_name} ne 'li'),
10750     p => ($token->{tag_name} ne 'p'),
10751     td => 1, th => 1, tr => 1,
10752     tbody => 1, tfoot=> 1, thead => 1,
10753     }->{$self->{open_elements}->[-1]->[1]}) {
10754 wakaba 1.79
10755     $Whatpm::HTML::Debug::cp_pass->('t409') if $Whatpm::HTML::Debug::cp_pass;
10756     BEGIN {
10757     $Whatpm::HTML::Debug::cp->{'t409'} = 1;
10758     }
10759    
10760 wakaba 1.54 unshift @{$self->{token}}, $token;
10761 wakaba 1.57 $token = {type => END_TAG_TOKEN,
10762 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
10763 wakaba 1.55 redo B;
10764 wakaba 1.54 }
10765 wakaba 1.79
10766    
10767     $Whatpm::HTML::Debug::cp_pass->('t410') if $Whatpm::HTML::Debug::cp_pass;
10768     BEGIN {
10769     $Whatpm::HTML::Debug::cp->{'t410'} = 1;
10770     }
10771    
10772 wakaba 1.54 $i = $_;
10773     last INSCOPE unless $token->{tag_name} eq 'p';
10774     } elsif ({
10775     table => 1, caption => 1, td => 1, th => 1,
10776     button => 1, marquee => 1, object => 1, html => 1,
10777     }->{$node->[1]}) {
10778 wakaba 1.79
10779     $Whatpm::HTML::Debug::cp_pass->('t411') if $Whatpm::HTML::Debug::cp_pass;
10780     BEGIN {
10781     $Whatpm::HTML::Debug::cp->{'t411'} = 1;
10782     }
10783    
10784 wakaba 1.54 last INSCOPE;
10785     }
10786     } # INSCOPE
10787    
10788     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
10789     if (defined $i) {
10790 wakaba 1.79
10791     $Whatpm::HTML::Debug::cp_pass->('t412') if $Whatpm::HTML::Debug::cp_pass;
10792     BEGIN {
10793     $Whatpm::HTML::Debug::cp->{'t412'} = 1;
10794     }
10795    
10796 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
10797 wakaba 1.1 } else {
10798 wakaba 1.79
10799     $Whatpm::HTML::Debug::cp_pass->('t413') if $Whatpm::HTML::Debug::cp_pass;
10800     BEGIN {
10801     $Whatpm::HTML::Debug::cp->{'t413'} = 1;
10802     }
10803    
10804 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10805 wakaba 1.1 }
10806 wakaba 1.53 }
10807 wakaba 1.54
10808     if (defined $i) {
10809 wakaba 1.79
10810     $Whatpm::HTML::Debug::cp_pass->('t414') if $Whatpm::HTML::Debug::cp_pass;
10811     BEGIN {
10812     $Whatpm::HTML::Debug::cp->{'t414'} = 1;
10813     }
10814    
10815 wakaba 1.54 splice @{$self->{open_elements}}, $i;
10816     } elsif ($token->{tag_name} eq 'p') {
10817 wakaba 1.79
10818     $Whatpm::HTML::Debug::cp_pass->('t415') if $Whatpm::HTML::Debug::cp_pass;
10819     BEGIN {
10820     $Whatpm::HTML::Debug::cp->{'t415'} = 1;
10821     }
10822    
10823 wakaba 1.54 ## As if <p>, then reprocess the current token
10824     my $el;
10825 wakaba 1.53
10826 wakaba 1.54 $el = $self->{document}->create_element_ns
10827     (q<http://www.w3.org/1999/xhtml>, [undef, 'p']);
10828    
10829     $insert->($el);
10830 wakaba 1.79 } else {
10831    
10832     $Whatpm::HTML::Debug::cp_pass->('t416') if $Whatpm::HTML::Debug::cp_pass;
10833     BEGIN {
10834     $Whatpm::HTML::Debug::cp->{'t416'} = 1;
10835     }
10836    
10837 wakaba 1.54 }
10838     $clear_up_to_marker->()
10839     if {
10840     button => 1, marquee => 1, object => 1,
10841     }->{$token->{tag_name}};
10842     $token = $self->_get_next_token;
10843 wakaba 1.55 redo B;
10844 wakaba 1.54 } elsif ($token->{tag_name} eq 'form') {
10845     ## has an element in scope
10846     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10847     my $node = $self->{open_elements}->[$_];
10848     if ($node->[1] eq $token->{tag_name}) {
10849     ## generate implied end tags
10850     if ({
10851     dd => 1, dt => 1, li => 1, p => 1,
10852 wakaba 1.83
10853     ## NOTE: The following elements never appear here, maybe.
10854 wakaba 1.54 td => 1, th => 1, tr => 1,
10855 wakaba 1.83 tbody => 1, tfoot => 1, thead => 1,
10856 wakaba 1.54 }->{$self->{open_elements}->[-1]->[1]}) {
10857 wakaba 1.79
10858     $Whatpm::HTML::Debug::cp_pass->('t417') if $Whatpm::HTML::Debug::cp_pass;
10859     BEGIN {
10860     $Whatpm::HTML::Debug::cp->{'t417'} = 1;
10861     }
10862    
10863 wakaba 1.54 unshift @{$self->{token}}, $token;
10864 wakaba 1.57 $token = {type => END_TAG_TOKEN,
10865 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
10866 wakaba 1.55 redo B;
10867 wakaba 1.54 }
10868 wakaba 1.79
10869    
10870     $Whatpm::HTML::Debug::cp_pass->('t418') if $Whatpm::HTML::Debug::cp_pass;
10871     BEGIN {
10872     $Whatpm::HTML::Debug::cp->{'t418'} = 1;
10873     }
10874    
10875 wakaba 1.54 last INSCOPE;
10876     } elsif ({
10877     table => 1, caption => 1, td => 1, th => 1,
10878     button => 1, marquee => 1, object => 1, html => 1,
10879     }->{$node->[1]}) {
10880 wakaba 1.79
10881     $Whatpm::HTML::Debug::cp_pass->('t419') if $Whatpm::HTML::Debug::cp_pass;
10882     BEGIN {
10883     $Whatpm::HTML::Debug::cp->{'t419'} = 1;
10884     }
10885    
10886 wakaba 1.54 last INSCOPE;
10887 wakaba 1.36 }
10888 wakaba 1.54 } # INSCOPE
10889    
10890     if ($self->{open_elements}->[-1]->[1] eq $token->{tag_name}) {
10891 wakaba 1.79
10892     $Whatpm::HTML::Debug::cp_pass->('t420') if $Whatpm::HTML::Debug::cp_pass;
10893     BEGIN {
10894     $Whatpm::HTML::Debug::cp->{'t420'} = 1;
10895     }
10896    
10897 wakaba 1.54 pop @{$self->{open_elements}};
10898     } else {
10899 wakaba 1.79
10900     $Whatpm::HTML::Debug::cp_pass->('t421') if $Whatpm::HTML::Debug::cp_pass;
10901     BEGIN {
10902     $Whatpm::HTML::Debug::cp->{'t421'} = 1;
10903     }
10904    
10905 wakaba 1.60 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10906 wakaba 1.36 }
10907    
10908 wakaba 1.54 undef $self->{form_element};
10909     $token = $self->_get_next_token;
10910 wakaba 1.55 redo B;
10911 wakaba 1.54 } elsif ({
10912     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
10913     }->{$token->{tag_name}}) {
10914     ## has an element in scope
10915     my $i;
10916     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10917     my $node = $self->{open_elements}->[$_];
10918     if ({
10919     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
10920     }->{$node->[1]}) {
10921     ## generate implied end tags
10922     if ({
10923     dd => 1, dt => 1, li => 1, p => 1,
10924     td => 1, th => 1, tr => 1,
10925     tbody => 1, tfoot=> 1, thead => 1,
10926     }->{$self->{open_elements}->[-1]->[1]}) {
10927 wakaba 1.79
10928     $Whatpm::HTML::Debug::cp_pass->('t422') if $Whatpm::HTML::Debug::cp_pass;
10929     BEGIN {
10930     $Whatpm::HTML::Debug::cp->{'t422'} = 1;
10931     }
10932    
10933 wakaba 1.54 unshift @{$self->{token}}, $token;
10934 wakaba 1.57 $token = {type => END_TAG_TOKEN,
10935 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
10936 wakaba 1.55 redo B;
10937 wakaba 1.54 }
10938 wakaba 1.79
10939    
10940     $Whatpm::HTML::Debug::cp_pass->('t423') if $Whatpm::HTML::Debug::cp_pass;
10941     BEGIN {
10942     $Whatpm::HTML::Debug::cp->{'t423'} = 1;
10943     }
10944    
10945 wakaba 1.54 $i = $_;
10946     last INSCOPE;
10947     } elsif ({
10948     table => 1, caption => 1, td => 1, th => 1,
10949     button => 1, marquee => 1, object => 1, html => 1,
10950     }->{$node->[1]}) {
10951 wakaba 1.79
10952     $Whatpm::HTML::Debug::cp_pass->('t424') if $Whatpm::HTML::Debug::cp_pass;
10953     BEGIN {
10954     $Whatpm::HTML::Debug::cp->{'t424'} = 1;
10955     }
10956    
10957 wakaba 1.54 last INSCOPE;
10958 wakaba 1.53 }
10959 wakaba 1.54 } # INSCOPE
10960    
10961     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
10962 wakaba 1.79
10963     $Whatpm::HTML::Debug::cp_pass->('t425') if $Whatpm::HTML::Debug::cp_pass;
10964     BEGIN {
10965     $Whatpm::HTML::Debug::cp->{'t425'} = 1;
10966     }
10967    
10968 wakaba 1.60 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10969 wakaba 1.79 } else {
10970    
10971     $Whatpm::HTML::Debug::cp_pass->('t426') if $Whatpm::HTML::Debug::cp_pass;
10972     BEGIN {
10973     $Whatpm::HTML::Debug::cp->{'t426'} = 1;
10974     }
10975    
10976 wakaba 1.53 }
10977    
10978 wakaba 1.54 splice @{$self->{open_elements}}, $i if defined $i;
10979     $token = $self->_get_next_token;
10980 wakaba 1.55 redo B;
10981 wakaba 1.54 } elsif ({
10982     a => 1,
10983     b => 1, big => 1, em => 1, font => 1, i => 1,
10984     nobr => 1, s => 1, small => 1, strile => 1,
10985     strong => 1, tt => 1, u => 1,
10986     }->{$token->{tag_name}}) {
10987 wakaba 1.79
10988     $Whatpm::HTML::Debug::cp_pass->('t427') if $Whatpm::HTML::Debug::cp_pass;
10989     BEGIN {
10990     $Whatpm::HTML::Debug::cp->{'t427'} = 1;
10991     }
10992    
10993 wakaba 1.54 $formatting_end_tag->($token->{tag_name});
10994 wakaba 1.55 redo B;
10995 wakaba 1.54 } elsif ($token->{tag_name} eq 'br') {
10996 wakaba 1.79
10997     $Whatpm::HTML::Debug::cp_pass->('t428') if $Whatpm::HTML::Debug::cp_pass;
10998     BEGIN {
10999     $Whatpm::HTML::Debug::cp->{'t428'} = 1;
11000     }
11001    
11002 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:br');
11003 wakaba 1.53
11004 wakaba 1.54 ## As if <br>
11005     $reconstruct_active_formatting_elements->($insert_to_current);
11006    
11007     my $el;
11008    
11009 wakaba 1.1 $el = $self->{document}->create_element_ns
11010 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'br']);
11011 wakaba 1.1
11012 wakaba 1.54 $insert->($el);
11013    
11014     ## Ignore the token.
11015     $token = $self->_get_next_token;
11016 wakaba 1.55 redo B;
11017 wakaba 1.54 } elsif ({
11018     caption => 1, col => 1, colgroup => 1, frame => 1,
11019     frameset => 1, head => 1, option => 1, optgroup => 1,
11020     tbody => 1, td => 1, tfoot => 1, th => 1,
11021     thead => 1, tr => 1,
11022     area => 1, basefont => 1, bgsound => 1,
11023     embed => 1, hr => 1, iframe => 1, image => 1,
11024     img => 1, input => 1, isindex => 1, noembed => 1,
11025     noframes => 1, param => 1, select => 1, spacer => 1,
11026     table => 1, textarea => 1, wbr => 1,
11027     noscript => 0, ## TODO: if scripting is enabled
11028     }->{$token->{tag_name}}) {
11029 wakaba 1.79
11030     $Whatpm::HTML::Debug::cp_pass->('t429') if $Whatpm::HTML::Debug::cp_pass;
11031     BEGIN {
11032     $Whatpm::HTML::Debug::cp->{'t429'} = 1;
11033     }
11034    
11035 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
11036     ## Ignore the token
11037     $token = $self->_get_next_token;
11038 wakaba 1.55 redo B;
11039 wakaba 1.54
11040     ## ISSUE: Issue on HTML5 new elements in spec
11041    
11042     } else {
11043     ## Step 1
11044     my $node_i = -1;
11045     my $node = $self->{open_elements}->[$node_i];
11046    
11047     ## Step 2
11048     S2: {
11049     if ($node->[1] eq $token->{tag_name}) {
11050     ## Step 1
11051     ## generate implied end tags
11052     if ({
11053     dd => 1, dt => 1, li => 1, p => 1,
11054     td => 1, th => 1, tr => 1,
11055 wakaba 1.57 tbody => 1, tfoot => 1, thead => 1,
11056 wakaba 1.54 }->{$self->{open_elements}->[-1]->[1]}) {
11057 wakaba 1.79
11058     $Whatpm::HTML::Debug::cp_pass->('t430') if $Whatpm::HTML::Debug::cp_pass;
11059     BEGIN {
11060     $Whatpm::HTML::Debug::cp->{'t430'} = 1;
11061     }
11062    
11063 wakaba 1.83 ## ISSUE: Can this case be reached?
11064 wakaba 1.54 unshift @{$self->{token}}, $token;
11065 wakaba 1.57 $token = {type => END_TAG_TOKEN,
11066 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
11067 wakaba 1.55 redo B;
11068 wakaba 1.54 }
11069    
11070     ## Step 2
11071     if ($token->{tag_name} ne $self->{open_elements}->[-1]->[1]) {
11072 wakaba 1.79
11073     $Whatpm::HTML::Debug::cp_pass->('t431') if $Whatpm::HTML::Debug::cp_pass;
11074     BEGIN {
11075     $Whatpm::HTML::Debug::cp->{'t431'} = 1;
11076     }
11077    
11078 wakaba 1.60 ## NOTE: <x><y></x>
11079 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
11080 wakaba 1.79 } else {
11081    
11082     $Whatpm::HTML::Debug::cp_pass->('t432') if $Whatpm::HTML::Debug::cp_pass;
11083     BEGIN {
11084     $Whatpm::HTML::Debug::cp->{'t432'} = 1;
11085     }
11086    
11087 wakaba 1.54 }
11088    
11089     ## Step 3
11090     splice @{$self->{open_elements}}, $node_i;
11091 wakaba 1.53
11092 wakaba 1.36 $token = $self->_get_next_token;
11093 wakaba 1.54 last S2;
11094 wakaba 1.1 } else {
11095 wakaba 1.54 ## Step 3
11096     if (not $formatting_category->{$node->[1]} and
11097     #not $phrasing_category->{$node->[1]} and
11098     ($special_category->{$node->[1]} or
11099     $scoping_category->{$node->[1]})) {
11100 wakaba 1.79
11101     $Whatpm::HTML::Debug::cp_pass->('t433') if $Whatpm::HTML::Debug::cp_pass;
11102     BEGIN {
11103     $Whatpm::HTML::Debug::cp->{'t433'} = 1;
11104     }
11105    
11106 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
11107     ## Ignore the token
11108     $token = $self->_get_next_token;
11109     last S2;
11110     }
11111 wakaba 1.79
11112    
11113     $Whatpm::HTML::Debug::cp_pass->('t434') if $Whatpm::HTML::Debug::cp_pass;
11114     BEGIN {
11115     $Whatpm::HTML::Debug::cp->{'t434'} = 1;
11116     }
11117    
11118 wakaba 1.1 }
11119 wakaba 1.54
11120     ## Step 4
11121     $node_i--;
11122     $node = $self->{open_elements}->[$node_i];
11123    
11124     ## Step 5;
11125     redo S2;
11126     } # S2
11127 wakaba 1.55 redo B;
11128 wakaba 1.1 }
11129     }
11130 wakaba 1.54 redo B;
11131 wakaba 1.1 } # B
11132    
11133     ## Stop parsing # MUST
11134    
11135     ## TODO: script stuffs
11136 wakaba 1.3 } # _tree_construct_main
11137    
11138     sub set_inner_html ($$$) {
11139     my $class = shift;
11140     my $node = shift;
11141     my $s = \$_[0];
11142     my $onerror = $_[1];
11143    
11144 wakaba 1.65 ## ISSUE: Should {confident} be true?
11145    
11146 wakaba 1.3 my $nt = $node->node_type;
11147     if ($nt == 9) {
11148     # MUST
11149    
11150     ## Step 1 # MUST
11151     ## TODO: If the document has an active parser, ...
11152     ## ISSUE: There is an issue in the spec.
11153    
11154     ## Step 2 # MUST
11155     my @cn = @{$node->child_nodes};
11156     for (@cn) {
11157     $node->remove_child ($_);
11158     }
11159    
11160     ## Step 3, 4, 5 # MUST
11161     $class->parse_string ($$s => $node, $onerror);
11162     } elsif ($nt == 1) {
11163     ## TODO: If non-html element
11164    
11165     ## NOTE: Most of this code is copied from |parse_string|
11166    
11167     ## Step 1 # MUST
11168 wakaba 1.14 my $this_doc = $node->owner_document;
11169     my $doc = $this_doc->implementation->create_document;
11170 wakaba 1.18 $doc->manakai_is_html (1);
11171 wakaba 1.3 my $p = $class->new;
11172     $p->{document} = $doc;
11173    
11174 wakaba 1.84 ## Step 8 # MUST
11175 wakaba 1.3 my $i = 0;
11176     my $line = 1;
11177     my $column = 0;
11178 wakaba 1.76 $p->{set_next_char} = sub {
11179 wakaba 1.3 my $self = shift;
11180 wakaba 1.14
11181 wakaba 1.76 pop @{$self->{prev_char}};
11182     unshift @{$self->{prev_char}}, $self->{next_char};
11183 wakaba 1.14
11184 wakaba 1.76 $self->{next_char} = -1 and return if $i >= length $$s;
11185     $self->{next_char} = ord substr $$s, $i++, 1;
11186 wakaba 1.3 $column++;
11187 wakaba 1.4
11188 wakaba 1.76 if ($self->{next_char} == 0x000A) { # LF
11189 wakaba 1.4 $line++;
11190     $column = 0;
11191 wakaba 1.79
11192     $Whatpm::HTML::Debug::cp_pass->('i1') if $Whatpm::HTML::Debug::cp_pass;
11193     BEGIN {
11194     $Whatpm::HTML::Debug::cp->{'i1'} = 1;
11195     }
11196    
11197 wakaba 1.76 } elsif ($self->{next_char} == 0x000D) { # CR
11198 wakaba 1.15 $i++ if substr ($$s, $i, 1) eq "\x0A";
11199 wakaba 1.76 $self->{next_char} = 0x000A; # LF # MUST
11200 wakaba 1.3 $line++;
11201 wakaba 1.4 $column = 0;
11202 wakaba 1.79
11203     $Whatpm::HTML::Debug::cp_pass->('i2') if $Whatpm::HTML::Debug::cp_pass;
11204     BEGIN {
11205     $Whatpm::HTML::Debug::cp->{'i2'} = 1;
11206     }
11207    
11208 wakaba 1.76 } elsif ($self->{next_char} > 0x10FFFF) {
11209     $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
11210 wakaba 1.79
11211     $Whatpm::HTML::Debug::cp_pass->('i3') if $Whatpm::HTML::Debug::cp_pass;
11212     BEGIN {
11213     $Whatpm::HTML::Debug::cp->{'i3'} = 1;
11214     }
11215    
11216 wakaba 1.76 } elsif ($self->{next_char} == 0x0000) { # NULL
11217 wakaba 1.79
11218     $Whatpm::HTML::Debug::cp_pass->('i4') if $Whatpm::HTML::Debug::cp_pass;
11219     BEGIN {
11220     $Whatpm::HTML::Debug::cp->{'i4'} = 1;
11221     }
11222    
11223 wakaba 1.14 $self->{parse_error}-> (type => 'NULL');
11224 wakaba 1.76 $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
11225 wakaba 1.3 }
11226     };
11227 wakaba 1.76 $p->{prev_char} = [-1, -1, -1];
11228     $p->{next_char} = -1;
11229 wakaba 1.3
11230     my $ponerror = $onerror || sub {
11231     my (%opt) = @_;
11232     warn "Parse error ($opt{type}) at line $opt{line} column $opt{column}\n";
11233     };
11234     $p->{parse_error} = sub {
11235     $ponerror->(@_, line => $line, column => $column);
11236     };
11237    
11238     $p->_initialize_tokenizer;
11239     $p->_initialize_tree_constructor;
11240    
11241     ## Step 2
11242 wakaba 1.71 my $node_ln = $node->manakai_local_name;
11243 wakaba 1.41 $p->{content_model} = {
11244     title => RCDATA_CONTENT_MODEL,
11245     textarea => RCDATA_CONTENT_MODEL,
11246     style => CDATA_CONTENT_MODEL,
11247     script => CDATA_CONTENT_MODEL,
11248     xmp => CDATA_CONTENT_MODEL,
11249     iframe => CDATA_CONTENT_MODEL,
11250     noembed => CDATA_CONTENT_MODEL,
11251     noframes => CDATA_CONTENT_MODEL,
11252     noscript => CDATA_CONTENT_MODEL,
11253     plaintext => PLAINTEXT_CONTENT_MODEL,
11254     }->{$node_ln};
11255     $p->{content_model} = PCDATA_CONTENT_MODEL
11256     unless defined $p->{content_model};
11257     ## ISSUE: What is "the name of the element"? local name?
11258 wakaba 1.3
11259     $p->{inner_html_node} = [$node, $node_ln];
11260    
11261 wakaba 1.84 ## Step 3
11262 wakaba 1.3 my $root = $doc->create_element_ns
11263     ('http://www.w3.org/1999/xhtml', [undef, 'html']);
11264    
11265 wakaba 1.84 ## Step 4 # MUST
11266 wakaba 1.3 $doc->append_child ($root);
11267    
11268 wakaba 1.84 ## Step 5 # MUST
11269 wakaba 1.3 push @{$p->{open_elements}}, [$root, 'html'];
11270    
11271     undef $p->{head_element};
11272    
11273 wakaba 1.84 ## Step 6 # MUST
11274 wakaba 1.3 $p->_reset_insertion_mode;
11275    
11276 wakaba 1.84 ## Step 7 # MUST
11277 wakaba 1.3 my $anode = $node;
11278     AN: while (defined $anode) {
11279     if ($anode->node_type == 1) {
11280     my $nsuri = $anode->namespace_uri;
11281     if (defined $nsuri and $nsuri eq 'http://www.w3.org/1999/xhtml') {
11282 wakaba 1.71 if ($anode->manakai_local_name eq 'form') {
11283 wakaba 1.79
11284     $Whatpm::HTML::Debug::cp_pass->('i5') if $Whatpm::HTML::Debug::cp_pass;
11285     BEGIN {
11286     $Whatpm::HTML::Debug::cp->{'i5'} = 1;
11287     }
11288    
11289 wakaba 1.3 $p->{form_element} = $anode;
11290     last AN;
11291     }
11292     }
11293     }
11294     $anode = $anode->parent_node;
11295     } # AN
11296    
11297 wakaba 1.84 ## Step 9 # MUST
11298 wakaba 1.3 {
11299     my $self = $p;
11300     $token = $self->_get_next_token;
11301     }
11302     $p->_tree_construction_main;
11303    
11304 wakaba 1.84 ## Step 10 # MUST
11305 wakaba 1.3 my @cn = @{$node->child_nodes};
11306     for (@cn) {
11307     $node->remove_child ($_);
11308     }
11309     ## ISSUE: mutation events? read-only?
11310    
11311 wakaba 1.84 ## Step 11 # MUST
11312 wakaba 1.3 @cn = @{$root->child_nodes};
11313     for (@cn) {
11314 wakaba 1.14 $this_doc->adopt_node ($_);
11315 wakaba 1.3 $node->append_child ($_);
11316     }
11317 wakaba 1.14 ## ISSUE: mutation events?
11318 wakaba 1.3
11319     $p->_terminate_tree_constructor;
11320     } else {
11321     die "$0: |set_inner_html| is not defined for node of type $nt";
11322     }
11323     } # set_inner_html
11324    
11325     } # tree construction stage
11326 wakaba 1.1
11327 wakaba 1.65 package Whatpm::HTML::RestartParser;
11328     push our @ISA, 'Error';
11329    
11330 wakaba 1.1 1;
11331 wakaba 1.85 # $Date: 2008/03/06 15:23:17 $

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24