/[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.88 - (hide annotations) (download)
Sat Mar 8 02:35:04 2008 UTC (18 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.87: +3 -3 lines
++ whatpm/Whatpm/ChangeLog	8 Mar 2008 02:30:25 -0000
	* HTML.pm.src: Remove strange |if| condition; however, it should
	have had no harm in theory.

2008-03-08  Wakaba  <wakaba@suika.fam.cx>

1 wakaba 1.2 package Whatpm::HTML;
2 wakaba 1.1 use strict;
3 wakaba 1.88 our $VERSION=do{my @r=(q$Revision: 1.87 $=~/\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 wakaba 1.86 while ({
5770     dd => 1, dt => 1, li => 1, p => 1,
5771     }->{$self->{open_elements}->[-1]->[1]}) {
5772 wakaba 1.79
5773     $Whatpm::HTML::Debug::cp_pass->('t75') if $Whatpm::HTML::Debug::cp_pass;
5774     BEGIN {
5775     $Whatpm::HTML::Debug::cp->{'t75'} = 1;
5776     }
5777    
5778 wakaba 1.86 pop @{$self->{open_elements}};
5779 wakaba 1.54 }
5780 wakaba 1.1
5781 wakaba 1.54 if (@{$self->{open_elements}} > 2 or
5782     (@{$self->{open_elements}} == 2 and $self->{open_elements}->[1]->[1] ne 'body')) {
5783 wakaba 1.79
5784     $Whatpm::HTML::Debug::cp_pass->('t76') if $Whatpm::HTML::Debug::cp_pass;
5785     BEGIN {
5786     $Whatpm::HTML::Debug::cp->{'t76'} = 1;
5787     }
5788    
5789 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5790     } elsif (defined $self->{inner_html_node} and
5791     @{$self->{open_elements}} > 1 and
5792     $self->{open_elements}->[1]->[1] ne 'body') {
5793 wakaba 1.81 ## ISSUE: This case is never reached.
5794 wakaba 1.79
5795     $Whatpm::HTML::Debug::cp_pass->('t77') if $Whatpm::HTML::Debug::cp_pass;
5796     BEGIN {
5797     $Whatpm::HTML::Debug::cp->{'t77'} = 1;
5798     }
5799    
5800 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5801 wakaba 1.79 } else {
5802    
5803     $Whatpm::HTML::Debug::cp_pass->('t78') if $Whatpm::HTML::Debug::cp_pass;
5804     BEGIN {
5805     $Whatpm::HTML::Debug::cp->{'t78'} = 1;
5806     }
5807    
5808 wakaba 1.54 }
5809    
5810     ## ISSUE: There is an issue in the spec.
5811     }
5812    
5813     ## Stop parsing
5814     last B;
5815 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN and
5816 wakaba 1.54 $token->{tag_name} eq 'html') {
5817 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
5818 wakaba 1.79
5819     $Whatpm::HTML::Debug::cp_pass->('t79') if $Whatpm::HTML::Debug::cp_pass;
5820     BEGIN {
5821     $Whatpm::HTML::Debug::cp->{'t79'} = 1;
5822     }
5823    
5824 wakaba 1.54 $self->{parse_error}-> (type => 'after html:html');
5825 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
5826     } elsif ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
5827 wakaba 1.79
5828     $Whatpm::HTML::Debug::cp_pass->('t80') if $Whatpm::HTML::Debug::cp_pass;
5829     BEGIN {
5830     $Whatpm::HTML::Debug::cp->{'t80'} = 1;
5831     }
5832    
5833 wakaba 1.54 $self->{parse_error}-> (type => 'after html:html');
5834 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
5835 wakaba 1.79 } else {
5836    
5837     $Whatpm::HTML::Debug::cp_pass->('t81') if $Whatpm::HTML::Debug::cp_pass;
5838     BEGIN {
5839     $Whatpm::HTML::Debug::cp->{'t81'} = 1;
5840     }
5841    
5842 wakaba 1.54 }
5843    
5844 wakaba 1.84
5845 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t82') if $Whatpm::HTML::Debug::cp_pass;
5846     BEGIN {
5847     $Whatpm::HTML::Debug::cp->{'t82'} = 1;
5848     }
5849    
5850 wakaba 1.84 $self->{parse_error}-> (type => 'not first start tag');
5851 wakaba 1.54 my $top_el = $self->{open_elements}->[0]->[0];
5852     for my $attr_name (keys %{$token->{attributes}}) {
5853     unless ($top_el->has_attribute_ns (undef, $attr_name)) {
5854 wakaba 1.79
5855     $Whatpm::HTML::Debug::cp_pass->('t84') if $Whatpm::HTML::Debug::cp_pass;
5856     BEGIN {
5857     $Whatpm::HTML::Debug::cp->{'t84'} = 1;
5858     }
5859    
5860 wakaba 1.54 $top_el->set_attribute_ns
5861     (undef, [undef, $attr_name],
5862     $token->{attributes}->{$attr_name}->{value});
5863     }
5864     }
5865     $token = $self->_get_next_token;
5866     redo B;
5867 wakaba 1.57 } elsif ($token->{type} == COMMENT_TOKEN) {
5868 wakaba 1.54 my $comment = $self->{document}->create_comment ($token->{data});
5869 wakaba 1.58 if ($self->{insertion_mode} & AFTER_HTML_IMS) {
5870 wakaba 1.79
5871     $Whatpm::HTML::Debug::cp_pass->('t85') if $Whatpm::HTML::Debug::cp_pass;
5872     BEGIN {
5873     $Whatpm::HTML::Debug::cp->{'t85'} = 1;
5874     }
5875    
5876 wakaba 1.54 $self->{document}->append_child ($comment);
5877 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_BODY_IM) {
5878 wakaba 1.79
5879     $Whatpm::HTML::Debug::cp_pass->('t86') if $Whatpm::HTML::Debug::cp_pass;
5880     BEGIN {
5881     $Whatpm::HTML::Debug::cp->{'t86'} = 1;
5882     }
5883    
5884 wakaba 1.54 $self->{open_elements}->[0]->[0]->append_child ($comment);
5885     } else {
5886 wakaba 1.79
5887     $Whatpm::HTML::Debug::cp_pass->('t87') if $Whatpm::HTML::Debug::cp_pass;
5888     BEGIN {
5889     $Whatpm::HTML::Debug::cp->{'t87'} = 1;
5890     }
5891    
5892 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($comment);
5893     }
5894     $token = $self->_get_next_token;
5895     redo B;
5896 wakaba 1.58 } elsif ($self->{insertion_mode} & HEAD_IMS) {
5897 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
5898 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
5899     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
5900     unless (length $token->{data}) {
5901 wakaba 1.79
5902     $Whatpm::HTML::Debug::cp_pass->('t88') if $Whatpm::HTML::Debug::cp_pass;
5903     BEGIN {
5904     $Whatpm::HTML::Debug::cp->{'t88'} = 1;
5905     }
5906    
5907 wakaba 1.54 $token = $self->_get_next_token;
5908     redo B;
5909     }
5910     }
5911    
5912 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
5913 wakaba 1.79
5914     $Whatpm::HTML::Debug::cp_pass->('t89') if $Whatpm::HTML::Debug::cp_pass;
5915     BEGIN {
5916     $Whatpm::HTML::Debug::cp->{'t89'} = 1;
5917     }
5918    
5919 wakaba 1.54 ## As if <head>
5920    
5921     $self->{head_element} = $self->{document}->create_element_ns
5922     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
5923    
5924     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
5925     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
5926    
5927     ## Reprocess in the "in head" insertion mode...
5928     pop @{$self->{open_elements}};
5929    
5930     ## Reprocess in the "after head" insertion mode...
5931 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
5932 wakaba 1.79
5933     $Whatpm::HTML::Debug::cp_pass->('t90') if $Whatpm::HTML::Debug::cp_pass;
5934     BEGIN {
5935     $Whatpm::HTML::Debug::cp->{'t90'} = 1;
5936     }
5937    
5938 wakaba 1.54 ## As if </noscript>
5939     pop @{$self->{open_elements}};
5940     $self->{parse_error}-> (type => 'in noscript:#character');
5941    
5942     ## Reprocess in the "in head" insertion mode...
5943     ## As if </head>
5944     pop @{$self->{open_elements}};
5945    
5946     ## Reprocess in the "after head" insertion mode...
5947 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
5948 wakaba 1.79
5949     $Whatpm::HTML::Debug::cp_pass->('t91') if $Whatpm::HTML::Debug::cp_pass;
5950     BEGIN {
5951     $Whatpm::HTML::Debug::cp->{'t91'} = 1;
5952     }
5953    
5954 wakaba 1.54 pop @{$self->{open_elements}};
5955    
5956     ## Reprocess in the "after head" insertion mode...
5957 wakaba 1.79 } else {
5958    
5959     $Whatpm::HTML::Debug::cp_pass->('t92') if $Whatpm::HTML::Debug::cp_pass;
5960     BEGIN {
5961     $Whatpm::HTML::Debug::cp->{'t92'} = 1;
5962     }
5963    
5964 wakaba 1.54 }
5965    
5966     ## "after head" insertion mode
5967     ## As if <body>
5968    
5969     {
5970     my $el;
5971    
5972     $el = $self->{document}->create_element_ns
5973     (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
5974    
5975     $self->{open_elements}->[-1]->[0]->append_child ($el);
5976     push @{$self->{open_elements}}, [$el, 'body'];
5977     }
5978    
5979 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
5980 wakaba 1.54 ## reprocess
5981     redo B;
5982 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
5983 wakaba 1.54 if ($token->{tag_name} eq 'head') {
5984 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
5985 wakaba 1.54
5986 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t93') if $Whatpm::HTML::Debug::cp_pass;
5987     BEGIN {
5988     $Whatpm::HTML::Debug::cp->{'t93'} = 1;
5989     }
5990    
5991    
5992 wakaba 1.54 $self->{head_element} = $self->{document}->create_element_ns
5993     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
5994    
5995     for my $attr_name (keys %{ $token->{attributes}}) {
5996     $self->{head_element}->set_attribute_ns (undef, [undef, $attr_name],
5997     $token->{attributes} ->{$attr_name}->{value});
5998     }
5999    
6000     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6001     push @{$self->{open_elements}}, [$self->{head_element}, $token->{tag_name}];
6002 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6003 wakaba 1.54 $token = $self->_get_next_token;
6004     redo B;
6005 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
6006 wakaba 1.79
6007     $Whatpm::HTML::Debug::cp_pass->('t94') if $Whatpm::HTML::Debug::cp_pass;
6008     BEGIN {
6009     $Whatpm::HTML::Debug::cp->{'t94'} = 1;
6010     }
6011    
6012 wakaba 1.56 #
6013     } else {
6014 wakaba 1.79
6015     $Whatpm::HTML::Debug::cp_pass->('t95') if $Whatpm::HTML::Debug::cp_pass;
6016     BEGIN {
6017     $Whatpm::HTML::Debug::cp->{'t95'} = 1;
6018     }
6019    
6020 wakaba 1.54 $self->{parse_error}-> (type => 'in head:head'); # or in head noscript
6021     ## Ignore the token
6022     $token = $self->_get_next_token;
6023     redo B;
6024     }
6025 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6026 wakaba 1.79
6027     $Whatpm::HTML::Debug::cp_pass->('t96') if $Whatpm::HTML::Debug::cp_pass;
6028     BEGIN {
6029     $Whatpm::HTML::Debug::cp->{'t96'} = 1;
6030     }
6031    
6032 wakaba 1.54 ## As if <head>
6033    
6034     $self->{head_element} = $self->{document}->create_element_ns
6035     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6036    
6037     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6038     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6039    
6040 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6041 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6042 wakaba 1.79 } else {
6043    
6044     $Whatpm::HTML::Debug::cp_pass->('t97') if $Whatpm::HTML::Debug::cp_pass;
6045     BEGIN {
6046     $Whatpm::HTML::Debug::cp->{'t97'} = 1;
6047     }
6048    
6049 wakaba 1.54 }
6050    
6051     if ($token->{tag_name} eq 'base') {
6052 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6053 wakaba 1.79
6054     $Whatpm::HTML::Debug::cp_pass->('t98') if $Whatpm::HTML::Debug::cp_pass;
6055     BEGIN {
6056     $Whatpm::HTML::Debug::cp->{'t98'} = 1;
6057     }
6058    
6059 wakaba 1.54 ## As if </noscript>
6060     pop @{$self->{open_elements}};
6061     $self->{parse_error}-> (type => 'in noscript:base');
6062    
6063 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6064 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6065 wakaba 1.79 } else {
6066    
6067     $Whatpm::HTML::Debug::cp_pass->('t99') if $Whatpm::HTML::Debug::cp_pass;
6068     BEGIN {
6069     $Whatpm::HTML::Debug::cp->{'t99'} = 1;
6070     }
6071    
6072 wakaba 1.54 }
6073    
6074     ## NOTE: There is a "as if in head" code clone.
6075 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6076 wakaba 1.79
6077     $Whatpm::HTML::Debug::cp_pass->('t100') if $Whatpm::HTML::Debug::cp_pass;
6078     BEGIN {
6079     $Whatpm::HTML::Debug::cp->{'t100'} = 1;
6080     }
6081    
6082 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6083     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6084 wakaba 1.79 } else {
6085    
6086     $Whatpm::HTML::Debug::cp_pass->('t101') if $Whatpm::HTML::Debug::cp_pass;
6087     BEGIN {
6088     $Whatpm::HTML::Debug::cp->{'t101'} = 1;
6089     }
6090    
6091 wakaba 1.54 }
6092    
6093     {
6094     my $el;
6095    
6096     $el = $self->{document}->create_element_ns
6097     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6098    
6099     for my $attr_name (keys %{ $token->{attributes}}) {
6100     $el->set_attribute_ns (undef, [undef, $attr_name],
6101     $token->{attributes} ->{$attr_name}->{value});
6102     }
6103    
6104     $self->{open_elements}->[-1]->[0]->append_child ($el);
6105     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6106     }
6107    
6108     pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6109     pop @{$self->{open_elements}}
6110 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6111 wakaba 1.54 $token = $self->_get_next_token;
6112     redo B;
6113     } elsif ($token->{tag_name} eq 'link') {
6114     ## NOTE: There is a "as if in head" code clone.
6115 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6116 wakaba 1.79
6117     $Whatpm::HTML::Debug::cp_pass->('t102') if $Whatpm::HTML::Debug::cp_pass;
6118     BEGIN {
6119     $Whatpm::HTML::Debug::cp->{'t102'} = 1;
6120     }
6121    
6122 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6123     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6124 wakaba 1.79 } else {
6125    
6126     $Whatpm::HTML::Debug::cp_pass->('t103') if $Whatpm::HTML::Debug::cp_pass;
6127     BEGIN {
6128     $Whatpm::HTML::Debug::cp->{'t103'} = 1;
6129     }
6130    
6131 wakaba 1.54 }
6132    
6133 wakaba 1.25 {
6134     my $el;
6135    
6136 wakaba 1.1 $el = $self->{document}->create_element_ns
6137     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6138    
6139 wakaba 1.25 for my $attr_name (keys %{ $token->{attributes}}) {
6140 wakaba 1.1 $el->set_attribute_ns (undef, [undef, $attr_name],
6141 wakaba 1.25 $token->{attributes} ->{$attr_name}->{value});
6142 wakaba 1.1 }
6143    
6144 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6145 wakaba 1.25 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6146     }
6147    
6148 wakaba 1.54 pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6149     pop @{$self->{open_elements}}
6150 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6151 wakaba 1.54 $token = $self->_get_next_token;
6152     redo B;
6153     } elsif ($token->{tag_name} eq 'meta') {
6154     ## NOTE: There is a "as if in head" code clone.
6155 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6156 wakaba 1.79
6157     $Whatpm::HTML::Debug::cp_pass->('t104') if $Whatpm::HTML::Debug::cp_pass;
6158     BEGIN {
6159     $Whatpm::HTML::Debug::cp->{'t104'} = 1;
6160     }
6161    
6162 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6163     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6164 wakaba 1.79 } else {
6165    
6166     $Whatpm::HTML::Debug::cp_pass->('t105') if $Whatpm::HTML::Debug::cp_pass;
6167     BEGIN {
6168     $Whatpm::HTML::Debug::cp->{'t105'} = 1;
6169     }
6170    
6171 wakaba 1.54 }
6172    
6173 wakaba 1.34 {
6174     my $el;
6175    
6176     $el = $self->{document}->create_element_ns
6177     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6178    
6179     for my $attr_name (keys %{ $token->{attributes}}) {
6180     $el->set_attribute_ns (undef, [undef, $attr_name],
6181     $token->{attributes} ->{$attr_name}->{value});
6182     }
6183    
6184 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6185 wakaba 1.34 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6186     }
6187    
6188 wakaba 1.68 my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6189 wakaba 1.34
6190 wakaba 1.54 unless ($self->{confident}) {
6191     if ($token->{attributes}->{charset}) { ## TODO: And if supported
6192 wakaba 1.79
6193     $Whatpm::HTML::Debug::cp_pass->('t106') if $Whatpm::HTML::Debug::cp_pass;
6194     BEGIN {
6195     $Whatpm::HTML::Debug::cp->{'t106'} = 1;
6196     }
6197    
6198 wakaba 1.65 $self->{change_encoding}
6199     ->($self, $token->{attributes}->{charset}->{value});
6200 wakaba 1.68
6201     $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
6202     ->set_user_data (manakai_has_reference =>
6203     $token->{attributes}->{charset}
6204     ->{has_reference});
6205 wakaba 1.65 } elsif ($token->{attributes}->{content}) {
6206 wakaba 1.54 ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.
6207 wakaba 1.65 if ($token->{attributes}->{content}->{value}
6208 wakaba 1.71 =~ /\A[^;]*;[\x09-\x0D\x20]*[Cc][Hh][Aa][Rr][Ss][Ee][Tt]
6209     [\x09-\x0D\x20]*=
6210 wakaba 1.54 [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
6211     ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
6212 wakaba 1.79
6213     $Whatpm::HTML::Debug::cp_pass->('t107') if $Whatpm::HTML::Debug::cp_pass;
6214     BEGIN {
6215     $Whatpm::HTML::Debug::cp->{'t107'} = 1;
6216     }
6217    
6218 wakaba 1.65 $self->{change_encoding}
6219     ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);
6220 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
6221     ->set_user_data (manakai_has_reference =>
6222     $token->{attributes}->{content}
6223     ->{has_reference});
6224 wakaba 1.79 } else {
6225    
6226     $Whatpm::HTML::Debug::cp_pass->('t108') if $Whatpm::HTML::Debug::cp_pass;
6227     BEGIN {
6228     $Whatpm::HTML::Debug::cp->{'t108'} = 1;
6229     }
6230    
6231 wakaba 1.65 }
6232 wakaba 1.54 }
6233 wakaba 1.68 } else {
6234     if ($token->{attributes}->{charset}) {
6235 wakaba 1.79
6236     $Whatpm::HTML::Debug::cp_pass->('t109') if $Whatpm::HTML::Debug::cp_pass;
6237     BEGIN {
6238     $Whatpm::HTML::Debug::cp->{'t109'} = 1;
6239     }
6240    
6241 wakaba 1.68 $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
6242     ->set_user_data (manakai_has_reference =>
6243     $token->{attributes}->{charset}
6244     ->{has_reference});
6245     }
6246 wakaba 1.69 if ($token->{attributes}->{content}) {
6247 wakaba 1.79
6248     $Whatpm::HTML::Debug::cp_pass->('t110') if $Whatpm::HTML::Debug::cp_pass;
6249     BEGIN {
6250     $Whatpm::HTML::Debug::cp->{'t110'} = 1;
6251     }
6252    
6253 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
6254     ->set_user_data (manakai_has_reference =>
6255     $token->{attributes}->{content}
6256     ->{has_reference});
6257     }
6258 wakaba 1.54 }
6259 wakaba 1.34
6260 wakaba 1.54 pop @{$self->{open_elements}}
6261 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6262 wakaba 1.54 $token = $self->_get_next_token;
6263     redo B;
6264     } elsif ($token->{tag_name} eq 'title') {
6265 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6266 wakaba 1.79
6267     $Whatpm::HTML::Debug::cp_pass->('t111') if $Whatpm::HTML::Debug::cp_pass;
6268     BEGIN {
6269     $Whatpm::HTML::Debug::cp->{'t111'} = 1;
6270     }
6271    
6272 wakaba 1.54 ## As if </noscript>
6273     pop @{$self->{open_elements}};
6274     $self->{parse_error}-> (type => 'in noscript:title');
6275 wakaba 1.1
6276 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6277 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6278 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
6279 wakaba 1.79
6280     $Whatpm::HTML::Debug::cp_pass->('t112') if $Whatpm::HTML::Debug::cp_pass;
6281     BEGIN {
6282     $Whatpm::HTML::Debug::cp->{'t112'} = 1;
6283     }
6284    
6285 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6286     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6287 wakaba 1.79 } else {
6288    
6289     $Whatpm::HTML::Debug::cp_pass->('t113') if $Whatpm::HTML::Debug::cp_pass;
6290     BEGIN {
6291     $Whatpm::HTML::Debug::cp->{'t113'} = 1;
6292     }
6293    
6294 wakaba 1.54 }
6295    
6296     ## NOTE: There is a "as if in head" code clone.
6297     my $parent = defined $self->{head_element} ? $self->{head_element}
6298     : $self->{open_elements}->[-1]->[0];
6299     $parse_rcdata->(RCDATA_CONTENT_MODEL,
6300     sub { $parent->append_child ($_[0]) });
6301     pop @{$self->{open_elements}}
6302 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6303 wakaba 1.54 redo B;
6304     } elsif ($token->{tag_name} eq 'style') {
6305     ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and
6306 wakaba 1.56 ## insertion mode IN_HEAD_IM)
6307 wakaba 1.54 ## NOTE: There is a "as if in head" code clone.
6308 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6309 wakaba 1.79
6310     $Whatpm::HTML::Debug::cp_pass->('t114') if $Whatpm::HTML::Debug::cp_pass;
6311     BEGIN {
6312     $Whatpm::HTML::Debug::cp->{'t114'} = 1;
6313     }
6314    
6315 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6316     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6317 wakaba 1.79 } else {
6318    
6319     $Whatpm::HTML::Debug::cp_pass->('t115') if $Whatpm::HTML::Debug::cp_pass;
6320     BEGIN {
6321     $Whatpm::HTML::Debug::cp->{'t115'} = 1;
6322     }
6323    
6324 wakaba 1.54 }
6325     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert_to_current);
6326     pop @{$self->{open_elements}}
6327 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6328 wakaba 1.54 redo B;
6329     } elsif ($token->{tag_name} eq 'noscript') {
6330 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_IM) {
6331 wakaba 1.79
6332     $Whatpm::HTML::Debug::cp_pass->('t116') if $Whatpm::HTML::Debug::cp_pass;
6333     BEGIN {
6334     $Whatpm::HTML::Debug::cp->{'t116'} = 1;
6335     }
6336    
6337 wakaba 1.54 ## NOTE: and scripting is disalbed
6338    
6339 wakaba 1.1 {
6340     my $el;
6341    
6342     $el = $self->{document}->create_element_ns
6343     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6344    
6345     for my $attr_name (keys %{ $token->{attributes}}) {
6346     $el->set_attribute_ns (undef, [undef, $attr_name],
6347     $token->{attributes} ->{$attr_name}->{value});
6348     }
6349    
6350 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6351 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6352 wakaba 1.1 }
6353    
6354 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_NOSCRIPT_IM;
6355 wakaba 1.54 $token = $self->_get_next_token;
6356     redo B;
6357 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6358 wakaba 1.79
6359     $Whatpm::HTML::Debug::cp_pass->('t117') if $Whatpm::HTML::Debug::cp_pass;
6360     BEGIN {
6361     $Whatpm::HTML::Debug::cp->{'t117'} = 1;
6362     }
6363    
6364 wakaba 1.54 $self->{parse_error}-> (type => 'in noscript:noscript');
6365     ## Ignore the token
6366     $token = $self->_get_next_token;
6367     redo B;
6368     } else {
6369 wakaba 1.79
6370     $Whatpm::HTML::Debug::cp_pass->('t118') if $Whatpm::HTML::Debug::cp_pass;
6371     BEGIN {
6372     $Whatpm::HTML::Debug::cp->{'t118'} = 1;
6373     }
6374    
6375 wakaba 1.54 #
6376     }
6377     } elsif ($token->{tag_name} eq 'script') {
6378 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6379 wakaba 1.79
6380     $Whatpm::HTML::Debug::cp_pass->('t119') if $Whatpm::HTML::Debug::cp_pass;
6381     BEGIN {
6382     $Whatpm::HTML::Debug::cp->{'t119'} = 1;
6383     }
6384    
6385 wakaba 1.54 ## As if </noscript>
6386     pop @{$self->{open_elements}};
6387     $self->{parse_error}-> (type => 'in noscript:script');
6388    
6389 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6390 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6391 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
6392 wakaba 1.79
6393     $Whatpm::HTML::Debug::cp_pass->('t120') if $Whatpm::HTML::Debug::cp_pass;
6394     BEGIN {
6395     $Whatpm::HTML::Debug::cp->{'t120'} = 1;
6396     }
6397    
6398 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6399     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6400 wakaba 1.79 } else {
6401    
6402     $Whatpm::HTML::Debug::cp_pass->('t121') if $Whatpm::HTML::Debug::cp_pass;
6403     BEGIN {
6404     $Whatpm::HTML::Debug::cp->{'t121'} = 1;
6405     }
6406    
6407 wakaba 1.54 }
6408    
6409     ## NOTE: There is a "as if in head" code clone.
6410     $script_start_tag->($insert_to_current);
6411     pop @{$self->{open_elements}}
6412 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6413 wakaba 1.54 redo B;
6414     } elsif ($token->{tag_name} eq 'body' or
6415     $token->{tag_name} eq 'frameset') {
6416 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6417 wakaba 1.79
6418     $Whatpm::HTML::Debug::cp_pass->('t122') if $Whatpm::HTML::Debug::cp_pass;
6419     BEGIN {
6420     $Whatpm::HTML::Debug::cp->{'t122'} = 1;
6421     }
6422    
6423 wakaba 1.54 ## As if </noscript>
6424     pop @{$self->{open_elements}};
6425     $self->{parse_error}-> (type => 'in noscript:'.$token->{tag_name});
6426    
6427     ## Reprocess in the "in head" insertion mode...
6428     ## As if </head>
6429     pop @{$self->{open_elements}};
6430    
6431     ## Reprocess in the "after head" insertion mode...
6432 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6433 wakaba 1.79
6434     $Whatpm::HTML::Debug::cp_pass->('t124') if $Whatpm::HTML::Debug::cp_pass;
6435     BEGIN {
6436     $Whatpm::HTML::Debug::cp->{'t124'} = 1;
6437     }
6438    
6439 wakaba 1.54 pop @{$self->{open_elements}};
6440    
6441     ## Reprocess in the "after head" insertion mode...
6442 wakaba 1.79 } else {
6443    
6444     $Whatpm::HTML::Debug::cp_pass->('t125') if $Whatpm::HTML::Debug::cp_pass;
6445     BEGIN {
6446     $Whatpm::HTML::Debug::cp->{'t125'} = 1;
6447     }
6448    
6449 wakaba 1.54 }
6450    
6451     ## "after head" insertion mode
6452    
6453 wakaba 1.1 {
6454     my $el;
6455    
6456     $el = $self->{document}->create_element_ns
6457     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6458    
6459     for my $attr_name (keys %{ $token->{attributes}}) {
6460     $el->set_attribute_ns (undef, [undef, $attr_name],
6461     $token->{attributes} ->{$attr_name}->{value});
6462     }
6463    
6464 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6465 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6466 wakaba 1.1 }
6467    
6468 wakaba 1.56 if ($token->{tag_name} eq 'body') {
6469 wakaba 1.79
6470     $Whatpm::HTML::Debug::cp_pass->('t126') if $Whatpm::HTML::Debug::cp_pass;
6471     BEGIN {
6472     $Whatpm::HTML::Debug::cp->{'t126'} = 1;
6473     }
6474    
6475 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6476     } elsif ($token->{tag_name} eq 'frameset') {
6477 wakaba 1.79
6478     $Whatpm::HTML::Debug::cp_pass->('t127') if $Whatpm::HTML::Debug::cp_pass;
6479     BEGIN {
6480     $Whatpm::HTML::Debug::cp->{'t127'} = 1;
6481     }
6482    
6483 wakaba 1.56 $self->{insertion_mode} = IN_FRAMESET_IM;
6484     } else {
6485     die "$0: tag name: $self->{tag_name}";
6486     }
6487 wakaba 1.54 $token = $self->_get_next_token;
6488     redo B;
6489     } else {
6490 wakaba 1.79
6491     $Whatpm::HTML::Debug::cp_pass->('t128') if $Whatpm::HTML::Debug::cp_pass;
6492     BEGIN {
6493     $Whatpm::HTML::Debug::cp->{'t128'} = 1;
6494     }
6495    
6496 wakaba 1.54 #
6497 wakaba 1.8 }
6498 wakaba 1.54
6499 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6500 wakaba 1.79
6501     $Whatpm::HTML::Debug::cp_pass->('t129') if $Whatpm::HTML::Debug::cp_pass;
6502     BEGIN {
6503     $Whatpm::HTML::Debug::cp->{'t129'} = 1;
6504     }
6505    
6506 wakaba 1.54 ## As if </noscript>
6507     pop @{$self->{open_elements}};
6508     $self->{parse_error}-> (type => 'in noscript:/'.$token->{tag_name});
6509    
6510     ## Reprocess in the "in head" insertion mode...
6511     ## As if </head>
6512     pop @{$self->{open_elements}};
6513    
6514     ## Reprocess in the "after head" insertion mode...
6515 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6516 wakaba 1.79
6517     $Whatpm::HTML::Debug::cp_pass->('t130') if $Whatpm::HTML::Debug::cp_pass;
6518     BEGIN {
6519     $Whatpm::HTML::Debug::cp->{'t130'} = 1;
6520     }
6521    
6522 wakaba 1.54 ## As if </head>
6523     pop @{$self->{open_elements}};
6524    
6525     ## Reprocess in the "after head" insertion mode...
6526 wakaba 1.79 } else {
6527    
6528     $Whatpm::HTML::Debug::cp_pass->('t131') if $Whatpm::HTML::Debug::cp_pass;
6529     BEGIN {
6530     $Whatpm::HTML::Debug::cp->{'t131'} = 1;
6531     }
6532    
6533 wakaba 1.54 }
6534    
6535     ## "after head" insertion mode
6536     ## As if <body>
6537    
6538 wakaba 1.1 {
6539     my $el;
6540    
6541     $el = $self->{document}->create_element_ns
6542 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
6543 wakaba 1.1
6544 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6545     push @{$self->{open_elements}}, [$el, 'body'];
6546 wakaba 1.1 }
6547    
6548 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6549 wakaba 1.54 ## reprocess
6550     redo B;
6551 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
6552 wakaba 1.54 if ($token->{tag_name} eq 'head') {
6553 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6554 wakaba 1.79
6555     $Whatpm::HTML::Debug::cp_pass->('t132') if $Whatpm::HTML::Debug::cp_pass;
6556     BEGIN {
6557     $Whatpm::HTML::Debug::cp->{'t132'} = 1;
6558     }
6559    
6560 wakaba 1.54 ## As if <head>
6561    
6562     $self->{head_element} = $self->{document}->create_element_ns
6563     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6564    
6565     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6566     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6567    
6568     ## Reprocess in the "in head" insertion mode...
6569     pop @{$self->{open_elements}};
6570 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6571 wakaba 1.54 $token = $self->_get_next_token;
6572     redo B;
6573 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6574 wakaba 1.79
6575     $Whatpm::HTML::Debug::cp_pass->('t133') if $Whatpm::HTML::Debug::cp_pass;
6576     BEGIN {
6577     $Whatpm::HTML::Debug::cp->{'t133'} = 1;
6578     }
6579    
6580 wakaba 1.54 ## As if </noscript>
6581     pop @{$self->{open_elements}};
6582 wakaba 1.82 $self->{parse_error}-> (type => 'in noscript:/head');
6583 wakaba 1.54
6584     ## Reprocess in the "in head" insertion mode...
6585     pop @{$self->{open_elements}};
6586 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6587 wakaba 1.54 $token = $self->_get_next_token;
6588     redo B;
6589 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6590 wakaba 1.79
6591     $Whatpm::HTML::Debug::cp_pass->('t134') if $Whatpm::HTML::Debug::cp_pass;
6592     BEGIN {
6593     $Whatpm::HTML::Debug::cp->{'t134'} = 1;
6594     }
6595    
6596 wakaba 1.54 pop @{$self->{open_elements}};
6597 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6598 wakaba 1.54 $token = $self->_get_next_token;
6599     redo B;
6600     } else {
6601 wakaba 1.79
6602     $Whatpm::HTML::Debug::cp_pass->('t135') if $Whatpm::HTML::Debug::cp_pass;
6603     BEGIN {
6604     $Whatpm::HTML::Debug::cp->{'t135'} = 1;
6605     }
6606    
6607 wakaba 1.54 #
6608     }
6609     } elsif ($token->{tag_name} eq 'noscript') {
6610 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6611 wakaba 1.79
6612     $Whatpm::HTML::Debug::cp_pass->('t136') if $Whatpm::HTML::Debug::cp_pass;
6613     BEGIN {
6614     $Whatpm::HTML::Debug::cp->{'t136'} = 1;
6615     }
6616    
6617 wakaba 1.54 pop @{$self->{open_elements}};
6618 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6619 wakaba 1.54 $token = $self->_get_next_token;
6620     redo B;
6621 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6622 wakaba 1.79
6623     $Whatpm::HTML::Debug::cp_pass->('t137') if $Whatpm::HTML::Debug::cp_pass;
6624     BEGIN {
6625     $Whatpm::HTML::Debug::cp->{'t137'} = 1;
6626     }
6627    
6628 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:noscript');
6629     ## Ignore the token ## ISSUE: An issue in the spec.
6630     $token = $self->_get_next_token;
6631     redo B;
6632     } else {
6633 wakaba 1.79
6634     $Whatpm::HTML::Debug::cp_pass->('t138') if $Whatpm::HTML::Debug::cp_pass;
6635     BEGIN {
6636     $Whatpm::HTML::Debug::cp->{'t138'} = 1;
6637     }
6638    
6639 wakaba 1.54 #
6640     }
6641     } elsif ({
6642     body => 1, html => 1,
6643     }->{$token->{tag_name}}) {
6644 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6645 wakaba 1.79
6646     $Whatpm::HTML::Debug::cp_pass->('t139') if $Whatpm::HTML::Debug::cp_pass;
6647     BEGIN {
6648     $Whatpm::HTML::Debug::cp->{'t139'} = 1;
6649     }
6650    
6651 wakaba 1.54 ## As if <head>
6652    
6653     $self->{head_element} = $self->{document}->create_element_ns
6654     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6655    
6656     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6657     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6658    
6659 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6660 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6661 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6662 wakaba 1.79
6663     $Whatpm::HTML::Debug::cp_pass->('t140') if $Whatpm::HTML::Debug::cp_pass;
6664     BEGIN {
6665     $Whatpm::HTML::Debug::cp->{'t140'} = 1;
6666     }
6667    
6668 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6669     ## Ignore the token
6670     $token = $self->_get_next_token;
6671     redo B;
6672 wakaba 1.79 } else {
6673    
6674     $Whatpm::HTML::Debug::cp_pass->('t141') if $Whatpm::HTML::Debug::cp_pass;
6675     BEGIN {
6676     $Whatpm::HTML::Debug::cp->{'t141'} = 1;
6677     }
6678    
6679 wakaba 1.54 }
6680    
6681     #
6682     } elsif ({
6683     p => 1, br => 1,
6684     }->{$token->{tag_name}}) {
6685 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6686 wakaba 1.79
6687     $Whatpm::HTML::Debug::cp_pass->('t142') if $Whatpm::HTML::Debug::cp_pass;
6688     BEGIN {
6689     $Whatpm::HTML::Debug::cp->{'t142'} = 1;
6690     }
6691    
6692 wakaba 1.54 ## As if <head>
6693    
6694     $self->{head_element} = $self->{document}->create_element_ns
6695     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6696    
6697     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6698     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6699    
6700 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6701 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6702 wakaba 1.79 } else {
6703    
6704     $Whatpm::HTML::Debug::cp_pass->('t143') if $Whatpm::HTML::Debug::cp_pass;
6705     BEGIN {
6706     $Whatpm::HTML::Debug::cp->{'t143'} = 1;
6707     }
6708    
6709 wakaba 1.54 }
6710    
6711     #
6712     } else {
6713 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6714 wakaba 1.79
6715     $Whatpm::HTML::Debug::cp_pass->('t144') if $Whatpm::HTML::Debug::cp_pass;
6716     BEGIN {
6717     $Whatpm::HTML::Debug::cp->{'t144'} = 1;
6718     }
6719    
6720 wakaba 1.56 #
6721     } else {
6722 wakaba 1.79
6723     $Whatpm::HTML::Debug::cp_pass->('t145') if $Whatpm::HTML::Debug::cp_pass;
6724     BEGIN {
6725     $Whatpm::HTML::Debug::cp->{'t145'} = 1;
6726     }
6727    
6728 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6729     ## Ignore the token
6730     $token = $self->_get_next_token;
6731     redo B;
6732     }
6733     }
6734    
6735 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6736 wakaba 1.79
6737     $Whatpm::HTML::Debug::cp_pass->('t146') if $Whatpm::HTML::Debug::cp_pass;
6738     BEGIN {
6739     $Whatpm::HTML::Debug::cp->{'t146'} = 1;
6740     }
6741    
6742 wakaba 1.54 ## As if </noscript>
6743     pop @{$self->{open_elements}};
6744     $self->{parse_error}-> (type => 'in noscript:/'.$token->{tag_name});
6745    
6746     ## Reprocess in the "in head" insertion mode...
6747     ## As if </head>
6748     pop @{$self->{open_elements}};
6749    
6750     ## Reprocess in the "after head" insertion mode...
6751 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6752 wakaba 1.79
6753     $Whatpm::HTML::Debug::cp_pass->('t147') if $Whatpm::HTML::Debug::cp_pass;
6754     BEGIN {
6755     $Whatpm::HTML::Debug::cp->{'t147'} = 1;
6756     }
6757    
6758 wakaba 1.54 ## As if </head>
6759     pop @{$self->{open_elements}};
6760    
6761     ## Reprocess in the "after head" insertion mode...
6762 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6763 wakaba 1.82 ## ISSUE: This case cannot be reached?
6764 wakaba 1.79
6765     $Whatpm::HTML::Debug::cp_pass->('t148') if $Whatpm::HTML::Debug::cp_pass;
6766     BEGIN {
6767     $Whatpm::HTML::Debug::cp->{'t148'} = 1;
6768     }
6769    
6770 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6771     ## Ignore the token ## ISSUE: An issue in the spec.
6772     $token = $self->_get_next_token;
6773     redo B;
6774 wakaba 1.79 } else {
6775    
6776     $Whatpm::HTML::Debug::cp_pass->('t149') if $Whatpm::HTML::Debug::cp_pass;
6777     BEGIN {
6778     $Whatpm::HTML::Debug::cp->{'t149'} = 1;
6779     }
6780    
6781 wakaba 1.8 }
6782 wakaba 1.54
6783     ## "after head" insertion mode
6784     ## As if <body>
6785    
6786 wakaba 1.1 {
6787     my $el;
6788    
6789     $el = $self->{document}->create_element_ns
6790 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
6791 wakaba 1.1
6792 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6793     push @{$self->{open_elements}}, [$el, 'body'];
6794 wakaba 1.1 }
6795    
6796 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6797 wakaba 1.54 ## reprocess
6798     redo B;
6799     } else {
6800     die "$0: $token->{type}: Unknown token type";
6801 wakaba 1.1 }
6802 wakaba 1.54
6803     ## ISSUE: An issue in the spec.
6804 wakaba 1.58 } elsif ($self->{insertion_mode} & BODY_IMS) {
6805 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
6806 wakaba 1.79
6807     $Whatpm::HTML::Debug::cp_pass->('t150') if $Whatpm::HTML::Debug::cp_pass;
6808     BEGIN {
6809     $Whatpm::HTML::Debug::cp->{'t150'} = 1;
6810     }
6811    
6812 wakaba 1.54 ## NOTE: There is a code clone of "character in body".
6813     $reconstruct_active_formatting_elements->($insert_to_current);
6814    
6815     $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
6816    
6817     $token = $self->_get_next_token;
6818     redo B;
6819 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
6820 wakaba 1.54 if ({
6821     caption => 1, col => 1, colgroup => 1, tbody => 1,
6822     td => 1, tfoot => 1, th => 1, thead => 1, tr => 1,
6823     }->{$token->{tag_name}}) {
6824 wakaba 1.56 if ($self->{insertion_mode} == IN_CELL_IM) {
6825 wakaba 1.54 ## have an element in table scope
6826     my $tn;
6827     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6828     my $node = $self->{open_elements}->[$_];
6829     if ($node->[1] eq 'td' or $node->[1] eq 'th') {
6830 wakaba 1.79
6831     $Whatpm::HTML::Debug::cp_pass->('t151') if $Whatpm::HTML::Debug::cp_pass;
6832     BEGIN {
6833     $Whatpm::HTML::Debug::cp->{'t151'} = 1;
6834     }
6835    
6836 wakaba 1.54 $tn = $node->[1];
6837     last INSCOPE;
6838     } elsif ({
6839     table => 1, html => 1,
6840     }->{$node->[1]}) {
6841 wakaba 1.79
6842     $Whatpm::HTML::Debug::cp_pass->('t152') if $Whatpm::HTML::Debug::cp_pass;
6843     BEGIN {
6844     $Whatpm::HTML::Debug::cp->{'t152'} = 1;
6845     }
6846    
6847 wakaba 1.54 last INSCOPE;
6848     }
6849     } # INSCOPE
6850     unless (defined $tn) {
6851 wakaba 1.79
6852     $Whatpm::HTML::Debug::cp_pass->('t153') if $Whatpm::HTML::Debug::cp_pass;
6853     BEGIN {
6854     $Whatpm::HTML::Debug::cp->{'t153'} = 1;
6855     }
6856    
6857 wakaba 1.82 ## TODO: This error type is wrong.
6858 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6859     ## Ignore the token
6860     $token = $self->_get_next_token;
6861     redo B;
6862     }
6863    
6864 wakaba 1.79
6865     $Whatpm::HTML::Debug::cp_pass->('t154') if $Whatpm::HTML::Debug::cp_pass;
6866     BEGIN {
6867     $Whatpm::HTML::Debug::cp->{'t154'} = 1;
6868     }
6869    
6870 wakaba 1.54 ## Close the cell
6871     unshift @{$self->{token}}, $token; # <?>
6872 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => $tn};
6873 wakaba 1.54 redo B;
6874 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {
6875 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:caption');
6876    
6877     ## As if </caption>
6878     ## have a table element in table scope
6879     my $i;
6880     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6881     my $node = $self->{open_elements}->[$_];
6882     if ($node->[1] eq 'caption') {
6883 wakaba 1.79
6884     $Whatpm::HTML::Debug::cp_pass->('t155') if $Whatpm::HTML::Debug::cp_pass;
6885     BEGIN {
6886     $Whatpm::HTML::Debug::cp->{'t155'} = 1;
6887     }
6888    
6889 wakaba 1.54 $i = $_;
6890     last INSCOPE;
6891     } elsif ({
6892     table => 1, html => 1,
6893     }->{$node->[1]}) {
6894 wakaba 1.79
6895     $Whatpm::HTML::Debug::cp_pass->('t156') if $Whatpm::HTML::Debug::cp_pass;
6896     BEGIN {
6897     $Whatpm::HTML::Debug::cp->{'t156'} = 1;
6898     }
6899    
6900 wakaba 1.54 last INSCOPE;
6901     }
6902     } # INSCOPE
6903     unless (defined $i) {
6904 wakaba 1.79
6905     $Whatpm::HTML::Debug::cp_pass->('t157') if $Whatpm::HTML::Debug::cp_pass;
6906     BEGIN {
6907     $Whatpm::HTML::Debug::cp->{'t157'} = 1;
6908     }
6909    
6910 wakaba 1.83 ## TODO: this type is wrong.
6911 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:caption');
6912     ## Ignore the token
6913     $token = $self->_get_next_token;
6914     redo B;
6915     }
6916    
6917     ## generate implied end tags
6918 wakaba 1.86 while ({
6919     dd => 1, dt => 1, li => 1, p => 1,
6920     }->{$self->{open_elements}->[-1]->[1]}) {
6921 wakaba 1.79
6922     $Whatpm::HTML::Debug::cp_pass->('t158') if $Whatpm::HTML::Debug::cp_pass;
6923     BEGIN {
6924     $Whatpm::HTML::Debug::cp->{'t158'} = 1;
6925     }
6926    
6927 wakaba 1.86 pop @{$self->{open_elements}};
6928 wakaba 1.54 }
6929    
6930     if ($self->{open_elements}->[-1]->[1] ne 'caption') {
6931 wakaba 1.79
6932     $Whatpm::HTML::Debug::cp_pass->('t159') if $Whatpm::HTML::Debug::cp_pass;
6933     BEGIN {
6934     $Whatpm::HTML::Debug::cp->{'t159'} = 1;
6935     }
6936    
6937 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
6938 wakaba 1.79 } else {
6939    
6940     $Whatpm::HTML::Debug::cp_pass->('t160') if $Whatpm::HTML::Debug::cp_pass;
6941     BEGIN {
6942     $Whatpm::HTML::Debug::cp->{'t160'} = 1;
6943     }
6944    
6945 wakaba 1.54 }
6946    
6947     splice @{$self->{open_elements}}, $i;
6948    
6949     $clear_up_to_marker->();
6950    
6951 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
6952 wakaba 1.54
6953     ## reprocess
6954     redo B;
6955     } else {
6956 wakaba 1.79
6957     $Whatpm::HTML::Debug::cp_pass->('t161') if $Whatpm::HTML::Debug::cp_pass;
6958     BEGIN {
6959     $Whatpm::HTML::Debug::cp->{'t161'} = 1;
6960     }
6961    
6962 wakaba 1.54 #
6963     }
6964     } else {
6965 wakaba 1.79
6966     $Whatpm::HTML::Debug::cp_pass->('t162') if $Whatpm::HTML::Debug::cp_pass;
6967     BEGIN {
6968     $Whatpm::HTML::Debug::cp->{'t162'} = 1;
6969     }
6970    
6971 wakaba 1.54 #
6972     }
6973 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
6974 wakaba 1.54 if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') {
6975 wakaba 1.56 if ($self->{insertion_mode} == IN_CELL_IM) {
6976 wakaba 1.54 ## have an element in table scope
6977     my $i;
6978     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6979     my $node = $self->{open_elements}->[$_];
6980     if ($node->[1] eq $token->{tag_name}) {
6981 wakaba 1.79
6982     $Whatpm::HTML::Debug::cp_pass->('t163') if $Whatpm::HTML::Debug::cp_pass;
6983     BEGIN {
6984     $Whatpm::HTML::Debug::cp->{'t163'} = 1;
6985     }
6986    
6987 wakaba 1.54 $i = $_;
6988     last INSCOPE;
6989     } elsif ({
6990     table => 1, html => 1,
6991     }->{$node->[1]}) {
6992 wakaba 1.79
6993     $Whatpm::HTML::Debug::cp_pass->('t164') if $Whatpm::HTML::Debug::cp_pass;
6994     BEGIN {
6995     $Whatpm::HTML::Debug::cp->{'t164'} = 1;
6996     }
6997    
6998 wakaba 1.54 last INSCOPE;
6999     }
7000     } # INSCOPE
7001     unless (defined $i) {
7002 wakaba 1.79
7003     $Whatpm::HTML::Debug::cp_pass->('t165') if $Whatpm::HTML::Debug::cp_pass;
7004     BEGIN {
7005     $Whatpm::HTML::Debug::cp->{'t165'} = 1;
7006     }
7007    
7008 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7009     ## Ignore the token
7010     $token = $self->_get_next_token;
7011     redo B;
7012     }
7013    
7014     ## generate implied end tags
7015 wakaba 1.86 while ({
7016     dd => 1, dt => 1, li => 1, p => 1,
7017     }->{$self->{open_elements}->[-1]->[1]}) {
7018 wakaba 1.79
7019     $Whatpm::HTML::Debug::cp_pass->('t166') if $Whatpm::HTML::Debug::cp_pass;
7020     BEGIN {
7021     $Whatpm::HTML::Debug::cp->{'t166'} = 1;
7022     }
7023    
7024 wakaba 1.86 pop @{$self->{open_elements}};
7025 wakaba 1.54 }
7026 wakaba 1.86
7027 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
7028 wakaba 1.79
7029     $Whatpm::HTML::Debug::cp_pass->('t167') if $Whatpm::HTML::Debug::cp_pass;
7030     BEGIN {
7031     $Whatpm::HTML::Debug::cp->{'t167'} = 1;
7032     }
7033    
7034 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7035 wakaba 1.79 } else {
7036    
7037     $Whatpm::HTML::Debug::cp_pass->('t168') if $Whatpm::HTML::Debug::cp_pass;
7038     BEGIN {
7039     $Whatpm::HTML::Debug::cp->{'t168'} = 1;
7040     }
7041    
7042 wakaba 1.54 }
7043    
7044     splice @{$self->{open_elements}}, $i;
7045    
7046     $clear_up_to_marker->();
7047    
7048 wakaba 1.56 $self->{insertion_mode} = IN_ROW_IM;
7049 wakaba 1.54
7050     $token = $self->_get_next_token;
7051     redo B;
7052 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {
7053 wakaba 1.79
7054     $Whatpm::HTML::Debug::cp_pass->('t169') if $Whatpm::HTML::Debug::cp_pass;
7055     BEGIN {
7056     $Whatpm::HTML::Debug::cp->{'t169'} = 1;
7057     }
7058    
7059 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7060     ## Ignore the token
7061     $token = $self->_get_next_token;
7062     redo B;
7063     } else {
7064 wakaba 1.79
7065     $Whatpm::HTML::Debug::cp_pass->('t170') if $Whatpm::HTML::Debug::cp_pass;
7066     BEGIN {
7067     $Whatpm::HTML::Debug::cp->{'t170'} = 1;
7068     }
7069    
7070 wakaba 1.54 #
7071     }
7072     } elsif ($token->{tag_name} eq 'caption') {
7073 wakaba 1.56 if ($self->{insertion_mode} == IN_CAPTION_IM) {
7074 wakaba 1.54 ## have a table element in table scope
7075     my $i;
7076     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7077     my $node = $self->{open_elements}->[$_];
7078     if ($node->[1] eq $token->{tag_name}) {
7079 wakaba 1.79
7080     $Whatpm::HTML::Debug::cp_pass->('t171') if $Whatpm::HTML::Debug::cp_pass;
7081     BEGIN {
7082     $Whatpm::HTML::Debug::cp->{'t171'} = 1;
7083     }
7084    
7085 wakaba 1.54 $i = $_;
7086     last INSCOPE;
7087     } elsif ({
7088     table => 1, html => 1,
7089     }->{$node->[1]}) {
7090 wakaba 1.79
7091     $Whatpm::HTML::Debug::cp_pass->('t172') if $Whatpm::HTML::Debug::cp_pass;
7092     BEGIN {
7093     $Whatpm::HTML::Debug::cp->{'t172'} = 1;
7094     }
7095    
7096 wakaba 1.54 last INSCOPE;
7097     }
7098     } # INSCOPE
7099     unless (defined $i) {
7100 wakaba 1.79
7101     $Whatpm::HTML::Debug::cp_pass->('t173') if $Whatpm::HTML::Debug::cp_pass;
7102     BEGIN {
7103     $Whatpm::HTML::Debug::cp->{'t173'} = 1;
7104     }
7105    
7106 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7107     ## Ignore the token
7108     $token = $self->_get_next_token;
7109     redo B;
7110     }
7111    
7112     ## generate implied end tags
7113 wakaba 1.86 while ({
7114     dd => 1, dt => 1, li => 1, p => 1,
7115     }->{$self->{open_elements}->[-1]->[1]}) {
7116 wakaba 1.79
7117     $Whatpm::HTML::Debug::cp_pass->('t174') if $Whatpm::HTML::Debug::cp_pass;
7118     BEGIN {
7119     $Whatpm::HTML::Debug::cp->{'t174'} = 1;
7120     }
7121    
7122 wakaba 1.86 pop @{$self->{open_elements}};
7123 wakaba 1.54 }
7124    
7125     if ($self->{open_elements}->[-1]->[1] ne 'caption') {
7126 wakaba 1.79
7127     $Whatpm::HTML::Debug::cp_pass->('t175') if $Whatpm::HTML::Debug::cp_pass;
7128     BEGIN {
7129     $Whatpm::HTML::Debug::cp->{'t175'} = 1;
7130     }
7131    
7132 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7133 wakaba 1.79 } else {
7134    
7135     $Whatpm::HTML::Debug::cp_pass->('t176') if $Whatpm::HTML::Debug::cp_pass;
7136     BEGIN {
7137     $Whatpm::HTML::Debug::cp->{'t176'} = 1;
7138     }
7139    
7140 wakaba 1.54 }
7141    
7142     splice @{$self->{open_elements}}, $i;
7143    
7144     $clear_up_to_marker->();
7145    
7146 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7147 wakaba 1.54
7148     $token = $self->_get_next_token;
7149     redo B;
7150 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CELL_IM) {
7151 wakaba 1.79
7152     $Whatpm::HTML::Debug::cp_pass->('t177') if $Whatpm::HTML::Debug::cp_pass;
7153     BEGIN {
7154     $Whatpm::HTML::Debug::cp->{'t177'} = 1;
7155     }
7156    
7157 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7158     ## Ignore the token
7159     $token = $self->_get_next_token;
7160     redo B;
7161     } else {
7162 wakaba 1.79
7163     $Whatpm::HTML::Debug::cp_pass->('t178') if $Whatpm::HTML::Debug::cp_pass;
7164     BEGIN {
7165     $Whatpm::HTML::Debug::cp->{'t178'} = 1;
7166     }
7167    
7168 wakaba 1.54 #
7169 wakaba 1.1 }
7170 wakaba 1.54 } elsif ({
7171     table => 1, tbody => 1, tfoot => 1,
7172     thead => 1, tr => 1,
7173     }->{$token->{tag_name}} and
7174 wakaba 1.56 $self->{insertion_mode} == IN_CELL_IM) {
7175 wakaba 1.54 ## have an element in table scope
7176     my $i;
7177     my $tn;
7178     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7179     my $node = $self->{open_elements}->[$_];
7180     if ($node->[1] eq $token->{tag_name}) {
7181 wakaba 1.79
7182     $Whatpm::HTML::Debug::cp_pass->('t179') if $Whatpm::HTML::Debug::cp_pass;
7183     BEGIN {
7184     $Whatpm::HTML::Debug::cp->{'t179'} = 1;
7185     }
7186    
7187 wakaba 1.54 $i = $_;
7188     last INSCOPE;
7189     } elsif ($node->[1] eq 'td' or $node->[1] eq 'th') {
7190 wakaba 1.79
7191     $Whatpm::HTML::Debug::cp_pass->('t180') if $Whatpm::HTML::Debug::cp_pass;
7192     BEGIN {
7193     $Whatpm::HTML::Debug::cp->{'t180'} = 1;
7194     }
7195    
7196 wakaba 1.54 $tn = $node->[1];
7197     ## NOTE: There is exactly one |td| or |th| element
7198     ## in scope in the stack of open elements by definition.
7199     } elsif ({
7200     table => 1, html => 1,
7201     }->{$node->[1]}) {
7202 wakaba 1.79
7203     $Whatpm::HTML::Debug::cp_pass->('t181') if $Whatpm::HTML::Debug::cp_pass;
7204     BEGIN {
7205     $Whatpm::HTML::Debug::cp->{'t181'} = 1;
7206     }
7207    
7208 wakaba 1.54 last INSCOPE;
7209     }
7210     } # INSCOPE
7211     unless (defined $i) {
7212 wakaba 1.79
7213     $Whatpm::HTML::Debug::cp_pass->('t182') if $Whatpm::HTML::Debug::cp_pass;
7214     BEGIN {
7215     $Whatpm::HTML::Debug::cp->{'t182'} = 1;
7216     }
7217    
7218 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7219     ## Ignore the token
7220     $token = $self->_get_next_token;
7221     redo B;
7222 wakaba 1.79 } else {
7223    
7224     $Whatpm::HTML::Debug::cp_pass->('t183') if $Whatpm::HTML::Debug::cp_pass;
7225     BEGIN {
7226     $Whatpm::HTML::Debug::cp->{'t183'} = 1;
7227     }
7228    
7229 wakaba 1.1 }
7230    
7231 wakaba 1.54 ## Close the cell
7232     unshift @{$self->{token}}, $token; # </?>
7233 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => $tn};
7234 wakaba 1.54 redo B;
7235     } elsif ($token->{tag_name} eq 'table' and
7236 wakaba 1.56 $self->{insertion_mode} == IN_CAPTION_IM) {
7237 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:caption');
7238 wakaba 1.31
7239 wakaba 1.54 ## As if </caption>
7240     ## have a table element in table scope
7241     my $i;
7242     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7243     my $node = $self->{open_elements}->[$_];
7244     if ($node->[1] eq 'caption') {
7245 wakaba 1.79
7246     $Whatpm::HTML::Debug::cp_pass->('t184') if $Whatpm::HTML::Debug::cp_pass;
7247     BEGIN {
7248     $Whatpm::HTML::Debug::cp->{'t184'} = 1;
7249     }
7250    
7251 wakaba 1.54 $i = $_;
7252     last INSCOPE;
7253     } elsif ({
7254     table => 1, html => 1,
7255     }->{$node->[1]}) {
7256 wakaba 1.79
7257     $Whatpm::HTML::Debug::cp_pass->('t185') if $Whatpm::HTML::Debug::cp_pass;
7258     BEGIN {
7259     $Whatpm::HTML::Debug::cp->{'t185'} = 1;
7260     }
7261    
7262 wakaba 1.54 last INSCOPE;
7263     }
7264     } # INSCOPE
7265     unless (defined $i) {
7266 wakaba 1.79
7267     $Whatpm::HTML::Debug::cp_pass->('t186') if $Whatpm::HTML::Debug::cp_pass;
7268     BEGIN {
7269     $Whatpm::HTML::Debug::cp->{'t186'} = 1;
7270     }
7271    
7272 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:caption');
7273     ## Ignore the token
7274     $token = $self->_get_next_token;
7275     redo B;
7276     }
7277    
7278     ## generate implied end tags
7279 wakaba 1.86 while ({
7280     dd => 1, dt => 1, li => 1, p => 1,
7281     }->{$self->{open_elements}->[-1]->[1]}) {
7282 wakaba 1.79
7283     $Whatpm::HTML::Debug::cp_pass->('t187') if $Whatpm::HTML::Debug::cp_pass;
7284     BEGIN {
7285     $Whatpm::HTML::Debug::cp->{'t187'} = 1;
7286     }
7287    
7288 wakaba 1.86 pop @{$self->{open_elements}};
7289 wakaba 1.54 }
7290 wakaba 1.20
7291 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] ne 'caption') {
7292 wakaba 1.79
7293     $Whatpm::HTML::Debug::cp_pass->('t188') if $Whatpm::HTML::Debug::cp_pass;
7294     BEGIN {
7295     $Whatpm::HTML::Debug::cp->{'t188'} = 1;
7296     }
7297    
7298 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7299 wakaba 1.79 } else {
7300    
7301     $Whatpm::HTML::Debug::cp_pass->('t189') if $Whatpm::HTML::Debug::cp_pass;
7302     BEGIN {
7303     $Whatpm::HTML::Debug::cp->{'t189'} = 1;
7304     }
7305    
7306 wakaba 1.54 }
7307 wakaba 1.12
7308 wakaba 1.54 splice @{$self->{open_elements}}, $i;
7309 wakaba 1.31
7310 wakaba 1.54 $clear_up_to_marker->();
7311 wakaba 1.1
7312 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7313 wakaba 1.3
7314 wakaba 1.54 ## reprocess
7315     redo B;
7316     } elsif ({
7317     body => 1, col => 1, colgroup => 1, html => 1,
7318     }->{$token->{tag_name}}) {
7319 wakaba 1.58 if ($self->{insertion_mode} & BODY_TABLE_IMS) {
7320 wakaba 1.79
7321     $Whatpm::HTML::Debug::cp_pass->('t190') if $Whatpm::HTML::Debug::cp_pass;
7322     BEGIN {
7323     $Whatpm::HTML::Debug::cp->{'t190'} = 1;
7324     }
7325    
7326 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7327     ## Ignore the token
7328     $token = $self->_get_next_token;
7329     redo B;
7330     } else {
7331 wakaba 1.79
7332     $Whatpm::HTML::Debug::cp_pass->('t191') if $Whatpm::HTML::Debug::cp_pass;
7333     BEGIN {
7334     $Whatpm::HTML::Debug::cp->{'t191'} = 1;
7335     }
7336    
7337 wakaba 1.54 #
7338     }
7339     } elsif ({
7340     tbody => 1, tfoot => 1,
7341     thead => 1, tr => 1,
7342     }->{$token->{tag_name}} and
7343 wakaba 1.56 $self->{insertion_mode} == IN_CAPTION_IM) {
7344 wakaba 1.79
7345     $Whatpm::HTML::Debug::cp_pass->('t192') if $Whatpm::HTML::Debug::cp_pass;
7346     BEGIN {
7347     $Whatpm::HTML::Debug::cp->{'t192'} = 1;
7348     }
7349    
7350 wakaba 1.25 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7351 wakaba 1.1 ## Ignore the token
7352     $token = $self->_get_next_token;
7353 wakaba 1.54 redo B;
7354     } else {
7355 wakaba 1.79
7356     $Whatpm::HTML::Debug::cp_pass->('t193') if $Whatpm::HTML::Debug::cp_pass;
7357     BEGIN {
7358     $Whatpm::HTML::Debug::cp->{'t193'} = 1;
7359     }
7360    
7361 wakaba 1.54 #
7362 wakaba 1.1 }
7363 wakaba 1.54 } else {
7364     die "$0: $token->{type}: Unknown token type";
7365 wakaba 1.1 }
7366    
7367 wakaba 1.54 $insert = $insert_to_current;
7368     #
7369 wakaba 1.58 } elsif ($self->{insertion_mode} & TABLE_IMS) {
7370 wakaba 1.60 if ($token->{type} == CHARACTER_TOKEN) {
7371 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
7372     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
7373    
7374     unless (length $token->{data}) {
7375 wakaba 1.79
7376     $Whatpm::HTML::Debug::cp_pass->('t194') if $Whatpm::HTML::Debug::cp_pass;
7377     BEGIN {
7378     $Whatpm::HTML::Debug::cp->{'t194'} = 1;
7379     }
7380    
7381 wakaba 1.54 $token = $self->_get_next_token;
7382     redo B;
7383 wakaba 1.79 } else {
7384    
7385     $Whatpm::HTML::Debug::cp_pass->('t195') if $Whatpm::HTML::Debug::cp_pass;
7386     BEGIN {
7387     $Whatpm::HTML::Debug::cp->{'t195'} = 1;
7388     }
7389    
7390 wakaba 1.54 }
7391     }
7392 wakaba 1.1
7393 wakaba 1.54 $self->{parse_error}-> (type => 'in table:#character');
7394 wakaba 1.1
7395 wakaba 1.54 ## As if in body, but insert into foster parent element
7396     ## ISSUE: Spec says that "whenever a node would be inserted
7397     ## into the current node" while characters might not be
7398     ## result in a new Text node.
7399     $reconstruct_active_formatting_elements->($insert_to_foster);
7400    
7401     if ({
7402     table => 1, tbody => 1, tfoot => 1,
7403     thead => 1, tr => 1,
7404     }->{$self->{open_elements}->[-1]->[1]}) {
7405     # MUST
7406     my $foster_parent_element;
7407     my $next_sibling;
7408     my $prev_sibling;
7409     OE: for (reverse 0..$#{$self->{open_elements}}) {
7410     if ($self->{open_elements}->[$_]->[1] eq 'table') {
7411     my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
7412     if (defined $parent and $parent->node_type == 1) {
7413 wakaba 1.79
7414     $Whatpm::HTML::Debug::cp_pass->('t196') if $Whatpm::HTML::Debug::cp_pass;
7415     BEGIN {
7416     $Whatpm::HTML::Debug::cp->{'t196'} = 1;
7417     }
7418    
7419 wakaba 1.54 $foster_parent_element = $parent;
7420     $next_sibling = $self->{open_elements}->[$_]->[0];
7421     $prev_sibling = $next_sibling->previous_sibling;
7422     } else {
7423 wakaba 1.79
7424     $Whatpm::HTML::Debug::cp_pass->('t197') if $Whatpm::HTML::Debug::cp_pass;
7425     BEGIN {
7426     $Whatpm::HTML::Debug::cp->{'t197'} = 1;
7427     }
7428    
7429 wakaba 1.54 $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
7430     $prev_sibling = $foster_parent_element->last_child;
7431     }
7432     last OE;
7433     }
7434     } # OE
7435     $foster_parent_element = $self->{open_elements}->[0]->[0] and
7436     $prev_sibling = $foster_parent_element->last_child
7437     unless defined $foster_parent_element;
7438     if (defined $prev_sibling and
7439     $prev_sibling->node_type == 3) {
7440 wakaba 1.79
7441     $Whatpm::HTML::Debug::cp_pass->('t198') if $Whatpm::HTML::Debug::cp_pass;
7442     BEGIN {
7443     $Whatpm::HTML::Debug::cp->{'t198'} = 1;
7444     }
7445    
7446 wakaba 1.54 $prev_sibling->manakai_append_text ($token->{data});
7447     } else {
7448 wakaba 1.79
7449     $Whatpm::HTML::Debug::cp_pass->('t199') if $Whatpm::HTML::Debug::cp_pass;
7450     BEGIN {
7451     $Whatpm::HTML::Debug::cp->{'t199'} = 1;
7452     }
7453    
7454 wakaba 1.54 $foster_parent_element->insert_before
7455     ($self->{document}->create_text_node ($token->{data}),
7456     $next_sibling);
7457     }
7458     } else {
7459 wakaba 1.79
7460     $Whatpm::HTML::Debug::cp_pass->('t200') if $Whatpm::HTML::Debug::cp_pass;
7461     BEGIN {
7462     $Whatpm::HTML::Debug::cp->{'t200'} = 1;
7463     }
7464    
7465 wakaba 1.54 $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
7466     }
7467    
7468 wakaba 1.52 $token = $self->_get_next_token;
7469 wakaba 1.1 redo B;
7470 wakaba 1.60 } elsif ($token->{type} == START_TAG_TOKEN) {
7471 wakaba 1.54 if ({
7472 wakaba 1.56 tr => ($self->{insertion_mode} != IN_ROW_IM),
7473 wakaba 1.54 th => 1, td => 1,
7474     }->{$token->{tag_name}}) {
7475 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_IM) {
7476 wakaba 1.54 ## Clear back to table context
7477     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7478     $self->{open_elements}->[-1]->[1] ne 'html') {
7479 wakaba 1.79
7480     $Whatpm::HTML::Debug::cp_pass->('t201') if $Whatpm::HTML::Debug::cp_pass;
7481     BEGIN {
7482     $Whatpm::HTML::Debug::cp->{'t201'} = 1;
7483     }
7484    
7485 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7486     pop @{$self->{open_elements}};
7487     }
7488    
7489    
7490     {
7491     my $el;
7492    
7493     $el = $self->{document}->create_element_ns
7494     (q<http://www.w3.org/1999/xhtml>, [undef, 'tbody']);
7495    
7496     $self->{open_elements}->[-1]->[0]->append_child ($el);
7497     push @{$self->{open_elements}}, [$el, 'tbody'];
7498     }
7499    
7500 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
7501 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
7502     }
7503    
7504 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
7505 wakaba 1.54 unless ($token->{tag_name} eq 'tr') {
7506 wakaba 1.79
7507     $Whatpm::HTML::Debug::cp_pass->('t202') if $Whatpm::HTML::Debug::cp_pass;
7508     BEGIN {
7509     $Whatpm::HTML::Debug::cp->{'t202'} = 1;
7510     }
7511    
7512 wakaba 1.54 $self->{parse_error}-> (type => 'missing start tag:tr');
7513     }
7514    
7515     ## Clear back to table body context
7516     while (not {
7517     tbody => 1, tfoot => 1, thead => 1, html => 1,
7518     }->{$self->{open_elements}->[-1]->[1]}) {
7519 wakaba 1.79
7520     $Whatpm::HTML::Debug::cp_pass->('t203') if $Whatpm::HTML::Debug::cp_pass;
7521     BEGIN {
7522     $Whatpm::HTML::Debug::cp->{'t203'} = 1;
7523     }
7524    
7525 wakaba 1.83 ## ISSUE: Can this case be reached?
7526 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7527     pop @{$self->{open_elements}};
7528     }
7529    
7530 wakaba 1.56 $self->{insertion_mode} = IN_ROW_IM;
7531 wakaba 1.54 if ($token->{tag_name} eq 'tr') {
7532    
7533 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t204') if $Whatpm::HTML::Debug::cp_pass;
7534     BEGIN {
7535     $Whatpm::HTML::Debug::cp->{'t204'} = 1;
7536     }
7537    
7538    
7539 wakaba 1.54 {
7540     my $el;
7541    
7542     $el = $self->{document}->create_element_ns
7543     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7544    
7545     for my $attr_name (keys %{ $token->{attributes}}) {
7546     $el->set_attribute_ns (undef, [undef, $attr_name],
7547     $token->{attributes} ->{$attr_name}->{value});
7548 wakaba 1.1 }
7549 wakaba 1.54
7550     $self->{open_elements}->[-1]->[0]->append_child ($el);
7551     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7552     }
7553    
7554     $token = $self->_get_next_token;
7555     redo B;
7556     } else {
7557    
7558 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t205') if $Whatpm::HTML::Debug::cp_pass;
7559     BEGIN {
7560     $Whatpm::HTML::Debug::cp->{'t205'} = 1;
7561     }
7562    
7563    
7564 wakaba 1.54 {
7565     my $el;
7566    
7567     $el = $self->{document}->create_element_ns
7568     (q<http://www.w3.org/1999/xhtml>, [undef, 'tr']);
7569    
7570     $self->{open_elements}->[-1]->[0]->append_child ($el);
7571     push @{$self->{open_elements}}, [$el, 'tr'];
7572     }
7573    
7574     ## reprocess in the "in row" insertion mode
7575     }
7576 wakaba 1.79 } else {
7577    
7578     $Whatpm::HTML::Debug::cp_pass->('t206') if $Whatpm::HTML::Debug::cp_pass;
7579     BEGIN {
7580     $Whatpm::HTML::Debug::cp->{'t206'} = 1;
7581     }
7582    
7583 wakaba 1.54 }
7584 wakaba 1.52
7585 wakaba 1.54 ## Clear back to table row context
7586     while (not {
7587     tr => 1, html => 1,
7588     }->{$self->{open_elements}->[-1]->[1]}) {
7589 wakaba 1.79
7590     $Whatpm::HTML::Debug::cp_pass->('t207') if $Whatpm::HTML::Debug::cp_pass;
7591     BEGIN {
7592     $Whatpm::HTML::Debug::cp->{'t207'} = 1;
7593     }
7594    
7595 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7596     pop @{$self->{open_elements}};
7597     }
7598    
7599    
7600     {
7601     my $el;
7602    
7603     $el = $self->{document}->create_element_ns
7604     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7605 wakaba 1.1
7606 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
7607     $el->set_attribute_ns (undef, [undef, $attr_name],
7608     $token->{attributes} ->{$attr_name}->{value});
7609     }
7610    
7611     $self->{open_elements}->[-1]->[0]->append_child ($el);
7612     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7613     }
7614    
7615 wakaba 1.56 $self->{insertion_mode} = IN_CELL_IM;
7616 wakaba 1.54
7617     push @$active_formatting_elements, ['#marker', ''];
7618    
7619     $token = $self->_get_next_token;
7620     redo B;
7621     } elsif ({
7622     caption => 1, col => 1, colgroup => 1,
7623     tbody => 1, tfoot => 1, thead => 1,
7624 wakaba 1.56 tr => 1, # $self->{insertion_mode} == IN_ROW_IM
7625 wakaba 1.54 }->{$token->{tag_name}}) {
7626 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
7627 wakaba 1.54 ## As if </tr>
7628     ## have an element in table scope
7629     my $i;
7630     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7631     my $node = $self->{open_elements}->[$_];
7632     if ($node->[1] eq 'tr') {
7633 wakaba 1.79
7634     $Whatpm::HTML::Debug::cp_pass->('t208') if $Whatpm::HTML::Debug::cp_pass;
7635     BEGIN {
7636     $Whatpm::HTML::Debug::cp->{'t208'} = 1;
7637     }
7638    
7639 wakaba 1.54 $i = $_;
7640     last INSCOPE;
7641     } elsif ({
7642 wakaba 1.83 html => 1,
7643    
7644     ## NOTE: This element does not appear here, maybe.
7645     table => 1,
7646 wakaba 1.54 }->{$node->[1]}) {
7647 wakaba 1.79
7648     $Whatpm::HTML::Debug::cp_pass->('t209') if $Whatpm::HTML::Debug::cp_pass;
7649     BEGIN {
7650     $Whatpm::HTML::Debug::cp->{'t209'} = 1;
7651     }
7652    
7653 wakaba 1.54 last INSCOPE;
7654     }
7655     } # INSCOPE
7656 wakaba 1.79 unless (defined $i) {
7657    
7658     $Whatpm::HTML::Debug::cp_pass->('t210') if $Whatpm::HTML::Debug::cp_pass;
7659     BEGIN {
7660     $Whatpm::HTML::Debug::cp->{'t210'} = 1;
7661     }
7662    
7663 wakaba 1.83 ## TODO: This type is wrong.
7664 wakaba 1.79 $self->{parse_error}-> (type => 'unmacthed end tag:'.$token->{tag_name});
7665 wakaba 1.54 ## Ignore the token
7666     $token = $self->_get_next_token;
7667     redo B;
7668     }
7669    
7670     ## Clear back to table row context
7671     while (not {
7672     tr => 1, html => 1,
7673     }->{$self->{open_elements}->[-1]->[1]}) {
7674 wakaba 1.79
7675     $Whatpm::HTML::Debug::cp_pass->('t211') if $Whatpm::HTML::Debug::cp_pass;
7676     BEGIN {
7677     $Whatpm::HTML::Debug::cp->{'t211'} = 1;
7678     }
7679    
7680 wakaba 1.83 ## ISSUE: Can this case be reached?
7681 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7682     pop @{$self->{open_elements}};
7683     }
7684    
7685     pop @{$self->{open_elements}}; # tr
7686 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
7687 wakaba 1.54 if ($token->{tag_name} eq 'tr') {
7688 wakaba 1.79
7689     $Whatpm::HTML::Debug::cp_pass->('t212') if $Whatpm::HTML::Debug::cp_pass;
7690     BEGIN {
7691     $Whatpm::HTML::Debug::cp->{'t212'} = 1;
7692     }
7693    
7694 wakaba 1.54 ## reprocess
7695     redo B;
7696     } else {
7697 wakaba 1.79
7698     $Whatpm::HTML::Debug::cp_pass->('t213') if $Whatpm::HTML::Debug::cp_pass;
7699     BEGIN {
7700     $Whatpm::HTML::Debug::cp->{'t213'} = 1;
7701     }
7702    
7703 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
7704     }
7705     }
7706 wakaba 1.52
7707 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
7708 wakaba 1.54 ## have an element in table scope
7709     my $i;
7710     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7711     my $node = $self->{open_elements}->[$_];
7712     if ({
7713     tbody => 1, thead => 1, tfoot => 1,
7714     }->{$node->[1]}) {
7715 wakaba 1.79
7716     $Whatpm::HTML::Debug::cp_pass->('t214') if $Whatpm::HTML::Debug::cp_pass;
7717     BEGIN {
7718     $Whatpm::HTML::Debug::cp->{'t214'} = 1;
7719     }
7720    
7721 wakaba 1.54 $i = $_;
7722     last INSCOPE;
7723     } elsif ({
7724     table => 1, html => 1,
7725     }->{$node->[1]}) {
7726 wakaba 1.79
7727     $Whatpm::HTML::Debug::cp_pass->('t215') if $Whatpm::HTML::Debug::cp_pass;
7728     BEGIN {
7729     $Whatpm::HTML::Debug::cp->{'t215'} = 1;
7730     }
7731    
7732 wakaba 1.54 last INSCOPE;
7733     }
7734     } # INSCOPE
7735     unless (defined $i) {
7736 wakaba 1.79
7737     $Whatpm::HTML::Debug::cp_pass->('t216') if $Whatpm::HTML::Debug::cp_pass;
7738     BEGIN {
7739     $Whatpm::HTML::Debug::cp->{'t216'} = 1;
7740     }
7741    
7742 wakaba 1.83 ## TODO: This erorr type ios wrong.
7743     $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7744 wakaba 1.54 ## Ignore the token
7745     $token = $self->_get_next_token;
7746     redo B;
7747     }
7748 wakaba 1.52
7749 wakaba 1.54 ## Clear back to table body context
7750     while (not {
7751     tbody => 1, tfoot => 1, thead => 1, html => 1,
7752     }->{$self->{open_elements}->[-1]->[1]}) {
7753 wakaba 1.79
7754     $Whatpm::HTML::Debug::cp_pass->('t217') if $Whatpm::HTML::Debug::cp_pass;
7755     BEGIN {
7756     $Whatpm::HTML::Debug::cp->{'t217'} = 1;
7757     }
7758    
7759 wakaba 1.83 ## ISSUE: Can this state be reached?
7760 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7761     pop @{$self->{open_elements}};
7762     }
7763    
7764     ## As if <{current node}>
7765     ## have an element in table scope
7766     ## true by definition
7767    
7768     ## Clear back to table body context
7769     ## nop by definition
7770    
7771     pop @{$self->{open_elements}};
7772 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7773 wakaba 1.54 ## reprocess in "in table" insertion mode...
7774 wakaba 1.79 } else {
7775    
7776     $Whatpm::HTML::Debug::cp_pass->('t218') if $Whatpm::HTML::Debug::cp_pass;
7777     BEGIN {
7778     $Whatpm::HTML::Debug::cp->{'t218'} = 1;
7779     }
7780    
7781 wakaba 1.54 }
7782 wakaba 1.51
7783 wakaba 1.54 if ($token->{tag_name} eq 'col') {
7784     ## Clear back to table context
7785     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7786     $self->{open_elements}->[-1]->[1] ne 'html') {
7787 wakaba 1.79
7788     $Whatpm::HTML::Debug::cp_pass->('t219') if $Whatpm::HTML::Debug::cp_pass;
7789     BEGIN {
7790     $Whatpm::HTML::Debug::cp->{'t219'} = 1;
7791     }
7792    
7793 wakaba 1.83 ## ISSUE: Can this state be reached?
7794 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7795     pop @{$self->{open_elements}};
7796     }
7797    
7798    
7799 wakaba 1.51 {
7800     my $el;
7801    
7802     $el = $self->{document}->create_element_ns
7803 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'colgroup']);
7804 wakaba 1.51
7805     $self->{open_elements}->[-1]->[0]->append_child ($el);
7806 wakaba 1.54 push @{$self->{open_elements}}, [$el, 'colgroup'];
7807 wakaba 1.51 }
7808    
7809 wakaba 1.56 $self->{insertion_mode} = IN_COLUMN_GROUP_IM;
7810 wakaba 1.54 ## reprocess
7811     redo B;
7812     } elsif ({
7813     caption => 1,
7814     colgroup => 1,
7815     tbody => 1, tfoot => 1, thead => 1,
7816     }->{$token->{tag_name}}) {
7817     ## Clear back to table context
7818     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7819     $self->{open_elements}->[-1]->[1] ne 'html') {
7820 wakaba 1.79
7821     $Whatpm::HTML::Debug::cp_pass->('t220') if $Whatpm::HTML::Debug::cp_pass;
7822     BEGIN {
7823     $Whatpm::HTML::Debug::cp->{'t220'} = 1;
7824     }
7825    
7826 wakaba 1.83 ## ISSUE: Can this state be reached?
7827 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7828     pop @{$self->{open_elements}};
7829     }
7830    
7831     push @$active_formatting_elements, ['#marker', '']
7832     if $token->{tag_name} eq 'caption';
7833    
7834 wakaba 1.52
7835 wakaba 1.54 {
7836     my $el;
7837    
7838     $el = $self->{document}->create_element_ns
7839 wakaba 1.52 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7840    
7841 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
7842     $el->set_attribute_ns (undef, [undef, $attr_name],
7843     $token->{attributes} ->{$attr_name}->{value});
7844 wakaba 1.52 }
7845    
7846 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
7847     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7848     }
7849    
7850     $self->{insertion_mode} = {
7851 wakaba 1.56 caption => IN_CAPTION_IM,
7852     colgroup => IN_COLUMN_GROUP_IM,
7853     tbody => IN_TABLE_BODY_IM,
7854     tfoot => IN_TABLE_BODY_IM,
7855     thead => IN_TABLE_BODY_IM,
7856 wakaba 1.54 }->{$token->{tag_name}};
7857 wakaba 1.52 $token = $self->_get_next_token;
7858     redo B;
7859 wakaba 1.54 } else {
7860     die "$0: in table: <>: $token->{tag_name}";
7861     }
7862     } elsif ($token->{tag_name} eq 'table') {
7863     $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7864    
7865     ## As if </table>
7866     ## have a table element in table scope
7867     my $i;
7868     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7869     my $node = $self->{open_elements}->[$_];
7870     if ($node->[1] eq 'table') {
7871 wakaba 1.79
7872     $Whatpm::HTML::Debug::cp_pass->('t221') if $Whatpm::HTML::Debug::cp_pass;
7873     BEGIN {
7874     $Whatpm::HTML::Debug::cp->{'t221'} = 1;
7875     }
7876    
7877 wakaba 1.54 $i = $_;
7878     last INSCOPE;
7879     } elsif ({
7880 wakaba 1.83 #table => 1,
7881     html => 1,
7882 wakaba 1.54 }->{$node->[1]}) {
7883 wakaba 1.79
7884     $Whatpm::HTML::Debug::cp_pass->('t222') if $Whatpm::HTML::Debug::cp_pass;
7885     BEGIN {
7886     $Whatpm::HTML::Debug::cp->{'t222'} = 1;
7887     }
7888    
7889 wakaba 1.54 last INSCOPE;
7890     }
7891     } # INSCOPE
7892     unless (defined $i) {
7893 wakaba 1.79
7894     $Whatpm::HTML::Debug::cp_pass->('t223') if $Whatpm::HTML::Debug::cp_pass;
7895     BEGIN {
7896     $Whatpm::HTML::Debug::cp->{'t223'} = 1;
7897     }
7898    
7899 wakaba 1.83 ## TODO: The following is wrong, maybe.
7900 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:table');
7901     ## Ignore tokens </table><table>
7902 wakaba 1.52 $token = $self->_get_next_token;
7903     redo B;
7904     }
7905    
7906 wakaba 1.54 ## generate implied end tags
7907 wakaba 1.86 while ({
7908     dd => 1, dt => 1, li => 1, p => 1,
7909     }->{$self->{open_elements}->[-1]->[1]}) {
7910 wakaba 1.79
7911     $Whatpm::HTML::Debug::cp_pass->('t224') if $Whatpm::HTML::Debug::cp_pass;
7912     BEGIN {
7913     $Whatpm::HTML::Debug::cp->{'t224'} = 1;
7914     }
7915    
7916 wakaba 1.86 pop @{$self->{open_elements}};
7917 wakaba 1.54 }
7918    
7919     if ($self->{open_elements}->[-1]->[1] ne 'table') {
7920 wakaba 1.79
7921     $Whatpm::HTML::Debug::cp_pass->('t225') if $Whatpm::HTML::Debug::cp_pass;
7922     BEGIN {
7923     $Whatpm::HTML::Debug::cp->{'t225'} = 1;
7924     }
7925    
7926 wakaba 1.83 ## ISSUE: Can this case be reached?
7927 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7928 wakaba 1.79 } else {
7929    
7930     $Whatpm::HTML::Debug::cp_pass->('t226') if $Whatpm::HTML::Debug::cp_pass;
7931     BEGIN {
7932     $Whatpm::HTML::Debug::cp->{'t226'} = 1;
7933     }
7934    
7935 wakaba 1.54 }
7936    
7937     splice @{$self->{open_elements}}, $i;
7938    
7939     $self->_reset_insertion_mode;
7940 wakaba 1.52
7941 wakaba 1.54 ## reprocess
7942     redo B;
7943 wakaba 1.60 } else {
7944 wakaba 1.79
7945     $Whatpm::HTML::Debug::cp_pass->('t227') if $Whatpm::HTML::Debug::cp_pass;
7946     BEGIN {
7947     $Whatpm::HTML::Debug::cp->{'t227'} = 1;
7948     }
7949    
7950 wakaba 1.60 $self->{parse_error}-> (type => 'in table:'.$token->{tag_name});
7951    
7952     $insert = $insert_to_foster;
7953     #
7954     }
7955     } elsif ($token->{type} == END_TAG_TOKEN) {
7956 wakaba 1.54 if ($token->{tag_name} eq 'tr' and
7957 wakaba 1.56 $self->{insertion_mode} == IN_ROW_IM) {
7958 wakaba 1.54 ## have an element in table scope
7959     my $i;
7960     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7961     my $node = $self->{open_elements}->[$_];
7962     if ($node->[1] eq $token->{tag_name}) {
7963 wakaba 1.79
7964     $Whatpm::HTML::Debug::cp_pass->('t228') if $Whatpm::HTML::Debug::cp_pass;
7965     BEGIN {
7966     $Whatpm::HTML::Debug::cp->{'t228'} = 1;
7967     }
7968    
7969 wakaba 1.54 $i = $_;
7970     last INSCOPE;
7971     } elsif ({
7972     table => 1, html => 1,
7973     }->{$node->[1]}) {
7974 wakaba 1.79
7975     $Whatpm::HTML::Debug::cp_pass->('t229') if $Whatpm::HTML::Debug::cp_pass;
7976     BEGIN {
7977     $Whatpm::HTML::Debug::cp->{'t229'} = 1;
7978     }
7979    
7980 wakaba 1.54 last INSCOPE;
7981     }
7982     } # INSCOPE
7983     unless (defined $i) {
7984 wakaba 1.79
7985     $Whatpm::HTML::Debug::cp_pass->('t230') if $Whatpm::HTML::Debug::cp_pass;
7986     BEGIN {
7987     $Whatpm::HTML::Debug::cp->{'t230'} = 1;
7988     }
7989    
7990 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7991     ## Ignore the token
7992     $token = $self->_get_next_token;
7993     redo B;
7994 wakaba 1.79 } else {
7995    
7996     $Whatpm::HTML::Debug::cp_pass->('t232') if $Whatpm::HTML::Debug::cp_pass;
7997     BEGIN {
7998     $Whatpm::HTML::Debug::cp->{'t232'} = 1;
7999     }
8000    
8001 wakaba 1.54 }
8002    
8003     ## Clear back to table row context
8004     while (not {
8005     tr => 1, html => 1,
8006     }->{$self->{open_elements}->[-1]->[1]}) {
8007 wakaba 1.79
8008     $Whatpm::HTML::Debug::cp_pass->('t231') if $Whatpm::HTML::Debug::cp_pass;
8009     BEGIN {
8010     $Whatpm::HTML::Debug::cp->{'t231'} = 1;
8011     }
8012    
8013 wakaba 1.83 ## ISSUE: Can this state be reached?
8014 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8015     pop @{$self->{open_elements}};
8016     }
8017    
8018     pop @{$self->{open_elements}}; # tr
8019 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8020 wakaba 1.54 $token = $self->_get_next_token;
8021     redo B;
8022     } elsif ($token->{tag_name} eq 'table') {
8023 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
8024 wakaba 1.54 ## As if </tr>
8025     ## have an element in table scope
8026     my $i;
8027     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8028     my $node = $self->{open_elements}->[$_];
8029     if ($node->[1] eq 'tr') {
8030 wakaba 1.79
8031     $Whatpm::HTML::Debug::cp_pass->('t233') if $Whatpm::HTML::Debug::cp_pass;
8032     BEGIN {
8033     $Whatpm::HTML::Debug::cp->{'t233'} = 1;
8034     }
8035    
8036 wakaba 1.54 $i = $_;
8037     last INSCOPE;
8038     } elsif ({
8039     table => 1, html => 1,
8040     }->{$node->[1]}) {
8041 wakaba 1.79
8042     $Whatpm::HTML::Debug::cp_pass->('t234') if $Whatpm::HTML::Debug::cp_pass;
8043     BEGIN {
8044     $Whatpm::HTML::Debug::cp->{'t234'} = 1;
8045     }
8046    
8047 wakaba 1.54 last INSCOPE;
8048     }
8049     } # INSCOPE
8050     unless (defined $i) {
8051 wakaba 1.79
8052     $Whatpm::HTML::Debug::cp_pass->('t235') if $Whatpm::HTML::Debug::cp_pass;
8053     BEGIN {
8054     $Whatpm::HTML::Debug::cp->{'t235'} = 1;
8055     }
8056    
8057 wakaba 1.83 ## TODO: The following is wrong.
8058 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{type});
8059     ## Ignore the token
8060     $token = $self->_get_next_token;
8061     redo B;
8062     }
8063    
8064     ## Clear back to table row context
8065     while (not {
8066     tr => 1, html => 1,
8067     }->{$self->{open_elements}->[-1]->[1]}) {
8068 wakaba 1.79
8069     $Whatpm::HTML::Debug::cp_pass->('t236') if $Whatpm::HTML::Debug::cp_pass;
8070     BEGIN {
8071     $Whatpm::HTML::Debug::cp->{'t236'} = 1;
8072     }
8073    
8074 wakaba 1.83 ## ISSUE: Can this state be reached?
8075 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8076     pop @{$self->{open_elements}};
8077     }
8078    
8079     pop @{$self->{open_elements}}; # tr
8080 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8081 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
8082     }
8083    
8084 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
8085 wakaba 1.54 ## have an element in table scope
8086     my $i;
8087     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8088     my $node = $self->{open_elements}->[$_];
8089     if ({
8090     tbody => 1, thead => 1, tfoot => 1,
8091     }->{$node->[1]}) {
8092 wakaba 1.79
8093     $Whatpm::HTML::Debug::cp_pass->('t237') if $Whatpm::HTML::Debug::cp_pass;
8094     BEGIN {
8095     $Whatpm::HTML::Debug::cp->{'t237'} = 1;
8096     }
8097    
8098 wakaba 1.54 $i = $_;
8099     last INSCOPE;
8100     } elsif ({
8101     table => 1, html => 1,
8102     }->{$node->[1]}) {
8103 wakaba 1.79
8104     $Whatpm::HTML::Debug::cp_pass->('t238') if $Whatpm::HTML::Debug::cp_pass;
8105     BEGIN {
8106     $Whatpm::HTML::Debug::cp->{'t238'} = 1;
8107     }
8108    
8109 wakaba 1.54 last INSCOPE;
8110     }
8111     } # INSCOPE
8112     unless (defined $i) {
8113 wakaba 1.79
8114     $Whatpm::HTML::Debug::cp_pass->('t239') if $Whatpm::HTML::Debug::cp_pass;
8115     BEGIN {
8116     $Whatpm::HTML::Debug::cp->{'t239'} = 1;
8117     }
8118    
8119 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8120     ## Ignore the token
8121     $token = $self->_get_next_token;
8122     redo B;
8123     }
8124    
8125     ## Clear back to table body context
8126     while (not {
8127     tbody => 1, tfoot => 1, thead => 1, html => 1,
8128     }->{$self->{open_elements}->[-1]->[1]}) {
8129 wakaba 1.79
8130     $Whatpm::HTML::Debug::cp_pass->('t240') if $Whatpm::HTML::Debug::cp_pass;
8131     BEGIN {
8132     $Whatpm::HTML::Debug::cp->{'t240'} = 1;
8133     }
8134    
8135 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8136     pop @{$self->{open_elements}};
8137     }
8138    
8139     ## As if <{current node}>
8140     ## have an element in table scope
8141     ## true by definition
8142    
8143     ## Clear back to table body context
8144     ## nop by definition
8145    
8146     pop @{$self->{open_elements}};
8147 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8148 wakaba 1.54 ## reprocess in the "in table" insertion mode...
8149     }
8150 wakaba 1.52
8151 wakaba 1.54 ## have a table element in table scope
8152     my $i;
8153     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8154     my $node = $self->{open_elements}->[$_];
8155     if ($node->[1] eq $token->{tag_name}) {
8156 wakaba 1.79
8157     $Whatpm::HTML::Debug::cp_pass->('t241') if $Whatpm::HTML::Debug::cp_pass;
8158     BEGIN {
8159     $Whatpm::HTML::Debug::cp->{'t241'} = 1;
8160     }
8161    
8162 wakaba 1.54 $i = $_;
8163     last INSCOPE;
8164     } elsif ({
8165     table => 1, html => 1,
8166     }->{$node->[1]}) {
8167 wakaba 1.79
8168     $Whatpm::HTML::Debug::cp_pass->('t242') if $Whatpm::HTML::Debug::cp_pass;
8169     BEGIN {
8170     $Whatpm::HTML::Debug::cp->{'t242'} = 1;
8171     }
8172    
8173 wakaba 1.54 last INSCOPE;
8174     }
8175     } # INSCOPE
8176     unless (defined $i) {
8177 wakaba 1.79
8178     $Whatpm::HTML::Debug::cp_pass->('t243') if $Whatpm::HTML::Debug::cp_pass;
8179     BEGIN {
8180     $Whatpm::HTML::Debug::cp->{'t243'} = 1;
8181     }
8182    
8183 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8184     ## Ignore the token
8185     $token = $self->_get_next_token;
8186     redo B;
8187 wakaba 1.51 }
8188    
8189 wakaba 1.54 ## generate implied end tags
8190 wakaba 1.86 while ({
8191     dd => 1, dt => 1, li => 1, p => 1,
8192     }->{$self->{open_elements}->[-1]->[1]}) {
8193 wakaba 1.79
8194     $Whatpm::HTML::Debug::cp_pass->('t244') if $Whatpm::HTML::Debug::cp_pass;
8195     BEGIN {
8196     $Whatpm::HTML::Debug::cp->{'t244'} = 1;
8197     }
8198    
8199 wakaba 1.83 ## ISSUE: Can this case be reached?
8200 wakaba 1.86 pop @{$self->{open_elements}};
8201 wakaba 1.51 }
8202    
8203 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] ne 'table') {
8204 wakaba 1.79
8205     $Whatpm::HTML::Debug::cp_pass->('t245') if $Whatpm::HTML::Debug::cp_pass;
8206     BEGIN {
8207     $Whatpm::HTML::Debug::cp->{'t245'} = 1;
8208     }
8209    
8210 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8211 wakaba 1.79 } else {
8212    
8213     $Whatpm::HTML::Debug::cp_pass->('t246') if $Whatpm::HTML::Debug::cp_pass;
8214     BEGIN {
8215     $Whatpm::HTML::Debug::cp->{'t246'} = 1;
8216     }
8217    
8218     }
8219 wakaba 1.54
8220     splice @{$self->{open_elements}}, $i;
8221    
8222     $self->_reset_insertion_mode;
8223 wakaba 1.1
8224     $token = $self->_get_next_token;
8225 wakaba 1.25 redo B;
8226 wakaba 1.54 } elsif ({
8227     tbody => 1, tfoot => 1, thead => 1,
8228     }->{$token->{tag_name}} and
8229 wakaba 1.58 $self->{insertion_mode} & ROW_IMS) {
8230 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
8231 wakaba 1.54 ## have an element in table scope
8232     my $i;
8233     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8234     my $node = $self->{open_elements}->[$_];
8235     if ($node->[1] eq $token->{tag_name}) {
8236 wakaba 1.79
8237     $Whatpm::HTML::Debug::cp_pass->('t247') if $Whatpm::HTML::Debug::cp_pass;
8238     BEGIN {
8239     $Whatpm::HTML::Debug::cp->{'t247'} = 1;
8240     }
8241    
8242 wakaba 1.54 $i = $_;
8243     last INSCOPE;
8244     } elsif ({
8245     table => 1, html => 1,
8246     }->{$node->[1]}) {
8247 wakaba 1.79
8248     $Whatpm::HTML::Debug::cp_pass->('t248') if $Whatpm::HTML::Debug::cp_pass;
8249     BEGIN {
8250     $Whatpm::HTML::Debug::cp->{'t248'} = 1;
8251     }
8252    
8253 wakaba 1.54 last INSCOPE;
8254     }
8255     } # INSCOPE
8256     unless (defined $i) {
8257 wakaba 1.79
8258     $Whatpm::HTML::Debug::cp_pass->('t249') if $Whatpm::HTML::Debug::cp_pass;
8259     BEGIN {
8260     $Whatpm::HTML::Debug::cp->{'t249'} = 1;
8261     }
8262    
8263 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8264     ## Ignore the token
8265     $token = $self->_get_next_token;
8266     redo B;
8267     }
8268    
8269     ## As if </tr>
8270     ## have an element in table scope
8271     my $i;
8272     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8273     my $node = $self->{open_elements}->[$_];
8274     if ($node->[1] eq 'tr') {
8275 wakaba 1.79
8276     $Whatpm::HTML::Debug::cp_pass->('t250') if $Whatpm::HTML::Debug::cp_pass;
8277     BEGIN {
8278     $Whatpm::HTML::Debug::cp->{'t250'} = 1;
8279     }
8280    
8281 wakaba 1.54 $i = $_;
8282     last INSCOPE;
8283     } elsif ({
8284     table => 1, html => 1,
8285     }->{$node->[1]}) {
8286 wakaba 1.79
8287     $Whatpm::HTML::Debug::cp_pass->('t251') if $Whatpm::HTML::Debug::cp_pass;
8288     BEGIN {
8289     $Whatpm::HTML::Debug::cp->{'t251'} = 1;
8290     }
8291    
8292 wakaba 1.54 last INSCOPE;
8293     }
8294     } # INSCOPE
8295     unless (defined $i) {
8296 wakaba 1.79
8297     $Whatpm::HTML::Debug::cp_pass->('t252') if $Whatpm::HTML::Debug::cp_pass;
8298     BEGIN {
8299     $Whatpm::HTML::Debug::cp->{'t252'} = 1;
8300     }
8301    
8302 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:tr');
8303     ## Ignore the token
8304     $token = $self->_get_next_token;
8305     redo B;
8306     }
8307    
8308     ## Clear back to table row context
8309     while (not {
8310     tr => 1, html => 1,
8311     }->{$self->{open_elements}->[-1]->[1]}) {
8312 wakaba 1.79
8313     $Whatpm::HTML::Debug::cp_pass->('t253') if $Whatpm::HTML::Debug::cp_pass;
8314     BEGIN {
8315     $Whatpm::HTML::Debug::cp->{'t253'} = 1;
8316     }
8317    
8318 wakaba 1.83 ## ISSUE: Can this case be reached?
8319 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8320     pop @{$self->{open_elements}};
8321     }
8322    
8323     pop @{$self->{open_elements}}; # tr
8324 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8325 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
8326 wakaba 1.34 }
8327    
8328 wakaba 1.54 ## have an element in table scope
8329     my $i;
8330     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8331     my $node = $self->{open_elements}->[$_];
8332     if ($node->[1] eq $token->{tag_name}) {
8333 wakaba 1.79
8334     $Whatpm::HTML::Debug::cp_pass->('t254') if $Whatpm::HTML::Debug::cp_pass;
8335     BEGIN {
8336     $Whatpm::HTML::Debug::cp->{'t254'} = 1;
8337     }
8338    
8339 wakaba 1.54 $i = $_;
8340     last INSCOPE;
8341     } elsif ({
8342     table => 1, html => 1,
8343     }->{$node->[1]}) {
8344 wakaba 1.79
8345     $Whatpm::HTML::Debug::cp_pass->('t255') if $Whatpm::HTML::Debug::cp_pass;
8346     BEGIN {
8347     $Whatpm::HTML::Debug::cp->{'t255'} = 1;
8348     }
8349    
8350 wakaba 1.54 last INSCOPE;
8351 wakaba 1.34 }
8352 wakaba 1.54 } # INSCOPE
8353     unless (defined $i) {
8354 wakaba 1.79
8355     $Whatpm::HTML::Debug::cp_pass->('t256') if $Whatpm::HTML::Debug::cp_pass;
8356     BEGIN {
8357     $Whatpm::HTML::Debug::cp->{'t256'} = 1;
8358     }
8359    
8360 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8361     ## Ignore the token
8362     $token = $self->_get_next_token;
8363     redo B;
8364 wakaba 1.34 }
8365    
8366 wakaba 1.54 ## Clear back to table body context
8367     while (not {
8368     tbody => 1, tfoot => 1, thead => 1, html => 1,
8369     }->{$self->{open_elements}->[-1]->[1]}) {
8370 wakaba 1.79
8371     $Whatpm::HTML::Debug::cp_pass->('t257') if $Whatpm::HTML::Debug::cp_pass;
8372     BEGIN {
8373     $Whatpm::HTML::Debug::cp->{'t257'} = 1;
8374     }
8375    
8376 wakaba 1.83 ## ISSUE: Can this case be reached?
8377 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8378 wakaba 1.51 pop @{$self->{open_elements}};
8379 wakaba 1.25 }
8380 wakaba 1.51
8381 wakaba 1.54 pop @{$self->{open_elements}};
8382 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8383 wakaba 1.54 $token = $self->_get_next_token;
8384     redo B;
8385     } elsif ({
8386     body => 1, caption => 1, col => 1, colgroup => 1,
8387     html => 1, td => 1, th => 1,
8388 wakaba 1.56 tr => 1, # $self->{insertion_mode} == IN_ROW_IM
8389     tbody => 1, tfoot => 1, thead => 1, # $self->{insertion_mode} == IN_TABLE_IM
8390 wakaba 1.54 }->{$token->{tag_name}}) {
8391 wakaba 1.79
8392     $Whatpm::HTML::Debug::cp_pass->('t258') if $Whatpm::HTML::Debug::cp_pass;
8393     BEGIN {
8394     $Whatpm::HTML::Debug::cp->{'t258'} = 1;
8395     }
8396    
8397 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8398     ## Ignore the token
8399     $token = $self->_get_next_token;
8400 wakaba 1.1 redo B;
8401 wakaba 1.60 } else {
8402 wakaba 1.79
8403     $Whatpm::HTML::Debug::cp_pass->('t259') if $Whatpm::HTML::Debug::cp_pass;
8404     BEGIN {
8405     $Whatpm::HTML::Debug::cp->{'t259'} = 1;
8406     }
8407    
8408 wakaba 1.60 $self->{parse_error}-> (type => 'in table:/'.$token->{tag_name});
8409 wakaba 1.54
8410 wakaba 1.60 $insert = $insert_to_foster;
8411     #
8412     }
8413     } else {
8414     die "$0: $token->{type}: Unknown token type";
8415     }
8416 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_COLUMN_GROUP_IM) {
8417 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
8418 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
8419     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
8420     unless (length $token->{data}) {
8421 wakaba 1.79
8422     $Whatpm::HTML::Debug::cp_pass->('t260') if $Whatpm::HTML::Debug::cp_pass;
8423     BEGIN {
8424     $Whatpm::HTML::Debug::cp->{'t260'} = 1;
8425     }
8426    
8427 wakaba 1.54 $token = $self->_get_next_token;
8428     redo B;
8429 wakaba 1.25 }
8430 wakaba 1.54 }
8431    
8432 wakaba 1.79
8433     $Whatpm::HTML::Debug::cp_pass->('t261') if $Whatpm::HTML::Debug::cp_pass;
8434     BEGIN {
8435     $Whatpm::HTML::Debug::cp->{'t261'} = 1;
8436     }
8437    
8438 wakaba 1.54 #
8439 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
8440 wakaba 1.54 if ($token->{tag_name} eq 'col') {
8441    
8442 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t262') if $Whatpm::HTML::Debug::cp_pass;
8443     BEGIN {
8444     $Whatpm::HTML::Debug::cp->{'t262'} = 1;
8445     }
8446    
8447    
8448 wakaba 1.25 {
8449     my $el;
8450    
8451 wakaba 1.1 $el = $self->{document}->create_element_ns
8452     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8453    
8454 wakaba 1.25 for my $attr_name (keys %{ $token->{attributes}}) {
8455 wakaba 1.1 $el->set_attribute_ns (undef, [undef, $attr_name],
8456 wakaba 1.25 $token->{attributes} ->{$attr_name}->{value});
8457 wakaba 1.1 }
8458    
8459 wakaba 1.25 $self->{open_elements}->[-1]->[0]->append_child ($el);
8460     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8461     }
8462    
8463 wakaba 1.54 pop @{$self->{open_elements}};
8464     $token = $self->_get_next_token;
8465     redo B;
8466     } else {
8467 wakaba 1.79
8468     $Whatpm::HTML::Debug::cp_pass->('t263') if $Whatpm::HTML::Debug::cp_pass;
8469     BEGIN {
8470     $Whatpm::HTML::Debug::cp->{'t263'} = 1;
8471     }
8472    
8473 wakaba 1.54 #
8474     }
8475 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
8476 wakaba 1.54 if ($token->{tag_name} eq 'colgroup') {
8477     if ($self->{open_elements}->[-1]->[1] eq 'html') {
8478 wakaba 1.79
8479     $Whatpm::HTML::Debug::cp_pass->('t264') if $Whatpm::HTML::Debug::cp_pass;
8480     BEGIN {
8481     $Whatpm::HTML::Debug::cp->{'t264'} = 1;
8482     }
8483    
8484 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:colgroup');
8485 wakaba 1.25 ## Ignore the token
8486 wakaba 1.42 $token = $self->_get_next_token;
8487 wakaba 1.25 redo B;
8488 wakaba 1.24 } else {
8489 wakaba 1.79
8490     $Whatpm::HTML::Debug::cp_pass->('t265') if $Whatpm::HTML::Debug::cp_pass;
8491     BEGIN {
8492     $Whatpm::HTML::Debug::cp->{'t265'} = 1;
8493     }
8494    
8495 wakaba 1.54 pop @{$self->{open_elements}}; # colgroup
8496 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8497 wakaba 1.54 $token = $self->_get_next_token;
8498     redo B;
8499 wakaba 1.25 }
8500 wakaba 1.54 } elsif ($token->{tag_name} eq 'col') {
8501 wakaba 1.79
8502     $Whatpm::HTML::Debug::cp_pass->('t266') if $Whatpm::HTML::Debug::cp_pass;
8503     BEGIN {
8504     $Whatpm::HTML::Debug::cp->{'t266'} = 1;
8505     }
8506    
8507 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:col');
8508     ## Ignore the token
8509     $token = $self->_get_next_token;
8510     redo B;
8511     } else {
8512 wakaba 1.79
8513     $Whatpm::HTML::Debug::cp_pass->('t267') if $Whatpm::HTML::Debug::cp_pass;
8514     BEGIN {
8515     $Whatpm::HTML::Debug::cp->{'t267'} = 1;
8516     }
8517    
8518 wakaba 1.54 #
8519     }
8520     } else {
8521 wakaba 1.83 die "$0: $token->{type}: Unknown token type";
8522 wakaba 1.54 }
8523 wakaba 1.51
8524 wakaba 1.54 ## As if </colgroup>
8525     if ($self->{open_elements}->[-1]->[1] eq 'html') {
8526 wakaba 1.79
8527     $Whatpm::HTML::Debug::cp_pass->('t269') if $Whatpm::HTML::Debug::cp_pass;
8528     BEGIN {
8529     $Whatpm::HTML::Debug::cp->{'t269'} = 1;
8530     }
8531    
8532 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:colgroup');
8533     ## Ignore the token
8534     $token = $self->_get_next_token;
8535     redo B;
8536     } else {
8537 wakaba 1.79
8538     $Whatpm::HTML::Debug::cp_pass->('t270') if $Whatpm::HTML::Debug::cp_pass;
8539     BEGIN {
8540     $Whatpm::HTML::Debug::cp->{'t270'} = 1;
8541     }
8542    
8543 wakaba 1.54 pop @{$self->{open_elements}}; # colgroup
8544 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8545 wakaba 1.54 ## reprocess
8546     redo B;
8547     }
8548 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_SELECT_IM) {
8549 wakaba 1.60 if ($token->{type} == CHARACTER_TOKEN) {
8550 wakaba 1.79
8551     $Whatpm::HTML::Debug::cp_pass->('t271') if $Whatpm::HTML::Debug::cp_pass;
8552     BEGIN {
8553     $Whatpm::HTML::Debug::cp->{'t271'} = 1;
8554     }
8555    
8556 wakaba 1.60 $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
8557     $token = $self->_get_next_token;
8558     redo B;
8559     } elsif ($token->{type} == START_TAG_TOKEN) {
8560 wakaba 1.54 if ($token->{tag_name} eq 'option') {
8561     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8562 wakaba 1.79
8563     $Whatpm::HTML::Debug::cp_pass->('t272') if $Whatpm::HTML::Debug::cp_pass;
8564     BEGIN {
8565     $Whatpm::HTML::Debug::cp->{'t272'} = 1;
8566     }
8567    
8568 wakaba 1.54 ## As if </option>
8569 wakaba 1.51 pop @{$self->{open_elements}};
8570 wakaba 1.79 } else {
8571    
8572     $Whatpm::HTML::Debug::cp_pass->('t273') if $Whatpm::HTML::Debug::cp_pass;
8573     BEGIN {
8574     $Whatpm::HTML::Debug::cp->{'t273'} = 1;
8575     }
8576    
8577 wakaba 1.51 }
8578    
8579 wakaba 1.1
8580     {
8581     my $el;
8582    
8583     $el = $self->{document}->create_element_ns
8584 wakaba 1.51 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8585 wakaba 1.1
8586     for my $attr_name (keys %{ $token->{attributes}}) {
8587     $el->set_attribute_ns (undef, [undef, $attr_name],
8588     $token->{attributes} ->{$attr_name}->{value});
8589     }
8590    
8591 wakaba 1.3 $self->{open_elements}->[-1]->[0]->append_child ($el);
8592 wakaba 1.51 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8593 wakaba 1.1 }
8594    
8595     $token = $self->_get_next_token;
8596     redo B;
8597 wakaba 1.54 } elsif ($token->{tag_name} eq 'optgroup') {
8598     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8599 wakaba 1.79
8600     $Whatpm::HTML::Debug::cp_pass->('t274') if $Whatpm::HTML::Debug::cp_pass;
8601     BEGIN {
8602     $Whatpm::HTML::Debug::cp->{'t274'} = 1;
8603     }
8604    
8605 wakaba 1.54 ## As if </option>
8606 wakaba 1.51 pop @{$self->{open_elements}};
8607 wakaba 1.79 } else {
8608    
8609     $Whatpm::HTML::Debug::cp_pass->('t275') if $Whatpm::HTML::Debug::cp_pass;
8610     BEGIN {
8611     $Whatpm::HTML::Debug::cp->{'t275'} = 1;
8612     }
8613    
8614 wakaba 1.51 }
8615 wakaba 1.54
8616     if ($self->{open_elements}->[-1]->[1] eq 'optgroup') {
8617 wakaba 1.79
8618     $Whatpm::HTML::Debug::cp_pass->('t276') if $Whatpm::HTML::Debug::cp_pass;
8619     BEGIN {
8620     $Whatpm::HTML::Debug::cp->{'t276'} = 1;
8621     }
8622    
8623 wakaba 1.54 ## As if </optgroup>
8624 wakaba 1.51 pop @{$self->{open_elements}};
8625 wakaba 1.79 } else {
8626    
8627     $Whatpm::HTML::Debug::cp_pass->('t277') if $Whatpm::HTML::Debug::cp_pass;
8628     BEGIN {
8629     $Whatpm::HTML::Debug::cp->{'t277'} = 1;
8630     }
8631    
8632 wakaba 1.51 }
8633    
8634    
8635 wakaba 1.1 {
8636     my $el;
8637    
8638     $el = $self->{document}->create_element_ns
8639 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8640 wakaba 1.1
8641 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
8642     $el->set_attribute_ns (undef, [undef, $attr_name],
8643     $token->{attributes} ->{$attr_name}->{value});
8644     }
8645    
8646 wakaba 1.3 $self->{open_elements}->[-1]->[0]->append_child ($el);
8647 wakaba 1.54 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8648 wakaba 1.1 }
8649    
8650 wakaba 1.54 $token = $self->_get_next_token;
8651     redo B;
8652     } elsif ($token->{tag_name} eq 'select') {
8653 wakaba 1.83 ## TODO: The type below is not good - <select> is replaced by </select>
8654 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:select');
8655     ## As if </select> instead
8656     ## have an element in table scope
8657     my $i;
8658     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8659     my $node = $self->{open_elements}->[$_];
8660     if ($node->[1] eq $token->{tag_name}) {
8661 wakaba 1.79
8662     $Whatpm::HTML::Debug::cp_pass->('t278') if $Whatpm::HTML::Debug::cp_pass;
8663     BEGIN {
8664     $Whatpm::HTML::Debug::cp->{'t278'} = 1;
8665     }
8666    
8667 wakaba 1.54 $i = $_;
8668     last INSCOPE;
8669     } elsif ({
8670     table => 1, html => 1,
8671     }->{$node->[1]}) {
8672 wakaba 1.79
8673     $Whatpm::HTML::Debug::cp_pass->('t279') if $Whatpm::HTML::Debug::cp_pass;
8674     BEGIN {
8675     $Whatpm::HTML::Debug::cp->{'t279'} = 1;
8676     }
8677    
8678 wakaba 1.54 last INSCOPE;
8679 wakaba 1.44 }
8680 wakaba 1.54 } # INSCOPE
8681     unless (defined $i) {
8682 wakaba 1.79
8683     $Whatpm::HTML::Debug::cp_pass->('t280') if $Whatpm::HTML::Debug::cp_pass;
8684     BEGIN {
8685     $Whatpm::HTML::Debug::cp->{'t280'} = 1;
8686     }
8687    
8688 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:select');
8689     ## Ignore the token
8690     $token = $self->_get_next_token;
8691 wakaba 1.44 redo B;
8692     }
8693 wakaba 1.54
8694 wakaba 1.79
8695     $Whatpm::HTML::Debug::cp_pass->('t281') if $Whatpm::HTML::Debug::cp_pass;
8696     BEGIN {
8697     $Whatpm::HTML::Debug::cp->{'t281'} = 1;
8698     }
8699    
8700 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8701    
8702     $self->_reset_insertion_mode;
8703    
8704     $token = $self->_get_next_token;
8705     redo B;
8706 wakaba 1.60 } else {
8707 wakaba 1.79
8708     $Whatpm::HTML::Debug::cp_pass->('t282') if $Whatpm::HTML::Debug::cp_pass;
8709     BEGIN {
8710     $Whatpm::HTML::Debug::cp->{'t282'} = 1;
8711     }
8712    
8713 wakaba 1.60 $self->{parse_error}-> (type => 'in select:'.$token->{tag_name});
8714     ## Ignore the token
8715     $token = $self->_get_next_token;
8716     redo B;
8717     }
8718     } elsif ($token->{type} == END_TAG_TOKEN) {
8719 wakaba 1.54 if ($token->{tag_name} eq 'optgroup') {
8720     if ($self->{open_elements}->[-1]->[1] eq 'option' and
8721     $self->{open_elements}->[-2]->[1] eq 'optgroup') {
8722 wakaba 1.79
8723     $Whatpm::HTML::Debug::cp_pass->('t283') if $Whatpm::HTML::Debug::cp_pass;
8724     BEGIN {
8725     $Whatpm::HTML::Debug::cp->{'t283'} = 1;
8726     }
8727    
8728 wakaba 1.54 ## As if </option>
8729     splice @{$self->{open_elements}}, -2;
8730     } elsif ($self->{open_elements}->[-1]->[1] eq 'optgroup') {
8731 wakaba 1.79
8732     $Whatpm::HTML::Debug::cp_pass->('t284') if $Whatpm::HTML::Debug::cp_pass;
8733     BEGIN {
8734     $Whatpm::HTML::Debug::cp->{'t284'} = 1;
8735     }
8736    
8737 wakaba 1.54 pop @{$self->{open_elements}};
8738     } else {
8739 wakaba 1.79
8740     $Whatpm::HTML::Debug::cp_pass->('t285') if $Whatpm::HTML::Debug::cp_pass;
8741     BEGIN {
8742     $Whatpm::HTML::Debug::cp->{'t285'} = 1;
8743     }
8744    
8745 wakaba 1.44 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8746 wakaba 1.43 ## Ignore the token
8747 wakaba 1.54 }
8748     $token = $self->_get_next_token;
8749     redo B;
8750     } elsif ($token->{tag_name} eq 'option') {
8751     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8752 wakaba 1.79
8753     $Whatpm::HTML::Debug::cp_pass->('t286') if $Whatpm::HTML::Debug::cp_pass;
8754     BEGIN {
8755     $Whatpm::HTML::Debug::cp->{'t286'} = 1;
8756     }
8757    
8758 wakaba 1.54 pop @{$self->{open_elements}};
8759 wakaba 1.44 } else {
8760 wakaba 1.79
8761     $Whatpm::HTML::Debug::cp_pass->('t287') if $Whatpm::HTML::Debug::cp_pass;
8762     BEGIN {
8763     $Whatpm::HTML::Debug::cp->{'t287'} = 1;
8764     }
8765    
8766 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8767     ## Ignore the token
8768 wakaba 1.43 }
8769 wakaba 1.54 $token = $self->_get_next_token;
8770     redo B;
8771     } elsif ($token->{tag_name} eq 'select') {
8772     ## have an element in table scope
8773     my $i;
8774     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8775     my $node = $self->{open_elements}->[$_];
8776     if ($node->[1] eq $token->{tag_name}) {
8777 wakaba 1.79
8778     $Whatpm::HTML::Debug::cp_pass->('t288') if $Whatpm::HTML::Debug::cp_pass;
8779     BEGIN {
8780     $Whatpm::HTML::Debug::cp->{'t288'} = 1;
8781     }
8782    
8783 wakaba 1.54 $i = $_;
8784     last INSCOPE;
8785     } elsif ({
8786     table => 1, html => 1,
8787     }->{$node->[1]}) {
8788 wakaba 1.79
8789     $Whatpm::HTML::Debug::cp_pass->('t289') if $Whatpm::HTML::Debug::cp_pass;
8790     BEGIN {
8791     $Whatpm::HTML::Debug::cp->{'t289'} = 1;
8792     }
8793    
8794 wakaba 1.54 last INSCOPE;
8795 wakaba 1.44 }
8796 wakaba 1.54 } # INSCOPE
8797     unless (defined $i) {
8798 wakaba 1.79
8799     $Whatpm::HTML::Debug::cp_pass->('t290') if $Whatpm::HTML::Debug::cp_pass;
8800     BEGIN {
8801     $Whatpm::HTML::Debug::cp->{'t290'} = 1;
8802     }
8803    
8804 wakaba 1.44 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8805     ## Ignore the token
8806     $token = $self->_get_next_token;
8807 wakaba 1.43 redo B;
8808     }
8809 wakaba 1.54
8810 wakaba 1.79
8811     $Whatpm::HTML::Debug::cp_pass->('t291') if $Whatpm::HTML::Debug::cp_pass;
8812     BEGIN {
8813     $Whatpm::HTML::Debug::cp->{'t291'} = 1;
8814     }
8815    
8816 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8817    
8818     $self->_reset_insertion_mode;
8819    
8820     $token = $self->_get_next_token;
8821     redo B;
8822 wakaba 1.44 } elsif ({
8823 wakaba 1.54 caption => 1, table => 1, tbody => 1,
8824     tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,
8825     }->{$token->{tag_name}}) {
8826 wakaba 1.83 ## TODO: The following is wrong?
8827 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8828    
8829 wakaba 1.44 ## have an element in table scope
8830 wakaba 1.43 my $i;
8831     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8832     my $node = $self->{open_elements}->[$_];
8833     if ($node->[1] eq $token->{tag_name}) {
8834 wakaba 1.79
8835     $Whatpm::HTML::Debug::cp_pass->('t292') if $Whatpm::HTML::Debug::cp_pass;
8836     BEGIN {
8837     $Whatpm::HTML::Debug::cp->{'t292'} = 1;
8838     }
8839    
8840 wakaba 1.43 $i = $_;
8841     last INSCOPE;
8842     } elsif ({
8843     table => 1, html => 1,
8844     }->{$node->[1]}) {
8845 wakaba 1.79
8846     $Whatpm::HTML::Debug::cp_pass->('t293') if $Whatpm::HTML::Debug::cp_pass;
8847     BEGIN {
8848     $Whatpm::HTML::Debug::cp->{'t293'} = 1;
8849     }
8850    
8851 wakaba 1.43 last INSCOPE;
8852     }
8853     } # INSCOPE
8854     unless (defined $i) {
8855 wakaba 1.79
8856     $Whatpm::HTML::Debug::cp_pass->('t294') if $Whatpm::HTML::Debug::cp_pass;
8857     BEGIN {
8858     $Whatpm::HTML::Debug::cp->{'t294'} = 1;
8859     }
8860    
8861 wakaba 1.43 ## Ignore the token
8862     $token = $self->_get_next_token;
8863     redo B;
8864     }
8865 wakaba 1.54
8866     ## As if </select>
8867     ## have an element in table scope
8868     undef $i;
8869 wakaba 1.43 INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8870     my $node = $self->{open_elements}->[$_];
8871 wakaba 1.54 if ($node->[1] eq 'select') {
8872 wakaba 1.79
8873     $Whatpm::HTML::Debug::cp_pass->('t295') if $Whatpm::HTML::Debug::cp_pass;
8874     BEGIN {
8875     $Whatpm::HTML::Debug::cp->{'t295'} = 1;
8876     }
8877    
8878 wakaba 1.43 $i = $_;
8879     last INSCOPE;
8880     } elsif ({
8881     table => 1, html => 1,
8882     }->{$node->[1]}) {
8883 wakaba 1.83 ## ISSUE: Can this state be reached?
8884 wakaba 1.79
8885     $Whatpm::HTML::Debug::cp_pass->('t296') if $Whatpm::HTML::Debug::cp_pass;
8886     BEGIN {
8887     $Whatpm::HTML::Debug::cp->{'t296'} = 1;
8888     }
8889    
8890 wakaba 1.43 last INSCOPE;
8891     }
8892     } # INSCOPE
8893     unless (defined $i) {
8894 wakaba 1.79
8895     $Whatpm::HTML::Debug::cp_pass->('t297') if $Whatpm::HTML::Debug::cp_pass;
8896     BEGIN {
8897     $Whatpm::HTML::Debug::cp->{'t297'} = 1;
8898     }
8899    
8900 wakaba 1.83 ## TODO: The following error type is correct?
8901 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:select');
8902     ## Ignore the </select> token
8903     $token = $self->_get_next_token; ## TODO: ok?
8904 wakaba 1.43 redo B;
8905     }
8906 wakaba 1.54
8907 wakaba 1.79
8908     $Whatpm::HTML::Debug::cp_pass->('t298') if $Whatpm::HTML::Debug::cp_pass;
8909     BEGIN {
8910     $Whatpm::HTML::Debug::cp->{'t298'} = 1;
8911     }
8912    
8913 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8914    
8915     $self->_reset_insertion_mode;
8916    
8917     ## reprocess
8918     redo B;
8919 wakaba 1.60 } else {
8920 wakaba 1.79
8921     $Whatpm::HTML::Debug::cp_pass->('t299') if $Whatpm::HTML::Debug::cp_pass;
8922     BEGIN {
8923     $Whatpm::HTML::Debug::cp->{'t299'} = 1;
8924     }
8925    
8926 wakaba 1.60 $self->{parse_error}-> (type => 'in select:/'.$token->{tag_name});
8927 wakaba 1.54 ## Ignore the token
8928     $token = $self->_get_next_token;
8929     redo B;
8930 wakaba 1.60 }
8931     } else {
8932     die "$0: $token->{type}: Unknown token type";
8933     }
8934 wakaba 1.58 } elsif ($self->{insertion_mode} & BODY_AFTER_IMS) {
8935 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
8936 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
8937     my $data = $1;
8938     ## As if in body
8939     $reconstruct_active_formatting_elements->($insert_to_current);
8940    
8941     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
8942    
8943     unless (length $token->{data}) {
8944 wakaba 1.79
8945     $Whatpm::HTML::Debug::cp_pass->('t300') if $Whatpm::HTML::Debug::cp_pass;
8946     BEGIN {
8947     $Whatpm::HTML::Debug::cp->{'t300'} = 1;
8948     }
8949    
8950 wakaba 1.54 $token = $self->_get_next_token;
8951     redo B;
8952     }
8953     }
8954    
8955 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
8956 wakaba 1.79
8957     $Whatpm::HTML::Debug::cp_pass->('t301') if $Whatpm::HTML::Debug::cp_pass;
8958     BEGIN {
8959     $Whatpm::HTML::Debug::cp->{'t301'} = 1;
8960     }
8961    
8962 wakaba 1.54 $self->{parse_error}-> (type => 'after html:#character');
8963    
8964 wakaba 1.85 ## Reprocess in the "after body" insertion mode.
8965 wakaba 1.79 } else {
8966    
8967     $Whatpm::HTML::Debug::cp_pass->('t302') if $Whatpm::HTML::Debug::cp_pass;
8968     BEGIN {
8969     $Whatpm::HTML::Debug::cp->{'t302'} = 1;
8970     }
8971    
8972 wakaba 1.54 }
8973    
8974     ## "after body" insertion mode
8975     $self->{parse_error}-> (type => 'after body:#character');
8976    
8977 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
8978 wakaba 1.54 ## reprocess
8979     redo B;
8980 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
8981 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
8982 wakaba 1.79
8983     $Whatpm::HTML::Debug::cp_pass->('t303') if $Whatpm::HTML::Debug::cp_pass;
8984     BEGIN {
8985     $Whatpm::HTML::Debug::cp->{'t303'} = 1;
8986     }
8987    
8988 wakaba 1.54 $self->{parse_error}-> (type => 'after html:'.$token->{tag_name});
8989    
8990 wakaba 1.85 ## Reprocess in the "after body" insertion mode.
8991 wakaba 1.79 } else {
8992    
8993     $Whatpm::HTML::Debug::cp_pass->('t304') if $Whatpm::HTML::Debug::cp_pass;
8994     BEGIN {
8995     $Whatpm::HTML::Debug::cp->{'t304'} = 1;
8996     }
8997    
8998 wakaba 1.54 }
8999    
9000     ## "after body" insertion mode
9001     $self->{parse_error}-> (type => 'after body:'.$token->{tag_name});
9002    
9003 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
9004 wakaba 1.54 ## reprocess
9005     redo B;
9006 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
9007 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
9008 wakaba 1.79
9009     $Whatpm::HTML::Debug::cp_pass->('t305') if $Whatpm::HTML::Debug::cp_pass;
9010     BEGIN {
9011     $Whatpm::HTML::Debug::cp->{'t305'} = 1;
9012     }
9013    
9014 wakaba 1.54 $self->{parse_error}-> (type => 'after html:/'.$token->{tag_name});
9015    
9016 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
9017 wakaba 1.85 ## Reprocess in the "after body" insertion mode.
9018 wakaba 1.79 } else {
9019    
9020     $Whatpm::HTML::Debug::cp_pass->('t306') if $Whatpm::HTML::Debug::cp_pass;
9021     BEGIN {
9022     $Whatpm::HTML::Debug::cp->{'t306'} = 1;
9023     }
9024    
9025 wakaba 1.54 }
9026    
9027     ## "after body" insertion mode
9028     if ($token->{tag_name} eq 'html') {
9029     if (defined $self->{inner_html_node}) {
9030 wakaba 1.79
9031     $Whatpm::HTML::Debug::cp_pass->('t307') if $Whatpm::HTML::Debug::cp_pass;
9032     BEGIN {
9033     $Whatpm::HTML::Debug::cp->{'t307'} = 1;
9034     }
9035    
9036 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:html');
9037     ## Ignore the token
9038     $token = $self->_get_next_token;
9039     redo B;
9040     } else {
9041 wakaba 1.79
9042     $Whatpm::HTML::Debug::cp_pass->('t308') if $Whatpm::HTML::Debug::cp_pass;
9043     BEGIN {
9044     $Whatpm::HTML::Debug::cp->{'t308'} = 1;
9045     }
9046    
9047 wakaba 1.56 $self->{insertion_mode} = AFTER_HTML_BODY_IM;
9048 wakaba 1.54 $token = $self->_get_next_token;
9049     redo B;
9050     }
9051     } else {
9052 wakaba 1.79
9053     $Whatpm::HTML::Debug::cp_pass->('t309') if $Whatpm::HTML::Debug::cp_pass;
9054     BEGIN {
9055     $Whatpm::HTML::Debug::cp->{'t309'} = 1;
9056     }
9057    
9058 wakaba 1.54 $self->{parse_error}-> (type => 'after body:/'.$token->{tag_name});
9059    
9060 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
9061 wakaba 1.54 ## reprocess
9062     redo B;
9063     }
9064     } else {
9065     die "$0: $token->{type}: Unknown token type";
9066     }
9067 wakaba 1.58 } elsif ($self->{insertion_mode} & FRAME_IMS) {
9068 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
9069 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
9070     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
9071    
9072     unless (length $token->{data}) {
9073 wakaba 1.79
9074     $Whatpm::HTML::Debug::cp_pass->('t310') if $Whatpm::HTML::Debug::cp_pass;
9075     BEGIN {
9076     $Whatpm::HTML::Debug::cp->{'t310'} = 1;
9077     }
9078    
9079 wakaba 1.54 $token = $self->_get_next_token;
9080     redo B;
9081     }
9082     }
9083    
9084     if ($token->{data} =~ s/^[^\x09\x0A\x0B\x0C\x20]+//) {
9085 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9086 wakaba 1.79
9087     $Whatpm::HTML::Debug::cp_pass->('t311') if $Whatpm::HTML::Debug::cp_pass;
9088     BEGIN {
9089     $Whatpm::HTML::Debug::cp->{'t311'} = 1;
9090     }
9091    
9092 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:#character');
9093 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_FRAMESET_IM) {
9094 wakaba 1.79
9095     $Whatpm::HTML::Debug::cp_pass->('t312') if $Whatpm::HTML::Debug::cp_pass;
9096     BEGIN {
9097     $Whatpm::HTML::Debug::cp->{'t312'} = 1;
9098     }
9099    
9100 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:#character');
9101     } else { # "after html frameset"
9102 wakaba 1.79
9103     $Whatpm::HTML::Debug::cp_pass->('t313') if $Whatpm::HTML::Debug::cp_pass;
9104     BEGIN {
9105     $Whatpm::HTML::Debug::cp->{'t313'} = 1;
9106     }
9107    
9108 wakaba 1.54 $self->{parse_error}-> (type => 'after html:#character');
9109    
9110 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9111 wakaba 1.85 ## Reprocess in the "after frameset" insertion mode.
9112 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:#character');
9113     }
9114    
9115     ## Ignore the token.
9116     if (length $token->{data}) {
9117 wakaba 1.79
9118     $Whatpm::HTML::Debug::cp_pass->('t314') if $Whatpm::HTML::Debug::cp_pass;
9119     BEGIN {
9120     $Whatpm::HTML::Debug::cp->{'t314'} = 1;
9121     }
9122    
9123 wakaba 1.54 ## reprocess the rest of characters
9124     } else {
9125 wakaba 1.79
9126     $Whatpm::HTML::Debug::cp_pass->('t315') if $Whatpm::HTML::Debug::cp_pass;
9127     BEGIN {
9128     $Whatpm::HTML::Debug::cp->{'t315'} = 1;
9129     }
9130    
9131 wakaba 1.54 $token = $self->_get_next_token;
9132     }
9133     redo B;
9134     }
9135    
9136     die qq[$0: Character "$token->{data}"];
9137 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
9138 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
9139 wakaba 1.79
9140     $Whatpm::HTML::Debug::cp_pass->('t316') if $Whatpm::HTML::Debug::cp_pass;
9141     BEGIN {
9142     $Whatpm::HTML::Debug::cp->{'t316'} = 1;
9143     }
9144    
9145 wakaba 1.54 $self->{parse_error}-> (type => 'after html:'.$token->{tag_name});
9146    
9147 wakaba 1.79 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9148 wakaba 1.85 ## Process in the "after frameset" insertion mode.
9149 wakaba 1.79 } else {
9150    
9151     $Whatpm::HTML::Debug::cp_pass->('t317') if $Whatpm::HTML::Debug::cp_pass;
9152     BEGIN {
9153     $Whatpm::HTML::Debug::cp->{'t317'} = 1;
9154     }
9155    
9156     }
9157    
9158 wakaba 1.54 if ($token->{tag_name} eq 'frameset' and
9159 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9160 wakaba 1.54
9161 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t318') if $Whatpm::HTML::Debug::cp_pass;
9162     BEGIN {
9163     $Whatpm::HTML::Debug::cp->{'t318'} = 1;
9164     }
9165    
9166    
9167 wakaba 1.54 {
9168     my $el;
9169    
9170     $el = $self->{document}->create_element_ns
9171     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9172    
9173     for my $attr_name (keys %{ $token->{attributes}}) {
9174     $el->set_attribute_ns (undef, [undef, $attr_name],
9175     $token->{attributes} ->{$attr_name}->{value});
9176     }
9177    
9178     $self->{open_elements}->[-1]->[0]->append_child ($el);
9179     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9180     }
9181    
9182     $token = $self->_get_next_token;
9183     redo B;
9184     } elsif ($token->{tag_name} eq 'frame' and
9185 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9186 wakaba 1.54
9187 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t319') if $Whatpm::HTML::Debug::cp_pass;
9188     BEGIN {
9189     $Whatpm::HTML::Debug::cp->{'t319'} = 1;
9190     }
9191    
9192    
9193 wakaba 1.54 {
9194     my $el;
9195    
9196     $el = $self->{document}->create_element_ns
9197     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9198    
9199     for my $attr_name (keys %{ $token->{attributes}}) {
9200     $el->set_attribute_ns (undef, [undef, $attr_name],
9201     $token->{attributes} ->{$attr_name}->{value});
9202     }
9203    
9204     $self->{open_elements}->[-1]->[0]->append_child ($el);
9205     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9206     }
9207    
9208     pop @{$self->{open_elements}};
9209     $token = $self->_get_next_token;
9210     redo B;
9211     } elsif ($token->{tag_name} eq 'noframes') {
9212 wakaba 1.79
9213     $Whatpm::HTML::Debug::cp_pass->('t320') if $Whatpm::HTML::Debug::cp_pass;
9214     BEGIN {
9215     $Whatpm::HTML::Debug::cp->{'t320'} = 1;
9216     }
9217    
9218 wakaba 1.54 ## NOTE: As if in body.
9219     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert_to_current);
9220     redo B;
9221     } else {
9222 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9223 wakaba 1.79
9224     $Whatpm::HTML::Debug::cp_pass->('t321') if $Whatpm::HTML::Debug::cp_pass;
9225     BEGIN {
9226     $Whatpm::HTML::Debug::cp->{'t321'} = 1;
9227     }
9228    
9229 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:'.$token->{tag_name});
9230     } else {
9231 wakaba 1.79
9232     $Whatpm::HTML::Debug::cp_pass->('t322') if $Whatpm::HTML::Debug::cp_pass;
9233     BEGIN {
9234     $Whatpm::HTML::Debug::cp->{'t322'} = 1;
9235     }
9236    
9237 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:'.$token->{tag_name});
9238     }
9239     ## Ignore the token
9240     $token = $self->_get_next_token;
9241     redo B;
9242     }
9243 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
9244 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
9245 wakaba 1.79
9246     $Whatpm::HTML::Debug::cp_pass->('t323') if $Whatpm::HTML::Debug::cp_pass;
9247     BEGIN {
9248     $Whatpm::HTML::Debug::cp->{'t323'} = 1;
9249     }
9250    
9251 wakaba 1.54 $self->{parse_error}-> (type => 'after html:/'.$token->{tag_name});
9252    
9253 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9254 wakaba 1.85 ## Process in the "after frameset" insertion mode.
9255 wakaba 1.79 } else {
9256    
9257     $Whatpm::HTML::Debug::cp_pass->('t324') if $Whatpm::HTML::Debug::cp_pass;
9258     BEGIN {
9259     $Whatpm::HTML::Debug::cp->{'t324'} = 1;
9260     }
9261    
9262 wakaba 1.54 }
9263    
9264     if ($token->{tag_name} eq 'frameset' and
9265 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9266 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] eq 'html' and
9267     @{$self->{open_elements}} == 1) {
9268 wakaba 1.79
9269     $Whatpm::HTML::Debug::cp_pass->('t325') if $Whatpm::HTML::Debug::cp_pass;
9270     BEGIN {
9271     $Whatpm::HTML::Debug::cp->{'t325'} = 1;
9272     }
9273    
9274 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
9275     ## Ignore the token
9276     $token = $self->_get_next_token;
9277     } else {
9278 wakaba 1.79
9279     $Whatpm::HTML::Debug::cp_pass->('t326') if $Whatpm::HTML::Debug::cp_pass;
9280     BEGIN {
9281     $Whatpm::HTML::Debug::cp->{'t326'} = 1;
9282     }
9283    
9284 wakaba 1.54 pop @{$self->{open_elements}};
9285     $token = $self->_get_next_token;
9286     }
9287 wakaba 1.43
9288 wakaba 1.54 if (not defined $self->{inner_html_node} and
9289     $self->{open_elements}->[-1]->[1] ne 'frameset') {
9290 wakaba 1.79
9291     $Whatpm::HTML::Debug::cp_pass->('t327') if $Whatpm::HTML::Debug::cp_pass;
9292     BEGIN {
9293     $Whatpm::HTML::Debug::cp->{'t327'} = 1;
9294     }
9295    
9296 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9297 wakaba 1.79 } else {
9298    
9299     $Whatpm::HTML::Debug::cp_pass->('t328') if $Whatpm::HTML::Debug::cp_pass;
9300     BEGIN {
9301     $Whatpm::HTML::Debug::cp->{'t328'} = 1;
9302     }
9303    
9304 wakaba 1.54 }
9305     redo B;
9306     } elsif ($token->{tag_name} eq 'html' and
9307 wakaba 1.56 $self->{insertion_mode} == AFTER_FRAMESET_IM) {
9308 wakaba 1.79
9309     $Whatpm::HTML::Debug::cp_pass->('t329') if $Whatpm::HTML::Debug::cp_pass;
9310     BEGIN {
9311     $Whatpm::HTML::Debug::cp->{'t329'} = 1;
9312     }
9313    
9314 wakaba 1.56 $self->{insertion_mode} = AFTER_HTML_FRAMESET_IM;
9315 wakaba 1.54 $token = $self->_get_next_token;
9316     redo B;
9317     } else {
9318 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9319 wakaba 1.79
9320     $Whatpm::HTML::Debug::cp_pass->('t330') if $Whatpm::HTML::Debug::cp_pass;
9321     BEGIN {
9322     $Whatpm::HTML::Debug::cp->{'t330'} = 1;
9323     }
9324    
9325 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:/'.$token->{tag_name});
9326     } else {
9327 wakaba 1.79
9328     $Whatpm::HTML::Debug::cp_pass->('t331') if $Whatpm::HTML::Debug::cp_pass;
9329     BEGIN {
9330     $Whatpm::HTML::Debug::cp->{'t331'} = 1;
9331     }
9332    
9333 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:/'.$token->{tag_name});
9334     }
9335     ## Ignore the token
9336     $token = $self->_get_next_token;
9337     redo B;
9338     }
9339     } else {
9340     die "$0: $token->{type}: Unknown token type";
9341     }
9342 wakaba 1.43
9343 wakaba 1.54 ## ISSUE: An issue in spec here
9344     } else {
9345     die "$0: $self->{insertion_mode}: Unknown insertion mode";
9346     }
9347 wakaba 1.43
9348 wakaba 1.54 ## "in body" insertion mode
9349 wakaba 1.57 if ($token->{type} == START_TAG_TOKEN) {
9350 wakaba 1.54 if ($token->{tag_name} eq 'script') {
9351 wakaba 1.79
9352     $Whatpm::HTML::Debug::cp_pass->('t332') if $Whatpm::HTML::Debug::cp_pass;
9353     BEGIN {
9354     $Whatpm::HTML::Debug::cp->{'t332'} = 1;
9355     }
9356    
9357 wakaba 1.54 ## NOTE: This is an "as if in head" code clone
9358     $script_start_tag->($insert);
9359 wakaba 1.55 redo B;
9360 wakaba 1.54 } elsif ($token->{tag_name} eq 'style') {
9361 wakaba 1.79
9362     $Whatpm::HTML::Debug::cp_pass->('t333') if $Whatpm::HTML::Debug::cp_pass;
9363     BEGIN {
9364     $Whatpm::HTML::Debug::cp->{'t333'} = 1;
9365     }
9366    
9367 wakaba 1.54 ## NOTE: This is an "as if in head" code clone
9368     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
9369 wakaba 1.55 redo B;
9370 wakaba 1.54 } elsif ({
9371     base => 1, link => 1,
9372     }->{$token->{tag_name}}) {
9373 wakaba 1.79
9374     $Whatpm::HTML::Debug::cp_pass->('t334') if $Whatpm::HTML::Debug::cp_pass;
9375     BEGIN {
9376     $Whatpm::HTML::Debug::cp->{'t334'} = 1;
9377     }
9378    
9379 wakaba 1.54 ## NOTE: This is an "as if in head" code clone, only "-t" differs
9380    
9381     {
9382     my $el;
9383    
9384     $el = $self->{document}->create_element_ns
9385     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9386    
9387     for my $attr_name (keys %{ $token->{attributes}}) {
9388     $el->set_attribute_ns (undef, [undef, $attr_name],
9389     $token->{attributes} ->{$attr_name}->{value});
9390     }
9391    
9392     $insert->($el);
9393     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9394     }
9395    
9396     pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
9397     $token = $self->_get_next_token;
9398 wakaba 1.55 redo B;
9399 wakaba 1.54 } elsif ($token->{tag_name} eq 'meta') {
9400     ## NOTE: This is an "as if in head" code clone, only "-t" differs
9401    
9402     {
9403     my $el;
9404    
9405     $el = $self->{document}->create_element_ns
9406     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9407    
9408     for my $attr_name (keys %{ $token->{attributes}}) {
9409     $el->set_attribute_ns (undef, [undef, $attr_name],
9410     $token->{attributes} ->{$attr_name}->{value});
9411     }
9412    
9413     $insert->($el);
9414     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9415     }
9416    
9417 wakaba 1.68 my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
9418 wakaba 1.43
9419 wakaba 1.54 unless ($self->{confident}) {
9420     if ($token->{attributes}->{charset}) { ## TODO: And if supported
9421 wakaba 1.79
9422     $Whatpm::HTML::Debug::cp_pass->('t335') if $Whatpm::HTML::Debug::cp_pass;
9423     BEGIN {
9424     $Whatpm::HTML::Debug::cp->{'t335'} = 1;
9425     }
9426    
9427 wakaba 1.65 $self->{change_encoding}
9428     ->($self, $token->{attributes}->{charset}->{value});
9429 wakaba 1.68
9430     $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
9431     ->set_user_data (manakai_has_reference =>
9432     $token->{attributes}->{charset}
9433     ->{has_reference});
9434 wakaba 1.65 } elsif ($token->{attributes}->{content}) {
9435 wakaba 1.54 ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.
9436 wakaba 1.65 if ($token->{attributes}->{content}->{value}
9437 wakaba 1.71 =~ /\A[^;]*;[\x09-\x0D\x20]*[Cc][Hh][Aa][Rr][Ss][Ee][Tt]
9438     [\x09-\x0D\x20]*=
9439 wakaba 1.54 [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
9440     ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
9441 wakaba 1.79
9442     $Whatpm::HTML::Debug::cp_pass->('t336') if $Whatpm::HTML::Debug::cp_pass;
9443     BEGIN {
9444     $Whatpm::HTML::Debug::cp->{'t336'} = 1;
9445     }
9446    
9447 wakaba 1.65 $self->{change_encoding}
9448     ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);
9449 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
9450     ->set_user_data (manakai_has_reference =>
9451     $token->{attributes}->{content}
9452     ->{has_reference});
9453 wakaba 1.65 }
9454 wakaba 1.54 }
9455 wakaba 1.68 } else {
9456     if ($token->{attributes}->{charset}) {
9457 wakaba 1.79
9458     $Whatpm::HTML::Debug::cp_pass->('t337') if $Whatpm::HTML::Debug::cp_pass;
9459     BEGIN {
9460     $Whatpm::HTML::Debug::cp->{'t337'} = 1;
9461     }
9462    
9463 wakaba 1.68 $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
9464     ->set_user_data (manakai_has_reference =>
9465     $token->{attributes}->{charset}
9466     ->{has_reference});
9467     }
9468 wakaba 1.69 if ($token->{attributes}->{content}) {
9469 wakaba 1.79
9470     $Whatpm::HTML::Debug::cp_pass->('t338') if $Whatpm::HTML::Debug::cp_pass;
9471     BEGIN {
9472     $Whatpm::HTML::Debug::cp->{'t338'} = 1;
9473     }
9474    
9475 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
9476     ->set_user_data (manakai_has_reference =>
9477     $token->{attributes}->{content}
9478     ->{has_reference});
9479     }
9480 wakaba 1.54 }
9481 wakaba 1.43
9482 wakaba 1.54 $token = $self->_get_next_token;
9483 wakaba 1.55 redo B;
9484 wakaba 1.54 } elsif ($token->{tag_name} eq 'title') {
9485 wakaba 1.79
9486     $Whatpm::HTML::Debug::cp_pass->('t341') if $Whatpm::HTML::Debug::cp_pass;
9487     BEGIN {
9488     $Whatpm::HTML::Debug::cp->{'t341'} = 1;
9489     }
9490    
9491 wakaba 1.54 $self->{parse_error}-> (type => 'in body:title');
9492     ## NOTE: This is an "as if in head" code clone
9493     $parse_rcdata->(RCDATA_CONTENT_MODEL, sub {
9494     if (defined $self->{head_element}) {
9495 wakaba 1.79
9496     $Whatpm::HTML::Debug::cp_pass->('t339') if $Whatpm::HTML::Debug::cp_pass;
9497     BEGIN {
9498     $Whatpm::HTML::Debug::cp->{'t339'} = 1;
9499     }
9500    
9501 wakaba 1.54 $self->{head_element}->append_child ($_[0]);
9502 wakaba 1.1 } else {
9503 wakaba 1.79
9504     $Whatpm::HTML::Debug::cp_pass->('t340') if $Whatpm::HTML::Debug::cp_pass;
9505     BEGIN {
9506     $Whatpm::HTML::Debug::cp->{'t340'} = 1;
9507     }
9508    
9509 wakaba 1.54 $insert->($_[0]);
9510 wakaba 1.1 }
9511 wakaba 1.54 });
9512 wakaba 1.55 redo B;
9513 wakaba 1.54 } elsif ($token->{tag_name} eq 'body') {
9514     $self->{parse_error}-> (type => 'in body:body');
9515 wakaba 1.1
9516 wakaba 1.54 if (@{$self->{open_elements}} == 1 or
9517     $self->{open_elements}->[1]->[1] ne 'body') {
9518 wakaba 1.79
9519     $Whatpm::HTML::Debug::cp_pass->('t342') if $Whatpm::HTML::Debug::cp_pass;
9520     BEGIN {
9521     $Whatpm::HTML::Debug::cp->{'t342'} = 1;
9522     }
9523    
9524 wakaba 1.54 ## Ignore the token
9525     } else {
9526     my $body_el = $self->{open_elements}->[1]->[0];
9527     for my $attr_name (keys %{$token->{attributes}}) {
9528     unless ($body_el->has_attribute_ns (undef, $attr_name)) {
9529 wakaba 1.79
9530     $Whatpm::HTML::Debug::cp_pass->('t343') if $Whatpm::HTML::Debug::cp_pass;
9531     BEGIN {
9532     $Whatpm::HTML::Debug::cp->{'t343'} = 1;
9533     }
9534    
9535 wakaba 1.54 $body_el->set_attribute_ns
9536     (undef, [undef, $attr_name],
9537     $token->{attributes}->{$attr_name}->{value});
9538 wakaba 1.1 }
9539 wakaba 1.54 }
9540     }
9541     $token = $self->_get_next_token;
9542 wakaba 1.55 redo B;
9543 wakaba 1.54 } elsif ({
9544     address => 1, blockquote => 1, center => 1, dir => 1,
9545 wakaba 1.85 div => 1, dl => 1, fieldset => 1,
9546     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
9547     listing => 1, menu => 1, ol => 1, p => 1, ul => 1,
9548 wakaba 1.54 pre => 1,
9549     }->{$token->{tag_name}}) {
9550     ## has a p element in scope
9551     INSCOPE: for (reverse @{$self->{open_elements}}) {
9552     if ($_->[1] eq 'p') {
9553 wakaba 1.79
9554     $Whatpm::HTML::Debug::cp_pass->('t344') if $Whatpm::HTML::Debug::cp_pass;
9555     BEGIN {
9556     $Whatpm::HTML::Debug::cp->{'t344'} = 1;
9557     }
9558    
9559 wakaba 1.54 unshift @{$self->{token}}, $token;
9560 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9561 wakaba 1.55 redo B;
9562 wakaba 1.54 } elsif ({
9563     table => 1, caption => 1, td => 1, th => 1,
9564     button => 1, marquee => 1, object => 1, html => 1,
9565     }->{$_->[1]}) {
9566 wakaba 1.79
9567     $Whatpm::HTML::Debug::cp_pass->('t345') if $Whatpm::HTML::Debug::cp_pass;
9568     BEGIN {
9569     $Whatpm::HTML::Debug::cp->{'t345'} = 1;
9570     }
9571    
9572 wakaba 1.54 last INSCOPE;
9573     }
9574     } # INSCOPE
9575    
9576    
9577 wakaba 1.48 {
9578     my $el;
9579    
9580     $el = $self->{document}->create_element_ns
9581 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9582 wakaba 1.48
9583 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9584     $el->set_attribute_ns (undef, [undef, $attr_name],
9585     $token->{attributes} ->{$attr_name}->{value});
9586     }
9587    
9588     $insert->($el);
9589     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9590 wakaba 1.48 }
9591    
9592 wakaba 1.54 if ($token->{tag_name} eq 'pre') {
9593     $token = $self->_get_next_token;
9594 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
9595 wakaba 1.54 $token->{data} =~ s/^\x0A//;
9596     unless (length $token->{data}) {
9597 wakaba 1.79
9598     $Whatpm::HTML::Debug::cp_pass->('t346') if $Whatpm::HTML::Debug::cp_pass;
9599     BEGIN {
9600     $Whatpm::HTML::Debug::cp->{'t346'} = 1;
9601     }
9602    
9603 wakaba 1.54 $token = $self->_get_next_token;
9604 wakaba 1.79 } else {
9605    
9606     $Whatpm::HTML::Debug::cp_pass->('t349') if $Whatpm::HTML::Debug::cp_pass;
9607     BEGIN {
9608     $Whatpm::HTML::Debug::cp->{'t349'} = 1;
9609     }
9610    
9611 wakaba 1.54 }
9612 wakaba 1.79 } else {
9613    
9614     $Whatpm::HTML::Debug::cp_pass->('t348') if $Whatpm::HTML::Debug::cp_pass;
9615     BEGIN {
9616     $Whatpm::HTML::Debug::cp->{'t348'} = 1;
9617     }
9618    
9619 wakaba 1.54 }
9620     } else {
9621 wakaba 1.79
9622     $Whatpm::HTML::Debug::cp_pass->('t347') if $Whatpm::HTML::Debug::cp_pass;
9623     BEGIN {
9624     $Whatpm::HTML::Debug::cp->{'t347'} = 1;
9625     }
9626    
9627 wakaba 1.54 $token = $self->_get_next_token;
9628     }
9629 wakaba 1.55 redo B;
9630 wakaba 1.54 } elsif ($token->{tag_name} eq 'form') {
9631     if (defined $self->{form_element}) {
9632 wakaba 1.79
9633     $Whatpm::HTML::Debug::cp_pass->('t350') if $Whatpm::HTML::Debug::cp_pass;
9634     BEGIN {
9635     $Whatpm::HTML::Debug::cp->{'t350'} = 1;
9636     }
9637    
9638 wakaba 1.54 $self->{parse_error}-> (type => 'in form:form');
9639     ## Ignore the token
9640     $token = $self->_get_next_token;
9641 wakaba 1.55 redo B;
9642 wakaba 1.54 } else {
9643     ## has a p element in scope
9644     INSCOPE: for (reverse @{$self->{open_elements}}) {
9645     if ($_->[1] eq 'p') {
9646 wakaba 1.79
9647     $Whatpm::HTML::Debug::cp_pass->('t351') if $Whatpm::HTML::Debug::cp_pass;
9648     BEGIN {
9649     $Whatpm::HTML::Debug::cp->{'t351'} = 1;
9650     }
9651    
9652 wakaba 1.54 unshift @{$self->{token}}, $token;
9653 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9654 wakaba 1.55 redo B;
9655 wakaba 1.54 } elsif ({
9656     table => 1, caption => 1, td => 1, th => 1,
9657     button => 1, marquee => 1, object => 1, html => 1,
9658     }->{$_->[1]}) {
9659 wakaba 1.79
9660     $Whatpm::HTML::Debug::cp_pass->('t352') if $Whatpm::HTML::Debug::cp_pass;
9661     BEGIN {
9662     $Whatpm::HTML::Debug::cp->{'t352'} = 1;
9663     }
9664    
9665 wakaba 1.54 last INSCOPE;
9666     }
9667     } # INSCOPE
9668    
9669    
9670 wakaba 1.1 {
9671     my $el;
9672    
9673     $el = $self->{document}->create_element_ns
9674     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9675    
9676     for my $attr_name (keys %{ $token->{attributes}}) {
9677     $el->set_attribute_ns (undef, [undef, $attr_name],
9678     $token->{attributes} ->{$attr_name}->{value});
9679     }
9680    
9681 wakaba 1.54 $insert->($el);
9682 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9683 wakaba 1.1 }
9684    
9685 wakaba 1.54 $self->{form_element} = $self->{open_elements}->[-1]->[0];
9686     $token = $self->_get_next_token;
9687 wakaba 1.55 redo B;
9688 wakaba 1.54 }
9689     } elsif ($token->{tag_name} eq 'li') {
9690     ## has a p element in scope
9691     INSCOPE: for (reverse @{$self->{open_elements}}) {
9692     if ($_->[1] eq 'p') {
9693 wakaba 1.79
9694     $Whatpm::HTML::Debug::cp_pass->('t353') if $Whatpm::HTML::Debug::cp_pass;
9695     BEGIN {
9696     $Whatpm::HTML::Debug::cp->{'t353'} = 1;
9697     }
9698    
9699 wakaba 1.54 unshift @{$self->{token}}, $token;
9700 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9701 wakaba 1.55 redo B;
9702 wakaba 1.54 } elsif ({
9703     table => 1, caption => 1, td => 1, th => 1,
9704     button => 1, marquee => 1, object => 1, html => 1,
9705     }->{$_->[1]}) {
9706 wakaba 1.79
9707     $Whatpm::HTML::Debug::cp_pass->('t354') if $Whatpm::HTML::Debug::cp_pass;
9708     BEGIN {
9709     $Whatpm::HTML::Debug::cp->{'t354'} = 1;
9710     }
9711    
9712 wakaba 1.54 last INSCOPE;
9713     }
9714     } # INSCOPE
9715    
9716     ## Step 1
9717     my $i = -1;
9718     my $node = $self->{open_elements}->[$i];
9719     LI: {
9720     ## Step 2
9721     if ($node->[1] eq 'li') {
9722     if ($i != -1) {
9723 wakaba 1.79
9724     $Whatpm::HTML::Debug::cp_pass->('t355') if $Whatpm::HTML::Debug::cp_pass;
9725     BEGIN {
9726     $Whatpm::HTML::Debug::cp->{'t355'} = 1;
9727     }
9728    
9729 wakaba 1.54 $self->{parse_error}-> (type => 'end tag missing:'.
9730     $self->{open_elements}->[-1]->[1]);
9731 wakaba 1.79 } else {
9732    
9733     $Whatpm::HTML::Debug::cp_pass->('t356') if $Whatpm::HTML::Debug::cp_pass;
9734     BEGIN {
9735     $Whatpm::HTML::Debug::cp->{'t356'} = 1;
9736     }
9737    
9738 wakaba 1.54 }
9739     splice @{$self->{open_elements}}, $i;
9740     last LI;
9741 wakaba 1.79 } else {
9742    
9743     $Whatpm::HTML::Debug::cp_pass->('t357') if $Whatpm::HTML::Debug::cp_pass;
9744     BEGIN {
9745     $Whatpm::HTML::Debug::cp->{'t357'} = 1;
9746     }
9747    
9748 wakaba 1.54 }
9749    
9750     ## Step 3
9751     if (not $formatting_category->{$node->[1]} and
9752     #not $phrasing_category->{$node->[1]} and
9753     ($special_category->{$node->[1]} or
9754     $scoping_category->{$node->[1]}) and
9755     $node->[1] ne 'address' and $node->[1] ne 'div') {
9756 wakaba 1.79
9757     $Whatpm::HTML::Debug::cp_pass->('t358') if $Whatpm::HTML::Debug::cp_pass;
9758     BEGIN {
9759     $Whatpm::HTML::Debug::cp->{'t358'} = 1;
9760     }
9761    
9762 wakaba 1.54 last LI;
9763     }
9764    
9765 wakaba 1.79
9766     $Whatpm::HTML::Debug::cp_pass->('t359') if $Whatpm::HTML::Debug::cp_pass;
9767     BEGIN {
9768     $Whatpm::HTML::Debug::cp->{'t359'} = 1;
9769     }
9770    
9771 wakaba 1.54 ## Step 4
9772     $i--;
9773     $node = $self->{open_elements}->[$i];
9774     redo LI;
9775     } # LI
9776    
9777    
9778 wakaba 1.48 {
9779     my $el;
9780    
9781     $el = $self->{document}->create_element_ns
9782 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9783 wakaba 1.48
9784 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9785     $el->set_attribute_ns (undef, [undef, $attr_name],
9786     $token->{attributes} ->{$attr_name}->{value});
9787     }
9788    
9789     $insert->($el);
9790     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9791 wakaba 1.48 }
9792    
9793 wakaba 1.54 $token = $self->_get_next_token;
9794 wakaba 1.55 redo B;
9795 wakaba 1.54 } elsif ($token->{tag_name} eq 'dd' or $token->{tag_name} eq 'dt') {
9796     ## has a p element in scope
9797     INSCOPE: for (reverse @{$self->{open_elements}}) {
9798     if ($_->[1] eq 'p') {
9799 wakaba 1.79
9800     $Whatpm::HTML::Debug::cp_pass->('t360') if $Whatpm::HTML::Debug::cp_pass;
9801     BEGIN {
9802     $Whatpm::HTML::Debug::cp->{'t360'} = 1;
9803     }
9804    
9805 wakaba 1.54 unshift @{$self->{token}}, $token;
9806 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9807 wakaba 1.55 redo B;
9808 wakaba 1.54 } elsif ({
9809     table => 1, caption => 1, td => 1, th => 1,
9810     button => 1, marquee => 1, object => 1, html => 1,
9811     }->{$_->[1]}) {
9812 wakaba 1.79
9813     $Whatpm::HTML::Debug::cp_pass->('t361') if $Whatpm::HTML::Debug::cp_pass;
9814     BEGIN {
9815     $Whatpm::HTML::Debug::cp->{'t361'} = 1;
9816     }
9817    
9818 wakaba 1.54 last INSCOPE;
9819     }
9820     } # INSCOPE
9821    
9822     ## Step 1
9823     my $i = -1;
9824     my $node = $self->{open_elements}->[$i];
9825     LI: {
9826     ## Step 2
9827     if ($node->[1] eq 'dt' or $node->[1] eq 'dd') {
9828     if ($i != -1) {
9829 wakaba 1.79
9830     $Whatpm::HTML::Debug::cp_pass->('t362') if $Whatpm::HTML::Debug::cp_pass;
9831     BEGIN {
9832     $Whatpm::HTML::Debug::cp->{'t362'} = 1;
9833     }
9834    
9835 wakaba 1.54 $self->{parse_error}-> (type => 'end tag missing:'.
9836     $self->{open_elements}->[-1]->[1]);
9837 wakaba 1.79 } else {
9838    
9839     $Whatpm::HTML::Debug::cp_pass->('t363') if $Whatpm::HTML::Debug::cp_pass;
9840     BEGIN {
9841     $Whatpm::HTML::Debug::cp->{'t363'} = 1;
9842     }
9843    
9844 wakaba 1.54 }
9845     splice @{$self->{open_elements}}, $i;
9846     last LI;
9847 wakaba 1.79 } else {
9848    
9849     $Whatpm::HTML::Debug::cp_pass->('t364') if $Whatpm::HTML::Debug::cp_pass;
9850     BEGIN {
9851     $Whatpm::HTML::Debug::cp->{'t364'} = 1;
9852     }
9853    
9854 wakaba 1.54 }
9855    
9856     ## Step 3
9857     if (not $formatting_category->{$node->[1]} and
9858     #not $phrasing_category->{$node->[1]} and
9859     ($special_category->{$node->[1]} or
9860     $scoping_category->{$node->[1]}) and
9861     $node->[1] ne 'address' and $node->[1] ne 'div') {
9862 wakaba 1.79
9863     $Whatpm::HTML::Debug::cp_pass->('t365') if $Whatpm::HTML::Debug::cp_pass;
9864     BEGIN {
9865     $Whatpm::HTML::Debug::cp->{'t365'} = 1;
9866     }
9867    
9868 wakaba 1.54 last LI;
9869     }
9870    
9871 wakaba 1.79
9872     $Whatpm::HTML::Debug::cp_pass->('t366') if $Whatpm::HTML::Debug::cp_pass;
9873     BEGIN {
9874     $Whatpm::HTML::Debug::cp->{'t366'} = 1;
9875     }
9876    
9877 wakaba 1.54 ## Step 4
9878     $i--;
9879     $node = $self->{open_elements}->[$i];
9880     redo LI;
9881     } # LI
9882    
9883    
9884 wakaba 1.49 {
9885     my $el;
9886    
9887     $el = $self->{document}->create_element_ns
9888     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9889    
9890     for my $attr_name (keys %{ $token->{attributes}}) {
9891     $el->set_attribute_ns (undef, [undef, $attr_name],
9892     $token->{attributes} ->{$attr_name}->{value});
9893     }
9894    
9895 wakaba 1.54 $insert->($el);
9896 wakaba 1.49 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9897     }
9898    
9899 wakaba 1.54 $token = $self->_get_next_token;
9900 wakaba 1.55 redo B;
9901 wakaba 1.54 } elsif ($token->{tag_name} eq 'plaintext') {
9902     ## has a p element in scope
9903     INSCOPE: for (reverse @{$self->{open_elements}}) {
9904     if ($_->[1] eq 'p') {
9905 wakaba 1.79
9906     $Whatpm::HTML::Debug::cp_pass->('t367') if $Whatpm::HTML::Debug::cp_pass;
9907     BEGIN {
9908     $Whatpm::HTML::Debug::cp->{'t367'} = 1;
9909     }
9910    
9911 wakaba 1.54 unshift @{$self->{token}}, $token;
9912 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9913 wakaba 1.55 redo B;
9914 wakaba 1.54 } elsif ({
9915     table => 1, caption => 1, td => 1, th => 1,
9916     button => 1, marquee => 1, object => 1, html => 1,
9917     }->{$_->[1]}) {
9918 wakaba 1.79
9919     $Whatpm::HTML::Debug::cp_pass->('t368') if $Whatpm::HTML::Debug::cp_pass;
9920     BEGIN {
9921     $Whatpm::HTML::Debug::cp->{'t368'} = 1;
9922     }
9923    
9924 wakaba 1.54 last INSCOPE;
9925     }
9926     } # INSCOPE
9927    
9928    
9929 wakaba 1.1 {
9930     my $el;
9931    
9932     $el = $self->{document}->create_element_ns
9933 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9934 wakaba 1.1
9935 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9936     $el->set_attribute_ns (undef, [undef, $attr_name],
9937     $token->{attributes} ->{$attr_name}->{value});
9938     }
9939    
9940     $insert->($el);
9941     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9942 wakaba 1.1 }
9943    
9944 wakaba 1.54
9945     $self->{content_model} = PLAINTEXT_CONTENT_MODEL;
9946    
9947     $token = $self->_get_next_token;
9948 wakaba 1.55 redo B;
9949 wakaba 1.54 } elsif ($token->{tag_name} eq 'a') {
9950     AFE: for my $i (reverse 0..$#$active_formatting_elements) {
9951     my $node = $active_formatting_elements->[$i];
9952     if ($node->[1] eq 'a') {
9953 wakaba 1.79
9954     $Whatpm::HTML::Debug::cp_pass->('t371') if $Whatpm::HTML::Debug::cp_pass;
9955     BEGIN {
9956     $Whatpm::HTML::Debug::cp->{'t371'} = 1;
9957     }
9958    
9959 wakaba 1.54 $self->{parse_error}-> (type => 'in a:a');
9960    
9961     unshift @{$self->{token}}, $token;
9962 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'a'};
9963 wakaba 1.54 $formatting_end_tag->($token->{tag_name});
9964    
9965     AFE2: for (reverse 0..$#$active_formatting_elements) {
9966     if ($active_formatting_elements->[$_]->[0] eq $node->[0]) {
9967 wakaba 1.79
9968     $Whatpm::HTML::Debug::cp_pass->('t372') if $Whatpm::HTML::Debug::cp_pass;
9969     BEGIN {
9970     $Whatpm::HTML::Debug::cp->{'t372'} = 1;
9971     }
9972    
9973 wakaba 1.54 splice @$active_formatting_elements, $_, 1;
9974     last AFE2;
9975 wakaba 1.49 }
9976 wakaba 1.54 } # AFE2
9977     OE: for (reverse 0..$#{$self->{open_elements}}) {
9978     if ($self->{open_elements}->[$_]->[0] eq $node->[0]) {
9979 wakaba 1.79
9980     $Whatpm::HTML::Debug::cp_pass->('t373') if $Whatpm::HTML::Debug::cp_pass;
9981     BEGIN {
9982     $Whatpm::HTML::Debug::cp->{'t373'} = 1;
9983     }
9984    
9985 wakaba 1.54 splice @{$self->{open_elements}}, $_, 1;
9986     last OE;
9987 wakaba 1.49 }
9988 wakaba 1.54 } # OE
9989     last AFE;
9990     } elsif ($node->[0] eq '#marker') {
9991 wakaba 1.79
9992     $Whatpm::HTML::Debug::cp_pass->('t374') if $Whatpm::HTML::Debug::cp_pass;
9993     BEGIN {
9994     $Whatpm::HTML::Debug::cp->{'t374'} = 1;
9995     }
9996    
9997 wakaba 1.54 last AFE;
9998     }
9999     } # AFE
10000    
10001     $reconstruct_active_formatting_elements->($insert_to_current);
10002 wakaba 1.49
10003 wakaba 1.54
10004     {
10005     my $el;
10006    
10007     $el = $self->{document}->create_element_ns
10008     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10009    
10010     for my $attr_name (keys %{ $token->{attributes}}) {
10011     $el->set_attribute_ns (undef, [undef, $attr_name],
10012     $token->{attributes} ->{$attr_name}->{value});
10013     }
10014    
10015     $insert->($el);
10016     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10017     }
10018    
10019     push @$active_formatting_elements, $self->{open_elements}->[-1];
10020 wakaba 1.48
10021 wakaba 1.54 $token = $self->_get_next_token;
10022 wakaba 1.55 redo B;
10023 wakaba 1.54 } elsif ({
10024     b => 1, big => 1, em => 1, font => 1, i => 1,
10025     s => 1, small => 1, strile => 1,
10026     strong => 1, tt => 1, u => 1,
10027     }->{$token->{tag_name}}) {
10028 wakaba 1.79
10029     $Whatpm::HTML::Debug::cp_pass->('t375') if $Whatpm::HTML::Debug::cp_pass;
10030     BEGIN {
10031     $Whatpm::HTML::Debug::cp->{'t375'} = 1;
10032     }
10033    
10034 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10035    
10036    
10037     {
10038     my $el;
10039    
10040     $el = $self->{document}->create_element_ns
10041     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10042    
10043     for my $attr_name (keys %{ $token->{attributes}}) {
10044     $el->set_attribute_ns (undef, [undef, $attr_name],
10045     $token->{attributes} ->{$attr_name}->{value});
10046     }
10047    
10048     $insert->($el);
10049     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10050     }
10051    
10052     push @$active_formatting_elements, $self->{open_elements}->[-1];
10053    
10054     $token = $self->_get_next_token;
10055 wakaba 1.55 redo B;
10056 wakaba 1.54 } elsif ($token->{tag_name} eq 'nobr') {
10057     $reconstruct_active_formatting_elements->($insert_to_current);
10058 wakaba 1.1
10059 wakaba 1.54 ## has a |nobr| element in scope
10060     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10061     my $node = $self->{open_elements}->[$_];
10062     if ($node->[1] eq 'nobr') {
10063 wakaba 1.79
10064     $Whatpm::HTML::Debug::cp_pass->('t376') if $Whatpm::HTML::Debug::cp_pass;
10065     BEGIN {
10066     $Whatpm::HTML::Debug::cp->{'t376'} = 1;
10067     }
10068    
10069 wakaba 1.60 $self->{parse_error}-> (type => 'in nobr:nobr');
10070 wakaba 1.54 unshift @{$self->{token}}, $token;
10071 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'nobr'};
10072 wakaba 1.55 redo B;
10073 wakaba 1.54 } elsif ({
10074     table => 1, caption => 1, td => 1, th => 1,
10075     button => 1, marquee => 1, object => 1, html => 1,
10076     }->{$node->[1]}) {
10077 wakaba 1.79
10078     $Whatpm::HTML::Debug::cp_pass->('t377') if $Whatpm::HTML::Debug::cp_pass;
10079     BEGIN {
10080     $Whatpm::HTML::Debug::cp->{'t377'} = 1;
10081     }
10082    
10083 wakaba 1.54 last INSCOPE;
10084     }
10085     } # INSCOPE
10086    
10087    
10088     {
10089     my $el;
10090    
10091     $el = $self->{document}->create_element_ns
10092     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10093    
10094     for my $attr_name (keys %{ $token->{attributes}}) {
10095     $el->set_attribute_ns (undef, [undef, $attr_name],
10096     $token->{attributes} ->{$attr_name}->{value});
10097     }
10098    
10099     $insert->($el);
10100     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10101     }
10102    
10103     push @$active_formatting_elements, $self->{open_elements}->[-1];
10104    
10105     $token = $self->_get_next_token;
10106 wakaba 1.55 redo B;
10107 wakaba 1.54 } elsif ($token->{tag_name} eq 'button') {
10108     ## has a button element in scope
10109     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10110     my $node = $self->{open_elements}->[$_];
10111     if ($node->[1] eq 'button') {
10112 wakaba 1.79
10113     $Whatpm::HTML::Debug::cp_pass->('t378') if $Whatpm::HTML::Debug::cp_pass;
10114     BEGIN {
10115     $Whatpm::HTML::Debug::cp->{'t378'} = 1;
10116     }
10117    
10118 wakaba 1.54 $self->{parse_error}-> (type => 'in button:button');
10119     unshift @{$self->{token}}, $token;
10120 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'button'};
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->('t379') if $Whatpm::HTML::Debug::cp_pass;
10128     BEGIN {
10129     $Whatpm::HTML::Debug::cp->{'t379'} = 1;
10130     }
10131    
10132 wakaba 1.54 last INSCOPE;
10133 wakaba 1.1 }
10134 wakaba 1.54 } # INSCOPE
10135    
10136     $reconstruct_active_formatting_elements->($insert_to_current);
10137    
10138    
10139     {
10140     my $el;
10141    
10142     $el = $self->{document}->create_element_ns
10143     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10144    
10145     for my $attr_name (keys %{ $token->{attributes}}) {
10146     $el->set_attribute_ns (undef, [undef, $attr_name],
10147     $token->{attributes} ->{$attr_name}->{value});
10148     }
10149    
10150     $insert->($el);
10151     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10152     }
10153    
10154 wakaba 1.86
10155     ## TODO: associate with $self->{form_element} if defined
10156    
10157 wakaba 1.54 push @$active_formatting_elements, ['#marker', ''];
10158 wakaba 1.1
10159 wakaba 1.54 $token = $self->_get_next_token;
10160 wakaba 1.55 redo B;
10161 wakaba 1.54 } elsif ($token->{tag_name} eq 'marquee' or
10162     $token->{tag_name} eq 'object') {
10163 wakaba 1.79
10164     $Whatpm::HTML::Debug::cp_pass->('t380') if $Whatpm::HTML::Debug::cp_pass;
10165     BEGIN {
10166     $Whatpm::HTML::Debug::cp->{'t380'} = 1;
10167     }
10168    
10169 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10170    
10171    
10172 wakaba 1.1 {
10173     my $el;
10174    
10175     $el = $self->{document}->create_element_ns
10176     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10177    
10178     for my $attr_name (keys %{ $token->{attributes}}) {
10179     $el->set_attribute_ns (undef, [undef, $attr_name],
10180     $token->{attributes} ->{$attr_name}->{value});
10181     }
10182    
10183 wakaba 1.54 $insert->($el);
10184 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10185 wakaba 1.1 }
10186    
10187 wakaba 1.54 push @$active_formatting_elements, ['#marker', ''];
10188    
10189     $token = $self->_get_next_token;
10190 wakaba 1.55 redo B;
10191 wakaba 1.54 } elsif ($token->{tag_name} eq 'xmp') {
10192 wakaba 1.79
10193     $Whatpm::HTML::Debug::cp_pass->('t381') if $Whatpm::HTML::Debug::cp_pass;
10194     BEGIN {
10195     $Whatpm::HTML::Debug::cp->{'t381'} = 1;
10196     }
10197    
10198 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10199     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
10200 wakaba 1.55 redo B;
10201 wakaba 1.54 } elsif ($token->{tag_name} eq 'table') {
10202     ## has a p element in scope
10203     INSCOPE: for (reverse @{$self->{open_elements}}) {
10204     if ($_->[1] eq 'p') {
10205 wakaba 1.79
10206     $Whatpm::HTML::Debug::cp_pass->('t382') if $Whatpm::HTML::Debug::cp_pass;
10207     BEGIN {
10208     $Whatpm::HTML::Debug::cp->{'t382'} = 1;
10209     }
10210    
10211 wakaba 1.54 unshift @{$self->{token}}, $token;
10212 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
10213 wakaba 1.55 redo B;
10214 wakaba 1.54 } elsif ({
10215     table => 1, caption => 1, td => 1, th => 1,
10216     button => 1, marquee => 1, object => 1, html => 1,
10217     }->{$_->[1]}) {
10218 wakaba 1.79
10219     $Whatpm::HTML::Debug::cp_pass->('t383') if $Whatpm::HTML::Debug::cp_pass;
10220     BEGIN {
10221     $Whatpm::HTML::Debug::cp->{'t383'} = 1;
10222     }
10223    
10224 wakaba 1.54 last INSCOPE;
10225 wakaba 1.1 }
10226 wakaba 1.54 } # INSCOPE
10227    
10228    
10229     {
10230     my $el;
10231    
10232     $el = $self->{document}->create_element_ns
10233     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10234    
10235     for my $attr_name (keys %{ $token->{attributes}}) {
10236     $el->set_attribute_ns (undef, [undef, $attr_name],
10237     $token->{attributes} ->{$attr_name}->{value});
10238     }
10239    
10240     $insert->($el);
10241     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10242     }
10243    
10244    
10245 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
10246 wakaba 1.54
10247     $token = $self->_get_next_token;
10248 wakaba 1.55 redo B;
10249 wakaba 1.54 } elsif ({
10250     area => 1, basefont => 1, bgsound => 1, br => 1,
10251     embed => 1, img => 1, param => 1, spacer => 1, wbr => 1,
10252     image => 1,
10253     }->{$token->{tag_name}}) {
10254     if ($token->{tag_name} eq 'image') {
10255 wakaba 1.79
10256     $Whatpm::HTML::Debug::cp_pass->('t384') if $Whatpm::HTML::Debug::cp_pass;
10257     BEGIN {
10258     $Whatpm::HTML::Debug::cp->{'t384'} = 1;
10259     }
10260    
10261 wakaba 1.54 $self->{parse_error}-> (type => 'image');
10262     $token->{tag_name} = 'img';
10263 wakaba 1.79 } else {
10264    
10265     $Whatpm::HTML::Debug::cp_pass->('t385') if $Whatpm::HTML::Debug::cp_pass;
10266     BEGIN {
10267     $Whatpm::HTML::Debug::cp->{'t385'} = 1;
10268     }
10269    
10270 wakaba 1.54 }
10271 wakaba 1.1
10272 wakaba 1.54 ## NOTE: There is an "as if <br>" code clone.
10273     $reconstruct_active_formatting_elements->($insert_to_current);
10274    
10275    
10276     {
10277     my $el;
10278    
10279     $el = $self->{document}->create_element_ns
10280     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10281    
10282     for my $attr_name (keys %{ $token->{attributes}}) {
10283     $el->set_attribute_ns (undef, [undef, $attr_name],
10284     $token->{attributes} ->{$attr_name}->{value});
10285     }
10286    
10287     $insert->($el);
10288     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10289     }
10290    
10291     pop @{$self->{open_elements}};
10292    
10293     $token = $self->_get_next_token;
10294 wakaba 1.55 redo B;
10295 wakaba 1.54 } elsif ($token->{tag_name} eq 'hr') {
10296     ## has a p element in scope
10297     INSCOPE: for (reverse @{$self->{open_elements}}) {
10298     if ($_->[1] eq 'p') {
10299 wakaba 1.79
10300     $Whatpm::HTML::Debug::cp_pass->('t386') if $Whatpm::HTML::Debug::cp_pass;
10301     BEGIN {
10302     $Whatpm::HTML::Debug::cp->{'t386'} = 1;
10303     }
10304    
10305 wakaba 1.54 unshift @{$self->{token}}, $token;
10306 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
10307 wakaba 1.55 redo B;
10308 wakaba 1.54 } elsif ({
10309     table => 1, caption => 1, td => 1, th => 1,
10310     button => 1, marquee => 1, object => 1, html => 1,
10311     }->{$_->[1]}) {
10312 wakaba 1.79
10313     $Whatpm::HTML::Debug::cp_pass->('t387') if $Whatpm::HTML::Debug::cp_pass;
10314     BEGIN {
10315     $Whatpm::HTML::Debug::cp->{'t387'} = 1;
10316     }
10317    
10318 wakaba 1.54 last INSCOPE;
10319 wakaba 1.1 }
10320 wakaba 1.54 } # INSCOPE
10321    
10322    
10323 wakaba 1.1 {
10324     my $el;
10325    
10326     $el = $self->{document}->create_element_ns
10327     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10328    
10329     for my $attr_name (keys %{ $token->{attributes}}) {
10330     $el->set_attribute_ns (undef, [undef, $attr_name],
10331     $token->{attributes} ->{$attr_name}->{value});
10332     }
10333    
10334 wakaba 1.54 $insert->($el);
10335 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10336 wakaba 1.1 }
10337    
10338 wakaba 1.54 pop @{$self->{open_elements}};
10339    
10340     $token = $self->_get_next_token;
10341 wakaba 1.55 redo B;
10342 wakaba 1.54 } elsif ($token->{tag_name} eq 'input') {
10343 wakaba 1.79
10344     $Whatpm::HTML::Debug::cp_pass->('t388') if $Whatpm::HTML::Debug::cp_pass;
10345     BEGIN {
10346     $Whatpm::HTML::Debug::cp->{'t388'} = 1;
10347     }
10348    
10349 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10350    
10351    
10352 wakaba 1.1 {
10353     my $el;
10354    
10355     $el = $self->{document}->create_element_ns
10356     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10357    
10358     for my $attr_name (keys %{ $token->{attributes}}) {
10359     $el->set_attribute_ns (undef, [undef, $attr_name],
10360     $token->{attributes} ->{$attr_name}->{value});
10361     }
10362    
10363 wakaba 1.54 $insert->($el);
10364 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10365 wakaba 1.1 }
10366    
10367 wakaba 1.54 ## TODO: associate with $self->{form_element} if defined
10368     pop @{$self->{open_elements}};
10369    
10370     $token = $self->_get_next_token;
10371 wakaba 1.55 redo B;
10372 wakaba 1.54 } elsif ($token->{tag_name} eq 'isindex') {
10373     $self->{parse_error}-> (type => 'isindex');
10374    
10375     if (defined $self->{form_element}) {
10376 wakaba 1.79
10377     $Whatpm::HTML::Debug::cp_pass->('t389') if $Whatpm::HTML::Debug::cp_pass;
10378     BEGIN {
10379     $Whatpm::HTML::Debug::cp->{'t389'} = 1;
10380     }
10381    
10382 wakaba 1.54 ## Ignore the token
10383     $token = $self->_get_next_token;
10384 wakaba 1.55 redo B;
10385 wakaba 1.54 } else {
10386     my $at = $token->{attributes};
10387     my $form_attrs;
10388     $form_attrs->{action} = $at->{action} if $at->{action};
10389     my $prompt_attr = $at->{prompt};
10390     $at->{name} = {name => 'name', value => 'isindex'};
10391     delete $at->{action};
10392     delete $at->{prompt};
10393     my @tokens = (
10394 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'form',
10395 wakaba 1.54 attributes => $form_attrs},
10396 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'hr'},
10397     {type => START_TAG_TOKEN, tag_name => 'p'},
10398     {type => START_TAG_TOKEN, tag_name => 'label'},
10399 wakaba 1.54 );
10400     if ($prompt_attr) {
10401 wakaba 1.79
10402     $Whatpm::HTML::Debug::cp_pass->('t390') if $Whatpm::HTML::Debug::cp_pass;
10403     BEGIN {
10404     $Whatpm::HTML::Debug::cp->{'t390'} = 1;
10405     }
10406    
10407 wakaba 1.57 push @tokens, {type => CHARACTER_TOKEN, data => $prompt_attr->{value}};
10408 wakaba 1.1 } else {
10409 wakaba 1.79
10410     $Whatpm::HTML::Debug::cp_pass->('t391') if $Whatpm::HTML::Debug::cp_pass;
10411     BEGIN {
10412     $Whatpm::HTML::Debug::cp->{'t391'} = 1;
10413     }
10414    
10415 wakaba 1.57 push @tokens, {type => CHARACTER_TOKEN,
10416 wakaba 1.54 data => 'This is a searchable index. Insert your search keywords here: '}; # SHOULD
10417     ## TODO: make this configurable
10418 wakaba 1.1 }
10419 wakaba 1.54 push @tokens,
10420 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'input', attributes => $at},
10421     #{type => CHARACTER_TOKEN, data => ''}, # SHOULD
10422     {type => END_TAG_TOKEN, tag_name => 'label'},
10423     {type => END_TAG_TOKEN, tag_name => 'p'},
10424     {type => START_TAG_TOKEN, tag_name => 'hr'},
10425     {type => END_TAG_TOKEN, tag_name => 'form'};
10426 wakaba 1.54 $token = shift @tokens;
10427     unshift @{$self->{token}}, (@tokens);
10428 wakaba 1.55 redo B;
10429 wakaba 1.54 }
10430     } elsif ($token->{tag_name} eq 'textarea') {
10431     my $tag_name = $token->{tag_name};
10432     my $el;
10433    
10434     $el = $self->{document}->create_element_ns
10435     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10436    
10437     for my $attr_name (keys %{ $token->{attributes}}) {
10438     $el->set_attribute_ns (undef, [undef, $attr_name],
10439     $token->{attributes} ->{$attr_name}->{value});
10440     }
10441    
10442    
10443     ## TODO: $self->{form_element} if defined
10444     $self->{content_model} = RCDATA_CONTENT_MODEL;
10445     delete $self->{escape}; # MUST
10446    
10447     $insert->($el);
10448    
10449     my $text = '';
10450     $token = $self->_get_next_token;
10451 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
10452 wakaba 1.54 $token->{data} =~ s/^\x0A//;
10453 wakaba 1.53 unless (length $token->{data}) {
10454 wakaba 1.79
10455     $Whatpm::HTML::Debug::cp_pass->('t392') if $Whatpm::HTML::Debug::cp_pass;
10456     BEGIN {
10457     $Whatpm::HTML::Debug::cp->{'t392'} = 1;
10458     }
10459    
10460 wakaba 1.53 $token = $self->_get_next_token;
10461 wakaba 1.79 } else {
10462    
10463     $Whatpm::HTML::Debug::cp_pass->('t393') if $Whatpm::HTML::Debug::cp_pass;
10464     BEGIN {
10465     $Whatpm::HTML::Debug::cp->{'t393'} = 1;
10466     }
10467    
10468 wakaba 1.53 }
10469 wakaba 1.79 } else {
10470    
10471     $Whatpm::HTML::Debug::cp_pass->('t394') if $Whatpm::HTML::Debug::cp_pass;
10472     BEGIN {
10473     $Whatpm::HTML::Debug::cp->{'t394'} = 1;
10474     }
10475    
10476 wakaba 1.53 }
10477 wakaba 1.57 while ($token->{type} == CHARACTER_TOKEN) {
10478 wakaba 1.79
10479     $Whatpm::HTML::Debug::cp_pass->('t395') if $Whatpm::HTML::Debug::cp_pass;
10480     BEGIN {
10481     $Whatpm::HTML::Debug::cp->{'t395'} = 1;
10482     }
10483    
10484 wakaba 1.54 $text .= $token->{data};
10485     $token = $self->_get_next_token;
10486     }
10487     if (length $text) {
10488 wakaba 1.79
10489     $Whatpm::HTML::Debug::cp_pass->('t396') if $Whatpm::HTML::Debug::cp_pass;
10490     BEGIN {
10491     $Whatpm::HTML::Debug::cp->{'t396'} = 1;
10492     }
10493    
10494 wakaba 1.54 $el->manakai_append_text ($text);
10495     }
10496    
10497     $self->{content_model} = PCDATA_CONTENT_MODEL;
10498    
10499 wakaba 1.57 if ($token->{type} == END_TAG_TOKEN and
10500 wakaba 1.54 $token->{tag_name} eq $tag_name) {
10501 wakaba 1.79
10502     $Whatpm::HTML::Debug::cp_pass->('t397') if $Whatpm::HTML::Debug::cp_pass;
10503     BEGIN {
10504     $Whatpm::HTML::Debug::cp->{'t397'} = 1;
10505     }
10506    
10507 wakaba 1.54 ## Ignore the token
10508     } else {
10509 wakaba 1.79
10510     $Whatpm::HTML::Debug::cp_pass->('t398') if $Whatpm::HTML::Debug::cp_pass;
10511     BEGIN {
10512     $Whatpm::HTML::Debug::cp->{'t398'} = 1;
10513     }
10514    
10515 wakaba 1.54 $self->{parse_error}-> (type => 'in RCDATA:#'.$token->{type});
10516     }
10517     $token = $self->_get_next_token;
10518 wakaba 1.55 redo B;
10519 wakaba 1.54 } elsif ({
10520     iframe => 1,
10521     noembed => 1,
10522     noframes => 1,
10523     noscript => 0, ## TODO: 1 if scripting is enabled
10524     }->{$token->{tag_name}}) {
10525 wakaba 1.79
10526     $Whatpm::HTML::Debug::cp_pass->('t399') if $Whatpm::HTML::Debug::cp_pass;
10527     BEGIN {
10528     $Whatpm::HTML::Debug::cp->{'t399'} = 1;
10529     }
10530    
10531 wakaba 1.60 ## NOTE: There is an "as if in body" code clone.
10532 wakaba 1.54 $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
10533 wakaba 1.55 redo B;
10534 wakaba 1.54 } elsif ($token->{tag_name} eq 'select') {
10535 wakaba 1.79
10536     $Whatpm::HTML::Debug::cp_pass->('t400') if $Whatpm::HTML::Debug::cp_pass;
10537     BEGIN {
10538     $Whatpm::HTML::Debug::cp->{'t400'} = 1;
10539     }
10540    
10541 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10542    
10543    
10544     {
10545     my $el;
10546    
10547     $el = $self->{document}->create_element_ns
10548     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10549    
10550     for my $attr_name (keys %{ $token->{attributes}}) {
10551     $el->set_attribute_ns (undef, [undef, $attr_name],
10552     $token->{attributes} ->{$attr_name}->{value});
10553     }
10554    
10555     $insert->($el);
10556     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10557     }
10558    
10559 wakaba 1.86
10560     ## TODO: associate with $self->{form_element} if defined
10561 wakaba 1.54
10562 wakaba 1.56 $self->{insertion_mode} = IN_SELECT_IM;
10563 wakaba 1.54 $token = $self->_get_next_token;
10564 wakaba 1.55 redo B;
10565 wakaba 1.54 } elsif ({
10566     caption => 1, col => 1, colgroup => 1, frame => 1,
10567     frameset => 1, head => 1, option => 1, optgroup => 1,
10568     tbody => 1, td => 1, tfoot => 1, th => 1,
10569     thead => 1, tr => 1,
10570     }->{$token->{tag_name}}) {
10571 wakaba 1.79
10572     $Whatpm::HTML::Debug::cp_pass->('t401') if $Whatpm::HTML::Debug::cp_pass;
10573     BEGIN {
10574     $Whatpm::HTML::Debug::cp->{'t401'} = 1;
10575     }
10576    
10577 wakaba 1.54 $self->{parse_error}-> (type => 'in body:'.$token->{tag_name});
10578     ## Ignore the token
10579     $token = $self->_get_next_token;
10580 wakaba 1.55 redo B;
10581 wakaba 1.54
10582     ## ISSUE: An issue on HTML5 new elements in the spec.
10583     } else {
10584 wakaba 1.79
10585     $Whatpm::HTML::Debug::cp_pass->('t402') if $Whatpm::HTML::Debug::cp_pass;
10586     BEGIN {
10587     $Whatpm::HTML::Debug::cp->{'t402'} = 1;
10588     }
10589    
10590 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10591 wakaba 1.53
10592 wakaba 1.54
10593     {
10594     my $el;
10595    
10596     $el = $self->{document}->create_element_ns
10597     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10598    
10599     for my $attr_name (keys %{ $token->{attributes}}) {
10600     $el->set_attribute_ns (undef, [undef, $attr_name],
10601     $token->{attributes} ->{$attr_name}->{value});
10602 wakaba 1.53 }
10603 wakaba 1.54
10604     $insert->($el);
10605     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10606     }
10607    
10608 wakaba 1.53
10609 wakaba 1.54 $token = $self->_get_next_token;
10610 wakaba 1.55 redo B;
10611 wakaba 1.54 }
10612 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
10613 wakaba 1.54 if ($token->{tag_name} eq 'body') {
10614     if (@{$self->{open_elements}} > 1 and
10615     $self->{open_elements}->[1]->[1] eq 'body') {
10616     for (@{$self->{open_elements}}) {
10617     unless ({
10618     dd => 1, dt => 1, li => 1, p => 1, td => 1,
10619     th => 1, tr => 1, body => 1, html => 1,
10620     tbody => 1, tfoot => 1, thead => 1,
10621     }->{$_->[1]}) {
10622 wakaba 1.79
10623     $Whatpm::HTML::Debug::cp_pass->('t403') if $Whatpm::HTML::Debug::cp_pass;
10624     BEGIN {
10625     $Whatpm::HTML::Debug::cp->{'t403'} = 1;
10626     }
10627    
10628 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$_->[1]);
10629 wakaba 1.79 } else {
10630    
10631     $Whatpm::HTML::Debug::cp_pass->('t404') if $Whatpm::HTML::Debug::cp_pass;
10632     BEGIN {
10633     $Whatpm::HTML::Debug::cp->{'t404'} = 1;
10634     }
10635    
10636 wakaba 1.54 }
10637     }
10638 wakaba 1.53
10639 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
10640 wakaba 1.54 $token = $self->_get_next_token;
10641 wakaba 1.55 redo B;
10642 wakaba 1.54 } else {
10643 wakaba 1.79
10644     $Whatpm::HTML::Debug::cp_pass->('t405') if $Whatpm::HTML::Debug::cp_pass;
10645     BEGIN {
10646     $Whatpm::HTML::Debug::cp->{'t405'} = 1;
10647     }
10648    
10649 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10650     ## Ignore the token
10651     $token = $self->_get_next_token;
10652 wakaba 1.55 redo B;
10653 wakaba 1.53 }
10654 wakaba 1.54 } elsif ($token->{tag_name} eq 'html') {
10655     if (@{$self->{open_elements}} > 1 and $self->{open_elements}->[1]->[1] eq 'body') {
10656     ## ISSUE: There is an issue in the spec.
10657     if ($self->{open_elements}->[-1]->[1] ne 'body') {
10658 wakaba 1.79
10659     $Whatpm::HTML::Debug::cp_pass->('t406') if $Whatpm::HTML::Debug::cp_pass;
10660     BEGIN {
10661     $Whatpm::HTML::Debug::cp->{'t406'} = 1;
10662     }
10663    
10664 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[1]->[1]);
10665 wakaba 1.79 } else {
10666    
10667     $Whatpm::HTML::Debug::cp_pass->('t407') if $Whatpm::HTML::Debug::cp_pass;
10668     BEGIN {
10669     $Whatpm::HTML::Debug::cp->{'t407'} = 1;
10670     }
10671    
10672 wakaba 1.54 }
10673 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
10674 wakaba 1.54 ## reprocess
10675 wakaba 1.55 redo B;
10676 wakaba 1.54 } else {
10677 wakaba 1.79
10678     $Whatpm::HTML::Debug::cp_pass->('t408') if $Whatpm::HTML::Debug::cp_pass;
10679     BEGIN {
10680     $Whatpm::HTML::Debug::cp->{'t408'} = 1;
10681     }
10682    
10683 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10684     ## Ignore the token
10685     $token = $self->_get_next_token;
10686 wakaba 1.55 redo B;
10687 wakaba 1.53 }
10688 wakaba 1.54 } elsif ({
10689     address => 1, blockquote => 1, center => 1, dir => 1,
10690     div => 1, dl => 1, fieldset => 1, listing => 1,
10691     menu => 1, ol => 1, pre => 1, ul => 1,
10692     dd => 1, dt => 1, li => 1,
10693     button => 1, marquee => 1, object => 1,
10694     }->{$token->{tag_name}}) {
10695     ## has an element in scope
10696     my $i;
10697     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10698     my $node = $self->{open_elements}->[$_];
10699     if ($node->[1] eq $token->{tag_name}) {
10700     ## generate implied end tags
10701 wakaba 1.86 while ({
10702     dd => ($token->{tag_name} ne 'dd'),
10703     dt => ($token->{tag_name} ne 'dt'),
10704     li => ($token->{tag_name} ne 'li'),
10705 wakaba 1.87 p => 1,
10706 wakaba 1.86 }->{$self->{open_elements}->[-1]->[1]}) {
10707 wakaba 1.79
10708     $Whatpm::HTML::Debug::cp_pass->('t409') if $Whatpm::HTML::Debug::cp_pass;
10709     BEGIN {
10710     $Whatpm::HTML::Debug::cp->{'t409'} = 1;
10711     }
10712    
10713 wakaba 1.86 pop @{$self->{open_elements}};
10714 wakaba 1.54 }
10715 wakaba 1.79
10716    
10717     $Whatpm::HTML::Debug::cp_pass->('t410') if $Whatpm::HTML::Debug::cp_pass;
10718     BEGIN {
10719     $Whatpm::HTML::Debug::cp->{'t410'} = 1;
10720     }
10721    
10722 wakaba 1.54 $i = $_;
10723 wakaba 1.87 last INSCOPE;
10724 wakaba 1.54 } elsif ({
10725     table => 1, caption => 1, td => 1, th => 1,
10726     button => 1, marquee => 1, object => 1, html => 1,
10727     }->{$node->[1]}) {
10728 wakaba 1.79
10729     $Whatpm::HTML::Debug::cp_pass->('t411') if $Whatpm::HTML::Debug::cp_pass;
10730     BEGIN {
10731     $Whatpm::HTML::Debug::cp->{'t411'} = 1;
10732     }
10733    
10734 wakaba 1.54 last INSCOPE;
10735     }
10736     } # INSCOPE
10737    
10738     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
10739     if (defined $i) {
10740 wakaba 1.79
10741     $Whatpm::HTML::Debug::cp_pass->('t412') if $Whatpm::HTML::Debug::cp_pass;
10742     BEGIN {
10743     $Whatpm::HTML::Debug::cp->{'t412'} = 1;
10744     }
10745    
10746 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
10747 wakaba 1.1 } else {
10748 wakaba 1.79
10749     $Whatpm::HTML::Debug::cp_pass->('t413') if $Whatpm::HTML::Debug::cp_pass;
10750     BEGIN {
10751     $Whatpm::HTML::Debug::cp->{'t413'} = 1;
10752     }
10753    
10754 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10755 wakaba 1.1 }
10756 wakaba 1.53 }
10757 wakaba 1.54
10758     if (defined $i) {
10759 wakaba 1.79
10760     $Whatpm::HTML::Debug::cp_pass->('t414') if $Whatpm::HTML::Debug::cp_pass;
10761     BEGIN {
10762     $Whatpm::HTML::Debug::cp->{'t414'} = 1;
10763     }
10764    
10765 wakaba 1.54 splice @{$self->{open_elements}}, $i;
10766 wakaba 1.79 } else {
10767    
10768     $Whatpm::HTML::Debug::cp_pass->('t416') if $Whatpm::HTML::Debug::cp_pass;
10769     BEGIN {
10770     $Whatpm::HTML::Debug::cp->{'t416'} = 1;
10771     }
10772    
10773 wakaba 1.54 }
10774     $clear_up_to_marker->()
10775     if {
10776     button => 1, marquee => 1, object => 1,
10777     }->{$token->{tag_name}};
10778     $token = $self->_get_next_token;
10779 wakaba 1.55 redo B;
10780 wakaba 1.54 } elsif ($token->{tag_name} eq 'form') {
10781     ## has an element in scope
10782     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10783     my $node = $self->{open_elements}->[$_];
10784     if ($node->[1] eq $token->{tag_name}) {
10785     ## generate implied end tags
10786 wakaba 1.86 while ({
10787     dd => 1, dt => 1, li => 1, p => 1,
10788     }->{$self->{open_elements}->[-1]->[1]}) {
10789 wakaba 1.79
10790     $Whatpm::HTML::Debug::cp_pass->('t417') if $Whatpm::HTML::Debug::cp_pass;
10791     BEGIN {
10792     $Whatpm::HTML::Debug::cp->{'t417'} = 1;
10793     }
10794    
10795 wakaba 1.86 pop @{$self->{open_elements}};
10796 wakaba 1.54 }
10797 wakaba 1.86
10798 wakaba 1.79
10799     $Whatpm::HTML::Debug::cp_pass->('t418') if $Whatpm::HTML::Debug::cp_pass;
10800     BEGIN {
10801     $Whatpm::HTML::Debug::cp->{'t418'} = 1;
10802     }
10803    
10804 wakaba 1.54 last INSCOPE;
10805     } elsif ({
10806     table => 1, caption => 1, td => 1, th => 1,
10807     button => 1, marquee => 1, object => 1, html => 1,
10808     }->{$node->[1]}) {
10809 wakaba 1.79
10810     $Whatpm::HTML::Debug::cp_pass->('t419') if $Whatpm::HTML::Debug::cp_pass;
10811     BEGIN {
10812     $Whatpm::HTML::Debug::cp->{'t419'} = 1;
10813     }
10814    
10815 wakaba 1.54 last INSCOPE;
10816 wakaba 1.36 }
10817 wakaba 1.54 } # INSCOPE
10818    
10819     if ($self->{open_elements}->[-1]->[1] eq $token->{tag_name}) {
10820 wakaba 1.79
10821     $Whatpm::HTML::Debug::cp_pass->('t420') if $Whatpm::HTML::Debug::cp_pass;
10822     BEGIN {
10823     $Whatpm::HTML::Debug::cp->{'t420'} = 1;
10824     }
10825    
10826 wakaba 1.54 pop @{$self->{open_elements}};
10827     } else {
10828 wakaba 1.79
10829     $Whatpm::HTML::Debug::cp_pass->('t421') if $Whatpm::HTML::Debug::cp_pass;
10830     BEGIN {
10831     $Whatpm::HTML::Debug::cp->{'t421'} = 1;
10832     }
10833    
10834 wakaba 1.60 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10835 wakaba 1.36 }
10836    
10837 wakaba 1.54 undef $self->{form_element};
10838     $token = $self->_get_next_token;
10839 wakaba 1.55 redo B;
10840 wakaba 1.54 } elsif ({
10841     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
10842     }->{$token->{tag_name}}) {
10843     ## has an element in scope
10844     my $i;
10845     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10846     my $node = $self->{open_elements}->[$_];
10847     if ({
10848     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
10849     }->{$node->[1]}) {
10850     ## generate implied end tags
10851 wakaba 1.86 while ({
10852     dd => 1, dt => 1, li => 1, p => 1,
10853     }->{$self->{open_elements}->[-1]->[1]}) {
10854 wakaba 1.79
10855     $Whatpm::HTML::Debug::cp_pass->('t422') if $Whatpm::HTML::Debug::cp_pass;
10856     BEGIN {
10857     $Whatpm::HTML::Debug::cp->{'t422'} = 1;
10858     }
10859    
10860 wakaba 1.86 pop @{$self->{open_elements}};
10861 wakaba 1.54 }
10862 wakaba 1.79
10863    
10864     $Whatpm::HTML::Debug::cp_pass->('t423') if $Whatpm::HTML::Debug::cp_pass;
10865     BEGIN {
10866     $Whatpm::HTML::Debug::cp->{'t423'} = 1;
10867     }
10868    
10869 wakaba 1.54 $i = $_;
10870     last INSCOPE;
10871     } elsif ({
10872     table => 1, caption => 1, td => 1, th => 1,
10873     button => 1, marquee => 1, object => 1, html => 1,
10874     }->{$node->[1]}) {
10875 wakaba 1.79
10876     $Whatpm::HTML::Debug::cp_pass->('t424') if $Whatpm::HTML::Debug::cp_pass;
10877     BEGIN {
10878     $Whatpm::HTML::Debug::cp->{'t424'} = 1;
10879     }
10880    
10881 wakaba 1.54 last INSCOPE;
10882 wakaba 1.53 }
10883 wakaba 1.54 } # INSCOPE
10884    
10885     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
10886 wakaba 1.79
10887     $Whatpm::HTML::Debug::cp_pass->('t425') if $Whatpm::HTML::Debug::cp_pass;
10888     BEGIN {
10889     $Whatpm::HTML::Debug::cp->{'t425'} = 1;
10890     }
10891    
10892 wakaba 1.60 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10893 wakaba 1.79 } else {
10894    
10895     $Whatpm::HTML::Debug::cp_pass->('t426') if $Whatpm::HTML::Debug::cp_pass;
10896     BEGIN {
10897     $Whatpm::HTML::Debug::cp->{'t426'} = 1;
10898     }
10899    
10900 wakaba 1.53 }
10901    
10902 wakaba 1.54 splice @{$self->{open_elements}}, $i if defined $i;
10903     $token = $self->_get_next_token;
10904 wakaba 1.55 redo B;
10905 wakaba 1.87 } elsif ($token->{tag_name} eq 'p') {
10906     ## has an element in scope
10907     my $i;
10908     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10909     my $node = $self->{open_elements}->[$_];
10910     if ($node->[1] eq $token->{tag_name}) {
10911     ## generate implied end tags
10912     while ({
10913     dd => 1, dt => 1, li => 1, p => 0,
10914     }->{$self->{open_elements}->[-1]->[1]}) {
10915    
10916     $Whatpm::HTML::Debug::cp_pass->('t409.1') if $Whatpm::HTML::Debug::cp_pass;
10917     BEGIN {
10918     $Whatpm::HTML::Debug::cp->{'t409.1'} = 1;
10919     }
10920    
10921     pop @{$self->{open_elements}};
10922     }
10923    
10924    
10925     $Whatpm::HTML::Debug::cp_pass->('t410.1') if $Whatpm::HTML::Debug::cp_pass;
10926     BEGIN {
10927     $Whatpm::HTML::Debug::cp->{'t410.1'} = 1;
10928     }
10929    
10930     $i = $_;
10931 wakaba 1.88 last INSCOPE;
10932 wakaba 1.87 } elsif ({
10933     table => 1, caption => 1, td => 1, th => 1,
10934     button => 1, marquee => 1, object => 1, html => 1,
10935     }->{$node->[1]}) {
10936    
10937     $Whatpm::HTML::Debug::cp_pass->('t411.1') if $Whatpm::HTML::Debug::cp_pass;
10938     BEGIN {
10939     $Whatpm::HTML::Debug::cp->{'t411.1'} = 1;
10940     }
10941    
10942     last INSCOPE;
10943     }
10944     } # INSCOPE
10945    
10946     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
10947     if (defined $i) {
10948    
10949     $Whatpm::HTML::Debug::cp_pass->('t412.1') if $Whatpm::HTML::Debug::cp_pass;
10950     BEGIN {
10951     $Whatpm::HTML::Debug::cp->{'t412.1'} = 1;
10952     }
10953    
10954     $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
10955     } else {
10956    
10957     $Whatpm::HTML::Debug::cp_pass->('t413.1') if $Whatpm::HTML::Debug::cp_pass;
10958     BEGIN {
10959     $Whatpm::HTML::Debug::cp->{'t413.1'} = 1;
10960     }
10961    
10962     $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10963     }
10964     }
10965    
10966     if (defined $i) {
10967    
10968     $Whatpm::HTML::Debug::cp_pass->('t414.1') if $Whatpm::HTML::Debug::cp_pass;
10969     BEGIN {
10970     $Whatpm::HTML::Debug::cp->{'t414.1'} = 1;
10971     }
10972    
10973     splice @{$self->{open_elements}}, $i;
10974     } else {
10975    
10976     $Whatpm::HTML::Debug::cp_pass->('t415.1') if $Whatpm::HTML::Debug::cp_pass;
10977     BEGIN {
10978     $Whatpm::HTML::Debug::cp->{'t415.1'} = 1;
10979     }
10980    
10981     ## As if <p>, then reprocess the current token
10982     my $el;
10983    
10984     $el = $self->{document}->create_element_ns
10985     (q<http://www.w3.org/1999/xhtml>, [undef, 'p']);
10986    
10987     $insert->($el);
10988     }
10989     $token = $self->_get_next_token;
10990     redo B;
10991 wakaba 1.54 } elsif ({
10992     a => 1,
10993     b => 1, big => 1, em => 1, font => 1, i => 1,
10994     nobr => 1, s => 1, small => 1, strile => 1,
10995     strong => 1, tt => 1, u => 1,
10996     }->{$token->{tag_name}}) {
10997 wakaba 1.79
10998     $Whatpm::HTML::Debug::cp_pass->('t427') if $Whatpm::HTML::Debug::cp_pass;
10999     BEGIN {
11000     $Whatpm::HTML::Debug::cp->{'t427'} = 1;
11001     }
11002    
11003 wakaba 1.54 $formatting_end_tag->($token->{tag_name});
11004 wakaba 1.55 redo B;
11005 wakaba 1.54 } elsif ($token->{tag_name} eq 'br') {
11006 wakaba 1.79
11007     $Whatpm::HTML::Debug::cp_pass->('t428') if $Whatpm::HTML::Debug::cp_pass;
11008     BEGIN {
11009     $Whatpm::HTML::Debug::cp->{'t428'} = 1;
11010     }
11011    
11012 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:br');
11013 wakaba 1.53
11014 wakaba 1.54 ## As if <br>
11015     $reconstruct_active_formatting_elements->($insert_to_current);
11016    
11017     my $el;
11018    
11019 wakaba 1.1 $el = $self->{document}->create_element_ns
11020 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'br']);
11021 wakaba 1.1
11022 wakaba 1.54 $insert->($el);
11023    
11024     ## Ignore the token.
11025     $token = $self->_get_next_token;
11026 wakaba 1.55 redo B;
11027 wakaba 1.54 } elsif ({
11028     caption => 1, col => 1, colgroup => 1, frame => 1,
11029     frameset => 1, head => 1, option => 1, optgroup => 1,
11030     tbody => 1, td => 1, tfoot => 1, th => 1,
11031     thead => 1, tr => 1,
11032     area => 1, basefont => 1, bgsound => 1,
11033     embed => 1, hr => 1, iframe => 1, image => 1,
11034     img => 1, input => 1, isindex => 1, noembed => 1,
11035     noframes => 1, param => 1, select => 1, spacer => 1,
11036     table => 1, textarea => 1, wbr => 1,
11037     noscript => 0, ## TODO: if scripting is enabled
11038     }->{$token->{tag_name}}) {
11039 wakaba 1.79
11040     $Whatpm::HTML::Debug::cp_pass->('t429') if $Whatpm::HTML::Debug::cp_pass;
11041     BEGIN {
11042     $Whatpm::HTML::Debug::cp->{'t429'} = 1;
11043     }
11044    
11045 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
11046     ## Ignore the token
11047     $token = $self->_get_next_token;
11048 wakaba 1.55 redo B;
11049 wakaba 1.54
11050     ## ISSUE: Issue on HTML5 new elements in spec
11051    
11052     } else {
11053     ## Step 1
11054     my $node_i = -1;
11055     my $node = $self->{open_elements}->[$node_i];
11056    
11057     ## Step 2
11058     S2: {
11059     if ($node->[1] eq $token->{tag_name}) {
11060     ## Step 1
11061     ## generate implied end tags
11062 wakaba 1.86 while ({
11063     dd => 1, dt => 1, li => 1, p => 1,
11064     }->{$self->{open_elements}->[-1]->[1]}) {
11065 wakaba 1.79
11066     $Whatpm::HTML::Debug::cp_pass->('t430') if $Whatpm::HTML::Debug::cp_pass;
11067     BEGIN {
11068     $Whatpm::HTML::Debug::cp->{'t430'} = 1;
11069     }
11070    
11071 wakaba 1.83 ## ISSUE: Can this case be reached?
11072 wakaba 1.86 pop @{$self->{open_elements}};
11073 wakaba 1.54 }
11074    
11075     ## Step 2
11076     if ($token->{tag_name} ne $self->{open_elements}->[-1]->[1]) {
11077 wakaba 1.79
11078     $Whatpm::HTML::Debug::cp_pass->('t431') if $Whatpm::HTML::Debug::cp_pass;
11079     BEGIN {
11080     $Whatpm::HTML::Debug::cp->{'t431'} = 1;
11081     }
11082    
11083 wakaba 1.60 ## NOTE: <x><y></x>
11084 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
11085 wakaba 1.79 } else {
11086    
11087     $Whatpm::HTML::Debug::cp_pass->('t432') if $Whatpm::HTML::Debug::cp_pass;
11088     BEGIN {
11089     $Whatpm::HTML::Debug::cp->{'t432'} = 1;
11090     }
11091    
11092 wakaba 1.54 }
11093    
11094     ## Step 3
11095     splice @{$self->{open_elements}}, $node_i;
11096 wakaba 1.53
11097 wakaba 1.36 $token = $self->_get_next_token;
11098 wakaba 1.54 last S2;
11099 wakaba 1.1 } else {
11100 wakaba 1.54 ## Step 3
11101     if (not $formatting_category->{$node->[1]} and
11102     #not $phrasing_category->{$node->[1]} and
11103     ($special_category->{$node->[1]} or
11104     $scoping_category->{$node->[1]})) {
11105 wakaba 1.79
11106     $Whatpm::HTML::Debug::cp_pass->('t433') if $Whatpm::HTML::Debug::cp_pass;
11107     BEGIN {
11108     $Whatpm::HTML::Debug::cp->{'t433'} = 1;
11109     }
11110    
11111 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
11112     ## Ignore the token
11113     $token = $self->_get_next_token;
11114     last S2;
11115     }
11116 wakaba 1.79
11117    
11118     $Whatpm::HTML::Debug::cp_pass->('t434') if $Whatpm::HTML::Debug::cp_pass;
11119     BEGIN {
11120     $Whatpm::HTML::Debug::cp->{'t434'} = 1;
11121     }
11122    
11123 wakaba 1.1 }
11124 wakaba 1.54
11125     ## Step 4
11126     $node_i--;
11127     $node = $self->{open_elements}->[$node_i];
11128    
11129     ## Step 5;
11130     redo S2;
11131     } # S2
11132 wakaba 1.55 redo B;
11133 wakaba 1.1 }
11134     }
11135 wakaba 1.54 redo B;
11136 wakaba 1.1 } # B
11137    
11138     ## Stop parsing # MUST
11139    
11140     ## TODO: script stuffs
11141 wakaba 1.3 } # _tree_construct_main
11142    
11143     sub set_inner_html ($$$) {
11144     my $class = shift;
11145     my $node = shift;
11146     my $s = \$_[0];
11147     my $onerror = $_[1];
11148    
11149 wakaba 1.65 ## ISSUE: Should {confident} be true?
11150    
11151 wakaba 1.3 my $nt = $node->node_type;
11152     if ($nt == 9) {
11153     # MUST
11154    
11155     ## Step 1 # MUST
11156     ## TODO: If the document has an active parser, ...
11157     ## ISSUE: There is an issue in the spec.
11158    
11159     ## Step 2 # MUST
11160     my @cn = @{$node->child_nodes};
11161     for (@cn) {
11162     $node->remove_child ($_);
11163     }
11164    
11165     ## Step 3, 4, 5 # MUST
11166     $class->parse_string ($$s => $node, $onerror);
11167     } elsif ($nt == 1) {
11168     ## TODO: If non-html element
11169    
11170     ## NOTE: Most of this code is copied from |parse_string|
11171    
11172     ## Step 1 # MUST
11173 wakaba 1.14 my $this_doc = $node->owner_document;
11174     my $doc = $this_doc->implementation->create_document;
11175 wakaba 1.18 $doc->manakai_is_html (1);
11176 wakaba 1.3 my $p = $class->new;
11177     $p->{document} = $doc;
11178    
11179 wakaba 1.84 ## Step 8 # MUST
11180 wakaba 1.3 my $i = 0;
11181     my $line = 1;
11182     my $column = 0;
11183 wakaba 1.76 $p->{set_next_char} = sub {
11184 wakaba 1.3 my $self = shift;
11185 wakaba 1.14
11186 wakaba 1.76 pop @{$self->{prev_char}};
11187     unshift @{$self->{prev_char}}, $self->{next_char};
11188 wakaba 1.14
11189 wakaba 1.76 $self->{next_char} = -1 and return if $i >= length $$s;
11190     $self->{next_char} = ord substr $$s, $i++, 1;
11191 wakaba 1.3 $column++;
11192 wakaba 1.4
11193 wakaba 1.76 if ($self->{next_char} == 0x000A) { # LF
11194 wakaba 1.4 $line++;
11195     $column = 0;
11196 wakaba 1.79
11197     $Whatpm::HTML::Debug::cp_pass->('i1') if $Whatpm::HTML::Debug::cp_pass;
11198     BEGIN {
11199     $Whatpm::HTML::Debug::cp->{'i1'} = 1;
11200     }
11201    
11202 wakaba 1.76 } elsif ($self->{next_char} == 0x000D) { # CR
11203 wakaba 1.15 $i++ if substr ($$s, $i, 1) eq "\x0A";
11204 wakaba 1.76 $self->{next_char} = 0x000A; # LF # MUST
11205 wakaba 1.3 $line++;
11206 wakaba 1.4 $column = 0;
11207 wakaba 1.79
11208     $Whatpm::HTML::Debug::cp_pass->('i2') if $Whatpm::HTML::Debug::cp_pass;
11209     BEGIN {
11210     $Whatpm::HTML::Debug::cp->{'i2'} = 1;
11211     }
11212    
11213 wakaba 1.76 } elsif ($self->{next_char} > 0x10FFFF) {
11214     $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
11215 wakaba 1.79
11216     $Whatpm::HTML::Debug::cp_pass->('i3') if $Whatpm::HTML::Debug::cp_pass;
11217     BEGIN {
11218     $Whatpm::HTML::Debug::cp->{'i3'} = 1;
11219     }
11220    
11221 wakaba 1.76 } elsif ($self->{next_char} == 0x0000) { # NULL
11222 wakaba 1.79
11223     $Whatpm::HTML::Debug::cp_pass->('i4') if $Whatpm::HTML::Debug::cp_pass;
11224     BEGIN {
11225     $Whatpm::HTML::Debug::cp->{'i4'} = 1;
11226     }
11227    
11228 wakaba 1.14 $self->{parse_error}-> (type => 'NULL');
11229 wakaba 1.76 $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
11230 wakaba 1.3 }
11231     };
11232 wakaba 1.76 $p->{prev_char} = [-1, -1, -1];
11233     $p->{next_char} = -1;
11234 wakaba 1.3
11235     my $ponerror = $onerror || sub {
11236     my (%opt) = @_;
11237     warn "Parse error ($opt{type}) at line $opt{line} column $opt{column}\n";
11238     };
11239     $p->{parse_error} = sub {
11240     $ponerror->(@_, line => $line, column => $column);
11241     };
11242    
11243     $p->_initialize_tokenizer;
11244     $p->_initialize_tree_constructor;
11245    
11246     ## Step 2
11247 wakaba 1.71 my $node_ln = $node->manakai_local_name;
11248 wakaba 1.41 $p->{content_model} = {
11249     title => RCDATA_CONTENT_MODEL,
11250     textarea => RCDATA_CONTENT_MODEL,
11251     style => CDATA_CONTENT_MODEL,
11252     script => CDATA_CONTENT_MODEL,
11253     xmp => CDATA_CONTENT_MODEL,
11254     iframe => CDATA_CONTENT_MODEL,
11255     noembed => CDATA_CONTENT_MODEL,
11256     noframes => CDATA_CONTENT_MODEL,
11257     noscript => CDATA_CONTENT_MODEL,
11258     plaintext => PLAINTEXT_CONTENT_MODEL,
11259     }->{$node_ln};
11260     $p->{content_model} = PCDATA_CONTENT_MODEL
11261     unless defined $p->{content_model};
11262     ## ISSUE: What is "the name of the element"? local name?
11263 wakaba 1.3
11264     $p->{inner_html_node} = [$node, $node_ln];
11265    
11266 wakaba 1.84 ## Step 3
11267 wakaba 1.3 my $root = $doc->create_element_ns
11268     ('http://www.w3.org/1999/xhtml', [undef, 'html']);
11269    
11270 wakaba 1.84 ## Step 4 # MUST
11271 wakaba 1.3 $doc->append_child ($root);
11272    
11273 wakaba 1.84 ## Step 5 # MUST
11274 wakaba 1.3 push @{$p->{open_elements}}, [$root, 'html'];
11275    
11276     undef $p->{head_element};
11277    
11278 wakaba 1.84 ## Step 6 # MUST
11279 wakaba 1.3 $p->_reset_insertion_mode;
11280    
11281 wakaba 1.84 ## Step 7 # MUST
11282 wakaba 1.3 my $anode = $node;
11283     AN: while (defined $anode) {
11284     if ($anode->node_type == 1) {
11285     my $nsuri = $anode->namespace_uri;
11286     if (defined $nsuri and $nsuri eq 'http://www.w3.org/1999/xhtml') {
11287 wakaba 1.71 if ($anode->manakai_local_name eq 'form') {
11288 wakaba 1.79
11289     $Whatpm::HTML::Debug::cp_pass->('i5') if $Whatpm::HTML::Debug::cp_pass;
11290     BEGIN {
11291     $Whatpm::HTML::Debug::cp->{'i5'} = 1;
11292     }
11293    
11294 wakaba 1.3 $p->{form_element} = $anode;
11295     last AN;
11296     }
11297     }
11298     }
11299     $anode = $anode->parent_node;
11300     } # AN
11301    
11302 wakaba 1.84 ## Step 9 # MUST
11303 wakaba 1.3 {
11304     my $self = $p;
11305     $token = $self->_get_next_token;
11306     }
11307     $p->_tree_construction_main;
11308    
11309 wakaba 1.84 ## Step 10 # MUST
11310 wakaba 1.3 my @cn = @{$node->child_nodes};
11311     for (@cn) {
11312     $node->remove_child ($_);
11313     }
11314     ## ISSUE: mutation events? read-only?
11315    
11316 wakaba 1.84 ## Step 11 # MUST
11317 wakaba 1.3 @cn = @{$root->child_nodes};
11318     for (@cn) {
11319 wakaba 1.14 $this_doc->adopt_node ($_);
11320 wakaba 1.3 $node->append_child ($_);
11321     }
11322 wakaba 1.14 ## ISSUE: mutation events?
11323 wakaba 1.3
11324     $p->_terminate_tree_constructor;
11325     } else {
11326     die "$0: |set_inner_html| is not defined for node of type $nt";
11327     }
11328     } # set_inner_html
11329    
11330     } # tree construction stage
11331 wakaba 1.1
11332 wakaba 1.65 package Whatpm::HTML::RestartParser;
11333     push our @ISA, 'Error';
11334    
11335 wakaba 1.1 1;
11336 wakaba 1.88 # $Date: 2008/03/08 02:29:22 $

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24