/[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.81 - (hide annotations) (download)
Tue Mar 4 14:51:54 2008 UTC (18 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.80: +7 -4 lines
++ whatpm/t/ChangeLog	4 Mar 2008 14:51:47 -0000
	* tree-test-1.dat: More test data for previously uncovered
	cases are added.

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

1 wakaba 1.2 package Whatpm::HTML;
2 wakaba 1.1 use strict;
3 wakaba 1.81 our $VERSION=do{my @r=(q$Revision: 1.80 $=~/\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     sub AFTER_HTML_BODY_IM () { AFTER_HTML_IMS | BODY_AFTER_IMS }
308     sub AFTER_HTML_FRAMESET_IM () { AFTER_HTML_IMS | FRAME_IMS }
309     sub IN_HEAD_IM () { HEAD_IMS | 0b00 }
310     sub IN_HEAD_NOSCRIPT_IM () { HEAD_IMS | 0b01 }
311     sub AFTER_HEAD_IM () { HEAD_IMS | 0b10 }
312     sub BEFORE_HEAD_IM () { HEAD_IMS | 0b11 }
313     sub IN_BODY_IM () { BODY_IMS }
314 wakaba 1.58 sub IN_CELL_IM () { BODY_IMS | BODY_TABLE_IMS | 0b01 }
315     sub IN_CAPTION_IM () { BODY_IMS | BODY_TABLE_IMS | 0b10 }
316     sub IN_ROW_IM () { TABLE_IMS | ROW_IMS | 0b01 }
317     sub IN_TABLE_BODY_IM () { TABLE_IMS | ROW_IMS | 0b10 }
318 wakaba 1.56 sub IN_TABLE_IM () { TABLE_IMS }
319     sub AFTER_BODY_IM () { BODY_AFTER_IMS }
320     sub IN_FRAMESET_IM () { FRAME_IMS | 0b01 }
321     sub AFTER_FRAMESET_IM () { FRAME_IMS | 0b10 }
322     sub IN_SELECT_IM () { 0b01 }
323     sub IN_COLUMN_GROUP_IM () { 0b10 }
324    
325 wakaba 1.1 ## Implementations MUST act as if state machine in the spec
326    
327     sub _initialize_tokenizer ($) {
328     my $self = shift;
329 wakaba 1.59 $self->{state} = DATA_STATE; # MUST
330 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # be
331 wakaba 1.1 undef $self->{current_token}; # start tag, end tag, comment, or DOCTYPE
332     undef $self->{current_attribute};
333     undef $self->{last_emitted_start_tag_name};
334     undef $self->{last_attribute_value_state};
335     $self->{char} = [];
336 wakaba 1.76 # $self->{next_char}
337 wakaba 1.1
338     if (@{$self->{char}}) {
339 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
340 wakaba 1.1 } else {
341 wakaba 1.76 $self->{set_next_char}->($self);
342 wakaba 1.1 }
343    
344     $self->{token} = [];
345 wakaba 1.18 # $self->{escape}
346 wakaba 1.1 } # _initialize_tokenizer
347    
348     ## A token has:
349 wakaba 1.57 ## ->{type} == DOCTYPE_TOKEN, START_TAG_TOKEN, END_TAG_TOKEN, COMMENT_TOKEN,
350     ## CHARACTER_TOKEN, or END_OF_FILE_TOKEN
351     ## ->{name} (DOCTYPE_TOKEN)
352     ## ->{tag_name} (START_TAG_TOKEN, END_TAG_TOKEN)
353     ## ->{public_identifier} (DOCTYPE_TOKEN)
354     ## ->{system_identifier} (DOCTYPE_TOKEN)
355 wakaba 1.75 ## ->{quirks} == 1 or 0 (DOCTYPE_TOKEN): "force-quirks" flag
356 wakaba 1.57 ## ->{attributes} isa HASH (START_TAG_TOKEN, END_TAG_TOKEN)
357 wakaba 1.68 ## ->{name}
358     ## ->{value}
359     ## ->{has_reference} == 1 or 0
360 wakaba 1.57 ## ->{data} (COMMENT_TOKEN, CHARACTER_TOKEN)
361 wakaba 1.1
362     ## Emitted token MUST immediately be handled by the tree construction state.
363    
364     ## Before each step, UA MAY check to see if either one of the scripts in
365     ## "list of scripts that will execute as soon as possible" or the first
366     ## script in the "list of scripts that will execute asynchronously",
367     ## has completed loading. If one has, then it MUST be executed
368     ## and removed from the list.
369    
370 wakaba 1.61 ## NOTE: HTML5 "Writing HTML documents" section, applied to
371     ## documents and not to user agents and conformance checkers,
372     ## contains some requirements that are not detected by the
373     ## parsing algorithm:
374     ## - Some requirements on character encoding declarations. ## TODO
375     ## - "Elements MUST NOT contain content that their content model disallows."
376     ## ... Some are parse error, some are not (will be reported by c.c.).
377     ## - Polytheistic slash SHOULD NOT be used. (Applied only to atheists.) ## TODO
378     ## - Text (in elements, attributes, and comments) SHOULD NOT contain
379     ## control characters other than space characters. ## TODO: (what is control character? C0, C1 and DEL? Unicode control character?)
380    
381     ## TODO: HTML5 poses authors two SHOULD-level requirements that cannot
382     ## be detected by the HTML5 parsing algorithm:
383     ## - Text,
384    
385 wakaba 1.1 sub _get_next_token ($) {
386     my $self = shift;
387     if (@{$self->{token}}) {
388     return shift @{$self->{token}};
389     }
390    
391     A: {
392 wakaba 1.59 if ($self->{state} == DATA_STATE) {
393 wakaba 1.76 if ($self->{next_char} == 0x0026) { # &
394 wakaba 1.72 if ($self->{content_model} & CM_ENTITY and # PCDATA | RCDATA
395     not $self->{escape}) {
396 wakaba 1.77
397     $Whatpm::HTML::Debug::cp_pass->(1) if $Whatpm::HTML::Debug::cp_pass;
398     BEGIN {
399     $Whatpm::HTML::Debug::cp->{1} = 1;
400     }
401    
402 wakaba 1.59 $self->{state} = ENTITY_DATA_STATE;
403 wakaba 1.1
404     if (@{$self->{char}}) {
405 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
406 wakaba 1.1 } else {
407 wakaba 1.76 $self->{set_next_char}->($self);
408 wakaba 1.1 }
409    
410     redo A;
411     } else {
412 wakaba 1.77
413     $Whatpm::HTML::Debug::cp_pass->(2) if $Whatpm::HTML::Debug::cp_pass;
414     BEGIN {
415     $Whatpm::HTML::Debug::cp->{2} = 1;
416     }
417    
418 wakaba 1.1 #
419     }
420 wakaba 1.76 } elsif ($self->{next_char} == 0x002D) { # -
421 wakaba 1.41 if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
422 wakaba 1.13 unless ($self->{escape}) {
423 wakaba 1.76 if ($self->{prev_char}->[0] == 0x002D and # -
424     $self->{prev_char}->[1] == 0x0021 and # !
425     $self->{prev_char}->[2] == 0x003C) { # <
426 wakaba 1.77
427     $Whatpm::HTML::Debug::cp_pass->(3) if $Whatpm::HTML::Debug::cp_pass;
428     BEGIN {
429     $Whatpm::HTML::Debug::cp->{3} = 1;
430     }
431    
432 wakaba 1.13 $self->{escape} = 1;
433 wakaba 1.77 } else {
434    
435     $Whatpm::HTML::Debug::cp_pass->(4) if $Whatpm::HTML::Debug::cp_pass;
436     BEGIN {
437     $Whatpm::HTML::Debug::cp->{4} = 1;
438     }
439    
440 wakaba 1.13 }
441 wakaba 1.77 } else {
442    
443     $Whatpm::HTML::Debug::cp_pass->(5) if $Whatpm::HTML::Debug::cp_pass;
444     BEGIN {
445     $Whatpm::HTML::Debug::cp->{5} = 1;
446     }
447    
448 wakaba 1.13 }
449     }
450    
451     #
452 wakaba 1.76 } elsif ($self->{next_char} == 0x003C) { # <
453 wakaba 1.41 if ($self->{content_model} & CM_FULL_MARKUP or # PCDATA
454     (($self->{content_model} & CM_LIMITED_MARKUP) and # CDATA | RCDATA
455 wakaba 1.13 not $self->{escape})) {
456 wakaba 1.77
457     $Whatpm::HTML::Debug::cp_pass->(6) if $Whatpm::HTML::Debug::cp_pass;
458     BEGIN {
459     $Whatpm::HTML::Debug::cp->{6} = 1;
460     }
461    
462 wakaba 1.59 $self->{state} = TAG_OPEN_STATE;
463 wakaba 1.1
464     if (@{$self->{char}}) {
465 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
466 wakaba 1.1 } else {
467 wakaba 1.76 $self->{set_next_char}->($self);
468 wakaba 1.1 }
469    
470     redo A;
471     } else {
472 wakaba 1.77
473     $Whatpm::HTML::Debug::cp_pass->(7) if $Whatpm::HTML::Debug::cp_pass;
474     BEGIN {
475     $Whatpm::HTML::Debug::cp->{7} = 1;
476     }
477    
478 wakaba 1.1 #
479     }
480 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
481 wakaba 1.13 if ($self->{escape} and
482 wakaba 1.41 ($self->{content_model} & CM_LIMITED_MARKUP)) { # RCDATA | CDATA
483 wakaba 1.76 if ($self->{prev_char}->[0] == 0x002D and # -
484     $self->{prev_char}->[1] == 0x002D) { # -
485 wakaba 1.77
486     $Whatpm::HTML::Debug::cp_pass->(8) if $Whatpm::HTML::Debug::cp_pass;
487     BEGIN {
488     $Whatpm::HTML::Debug::cp->{8} = 1;
489     }
490    
491 wakaba 1.13 delete $self->{escape};
492 wakaba 1.77 } else {
493    
494     $Whatpm::HTML::Debug::cp_pass->(9) if $Whatpm::HTML::Debug::cp_pass;
495     BEGIN {
496     $Whatpm::HTML::Debug::cp->{9} = 1;
497     }
498    
499 wakaba 1.13 }
500 wakaba 1.77 } else {
501    
502     $Whatpm::HTML::Debug::cp_pass->(10) if $Whatpm::HTML::Debug::cp_pass;
503     BEGIN {
504     $Whatpm::HTML::Debug::cp->{10} = 1;
505     }
506    
507 wakaba 1.13 }
508    
509     #
510 wakaba 1.76 } elsif ($self->{next_char} == -1) {
511 wakaba 1.77
512     $Whatpm::HTML::Debug::cp_pass->(11) if $Whatpm::HTML::Debug::cp_pass;
513     BEGIN {
514     $Whatpm::HTML::Debug::cp->{11} = 1;
515     }
516    
517 wakaba 1.57 return ({type => END_OF_FILE_TOKEN});
518 wakaba 1.1 last A; ## TODO: ok?
519 wakaba 1.77 } else {
520    
521     $Whatpm::HTML::Debug::cp_pass->(12) if $Whatpm::HTML::Debug::cp_pass;
522     BEGIN {
523     $Whatpm::HTML::Debug::cp->{12} = 1;
524     }
525    
526 wakaba 1.1 }
527     # Anything else
528 wakaba 1.57 my $token = {type => CHARACTER_TOKEN,
529 wakaba 1.76 data => chr $self->{next_char}};
530 wakaba 1.1 ## Stay in the data state
531    
532     if (@{$self->{char}}) {
533 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
534 wakaba 1.1 } else {
535 wakaba 1.76 $self->{set_next_char}->($self);
536 wakaba 1.1 }
537    
538    
539     return ($token);
540    
541     redo A;
542 wakaba 1.59 } elsif ($self->{state} == ENTITY_DATA_STATE) {
543 wakaba 1.1 ## (cannot happen in CDATA state)
544    
545 wakaba 1.72 my $token = $self->_tokenize_attempt_to_consume_an_entity (0, -1);
546 wakaba 1.1
547 wakaba 1.59 $self->{state} = DATA_STATE;
548 wakaba 1.1 # next-input-character is already done
549    
550     unless (defined $token) {
551 wakaba 1.77
552     $Whatpm::HTML::Debug::cp_pass->(13) if $Whatpm::HTML::Debug::cp_pass;
553     BEGIN {
554     $Whatpm::HTML::Debug::cp->{13} = 1;
555     }
556    
557 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '&'});
558 wakaba 1.1 } else {
559 wakaba 1.77
560     $Whatpm::HTML::Debug::cp_pass->(14) if $Whatpm::HTML::Debug::cp_pass;
561     BEGIN {
562     $Whatpm::HTML::Debug::cp->{14} = 1;
563     }
564    
565 wakaba 1.1 return ($token);
566     }
567    
568     redo A;
569 wakaba 1.59 } elsif ($self->{state} == TAG_OPEN_STATE) {
570 wakaba 1.41 if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
571 wakaba 1.76 if ($self->{next_char} == 0x002F) { # /
572 wakaba 1.1
573 wakaba 1.77 $Whatpm::HTML::Debug::cp_pass->(15) if $Whatpm::HTML::Debug::cp_pass;
574     BEGIN {
575     $Whatpm::HTML::Debug::cp->{15} = 1;
576     }
577    
578    
579 wakaba 1.1 if (@{$self->{char}}) {
580 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
581 wakaba 1.1 } else {
582 wakaba 1.76 $self->{set_next_char}->($self);
583 wakaba 1.1 }
584    
585 wakaba 1.59 $self->{state} = CLOSE_TAG_OPEN_STATE;
586 wakaba 1.1 redo A;
587     } else {
588 wakaba 1.77
589     $Whatpm::HTML::Debug::cp_pass->(16) if $Whatpm::HTML::Debug::cp_pass;
590     BEGIN {
591     $Whatpm::HTML::Debug::cp->{16} = 1;
592     }
593    
594 wakaba 1.1 ## reconsume
595 wakaba 1.59 $self->{state} = DATA_STATE;
596 wakaba 1.1
597 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '<'});
598 wakaba 1.1
599     redo A;
600     }
601 wakaba 1.41 } elsif ($self->{content_model} & CM_FULL_MARKUP) { # PCDATA
602 wakaba 1.76 if ($self->{next_char} == 0x0021) { # !
603 wakaba 1.77
604     $Whatpm::HTML::Debug::cp_pass->(17) if $Whatpm::HTML::Debug::cp_pass;
605     BEGIN {
606     $Whatpm::HTML::Debug::cp->{17} = 1;
607     }
608    
609 wakaba 1.59 $self->{state} = MARKUP_DECLARATION_OPEN_STATE;
610 wakaba 1.1
611     if (@{$self->{char}}) {
612 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
613 wakaba 1.1 } else {
614 wakaba 1.76 $self->{set_next_char}->($self);
615 wakaba 1.1 }
616    
617     redo A;
618 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
619 wakaba 1.77
620     $Whatpm::HTML::Debug::cp_pass->(18) if $Whatpm::HTML::Debug::cp_pass;
621     BEGIN {
622     $Whatpm::HTML::Debug::cp->{18} = 1;
623     }
624    
625 wakaba 1.59 $self->{state} = CLOSE_TAG_OPEN_STATE;
626 wakaba 1.1
627     if (@{$self->{char}}) {
628 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
629 wakaba 1.1 } else {
630 wakaba 1.76 $self->{set_next_char}->($self);
631 wakaba 1.1 }
632    
633     redo A;
634 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
635     $self->{next_char} <= 0x005A) { # A..Z
636 wakaba 1.77
637     $Whatpm::HTML::Debug::cp_pass->(19) if $Whatpm::HTML::Debug::cp_pass;
638     BEGIN {
639     $Whatpm::HTML::Debug::cp->{19} = 1;
640     }
641    
642 wakaba 1.1 $self->{current_token}
643 wakaba 1.57 = {type => START_TAG_TOKEN,
644 wakaba 1.76 tag_name => chr ($self->{next_char} + 0x0020)};
645 wakaba 1.59 $self->{state} = TAG_NAME_STATE;
646 wakaba 1.1
647     if (@{$self->{char}}) {
648 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
649 wakaba 1.1 } else {
650 wakaba 1.76 $self->{set_next_char}->($self);
651 wakaba 1.1 }
652    
653     redo A;
654 wakaba 1.76 } elsif (0x0061 <= $self->{next_char} and
655     $self->{next_char} <= 0x007A) { # a..z
656 wakaba 1.77
657     $Whatpm::HTML::Debug::cp_pass->(20) if $Whatpm::HTML::Debug::cp_pass;
658     BEGIN {
659     $Whatpm::HTML::Debug::cp->{20} = 1;
660     }
661    
662 wakaba 1.57 $self->{current_token} = {type => START_TAG_TOKEN,
663 wakaba 1.76 tag_name => chr ($self->{next_char})};
664 wakaba 1.59 $self->{state} = TAG_NAME_STATE;
665 wakaba 1.1
666     if (@{$self->{char}}) {
667 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
668 wakaba 1.1 } else {
669 wakaba 1.76 $self->{set_next_char}->($self);
670 wakaba 1.1 }
671    
672     redo A;
673 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
674 wakaba 1.77
675     $Whatpm::HTML::Debug::cp_pass->(21) if $Whatpm::HTML::Debug::cp_pass;
676     BEGIN {
677     $Whatpm::HTML::Debug::cp->{21} = 1;
678     }
679    
680 wakaba 1.3 $self->{parse_error}-> (type => 'empty start tag');
681 wakaba 1.59 $self->{state} = DATA_STATE;
682 wakaba 1.1
683     if (@{$self->{char}}) {
684 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
685 wakaba 1.1 } else {
686 wakaba 1.76 $self->{set_next_char}->($self);
687 wakaba 1.1 }
688    
689    
690 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '<>'});
691 wakaba 1.1
692     redo A;
693 wakaba 1.76 } elsif ($self->{next_char} == 0x003F) { # ?
694 wakaba 1.77
695     $Whatpm::HTML::Debug::cp_pass->(22) if $Whatpm::HTML::Debug::cp_pass;
696     BEGIN {
697     $Whatpm::HTML::Debug::cp->{22} = 1;
698     }
699    
700 wakaba 1.3 $self->{parse_error}-> (type => 'pio');
701 wakaba 1.59 $self->{state} = BOGUS_COMMENT_STATE;
702 wakaba 1.76 ## $self->{next_char} is intentionally left as is
703 wakaba 1.1 redo A;
704     } else {
705 wakaba 1.77
706     $Whatpm::HTML::Debug::cp_pass->(23) if $Whatpm::HTML::Debug::cp_pass;
707     BEGIN {
708     $Whatpm::HTML::Debug::cp->{23} = 1;
709     }
710    
711 wakaba 1.3 $self->{parse_error}-> (type => 'bare stago');
712 wakaba 1.59 $self->{state} = DATA_STATE;
713 wakaba 1.1 ## reconsume
714    
715 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '<'});
716 wakaba 1.1
717     redo A;
718     }
719     } else {
720 wakaba 1.41 die "$0: $self->{content_model} in tag open";
721 wakaba 1.1 }
722 wakaba 1.59 } elsif ($self->{state} == CLOSE_TAG_OPEN_STATE) {
723 wakaba 1.41 if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
724 wakaba 1.23 if (defined $self->{last_emitted_start_tag_name}) {
725 wakaba 1.30 ## NOTE: <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>
726 wakaba 1.23 my @next_char;
727     TAGNAME: for (my $i = 0; $i < length $self->{last_emitted_start_tag_name}; $i++) {
728 wakaba 1.76 push @next_char, $self->{next_char};
729 wakaba 1.23 my $c = ord substr ($self->{last_emitted_start_tag_name}, $i, 1);
730     my $C = 0x0061 <= $c && $c <= 0x007A ? $c - 0x0020 : $c;
731 wakaba 1.76 if ($self->{next_char} == $c or $self->{next_char} == $C) {
732 wakaba 1.23
733 wakaba 1.77 $Whatpm::HTML::Debug::cp_pass->(24) if $Whatpm::HTML::Debug::cp_pass;
734     BEGIN {
735     $Whatpm::HTML::Debug::cp->{24} = 1;
736     }
737    
738    
739 wakaba 1.1 if (@{$self->{char}}) {
740 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
741 wakaba 1.1 } else {
742 wakaba 1.76 $self->{set_next_char}->($self);
743 wakaba 1.1 }
744    
745 wakaba 1.23 next TAGNAME;
746     } else {
747 wakaba 1.77
748     $Whatpm::HTML::Debug::cp_pass->(25) if $Whatpm::HTML::Debug::cp_pass;
749     BEGIN {
750     $Whatpm::HTML::Debug::cp->{25} = 1;
751     }
752    
753 wakaba 1.76 $self->{next_char} = shift @next_char; # reconsume
754 wakaba 1.23 unshift @{$self->{char}}, (@next_char);
755 wakaba 1.59 $self->{state} = DATA_STATE;
756 wakaba 1.23
757 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '</'});
758 wakaba 1.23
759     redo A;
760     }
761     }
762 wakaba 1.76 push @next_char, $self->{next_char};
763 wakaba 1.23
764 wakaba 1.76 unless ($self->{next_char} == 0x0009 or # HT
765     $self->{next_char} == 0x000A or # LF
766     $self->{next_char} == 0x000B or # VT
767     $self->{next_char} == 0x000C or # FF
768     $self->{next_char} == 0x0020 or # SP
769     $self->{next_char} == 0x003E or # >
770     $self->{next_char} == 0x002F or # /
771     $self->{next_char} == -1) {
772 wakaba 1.77
773     $Whatpm::HTML::Debug::cp_pass->(26) if $Whatpm::HTML::Debug::cp_pass;
774     BEGIN {
775     $Whatpm::HTML::Debug::cp->{26} = 1;
776     }
777    
778 wakaba 1.76 $self->{next_char} = shift @next_char; # reconsume
779 wakaba 1.1 unshift @{$self->{char}}, (@next_char);
780 wakaba 1.59 $self->{state} = DATA_STATE;
781 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '</'});
782 wakaba 1.1 redo A;
783 wakaba 1.23 } else {
784 wakaba 1.77
785     $Whatpm::HTML::Debug::cp_pass->(27) if $Whatpm::HTML::Debug::cp_pass;
786     BEGIN {
787     $Whatpm::HTML::Debug::cp->{27} = 1;
788     }
789    
790 wakaba 1.76 $self->{next_char} = shift @next_char;
791 wakaba 1.23 unshift @{$self->{char}}, (@next_char);
792     # and consume...
793 wakaba 1.1 }
794 wakaba 1.23 } else {
795     ## No start tag token has ever been emitted
796 wakaba 1.77
797     $Whatpm::HTML::Debug::cp_pass->(28) if $Whatpm::HTML::Debug::cp_pass;
798     BEGIN {
799     $Whatpm::HTML::Debug::cp->{28} = 1;
800     }
801    
802 wakaba 1.23 # next-input-character is already done
803 wakaba 1.59 $self->{state} = DATA_STATE;
804 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '</'});
805 wakaba 1.1 redo A;
806     }
807     }
808    
809 wakaba 1.76 if (0x0041 <= $self->{next_char} and
810     $self->{next_char} <= 0x005A) { # A..Z
811 wakaba 1.77
812     $Whatpm::HTML::Debug::cp_pass->(29) if $Whatpm::HTML::Debug::cp_pass;
813     BEGIN {
814     $Whatpm::HTML::Debug::cp->{29} = 1;
815     }
816    
817 wakaba 1.57 $self->{current_token} = {type => END_TAG_TOKEN,
818 wakaba 1.76 tag_name => chr ($self->{next_char} + 0x0020)};
819 wakaba 1.59 $self->{state} = TAG_NAME_STATE;
820 wakaba 1.1
821     if (@{$self->{char}}) {
822 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
823 wakaba 1.1 } else {
824 wakaba 1.76 $self->{set_next_char}->($self);
825 wakaba 1.1 }
826    
827     redo A;
828 wakaba 1.76 } elsif (0x0061 <= $self->{next_char} and
829     $self->{next_char} <= 0x007A) { # a..z
830 wakaba 1.77
831     $Whatpm::HTML::Debug::cp_pass->(30) if $Whatpm::HTML::Debug::cp_pass;
832     BEGIN {
833     $Whatpm::HTML::Debug::cp->{30} = 1;
834     }
835    
836 wakaba 1.57 $self->{current_token} = {type => END_TAG_TOKEN,
837 wakaba 1.76 tag_name => chr ($self->{next_char})};
838 wakaba 1.59 $self->{state} = TAG_NAME_STATE;
839 wakaba 1.1
840     if (@{$self->{char}}) {
841 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
842 wakaba 1.1 } else {
843 wakaba 1.76 $self->{set_next_char}->($self);
844 wakaba 1.1 }
845    
846     redo A;
847 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
848 wakaba 1.77
849     $Whatpm::HTML::Debug::cp_pass->(31) if $Whatpm::HTML::Debug::cp_pass;
850     BEGIN {
851     $Whatpm::HTML::Debug::cp->{31} = 1;
852     }
853    
854 wakaba 1.3 $self->{parse_error}-> (type => 'empty end tag');
855 wakaba 1.59 $self->{state} = DATA_STATE;
856 wakaba 1.1
857     if (@{$self->{char}}) {
858 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
859 wakaba 1.1 } else {
860 wakaba 1.76 $self->{set_next_char}->($self);
861 wakaba 1.1 }
862    
863     redo A;
864 wakaba 1.76 } elsif ($self->{next_char} == -1) {
865 wakaba 1.77
866     $Whatpm::HTML::Debug::cp_pass->(32) if $Whatpm::HTML::Debug::cp_pass;
867     BEGIN {
868     $Whatpm::HTML::Debug::cp->{32} = 1;
869     }
870    
871 wakaba 1.3 $self->{parse_error}-> (type => 'bare etago');
872 wakaba 1.59 $self->{state} = DATA_STATE;
873 wakaba 1.1 # reconsume
874    
875 wakaba 1.57 return ({type => CHARACTER_TOKEN, data => '</'});
876 wakaba 1.1
877     redo A;
878     } else {
879 wakaba 1.77
880     $Whatpm::HTML::Debug::cp_pass->(33) if $Whatpm::HTML::Debug::cp_pass;
881     BEGIN {
882     $Whatpm::HTML::Debug::cp->{33} = 1;
883     }
884    
885 wakaba 1.3 $self->{parse_error}-> (type => 'bogus end tag');
886 wakaba 1.59 $self->{state} = BOGUS_COMMENT_STATE;
887 wakaba 1.76 ## $self->{next_char} is intentionally left as is
888 wakaba 1.1 redo A;
889     }
890 wakaba 1.59 } elsif ($self->{state} == TAG_NAME_STATE) {
891 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
892     $self->{next_char} == 0x000A or # LF
893     $self->{next_char} == 0x000B or # VT
894     $self->{next_char} == 0x000C or # FF
895     $self->{next_char} == 0x0020) { # SP
896 wakaba 1.77
897     $Whatpm::HTML::Debug::cp_pass->(34) if $Whatpm::HTML::Debug::cp_pass;
898     BEGIN {
899     $Whatpm::HTML::Debug::cp->{34} = 1;
900     }
901    
902 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
903 wakaba 1.1
904     if (@{$self->{char}}) {
905 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
906 wakaba 1.1 } else {
907 wakaba 1.76 $self->{set_next_char}->($self);
908 wakaba 1.1 }
909    
910     redo A;
911 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
912 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
913 wakaba 1.77
914     $Whatpm::HTML::Debug::cp_pass->(35) if $Whatpm::HTML::Debug::cp_pass;
915     BEGIN {
916     $Whatpm::HTML::Debug::cp->{35} = 1;
917     }
918    
919 wakaba 1.28 $self->{current_token}->{first_start_tag}
920     = not defined $self->{last_emitted_start_tag_name};
921 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
922 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
923 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
924 wakaba 1.78 #if ($self->{current_token}->{attributes}) {
925     # ## NOTE: This should never be reached.
926     # !!! cp (36);
927     # !!! parse-error (type => 'end tag attribute');
928     #} else {
929 wakaba 1.77
930     $Whatpm::HTML::Debug::cp_pass->(37) if $Whatpm::HTML::Debug::cp_pass;
931     BEGIN {
932     $Whatpm::HTML::Debug::cp->{37} = 1;
933     }
934    
935 wakaba 1.78 #}
936 wakaba 1.1 } else {
937     die "$0: $self->{current_token}->{type}: Unknown token type";
938     }
939 wakaba 1.59 $self->{state} = DATA_STATE;
940 wakaba 1.1
941     if (@{$self->{char}}) {
942 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
943 wakaba 1.1 } else {
944 wakaba 1.76 $self->{set_next_char}->($self);
945 wakaba 1.1 }
946    
947    
948     return ($self->{current_token}); # start tag or end tag
949    
950     redo A;
951 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
952     $self->{next_char} <= 0x005A) { # A..Z
953 wakaba 1.77
954     $Whatpm::HTML::Debug::cp_pass->(38) if $Whatpm::HTML::Debug::cp_pass;
955     BEGIN {
956     $Whatpm::HTML::Debug::cp->{38} = 1;
957     }
958    
959 wakaba 1.76 $self->{current_token}->{tag_name} .= chr ($self->{next_char} + 0x0020);
960 wakaba 1.1 # start tag or end tag
961     ## Stay in this state
962    
963     if (@{$self->{char}}) {
964 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
965 wakaba 1.1 } else {
966 wakaba 1.76 $self->{set_next_char}->($self);
967 wakaba 1.1 }
968    
969     redo A;
970 wakaba 1.76 } elsif ($self->{next_char} == -1) {
971 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
972 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
973 wakaba 1.77
974     $Whatpm::HTML::Debug::cp_pass->(39) if $Whatpm::HTML::Debug::cp_pass;
975     BEGIN {
976     $Whatpm::HTML::Debug::cp->{39} = 1;
977     }
978    
979 wakaba 1.28 $self->{current_token}->{first_start_tag}
980     = not defined $self->{last_emitted_start_tag_name};
981 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
982 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
983 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
984 wakaba 1.78 #if ($self->{current_token}->{attributes}) {
985     # ## NOTE: This state should never be reached.
986     # !!! cp (40);
987     # !!! parse-error (type => 'end tag attribute');
988     #} else {
989 wakaba 1.77
990     $Whatpm::HTML::Debug::cp_pass->(41) if $Whatpm::HTML::Debug::cp_pass;
991     BEGIN {
992     $Whatpm::HTML::Debug::cp->{41} = 1;
993     }
994    
995 wakaba 1.78 #}
996 wakaba 1.1 } else {
997     die "$0: $self->{current_token}->{type}: Unknown token type";
998     }
999 wakaba 1.59 $self->{state} = DATA_STATE;
1000 wakaba 1.1 # reconsume
1001    
1002     return ($self->{current_token}); # start tag or end tag
1003    
1004     redo A;
1005 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
1006 wakaba 1.1
1007     if (@{$self->{char}}) {
1008 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1009 wakaba 1.1 } else {
1010 wakaba 1.76 $self->{set_next_char}->($self);
1011 wakaba 1.1 }
1012    
1013 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
1014 wakaba 1.57 $self->{current_token}->{type} == START_TAG_TOKEN and
1015 wakaba 1.1 $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
1016     # permitted slash
1017 wakaba 1.77
1018     $Whatpm::HTML::Debug::cp_pass->(42) if $Whatpm::HTML::Debug::cp_pass;
1019     BEGIN {
1020     $Whatpm::HTML::Debug::cp->{42} = 1;
1021     }
1022    
1023 wakaba 1.1 #
1024     } else {
1025 wakaba 1.77
1026     $Whatpm::HTML::Debug::cp_pass->(43) if $Whatpm::HTML::Debug::cp_pass;
1027     BEGIN {
1028     $Whatpm::HTML::Debug::cp->{43} = 1;
1029     }
1030    
1031 wakaba 1.3 $self->{parse_error}-> (type => 'nestc');
1032 wakaba 1.1 }
1033 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1034 wakaba 1.1 # next-input-character is already done
1035     redo A;
1036     } else {
1037 wakaba 1.77
1038     $Whatpm::HTML::Debug::cp_pass->(44) if $Whatpm::HTML::Debug::cp_pass;
1039     BEGIN {
1040     $Whatpm::HTML::Debug::cp->{44} = 1;
1041     }
1042    
1043 wakaba 1.76 $self->{current_token}->{tag_name} .= chr $self->{next_char};
1044 wakaba 1.1 # start tag or end tag
1045     ## Stay in the state
1046    
1047     if (@{$self->{char}}) {
1048 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1049 wakaba 1.1 } else {
1050 wakaba 1.76 $self->{set_next_char}->($self);
1051 wakaba 1.1 }
1052    
1053     redo A;
1054     }
1055 wakaba 1.59 } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {
1056 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
1057     $self->{next_char} == 0x000A or # LF
1058     $self->{next_char} == 0x000B or # VT
1059     $self->{next_char} == 0x000C or # FF
1060     $self->{next_char} == 0x0020) { # SP
1061 wakaba 1.77
1062     $Whatpm::HTML::Debug::cp_pass->(45) if $Whatpm::HTML::Debug::cp_pass;
1063     BEGIN {
1064     $Whatpm::HTML::Debug::cp->{45} = 1;
1065     }
1066    
1067 wakaba 1.1 ## Stay in the state
1068    
1069     if (@{$self->{char}}) {
1070 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1071 wakaba 1.1 } else {
1072 wakaba 1.76 $self->{set_next_char}->($self);
1073 wakaba 1.1 }
1074    
1075     redo A;
1076 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
1077 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1078 wakaba 1.77
1079     $Whatpm::HTML::Debug::cp_pass->(46) if $Whatpm::HTML::Debug::cp_pass;
1080     BEGIN {
1081     $Whatpm::HTML::Debug::cp->{46} = 1;
1082     }
1083    
1084 wakaba 1.28 $self->{current_token}->{first_start_tag}
1085     = not defined $self->{last_emitted_start_tag_name};
1086 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1087 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1088 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1089 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1090 wakaba 1.77
1091     $Whatpm::HTML::Debug::cp_pass->(47) if $Whatpm::HTML::Debug::cp_pass;
1092     BEGIN {
1093     $Whatpm::HTML::Debug::cp->{47} = 1;
1094     }
1095    
1096 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1097 wakaba 1.77 } else {
1098    
1099     $Whatpm::HTML::Debug::cp_pass->(48) if $Whatpm::HTML::Debug::cp_pass;
1100     BEGIN {
1101     $Whatpm::HTML::Debug::cp->{48} = 1;
1102     }
1103    
1104 wakaba 1.1 }
1105     } else {
1106     die "$0: $self->{current_token}->{type}: Unknown token type";
1107     }
1108 wakaba 1.59 $self->{state} = DATA_STATE;
1109 wakaba 1.1
1110     if (@{$self->{char}}) {
1111 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1112 wakaba 1.1 } else {
1113 wakaba 1.76 $self->{set_next_char}->($self);
1114 wakaba 1.1 }
1115    
1116    
1117     return ($self->{current_token}); # start tag or end tag
1118    
1119     redo A;
1120 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
1121     $self->{next_char} <= 0x005A) { # A..Z
1122 wakaba 1.77
1123     $Whatpm::HTML::Debug::cp_pass->(49) if $Whatpm::HTML::Debug::cp_pass;
1124     BEGIN {
1125     $Whatpm::HTML::Debug::cp->{49} = 1;
1126     }
1127    
1128 wakaba 1.76 $self->{current_attribute} = {name => chr ($self->{next_char} + 0x0020),
1129 wakaba 1.1 value => ''};
1130 wakaba 1.59 $self->{state} = ATTRIBUTE_NAME_STATE;
1131 wakaba 1.1
1132     if (@{$self->{char}}) {
1133 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1134 wakaba 1.1 } else {
1135 wakaba 1.76 $self->{set_next_char}->($self);
1136 wakaba 1.1 }
1137    
1138     redo A;
1139 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
1140 wakaba 1.1
1141     if (@{$self->{char}}) {
1142 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1143 wakaba 1.1 } else {
1144 wakaba 1.76 $self->{set_next_char}->($self);
1145 wakaba 1.1 }
1146    
1147 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
1148 wakaba 1.57 $self->{current_token}->{type} == START_TAG_TOKEN and
1149 wakaba 1.1 $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
1150     # permitted slash
1151 wakaba 1.77
1152     $Whatpm::HTML::Debug::cp_pass->(50) if $Whatpm::HTML::Debug::cp_pass;
1153     BEGIN {
1154     $Whatpm::HTML::Debug::cp->{50} = 1;
1155     }
1156    
1157 wakaba 1.1 #
1158     } else {
1159 wakaba 1.77
1160     $Whatpm::HTML::Debug::cp_pass->(51) if $Whatpm::HTML::Debug::cp_pass;
1161     BEGIN {
1162     $Whatpm::HTML::Debug::cp->{51} = 1;
1163     }
1164    
1165 wakaba 1.3 $self->{parse_error}-> (type => 'nestc');
1166 wakaba 1.1 }
1167     ## Stay in the state
1168     # next-input-character is already done
1169     redo A;
1170 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1171 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
1172 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1173 wakaba 1.77
1174     $Whatpm::HTML::Debug::cp_pass->(52) if $Whatpm::HTML::Debug::cp_pass;
1175     BEGIN {
1176     $Whatpm::HTML::Debug::cp->{52} = 1;
1177     }
1178    
1179 wakaba 1.28 $self->{current_token}->{first_start_tag}
1180     = not defined $self->{last_emitted_start_tag_name};
1181 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1182 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1183 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1184 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1185 wakaba 1.77
1186     $Whatpm::HTML::Debug::cp_pass->(53) if $Whatpm::HTML::Debug::cp_pass;
1187     BEGIN {
1188     $Whatpm::HTML::Debug::cp->{53} = 1;
1189     }
1190    
1191 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1192 wakaba 1.77 } else {
1193    
1194     $Whatpm::HTML::Debug::cp_pass->(54) if $Whatpm::HTML::Debug::cp_pass;
1195     BEGIN {
1196     $Whatpm::HTML::Debug::cp->{54} = 1;
1197     }
1198    
1199 wakaba 1.1 }
1200     } else {
1201     die "$0: $self->{current_token}->{type}: Unknown token type";
1202     }
1203 wakaba 1.59 $self->{state} = DATA_STATE;
1204 wakaba 1.1 # reconsume
1205    
1206     return ($self->{current_token}); # start tag or end tag
1207    
1208     redo A;
1209     } else {
1210 wakaba 1.72 if ({
1211     0x0022 => 1, # "
1212     0x0027 => 1, # '
1213     0x003D => 1, # =
1214 wakaba 1.76 }->{$self->{next_char}}) {
1215 wakaba 1.77
1216     $Whatpm::HTML::Debug::cp_pass->(55) if $Whatpm::HTML::Debug::cp_pass;
1217     BEGIN {
1218     $Whatpm::HTML::Debug::cp->{55} = 1;
1219     }
1220    
1221 wakaba 1.72 $self->{parse_error}-> (type => 'bad attribute name');
1222 wakaba 1.77 } else {
1223    
1224     $Whatpm::HTML::Debug::cp_pass->(56) if $Whatpm::HTML::Debug::cp_pass;
1225     BEGIN {
1226     $Whatpm::HTML::Debug::cp->{56} = 1;
1227     }
1228    
1229 wakaba 1.72 }
1230 wakaba 1.76 $self->{current_attribute} = {name => chr ($self->{next_char}),
1231 wakaba 1.1 value => ''};
1232 wakaba 1.59 $self->{state} = ATTRIBUTE_NAME_STATE;
1233 wakaba 1.1
1234     if (@{$self->{char}}) {
1235 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1236 wakaba 1.1 } else {
1237 wakaba 1.76 $self->{set_next_char}->($self);
1238 wakaba 1.1 }
1239    
1240     redo A;
1241     }
1242 wakaba 1.59 } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {
1243 wakaba 1.1 my $before_leave = sub {
1244     if (exists $self->{current_token}->{attributes} # start tag or end tag
1245     ->{$self->{current_attribute}->{name}}) { # MUST
1246 wakaba 1.77
1247     $Whatpm::HTML::Debug::cp_pass->(57) if $Whatpm::HTML::Debug::cp_pass;
1248     BEGIN {
1249     $Whatpm::HTML::Debug::cp->{57} = 1;
1250     }
1251    
1252 wakaba 1.40 $self->{parse_error}-> (type => 'duplicate attribute:'.$self->{current_attribute}->{name});
1253 wakaba 1.1 ## Discard $self->{current_attribute} # MUST
1254     } else {
1255 wakaba 1.77
1256     $Whatpm::HTML::Debug::cp_pass->(58) if $Whatpm::HTML::Debug::cp_pass;
1257     BEGIN {
1258     $Whatpm::HTML::Debug::cp->{58} = 1;
1259     }
1260    
1261 wakaba 1.1 $self->{current_token}->{attributes}->{$self->{current_attribute}->{name}}
1262     = $self->{current_attribute};
1263     }
1264     }; # $before_leave
1265    
1266 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
1267     $self->{next_char} == 0x000A or # LF
1268     $self->{next_char} == 0x000B or # VT
1269     $self->{next_char} == 0x000C or # FF
1270     $self->{next_char} == 0x0020) { # SP
1271 wakaba 1.77
1272     $Whatpm::HTML::Debug::cp_pass->(59) if $Whatpm::HTML::Debug::cp_pass;
1273     BEGIN {
1274     $Whatpm::HTML::Debug::cp->{59} = 1;
1275     }
1276    
1277 wakaba 1.1 $before_leave->();
1278 wakaba 1.59 $self->{state} = AFTER_ATTRIBUTE_NAME_STATE;
1279 wakaba 1.1
1280     if (@{$self->{char}}) {
1281 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1282 wakaba 1.1 } else {
1283 wakaba 1.76 $self->{set_next_char}->($self);
1284 wakaba 1.1 }
1285    
1286     redo A;
1287 wakaba 1.76 } elsif ($self->{next_char} == 0x003D) { # =
1288 wakaba 1.77
1289     $Whatpm::HTML::Debug::cp_pass->(60) if $Whatpm::HTML::Debug::cp_pass;
1290     BEGIN {
1291     $Whatpm::HTML::Debug::cp->{60} = 1;
1292     }
1293    
1294 wakaba 1.1 $before_leave->();
1295 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;
1296 wakaba 1.1
1297     if (@{$self->{char}}) {
1298 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1299 wakaba 1.1 } else {
1300 wakaba 1.76 $self->{set_next_char}->($self);
1301 wakaba 1.1 }
1302    
1303     redo A;
1304 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
1305 wakaba 1.1 $before_leave->();
1306 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1307 wakaba 1.77
1308     $Whatpm::HTML::Debug::cp_pass->(61) if $Whatpm::HTML::Debug::cp_pass;
1309     BEGIN {
1310     $Whatpm::HTML::Debug::cp->{61} = 1;
1311     }
1312    
1313 wakaba 1.28 $self->{current_token}->{first_start_tag}
1314     = not defined $self->{last_emitted_start_tag_name};
1315 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1316 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1317 wakaba 1.77
1318     $Whatpm::HTML::Debug::cp_pass->(62) if $Whatpm::HTML::Debug::cp_pass;
1319     BEGIN {
1320     $Whatpm::HTML::Debug::cp->{62} = 1;
1321     }
1322    
1323 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1324 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1325 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1326 wakaba 1.1 }
1327     } else {
1328     die "$0: $self->{current_token}->{type}: Unknown token type";
1329     }
1330 wakaba 1.59 $self->{state} = DATA_STATE;
1331 wakaba 1.1
1332     if (@{$self->{char}}) {
1333 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1334 wakaba 1.1 } else {
1335 wakaba 1.76 $self->{set_next_char}->($self);
1336 wakaba 1.1 }
1337    
1338    
1339     return ($self->{current_token}); # start tag or end tag
1340    
1341     redo A;
1342 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
1343     $self->{next_char} <= 0x005A) { # A..Z
1344 wakaba 1.77
1345     $Whatpm::HTML::Debug::cp_pass->(63) if $Whatpm::HTML::Debug::cp_pass;
1346     BEGIN {
1347     $Whatpm::HTML::Debug::cp->{63} = 1;
1348     }
1349    
1350 wakaba 1.76 $self->{current_attribute}->{name} .= chr ($self->{next_char} + 0x0020);
1351 wakaba 1.1 ## Stay in the state
1352    
1353     if (@{$self->{char}}) {
1354 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1355 wakaba 1.1 } else {
1356 wakaba 1.76 $self->{set_next_char}->($self);
1357 wakaba 1.1 }
1358    
1359     redo A;
1360 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
1361 wakaba 1.1 $before_leave->();
1362    
1363     if (@{$self->{char}}) {
1364 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1365 wakaba 1.1 } else {
1366 wakaba 1.76 $self->{set_next_char}->($self);
1367 wakaba 1.1 }
1368    
1369 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
1370 wakaba 1.57 $self->{current_token}->{type} == START_TAG_TOKEN and
1371 wakaba 1.1 $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
1372     # permitted slash
1373 wakaba 1.77
1374     $Whatpm::HTML::Debug::cp_pass->(64) if $Whatpm::HTML::Debug::cp_pass;
1375     BEGIN {
1376     $Whatpm::HTML::Debug::cp->{64} = 1;
1377     }
1378    
1379 wakaba 1.1 #
1380     } else {
1381 wakaba 1.77
1382     $Whatpm::HTML::Debug::cp_pass->(65) if $Whatpm::HTML::Debug::cp_pass;
1383     BEGIN {
1384     $Whatpm::HTML::Debug::cp->{65} = 1;
1385     }
1386    
1387 wakaba 1.3 $self->{parse_error}-> (type => 'nestc');
1388 wakaba 1.1 }
1389 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1390 wakaba 1.1 # next-input-character is already done
1391     redo A;
1392 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1393 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
1394 wakaba 1.1 $before_leave->();
1395 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1396 wakaba 1.77
1397     $Whatpm::HTML::Debug::cp_pass->(66) if $Whatpm::HTML::Debug::cp_pass;
1398     BEGIN {
1399     $Whatpm::HTML::Debug::cp->{66} = 1;
1400     }
1401    
1402 wakaba 1.28 $self->{current_token}->{first_start_tag}
1403     = not defined $self->{last_emitted_start_tag_name};
1404 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1405 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1406 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1407 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1408 wakaba 1.77
1409     $Whatpm::HTML::Debug::cp_pass->(67) if $Whatpm::HTML::Debug::cp_pass;
1410     BEGIN {
1411     $Whatpm::HTML::Debug::cp->{67} = 1;
1412     }
1413    
1414 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1415 wakaba 1.77 } else {
1416 wakaba 1.78 ## NOTE: This state should never be reached.
1417 wakaba 1.77
1418     $Whatpm::HTML::Debug::cp_pass->(68) if $Whatpm::HTML::Debug::cp_pass;
1419     BEGIN {
1420     $Whatpm::HTML::Debug::cp->{68} = 1;
1421     }
1422    
1423 wakaba 1.1 }
1424     } else {
1425     die "$0: $self->{current_token}->{type}: Unknown token type";
1426     }
1427 wakaba 1.59 $self->{state} = DATA_STATE;
1428 wakaba 1.1 # reconsume
1429    
1430     return ($self->{current_token}); # start tag or end tag
1431    
1432     redo A;
1433     } else {
1434 wakaba 1.76 if ($self->{next_char} == 0x0022 or # "
1435     $self->{next_char} == 0x0027) { # '
1436 wakaba 1.77
1437     $Whatpm::HTML::Debug::cp_pass->(69) if $Whatpm::HTML::Debug::cp_pass;
1438     BEGIN {
1439     $Whatpm::HTML::Debug::cp->{69} = 1;
1440     }
1441    
1442 wakaba 1.72 $self->{parse_error}-> (type => 'bad attribute name');
1443 wakaba 1.77 } else {
1444    
1445     $Whatpm::HTML::Debug::cp_pass->(70) if $Whatpm::HTML::Debug::cp_pass;
1446     BEGIN {
1447     $Whatpm::HTML::Debug::cp->{70} = 1;
1448     }
1449    
1450 wakaba 1.72 }
1451 wakaba 1.76 $self->{current_attribute}->{name} .= chr ($self->{next_char});
1452 wakaba 1.1 ## Stay in the state
1453    
1454     if (@{$self->{char}}) {
1455 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1456 wakaba 1.1 } else {
1457 wakaba 1.76 $self->{set_next_char}->($self);
1458 wakaba 1.1 }
1459    
1460     redo A;
1461     }
1462 wakaba 1.59 } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {
1463 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
1464     $self->{next_char} == 0x000A or # LF
1465     $self->{next_char} == 0x000B or # VT
1466     $self->{next_char} == 0x000C or # FF
1467     $self->{next_char} == 0x0020) { # SP
1468 wakaba 1.77
1469     $Whatpm::HTML::Debug::cp_pass->(71) if $Whatpm::HTML::Debug::cp_pass;
1470     BEGIN {
1471     $Whatpm::HTML::Debug::cp->{71} = 1;
1472     }
1473    
1474 wakaba 1.1 ## Stay in the state
1475    
1476     if (@{$self->{char}}) {
1477 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1478 wakaba 1.1 } else {
1479 wakaba 1.76 $self->{set_next_char}->($self);
1480 wakaba 1.1 }
1481    
1482     redo A;
1483 wakaba 1.76 } elsif ($self->{next_char} == 0x003D) { # =
1484 wakaba 1.77
1485     $Whatpm::HTML::Debug::cp_pass->(72) if $Whatpm::HTML::Debug::cp_pass;
1486     BEGIN {
1487     $Whatpm::HTML::Debug::cp->{72} = 1;
1488     }
1489    
1490 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;
1491 wakaba 1.1
1492     if (@{$self->{char}}) {
1493 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1494 wakaba 1.1 } else {
1495 wakaba 1.76 $self->{set_next_char}->($self);
1496 wakaba 1.1 }
1497    
1498     redo A;
1499 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
1500 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1501 wakaba 1.77
1502     $Whatpm::HTML::Debug::cp_pass->(73) if $Whatpm::HTML::Debug::cp_pass;
1503     BEGIN {
1504     $Whatpm::HTML::Debug::cp->{73} = 1;
1505     }
1506    
1507 wakaba 1.28 $self->{current_token}->{first_start_tag}
1508     = not defined $self->{last_emitted_start_tag_name};
1509 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1510 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1511 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1512 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1513 wakaba 1.77
1514     $Whatpm::HTML::Debug::cp_pass->(74) if $Whatpm::HTML::Debug::cp_pass;
1515     BEGIN {
1516     $Whatpm::HTML::Debug::cp->{74} = 1;
1517     }
1518    
1519 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1520 wakaba 1.77 } else {
1521 wakaba 1.78 ## NOTE: This state should never be reached.
1522 wakaba 1.77
1523     $Whatpm::HTML::Debug::cp_pass->(75) if $Whatpm::HTML::Debug::cp_pass;
1524     BEGIN {
1525     $Whatpm::HTML::Debug::cp->{75} = 1;
1526     }
1527    
1528 wakaba 1.1 }
1529     } else {
1530     die "$0: $self->{current_token}->{type}: Unknown token type";
1531     }
1532 wakaba 1.59 $self->{state} = DATA_STATE;
1533 wakaba 1.1
1534     if (@{$self->{char}}) {
1535 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1536 wakaba 1.1 } else {
1537 wakaba 1.76 $self->{set_next_char}->($self);
1538 wakaba 1.1 }
1539    
1540    
1541     return ($self->{current_token}); # start tag or end tag
1542    
1543     redo A;
1544 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
1545     $self->{next_char} <= 0x005A) { # A..Z
1546 wakaba 1.77
1547     $Whatpm::HTML::Debug::cp_pass->(76) if $Whatpm::HTML::Debug::cp_pass;
1548     BEGIN {
1549     $Whatpm::HTML::Debug::cp->{76} = 1;
1550     }
1551    
1552 wakaba 1.76 $self->{current_attribute} = {name => chr ($self->{next_char} + 0x0020),
1553 wakaba 1.1 value => ''};
1554 wakaba 1.59 $self->{state} = ATTRIBUTE_NAME_STATE;
1555 wakaba 1.1
1556     if (@{$self->{char}}) {
1557 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1558 wakaba 1.1 } else {
1559 wakaba 1.76 $self->{set_next_char}->($self);
1560 wakaba 1.1 }
1561    
1562     redo A;
1563 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
1564 wakaba 1.1
1565     if (@{$self->{char}}) {
1566 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1567 wakaba 1.1 } else {
1568 wakaba 1.76 $self->{set_next_char}->($self);
1569 wakaba 1.1 }
1570    
1571 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
1572 wakaba 1.57 $self->{current_token}->{type} == START_TAG_TOKEN and
1573 wakaba 1.1 $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
1574     # permitted slash
1575 wakaba 1.77
1576     $Whatpm::HTML::Debug::cp_pass->(77) if $Whatpm::HTML::Debug::cp_pass;
1577     BEGIN {
1578     $Whatpm::HTML::Debug::cp->{77} = 1;
1579     }
1580    
1581 wakaba 1.1 #
1582     } else {
1583 wakaba 1.77
1584     $Whatpm::HTML::Debug::cp_pass->(78) if $Whatpm::HTML::Debug::cp_pass;
1585     BEGIN {
1586     $Whatpm::HTML::Debug::cp->{78} = 1;
1587     }
1588    
1589 wakaba 1.3 $self->{parse_error}-> (type => 'nestc');
1590 wakaba 1.33 ## TODO: Different error type for <aa / bb> than <aa/>
1591 wakaba 1.1 }
1592 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
1593 wakaba 1.1 # next-input-character is already done
1594     redo A;
1595 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1596 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
1597 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1598 wakaba 1.77
1599     $Whatpm::HTML::Debug::cp_pass->(79) if $Whatpm::HTML::Debug::cp_pass;
1600     BEGIN {
1601     $Whatpm::HTML::Debug::cp->{79} = 1;
1602     }
1603    
1604 wakaba 1.28 $self->{current_token}->{first_start_tag}
1605     = not defined $self->{last_emitted_start_tag_name};
1606 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1607 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1608 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1609 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1610 wakaba 1.77
1611     $Whatpm::HTML::Debug::cp_pass->(80) if $Whatpm::HTML::Debug::cp_pass;
1612     BEGIN {
1613     $Whatpm::HTML::Debug::cp->{80} = 1;
1614     }
1615    
1616 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1617 wakaba 1.77 } else {
1618 wakaba 1.78 ## NOTE: This state should never be reached.
1619 wakaba 1.77
1620     $Whatpm::HTML::Debug::cp_pass->(81) if $Whatpm::HTML::Debug::cp_pass;
1621     BEGIN {
1622     $Whatpm::HTML::Debug::cp->{81} = 1;
1623     }
1624    
1625 wakaba 1.1 }
1626     } else {
1627     die "$0: $self->{current_token}->{type}: Unknown token type";
1628     }
1629 wakaba 1.59 $self->{state} = DATA_STATE;
1630 wakaba 1.1 # reconsume
1631    
1632     return ($self->{current_token}); # start tag or end tag
1633    
1634     redo A;
1635     } else {
1636 wakaba 1.77
1637     $Whatpm::HTML::Debug::cp_pass->(82) if $Whatpm::HTML::Debug::cp_pass;
1638     BEGIN {
1639     $Whatpm::HTML::Debug::cp->{82} = 1;
1640     }
1641    
1642 wakaba 1.76 $self->{current_attribute} = {name => chr ($self->{next_char}),
1643 wakaba 1.1 value => ''};
1644 wakaba 1.59 $self->{state} = ATTRIBUTE_NAME_STATE;
1645 wakaba 1.1
1646     if (@{$self->{char}}) {
1647 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1648 wakaba 1.1 } else {
1649 wakaba 1.76 $self->{set_next_char}->($self);
1650 wakaba 1.1 }
1651    
1652     redo A;
1653     }
1654 wakaba 1.59 } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {
1655 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
1656     $self->{next_char} == 0x000A or # LF
1657     $self->{next_char} == 0x000B or # VT
1658     $self->{next_char} == 0x000C or # FF
1659     $self->{next_char} == 0x0020) { # SP
1660 wakaba 1.77
1661     $Whatpm::HTML::Debug::cp_pass->(83) if $Whatpm::HTML::Debug::cp_pass;
1662     BEGIN {
1663     $Whatpm::HTML::Debug::cp->{83} = 1;
1664     }
1665    
1666 wakaba 1.1 ## Stay in the state
1667    
1668     if (@{$self->{char}}) {
1669 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1670 wakaba 1.1 } else {
1671 wakaba 1.76 $self->{set_next_char}->($self);
1672 wakaba 1.1 }
1673    
1674     redo A;
1675 wakaba 1.76 } elsif ($self->{next_char} == 0x0022) { # "
1676 wakaba 1.77
1677     $Whatpm::HTML::Debug::cp_pass->(84) if $Whatpm::HTML::Debug::cp_pass;
1678     BEGIN {
1679     $Whatpm::HTML::Debug::cp->{84} = 1;
1680     }
1681    
1682 wakaba 1.59 $self->{state} = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;
1683 wakaba 1.1
1684     if (@{$self->{char}}) {
1685 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1686 wakaba 1.1 } else {
1687 wakaba 1.76 $self->{set_next_char}->($self);
1688 wakaba 1.1 }
1689    
1690     redo A;
1691 wakaba 1.76 } elsif ($self->{next_char} == 0x0026) { # &
1692 wakaba 1.77
1693     $Whatpm::HTML::Debug::cp_pass->(85) if $Whatpm::HTML::Debug::cp_pass;
1694     BEGIN {
1695     $Whatpm::HTML::Debug::cp->{85} = 1;
1696     }
1697    
1698 wakaba 1.59 $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;
1699 wakaba 1.1 ## reconsume
1700     redo A;
1701 wakaba 1.76 } elsif ($self->{next_char} == 0x0027) { # '
1702 wakaba 1.77
1703     $Whatpm::HTML::Debug::cp_pass->(86) if $Whatpm::HTML::Debug::cp_pass;
1704     BEGIN {
1705     $Whatpm::HTML::Debug::cp->{86} = 1;
1706     }
1707    
1708 wakaba 1.59 $self->{state} = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;
1709 wakaba 1.1
1710     if (@{$self->{char}}) {
1711 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1712 wakaba 1.1 } else {
1713 wakaba 1.76 $self->{set_next_char}->($self);
1714 wakaba 1.1 }
1715    
1716     redo A;
1717 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
1718 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1719 wakaba 1.77
1720     $Whatpm::HTML::Debug::cp_pass->(87) if $Whatpm::HTML::Debug::cp_pass;
1721     BEGIN {
1722     $Whatpm::HTML::Debug::cp->{87} = 1;
1723     }
1724    
1725 wakaba 1.28 $self->{current_token}->{first_start_tag}
1726     = not defined $self->{last_emitted_start_tag_name};
1727 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1728 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1729 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1730 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1731 wakaba 1.77
1732     $Whatpm::HTML::Debug::cp_pass->(88) if $Whatpm::HTML::Debug::cp_pass;
1733     BEGIN {
1734     $Whatpm::HTML::Debug::cp->{88} = 1;
1735     }
1736    
1737 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1738 wakaba 1.77 } else {
1739 wakaba 1.78 ## NOTE: This state should never be reached.
1740 wakaba 1.77
1741     $Whatpm::HTML::Debug::cp_pass->(89) if $Whatpm::HTML::Debug::cp_pass;
1742     BEGIN {
1743     $Whatpm::HTML::Debug::cp->{89} = 1;
1744     }
1745    
1746 wakaba 1.1 }
1747     } else {
1748     die "$0: $self->{current_token}->{type}: Unknown token type";
1749     }
1750 wakaba 1.59 $self->{state} = DATA_STATE;
1751 wakaba 1.1
1752     if (@{$self->{char}}) {
1753 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1754 wakaba 1.1 } else {
1755 wakaba 1.76 $self->{set_next_char}->($self);
1756 wakaba 1.1 }
1757    
1758    
1759     return ($self->{current_token}); # start tag or end tag
1760    
1761     redo A;
1762 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1763 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
1764 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1765 wakaba 1.77
1766     $Whatpm::HTML::Debug::cp_pass->(90) if $Whatpm::HTML::Debug::cp_pass;
1767     BEGIN {
1768     $Whatpm::HTML::Debug::cp->{90} = 1;
1769     }
1770    
1771 wakaba 1.28 $self->{current_token}->{first_start_tag}
1772     = not defined $self->{last_emitted_start_tag_name};
1773 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1774 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1775 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1776 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1777 wakaba 1.77
1778     $Whatpm::HTML::Debug::cp_pass->(91) if $Whatpm::HTML::Debug::cp_pass;
1779     BEGIN {
1780     $Whatpm::HTML::Debug::cp->{91} = 1;
1781     }
1782    
1783 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1784 wakaba 1.77 } else {
1785 wakaba 1.78 ## NOTE: This state should never be reached.
1786 wakaba 1.77
1787     $Whatpm::HTML::Debug::cp_pass->(92) if $Whatpm::HTML::Debug::cp_pass;
1788     BEGIN {
1789     $Whatpm::HTML::Debug::cp->{92} = 1;
1790     }
1791    
1792 wakaba 1.1 }
1793     } else {
1794     die "$0: $self->{current_token}->{type}: Unknown token type";
1795     }
1796 wakaba 1.59 $self->{state} = DATA_STATE;
1797 wakaba 1.1 ## reconsume
1798    
1799     return ($self->{current_token}); # start tag or end tag
1800    
1801     redo A;
1802     } else {
1803 wakaba 1.76 if ($self->{next_char} == 0x003D) { # =
1804 wakaba 1.77
1805     $Whatpm::HTML::Debug::cp_pass->(93) if $Whatpm::HTML::Debug::cp_pass;
1806     BEGIN {
1807     $Whatpm::HTML::Debug::cp->{93} = 1;
1808     }
1809    
1810 wakaba 1.72 $self->{parse_error}-> (type => 'bad attribute value');
1811 wakaba 1.77 } else {
1812    
1813     $Whatpm::HTML::Debug::cp_pass->(94) if $Whatpm::HTML::Debug::cp_pass;
1814     BEGIN {
1815     $Whatpm::HTML::Debug::cp->{94} = 1;
1816     }
1817    
1818 wakaba 1.72 }
1819 wakaba 1.76 $self->{current_attribute}->{value} .= chr ($self->{next_char});
1820 wakaba 1.59 $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;
1821 wakaba 1.1
1822     if (@{$self->{char}}) {
1823 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1824 wakaba 1.1 } else {
1825 wakaba 1.76 $self->{set_next_char}->($self);
1826 wakaba 1.1 }
1827    
1828     redo A;
1829     }
1830 wakaba 1.59 } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {
1831 wakaba 1.76 if ($self->{next_char} == 0x0022) { # "
1832 wakaba 1.77
1833     $Whatpm::HTML::Debug::cp_pass->(95) if $Whatpm::HTML::Debug::cp_pass;
1834     BEGIN {
1835     $Whatpm::HTML::Debug::cp->{95} = 1;
1836     }
1837    
1838 wakaba 1.72 $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1839 wakaba 1.1
1840     if (@{$self->{char}}) {
1841 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1842 wakaba 1.1 } else {
1843 wakaba 1.76 $self->{set_next_char}->($self);
1844 wakaba 1.1 }
1845    
1846     redo A;
1847 wakaba 1.76 } elsif ($self->{next_char} == 0x0026) { # &
1848 wakaba 1.77
1849     $Whatpm::HTML::Debug::cp_pass->(96) if $Whatpm::HTML::Debug::cp_pass;
1850     BEGIN {
1851     $Whatpm::HTML::Debug::cp->{96} = 1;
1852     }
1853    
1854 wakaba 1.59 $self->{last_attribute_value_state} = $self->{state};
1855     $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
1856 wakaba 1.1
1857     if (@{$self->{char}}) {
1858 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1859 wakaba 1.1 } else {
1860 wakaba 1.76 $self->{set_next_char}->($self);
1861 wakaba 1.1 }
1862    
1863     redo A;
1864 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1865 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed attribute value');
1866 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1867 wakaba 1.77
1868     $Whatpm::HTML::Debug::cp_pass->(97) if $Whatpm::HTML::Debug::cp_pass;
1869     BEGIN {
1870     $Whatpm::HTML::Debug::cp->{97} = 1;
1871     }
1872    
1873 wakaba 1.28 $self->{current_token}->{first_start_tag}
1874     = not defined $self->{last_emitted_start_tag_name};
1875 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1876 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1877 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1878 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1879 wakaba 1.77
1880     $Whatpm::HTML::Debug::cp_pass->(98) if $Whatpm::HTML::Debug::cp_pass;
1881     BEGIN {
1882     $Whatpm::HTML::Debug::cp->{98} = 1;
1883     }
1884    
1885 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1886 wakaba 1.77 } else {
1887 wakaba 1.78 ## NOTE: This state should never be reached.
1888 wakaba 1.77
1889     $Whatpm::HTML::Debug::cp_pass->(99) if $Whatpm::HTML::Debug::cp_pass;
1890     BEGIN {
1891     $Whatpm::HTML::Debug::cp->{99} = 1;
1892     }
1893    
1894 wakaba 1.1 }
1895     } else {
1896     die "$0: $self->{current_token}->{type}: Unknown token type";
1897     }
1898 wakaba 1.59 $self->{state} = DATA_STATE;
1899 wakaba 1.1 ## reconsume
1900    
1901     return ($self->{current_token}); # start tag or end tag
1902    
1903     redo A;
1904     } else {
1905 wakaba 1.77
1906     $Whatpm::HTML::Debug::cp_pass->(100) if $Whatpm::HTML::Debug::cp_pass;
1907     BEGIN {
1908     $Whatpm::HTML::Debug::cp->{100} = 1;
1909     }
1910    
1911 wakaba 1.76 $self->{current_attribute}->{value} .= chr ($self->{next_char});
1912 wakaba 1.1 ## Stay in the state
1913    
1914     if (@{$self->{char}}) {
1915 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1916 wakaba 1.1 } else {
1917 wakaba 1.76 $self->{set_next_char}->($self);
1918 wakaba 1.1 }
1919    
1920     redo A;
1921     }
1922 wakaba 1.59 } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {
1923 wakaba 1.76 if ($self->{next_char} == 0x0027) { # '
1924 wakaba 1.77
1925     $Whatpm::HTML::Debug::cp_pass->(101) if $Whatpm::HTML::Debug::cp_pass;
1926     BEGIN {
1927     $Whatpm::HTML::Debug::cp->{101} = 1;
1928     }
1929    
1930 wakaba 1.72 $self->{state} = AFTER_ATTRIBUTE_VALUE_QUOTED_STATE;
1931 wakaba 1.1
1932     if (@{$self->{char}}) {
1933 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1934 wakaba 1.1 } else {
1935 wakaba 1.76 $self->{set_next_char}->($self);
1936 wakaba 1.1 }
1937    
1938     redo A;
1939 wakaba 1.76 } elsif ($self->{next_char} == 0x0026) { # &
1940 wakaba 1.77
1941     $Whatpm::HTML::Debug::cp_pass->(102) if $Whatpm::HTML::Debug::cp_pass;
1942     BEGIN {
1943     $Whatpm::HTML::Debug::cp->{102} = 1;
1944     }
1945    
1946 wakaba 1.59 $self->{last_attribute_value_state} = $self->{state};
1947     $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
1948 wakaba 1.1
1949     if (@{$self->{char}}) {
1950 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
1951 wakaba 1.1 } else {
1952 wakaba 1.76 $self->{set_next_char}->($self);
1953 wakaba 1.1 }
1954    
1955     redo A;
1956 wakaba 1.76 } elsif ($self->{next_char} == -1) {
1957 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed attribute value');
1958 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1959 wakaba 1.77
1960     $Whatpm::HTML::Debug::cp_pass->(103) if $Whatpm::HTML::Debug::cp_pass;
1961     BEGIN {
1962     $Whatpm::HTML::Debug::cp->{103} = 1;
1963     }
1964    
1965 wakaba 1.28 $self->{current_token}->{first_start_tag}
1966     = not defined $self->{last_emitted_start_tag_name};
1967 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1968 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1969 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
1970 wakaba 1.1 if ($self->{current_token}->{attributes}) {
1971 wakaba 1.77
1972     $Whatpm::HTML::Debug::cp_pass->(104) if $Whatpm::HTML::Debug::cp_pass;
1973     BEGIN {
1974     $Whatpm::HTML::Debug::cp->{104} = 1;
1975     }
1976    
1977 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
1978 wakaba 1.77 } else {
1979 wakaba 1.78 ## NOTE: This state should never be reached.
1980 wakaba 1.77
1981     $Whatpm::HTML::Debug::cp_pass->(105) if $Whatpm::HTML::Debug::cp_pass;
1982     BEGIN {
1983     $Whatpm::HTML::Debug::cp->{105} = 1;
1984     }
1985    
1986 wakaba 1.1 }
1987     } else {
1988     die "$0: $self->{current_token}->{type}: Unknown token type";
1989     }
1990 wakaba 1.59 $self->{state} = DATA_STATE;
1991 wakaba 1.1 ## reconsume
1992    
1993     return ($self->{current_token}); # start tag or end tag
1994    
1995     redo A;
1996     } else {
1997 wakaba 1.77
1998     $Whatpm::HTML::Debug::cp_pass->(106) if $Whatpm::HTML::Debug::cp_pass;
1999     BEGIN {
2000     $Whatpm::HTML::Debug::cp->{106} = 1;
2001     }
2002    
2003 wakaba 1.76 $self->{current_attribute}->{value} .= chr ($self->{next_char});
2004 wakaba 1.1 ## Stay in the state
2005    
2006     if (@{$self->{char}}) {
2007 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2008 wakaba 1.1 } else {
2009 wakaba 1.76 $self->{set_next_char}->($self);
2010 wakaba 1.1 }
2011    
2012     redo A;
2013     }
2014 wakaba 1.59 } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {
2015 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2016     $self->{next_char} == 0x000A or # LF
2017     $self->{next_char} == 0x000B or # HT
2018     $self->{next_char} == 0x000C or # FF
2019     $self->{next_char} == 0x0020) { # SP
2020 wakaba 1.77
2021     $Whatpm::HTML::Debug::cp_pass->(107) if $Whatpm::HTML::Debug::cp_pass;
2022     BEGIN {
2023     $Whatpm::HTML::Debug::cp->{107} = 1;
2024     }
2025    
2026 wakaba 1.59 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
2027 wakaba 1.1
2028     if (@{$self->{char}}) {
2029 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2030 wakaba 1.1 } else {
2031 wakaba 1.76 $self->{set_next_char}->($self);
2032 wakaba 1.1 }
2033    
2034     redo A;
2035 wakaba 1.76 } elsif ($self->{next_char} == 0x0026) { # &
2036 wakaba 1.77
2037     $Whatpm::HTML::Debug::cp_pass->(108) if $Whatpm::HTML::Debug::cp_pass;
2038     BEGIN {
2039     $Whatpm::HTML::Debug::cp->{108} = 1;
2040     }
2041    
2042 wakaba 1.59 $self->{last_attribute_value_state} = $self->{state};
2043     $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
2044 wakaba 1.1
2045     if (@{$self->{char}}) {
2046 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2047 wakaba 1.1 } else {
2048 wakaba 1.76 $self->{set_next_char}->($self);
2049 wakaba 1.1 }
2050    
2051     redo A;
2052 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2053 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
2054 wakaba 1.77
2055     $Whatpm::HTML::Debug::cp_pass->(109) if $Whatpm::HTML::Debug::cp_pass;
2056     BEGIN {
2057     $Whatpm::HTML::Debug::cp->{109} = 1;
2058     }
2059    
2060 wakaba 1.28 $self->{current_token}->{first_start_tag}
2061     = not defined $self->{last_emitted_start_tag_name};
2062 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
2063 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
2064 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
2065 wakaba 1.1 if ($self->{current_token}->{attributes}) {
2066 wakaba 1.77
2067     $Whatpm::HTML::Debug::cp_pass->(110) if $Whatpm::HTML::Debug::cp_pass;
2068     BEGIN {
2069     $Whatpm::HTML::Debug::cp->{110} = 1;
2070     }
2071    
2072 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
2073 wakaba 1.77 } else {
2074 wakaba 1.78 ## NOTE: This state should never be reached.
2075 wakaba 1.77
2076     $Whatpm::HTML::Debug::cp_pass->(111) if $Whatpm::HTML::Debug::cp_pass;
2077     BEGIN {
2078     $Whatpm::HTML::Debug::cp->{111} = 1;
2079     }
2080    
2081 wakaba 1.1 }
2082     } else {
2083     die "$0: $self->{current_token}->{type}: Unknown token type";
2084     }
2085 wakaba 1.59 $self->{state} = DATA_STATE;
2086 wakaba 1.1
2087     if (@{$self->{char}}) {
2088 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2089 wakaba 1.1 } else {
2090 wakaba 1.76 $self->{set_next_char}->($self);
2091 wakaba 1.1 }
2092    
2093    
2094     return ($self->{current_token}); # start tag or end tag
2095    
2096     redo A;
2097 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2098 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed tag');
2099 wakaba 1.57 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
2100 wakaba 1.77
2101     $Whatpm::HTML::Debug::cp_pass->(112) if $Whatpm::HTML::Debug::cp_pass;
2102     BEGIN {
2103     $Whatpm::HTML::Debug::cp->{112} = 1;
2104     }
2105    
2106 wakaba 1.28 $self->{current_token}->{first_start_tag}
2107     = not defined $self->{last_emitted_start_tag_name};
2108 wakaba 1.1 $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
2109 wakaba 1.57 } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
2110 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
2111 wakaba 1.1 if ($self->{current_token}->{attributes}) {
2112 wakaba 1.77
2113     $Whatpm::HTML::Debug::cp_pass->(113) if $Whatpm::HTML::Debug::cp_pass;
2114     BEGIN {
2115     $Whatpm::HTML::Debug::cp->{113} = 1;
2116     }
2117    
2118 wakaba 1.3 $self->{parse_error}-> (type => 'end tag attribute');
2119 wakaba 1.77 } else {
2120 wakaba 1.78 ## NOTE: This state should never be reached.
2121 wakaba 1.77
2122     $Whatpm::HTML::Debug::cp_pass->(114) if $Whatpm::HTML::Debug::cp_pass;
2123     BEGIN {
2124     $Whatpm::HTML::Debug::cp->{114} = 1;
2125     }
2126    
2127 wakaba 1.1 }
2128     } else {
2129     die "$0: $self->{current_token}->{type}: Unknown token type";
2130     }
2131 wakaba 1.59 $self->{state} = DATA_STATE;
2132 wakaba 1.1 ## reconsume
2133    
2134     return ($self->{current_token}); # start tag or end tag
2135    
2136     redo A;
2137     } else {
2138 wakaba 1.72 if ({
2139     0x0022 => 1, # "
2140     0x0027 => 1, # '
2141     0x003D => 1, # =
2142 wakaba 1.76 }->{$self->{next_char}}) {
2143 wakaba 1.77
2144     $Whatpm::HTML::Debug::cp_pass->(115) if $Whatpm::HTML::Debug::cp_pass;
2145     BEGIN {
2146     $Whatpm::HTML::Debug::cp->{115} = 1;
2147     }
2148    
2149 wakaba 1.72 $self->{parse_error}-> (type => 'bad attribute value');
2150 wakaba 1.77 } else {
2151    
2152     $Whatpm::HTML::Debug::cp_pass->(116) if $Whatpm::HTML::Debug::cp_pass;
2153     BEGIN {
2154     $Whatpm::HTML::Debug::cp->{116} = 1;
2155     }
2156    
2157 wakaba 1.72 }
2158 wakaba 1.76 $self->{current_attribute}->{value} .= chr ($self->{next_char});
2159 wakaba 1.1 ## Stay in the state
2160    
2161     if (@{$self->{char}}) {
2162 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2163 wakaba 1.1 } else {
2164 wakaba 1.76 $self->{set_next_char}->($self);
2165 wakaba 1.1 }
2166    
2167     redo A;
2168     }
2169 wakaba 1.59 } elsif ($self->{state} == ENTITY_IN_ATTRIBUTE_VALUE_STATE) {
2170 wakaba 1.72 my $token = $self->_tokenize_attempt_to_consume_an_entity
2171     (1,
2172     $self->{last_attribute_value_state}
2173     == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE ? 0x0022 : # "
2174     $self->{last_attribute_value_state}
2175     == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE ? 0x0027 : # '
2176     -1);
2177 wakaba 1.1
2178     unless (defined $token) {
2179 wakaba 1.77
2180     $Whatpm::HTML::Debug::cp_pass->(117) if $Whatpm::HTML::Debug::cp_pass;
2181     BEGIN {
2182     $Whatpm::HTML::Debug::cp->{117} = 1;
2183     }
2184    
2185 wakaba 1.1 $self->{current_attribute}->{value} .= '&';
2186     } else {
2187 wakaba 1.77
2188     $Whatpm::HTML::Debug::cp_pass->(118) if $Whatpm::HTML::Debug::cp_pass;
2189     BEGIN {
2190     $Whatpm::HTML::Debug::cp->{118} = 1;
2191     }
2192    
2193 wakaba 1.1 $self->{current_attribute}->{value} .= $token->{data};
2194 wakaba 1.68 $self->{current_attribute}->{has_reference} = $token->{has_reference};
2195 wakaba 1.1 ## ISSUE: spec says "append the returned character token to the current attribute's value"
2196     }
2197    
2198     $self->{state} = $self->{last_attribute_value_state};
2199     # next-input-character is already done
2200     redo A;
2201 wakaba 1.72 } elsif ($self->{state} == AFTER_ATTRIBUTE_VALUE_QUOTED_STATE) {
2202 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2203     $self->{next_char} == 0x000A or # LF
2204     $self->{next_char} == 0x000B or # VT
2205     $self->{next_char} == 0x000C or # FF
2206     $self->{next_char} == 0x0020) { # SP
2207 wakaba 1.77
2208     $Whatpm::HTML::Debug::cp_pass->(118) if $Whatpm::HTML::Debug::cp_pass;
2209     BEGIN {
2210     $Whatpm::HTML::Debug::cp->{118} = 1;
2211     }
2212    
2213 wakaba 1.72 $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
2214    
2215     if (@{$self->{char}}) {
2216 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2217 wakaba 1.72 } else {
2218 wakaba 1.76 $self->{set_next_char}->($self);
2219 wakaba 1.72 }
2220    
2221     redo A;
2222 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2223 wakaba 1.72 if ($self->{current_token}->{type} == START_TAG_TOKEN) {
2224 wakaba 1.77
2225     $Whatpm::HTML::Debug::cp_pass->(119) if $Whatpm::HTML::Debug::cp_pass;
2226     BEGIN {
2227     $Whatpm::HTML::Debug::cp->{119} = 1;
2228     }
2229    
2230 wakaba 1.72 $self->{current_token}->{first_start_tag}
2231     = not defined $self->{last_emitted_start_tag_name};
2232     $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
2233     } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
2234     $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
2235     if ($self->{current_token}->{attributes}) {
2236 wakaba 1.77
2237     $Whatpm::HTML::Debug::cp_pass->(120) if $Whatpm::HTML::Debug::cp_pass;
2238     BEGIN {
2239     $Whatpm::HTML::Debug::cp->{120} = 1;
2240     }
2241    
2242 wakaba 1.72 $self->{parse_error}-> (type => 'end tag attribute');
2243 wakaba 1.77 } else {
2244 wakaba 1.78 ## NOTE: This state should never be reached.
2245 wakaba 1.77
2246     $Whatpm::HTML::Debug::cp_pass->(121) if $Whatpm::HTML::Debug::cp_pass;
2247     BEGIN {
2248     $Whatpm::HTML::Debug::cp->{121} = 1;
2249     }
2250    
2251 wakaba 1.72 }
2252     } else {
2253     die "$0: $self->{current_token}->{type}: Unknown token type";
2254     }
2255     $self->{state} = DATA_STATE;
2256    
2257     if (@{$self->{char}}) {
2258 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2259 wakaba 1.72 } else {
2260 wakaba 1.76 $self->{set_next_char}->($self);
2261 wakaba 1.72 }
2262    
2263    
2264     return ($self->{current_token}); # start tag or end tag
2265    
2266     redo A;
2267 wakaba 1.76 } elsif ($self->{next_char} == 0x002F) { # /
2268 wakaba 1.72
2269     if (@{$self->{char}}) {
2270 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2271 wakaba 1.72 } else {
2272 wakaba 1.76 $self->{set_next_char}->($self);
2273 wakaba 1.72 }
2274    
2275 wakaba 1.76 if ($self->{next_char} == 0x003E and # >
2276 wakaba 1.72 $self->{current_token}->{type} == START_TAG_TOKEN and
2277     $permitted_slash_tag_name->{$self->{current_token}->{tag_name}}) {
2278     # permitted slash
2279 wakaba 1.77
2280     $Whatpm::HTML::Debug::cp_pass->(122) if $Whatpm::HTML::Debug::cp_pass;
2281     BEGIN {
2282     $Whatpm::HTML::Debug::cp->{122} = 1;
2283     }
2284    
2285 wakaba 1.72 #
2286     } else {
2287 wakaba 1.77
2288     $Whatpm::HTML::Debug::cp_pass->(123) if $Whatpm::HTML::Debug::cp_pass;
2289     BEGIN {
2290     $Whatpm::HTML::Debug::cp->{123} = 1;
2291     }
2292    
2293 wakaba 1.72 $self->{parse_error}-> (type => 'nestc');
2294     }
2295     $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
2296     # next-input-character is already done
2297     redo A;
2298     } else {
2299 wakaba 1.77
2300     $Whatpm::HTML::Debug::cp_pass->(124) if $Whatpm::HTML::Debug::cp_pass;
2301     BEGIN {
2302     $Whatpm::HTML::Debug::cp->{124} = 1;
2303     }
2304    
2305 wakaba 1.72 $self->{parse_error}-> (type => 'no space between attributes');
2306     $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
2307     ## reconsume
2308     redo A;
2309     }
2310 wakaba 1.59 } elsif ($self->{state} == BOGUS_COMMENT_STATE) {
2311 wakaba 1.1 ## (only happen if PCDATA state)
2312    
2313 wakaba 1.57 my $token = {type => COMMENT_TOKEN, data => ''};
2314 wakaba 1.1
2315     BC: {
2316 wakaba 1.76 if ($self->{next_char} == 0x003E) { # >
2317 wakaba 1.77
2318     $Whatpm::HTML::Debug::cp_pass->(124) if $Whatpm::HTML::Debug::cp_pass;
2319     BEGIN {
2320     $Whatpm::HTML::Debug::cp->{124} = 1;
2321     }
2322    
2323 wakaba 1.59 $self->{state} = DATA_STATE;
2324 wakaba 1.1
2325     if (@{$self->{char}}) {
2326 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2327 wakaba 1.1 } else {
2328 wakaba 1.76 $self->{set_next_char}->($self);
2329 wakaba 1.1 }
2330    
2331    
2332     return ($token);
2333    
2334     redo A;
2335 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2336 wakaba 1.77
2337     $Whatpm::HTML::Debug::cp_pass->(125) if $Whatpm::HTML::Debug::cp_pass;
2338     BEGIN {
2339     $Whatpm::HTML::Debug::cp->{125} = 1;
2340     }
2341    
2342 wakaba 1.59 $self->{state} = DATA_STATE;
2343 wakaba 1.1 ## reconsume
2344    
2345     return ($token);
2346    
2347     redo A;
2348     } else {
2349 wakaba 1.77
2350     $Whatpm::HTML::Debug::cp_pass->(126) if $Whatpm::HTML::Debug::cp_pass;
2351     BEGIN {
2352     $Whatpm::HTML::Debug::cp->{126} = 1;
2353     }
2354    
2355 wakaba 1.76 $token->{data} .= chr ($self->{next_char});
2356 wakaba 1.1
2357     if (@{$self->{char}}) {
2358 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2359 wakaba 1.1 } else {
2360 wakaba 1.76 $self->{set_next_char}->($self);
2361 wakaba 1.1 }
2362    
2363     redo BC;
2364     }
2365     } # BC
2366 wakaba 1.77
2367     die "$0: _get_next_token: unexpected case [BC]";
2368 wakaba 1.59 } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {
2369 wakaba 1.1 ## (only happen if PCDATA state)
2370    
2371     my @next_char;
2372 wakaba 1.76 push @next_char, $self->{next_char};
2373 wakaba 1.1
2374 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2375 wakaba 1.1
2376     if (@{$self->{char}}) {
2377 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2378 wakaba 1.1 } else {
2379 wakaba 1.76 $self->{set_next_char}->($self);
2380 wakaba 1.1 }
2381    
2382 wakaba 1.76 push @next_char, $self->{next_char};
2383     if ($self->{next_char} == 0x002D) { # -
2384 wakaba 1.77
2385     $Whatpm::HTML::Debug::cp_pass->(127) if $Whatpm::HTML::Debug::cp_pass;
2386     BEGIN {
2387     $Whatpm::HTML::Debug::cp->{127} = 1;
2388     }
2389    
2390 wakaba 1.57 $self->{current_token} = {type => COMMENT_TOKEN, data => ''};
2391 wakaba 1.59 $self->{state} = COMMENT_START_STATE;
2392 wakaba 1.1
2393     if (@{$self->{char}}) {
2394 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2395 wakaba 1.1 } else {
2396 wakaba 1.76 $self->{set_next_char}->($self);
2397 wakaba 1.1 }
2398    
2399     redo A;
2400 wakaba 1.77 } else {
2401    
2402     $Whatpm::HTML::Debug::cp_pass->(128) if $Whatpm::HTML::Debug::cp_pass;
2403     BEGIN {
2404     $Whatpm::HTML::Debug::cp->{128} = 1;
2405     }
2406    
2407 wakaba 1.1 }
2408 wakaba 1.76 } elsif ($self->{next_char} == 0x0044 or # D
2409     $self->{next_char} == 0x0064) { # d
2410 wakaba 1.1
2411     if (@{$self->{char}}) {
2412 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2413 wakaba 1.1 } else {
2414 wakaba 1.76 $self->{set_next_char}->($self);
2415 wakaba 1.1 }
2416    
2417 wakaba 1.76 push @next_char, $self->{next_char};
2418     if ($self->{next_char} == 0x004F or # O
2419     $self->{next_char} == 0x006F) { # o
2420 wakaba 1.1
2421     if (@{$self->{char}}) {
2422 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2423 wakaba 1.1 } else {
2424 wakaba 1.76 $self->{set_next_char}->($self);
2425 wakaba 1.1 }
2426    
2427 wakaba 1.76 push @next_char, $self->{next_char};
2428     if ($self->{next_char} == 0x0043 or # C
2429     $self->{next_char} == 0x0063) { # c
2430 wakaba 1.1
2431     if (@{$self->{char}}) {
2432 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2433 wakaba 1.1 } else {
2434 wakaba 1.76 $self->{set_next_char}->($self);
2435 wakaba 1.1 }
2436    
2437 wakaba 1.76 push @next_char, $self->{next_char};
2438     if ($self->{next_char} == 0x0054 or # T
2439     $self->{next_char} == 0x0074) { # t
2440 wakaba 1.1
2441     if (@{$self->{char}}) {
2442 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2443 wakaba 1.1 } else {
2444 wakaba 1.76 $self->{set_next_char}->($self);
2445 wakaba 1.1 }
2446    
2447 wakaba 1.76 push @next_char, $self->{next_char};
2448     if ($self->{next_char} == 0x0059 or # Y
2449     $self->{next_char} == 0x0079) { # y
2450 wakaba 1.1
2451     if (@{$self->{char}}) {
2452 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2453 wakaba 1.1 } else {
2454 wakaba 1.76 $self->{set_next_char}->($self);
2455 wakaba 1.1 }
2456    
2457 wakaba 1.76 push @next_char, $self->{next_char};
2458     if ($self->{next_char} == 0x0050 or # P
2459     $self->{next_char} == 0x0070) { # p
2460 wakaba 1.1
2461     if (@{$self->{char}}) {
2462 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2463 wakaba 1.1 } else {
2464 wakaba 1.76 $self->{set_next_char}->($self);
2465 wakaba 1.1 }
2466    
2467 wakaba 1.76 push @next_char, $self->{next_char};
2468     if ($self->{next_char} == 0x0045 or # E
2469     $self->{next_char} == 0x0065) { # e
2470 wakaba 1.77
2471     $Whatpm::HTML::Debug::cp_pass->(129) if $Whatpm::HTML::Debug::cp_pass;
2472     BEGIN {
2473     $Whatpm::HTML::Debug::cp->{129} = 1;
2474     }
2475    
2476     ## TODO: What a stupid code this is!
2477 wakaba 1.59 $self->{state} = DOCTYPE_STATE;
2478 wakaba 1.1
2479     if (@{$self->{char}}) {
2480 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2481 wakaba 1.1 } else {
2482 wakaba 1.76 $self->{set_next_char}->($self);
2483 wakaba 1.1 }
2484    
2485     redo A;
2486 wakaba 1.77 } else {
2487    
2488     $Whatpm::HTML::Debug::cp_pass->(130) if $Whatpm::HTML::Debug::cp_pass;
2489     BEGIN {
2490     $Whatpm::HTML::Debug::cp->{130} = 1;
2491     }
2492    
2493 wakaba 1.1 }
2494 wakaba 1.77 } else {
2495    
2496     $Whatpm::HTML::Debug::cp_pass->(131) if $Whatpm::HTML::Debug::cp_pass;
2497     BEGIN {
2498     $Whatpm::HTML::Debug::cp->{131} = 1;
2499     }
2500    
2501 wakaba 1.1 }
2502 wakaba 1.77 } else {
2503    
2504     $Whatpm::HTML::Debug::cp_pass->(132) if $Whatpm::HTML::Debug::cp_pass;
2505     BEGIN {
2506     $Whatpm::HTML::Debug::cp->{132} = 1;
2507     }
2508    
2509 wakaba 1.1 }
2510 wakaba 1.77 } else {
2511    
2512     $Whatpm::HTML::Debug::cp_pass->(133) if $Whatpm::HTML::Debug::cp_pass;
2513     BEGIN {
2514     $Whatpm::HTML::Debug::cp->{133} = 1;
2515     }
2516    
2517 wakaba 1.1 }
2518 wakaba 1.77 } else {
2519    
2520     $Whatpm::HTML::Debug::cp_pass->(134) if $Whatpm::HTML::Debug::cp_pass;
2521     BEGIN {
2522     $Whatpm::HTML::Debug::cp->{134} = 1;
2523     }
2524    
2525 wakaba 1.1 }
2526 wakaba 1.77 } else {
2527    
2528     $Whatpm::HTML::Debug::cp_pass->(135) if $Whatpm::HTML::Debug::cp_pass;
2529     BEGIN {
2530     $Whatpm::HTML::Debug::cp->{135} = 1;
2531     }
2532    
2533 wakaba 1.1 }
2534 wakaba 1.77 } else {
2535    
2536     $Whatpm::HTML::Debug::cp_pass->(136) if $Whatpm::HTML::Debug::cp_pass;
2537     BEGIN {
2538     $Whatpm::HTML::Debug::cp->{136} = 1;
2539     }
2540    
2541 wakaba 1.1 }
2542    
2543 wakaba 1.30 $self->{parse_error}-> (type => 'bogus comment');
2544 wakaba 1.76 $self->{next_char} = shift @next_char;
2545 wakaba 1.1 unshift @{$self->{char}}, (@next_char);
2546 wakaba 1.59 $self->{state} = BOGUS_COMMENT_STATE;
2547 wakaba 1.1 redo A;
2548    
2549     ## ISSUE: typos in spec: chacacters, is is a parse error
2550     ## 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?
2551 wakaba 1.59 } elsif ($self->{state} == COMMENT_START_STATE) {
2552 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2553 wakaba 1.77
2554     $Whatpm::HTML::Debug::cp_pass->(137) if $Whatpm::HTML::Debug::cp_pass;
2555     BEGIN {
2556     $Whatpm::HTML::Debug::cp->{137} = 1;
2557     }
2558    
2559 wakaba 1.59 $self->{state} = COMMENT_START_DASH_STATE;
2560 wakaba 1.23
2561     if (@{$self->{char}}) {
2562 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2563 wakaba 1.23 } else {
2564 wakaba 1.76 $self->{set_next_char}->($self);
2565 wakaba 1.23 }
2566    
2567     redo A;
2568 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2569 wakaba 1.77
2570     $Whatpm::HTML::Debug::cp_pass->(138) if $Whatpm::HTML::Debug::cp_pass;
2571     BEGIN {
2572     $Whatpm::HTML::Debug::cp->{138} = 1;
2573     }
2574    
2575 wakaba 1.23 $self->{parse_error}-> (type => 'bogus comment');
2576 wakaba 1.59 $self->{state} = DATA_STATE;
2577 wakaba 1.23
2578     if (@{$self->{char}}) {
2579 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2580 wakaba 1.23 } else {
2581 wakaba 1.76 $self->{set_next_char}->($self);
2582 wakaba 1.23 }
2583    
2584    
2585     return ($self->{current_token}); # comment
2586    
2587     redo A;
2588 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2589 wakaba 1.77
2590     $Whatpm::HTML::Debug::cp_pass->(139) if $Whatpm::HTML::Debug::cp_pass;
2591     BEGIN {
2592     $Whatpm::HTML::Debug::cp->{139} = 1;
2593     }
2594    
2595 wakaba 1.23 $self->{parse_error}-> (type => 'unclosed comment');
2596 wakaba 1.59 $self->{state} = DATA_STATE;
2597 wakaba 1.23 ## reconsume
2598    
2599     return ($self->{current_token}); # comment
2600    
2601 wakaba 1.77 redo A;
2602     } else {
2603    
2604     $Whatpm::HTML::Debug::cp_pass->(140) if $Whatpm::HTML::Debug::cp_pass;
2605     BEGIN {
2606     $Whatpm::HTML::Debug::cp->{140} = 1;
2607     }
2608    
2609 wakaba 1.23 $self->{current_token}->{data} # comment
2610 wakaba 1.76 .= chr ($self->{next_char});
2611 wakaba 1.59 $self->{state} = COMMENT_STATE;
2612 wakaba 1.23
2613     if (@{$self->{char}}) {
2614 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2615 wakaba 1.23 } else {
2616 wakaba 1.76 $self->{set_next_char}->($self);
2617 wakaba 1.23 }
2618    
2619     redo A;
2620     }
2621 wakaba 1.59 } elsif ($self->{state} == COMMENT_START_DASH_STATE) {
2622 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2623 wakaba 1.77
2624     $Whatpm::HTML::Debug::cp_pass->(141) if $Whatpm::HTML::Debug::cp_pass;
2625     BEGIN {
2626     $Whatpm::HTML::Debug::cp->{141} = 1;
2627     }
2628    
2629 wakaba 1.59 $self->{state} = COMMENT_END_STATE;
2630 wakaba 1.23
2631     if (@{$self->{char}}) {
2632 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2633 wakaba 1.23 } else {
2634 wakaba 1.76 $self->{set_next_char}->($self);
2635 wakaba 1.23 }
2636    
2637     redo A;
2638 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2639 wakaba 1.77
2640     $Whatpm::HTML::Debug::cp_pass->(142) if $Whatpm::HTML::Debug::cp_pass;
2641     BEGIN {
2642     $Whatpm::HTML::Debug::cp->{142} = 1;
2643     }
2644    
2645 wakaba 1.23 $self->{parse_error}-> (type => 'bogus comment');
2646 wakaba 1.59 $self->{state} = DATA_STATE;
2647 wakaba 1.23
2648     if (@{$self->{char}}) {
2649 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2650 wakaba 1.23 } else {
2651 wakaba 1.76 $self->{set_next_char}->($self);
2652 wakaba 1.23 }
2653    
2654    
2655     return ($self->{current_token}); # comment
2656    
2657     redo A;
2658 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2659 wakaba 1.77
2660     $Whatpm::HTML::Debug::cp_pass->(143) if $Whatpm::HTML::Debug::cp_pass;
2661     BEGIN {
2662     $Whatpm::HTML::Debug::cp->{143} = 1;
2663     }
2664    
2665 wakaba 1.23 $self->{parse_error}-> (type => 'unclosed comment');
2666 wakaba 1.59 $self->{state} = DATA_STATE;
2667 wakaba 1.23 ## reconsume
2668    
2669     return ($self->{current_token}); # comment
2670    
2671     redo A;
2672     } else {
2673 wakaba 1.77
2674     $Whatpm::HTML::Debug::cp_pass->(144) if $Whatpm::HTML::Debug::cp_pass;
2675     BEGIN {
2676     $Whatpm::HTML::Debug::cp->{144} = 1;
2677     }
2678    
2679 wakaba 1.23 $self->{current_token}->{data} # comment
2680 wakaba 1.76 .= '-' . chr ($self->{next_char});
2681 wakaba 1.59 $self->{state} = COMMENT_STATE;
2682 wakaba 1.23
2683     if (@{$self->{char}}) {
2684 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2685 wakaba 1.23 } else {
2686 wakaba 1.76 $self->{set_next_char}->($self);
2687 wakaba 1.23 }
2688    
2689     redo A;
2690     }
2691 wakaba 1.59 } elsif ($self->{state} == COMMENT_STATE) {
2692 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2693 wakaba 1.77
2694     $Whatpm::HTML::Debug::cp_pass->(145) if $Whatpm::HTML::Debug::cp_pass;
2695     BEGIN {
2696     $Whatpm::HTML::Debug::cp->{145} = 1;
2697     }
2698    
2699 wakaba 1.59 $self->{state} = COMMENT_END_DASH_STATE;
2700 wakaba 1.1
2701     if (@{$self->{char}}) {
2702 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2703 wakaba 1.1 } else {
2704 wakaba 1.76 $self->{set_next_char}->($self);
2705 wakaba 1.1 }
2706    
2707     redo A;
2708 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2709 wakaba 1.77
2710     $Whatpm::HTML::Debug::cp_pass->(146) if $Whatpm::HTML::Debug::cp_pass;
2711     BEGIN {
2712     $Whatpm::HTML::Debug::cp->{146} = 1;
2713     }
2714    
2715 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed comment');
2716 wakaba 1.59 $self->{state} = DATA_STATE;
2717 wakaba 1.1 ## reconsume
2718    
2719     return ($self->{current_token}); # comment
2720    
2721     redo A;
2722     } else {
2723 wakaba 1.77
2724     $Whatpm::HTML::Debug::cp_pass->(147) if $Whatpm::HTML::Debug::cp_pass;
2725     BEGIN {
2726     $Whatpm::HTML::Debug::cp->{147} = 1;
2727     }
2728    
2729 wakaba 1.76 $self->{current_token}->{data} .= chr ($self->{next_char}); # comment
2730 wakaba 1.1 ## Stay in the state
2731    
2732     if (@{$self->{char}}) {
2733 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2734 wakaba 1.1 } else {
2735 wakaba 1.76 $self->{set_next_char}->($self);
2736 wakaba 1.1 }
2737    
2738     redo A;
2739     }
2740 wakaba 1.59 } elsif ($self->{state} == COMMENT_END_DASH_STATE) {
2741 wakaba 1.76 if ($self->{next_char} == 0x002D) { # -
2742 wakaba 1.77
2743     $Whatpm::HTML::Debug::cp_pass->(148) if $Whatpm::HTML::Debug::cp_pass;
2744     BEGIN {
2745     $Whatpm::HTML::Debug::cp->{148} = 1;
2746     }
2747    
2748 wakaba 1.59 $self->{state} = COMMENT_END_STATE;
2749 wakaba 1.1
2750     if (@{$self->{char}}) {
2751 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2752 wakaba 1.1 } else {
2753 wakaba 1.76 $self->{set_next_char}->($self);
2754 wakaba 1.1 }
2755    
2756     redo A;
2757 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2758 wakaba 1.77
2759     $Whatpm::HTML::Debug::cp_pass->(149) if $Whatpm::HTML::Debug::cp_pass;
2760     BEGIN {
2761     $Whatpm::HTML::Debug::cp->{149} = 1;
2762     }
2763    
2764 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed comment');
2765 wakaba 1.59 $self->{state} = DATA_STATE;
2766 wakaba 1.1 ## reconsume
2767    
2768     return ($self->{current_token}); # comment
2769    
2770     redo A;
2771     } else {
2772 wakaba 1.77
2773     $Whatpm::HTML::Debug::cp_pass->(150) if $Whatpm::HTML::Debug::cp_pass;
2774     BEGIN {
2775     $Whatpm::HTML::Debug::cp->{150} = 1;
2776     }
2777    
2778 wakaba 1.76 $self->{current_token}->{data} .= '-' . chr ($self->{next_char}); # comment
2779 wakaba 1.59 $self->{state} = COMMENT_STATE;
2780 wakaba 1.1
2781     if (@{$self->{char}}) {
2782 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2783 wakaba 1.1 } else {
2784 wakaba 1.76 $self->{set_next_char}->($self);
2785 wakaba 1.1 }
2786    
2787     redo A;
2788     }
2789 wakaba 1.59 } elsif ($self->{state} == COMMENT_END_STATE) {
2790 wakaba 1.76 if ($self->{next_char} == 0x003E) { # >
2791 wakaba 1.77
2792     $Whatpm::HTML::Debug::cp_pass->(151) if $Whatpm::HTML::Debug::cp_pass;
2793     BEGIN {
2794     $Whatpm::HTML::Debug::cp->{151} = 1;
2795     }
2796    
2797 wakaba 1.59 $self->{state} = DATA_STATE;
2798 wakaba 1.1
2799     if (@{$self->{char}}) {
2800 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2801 wakaba 1.1 } else {
2802 wakaba 1.76 $self->{set_next_char}->($self);
2803 wakaba 1.1 }
2804    
2805    
2806     return ($self->{current_token}); # comment
2807    
2808     redo A;
2809 wakaba 1.76 } elsif ($self->{next_char} == 0x002D) { # -
2810 wakaba 1.77
2811     $Whatpm::HTML::Debug::cp_pass->(152) if $Whatpm::HTML::Debug::cp_pass;
2812     BEGIN {
2813     $Whatpm::HTML::Debug::cp->{152} = 1;
2814     }
2815    
2816 wakaba 1.3 $self->{parse_error}-> (type => 'dash in comment');
2817 wakaba 1.1 $self->{current_token}->{data} .= '-'; # comment
2818     ## Stay in the state
2819    
2820     if (@{$self->{char}}) {
2821 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2822 wakaba 1.1 } else {
2823 wakaba 1.76 $self->{set_next_char}->($self);
2824 wakaba 1.1 }
2825    
2826     redo A;
2827 wakaba 1.76 } elsif ($self->{next_char} == -1) {
2828 wakaba 1.77
2829     $Whatpm::HTML::Debug::cp_pass->(153) if $Whatpm::HTML::Debug::cp_pass;
2830     BEGIN {
2831     $Whatpm::HTML::Debug::cp->{153} = 1;
2832     }
2833    
2834 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed comment');
2835 wakaba 1.59 $self->{state} = DATA_STATE;
2836 wakaba 1.1 ## reconsume
2837    
2838     return ($self->{current_token}); # comment
2839    
2840     redo A;
2841     } else {
2842 wakaba 1.77
2843     $Whatpm::HTML::Debug::cp_pass->(154) if $Whatpm::HTML::Debug::cp_pass;
2844     BEGIN {
2845     $Whatpm::HTML::Debug::cp->{154} = 1;
2846     }
2847    
2848 wakaba 1.3 $self->{parse_error}-> (type => 'dash in comment');
2849 wakaba 1.76 $self->{current_token}->{data} .= '--' . chr ($self->{next_char}); # comment
2850 wakaba 1.59 $self->{state} = COMMENT_STATE;
2851 wakaba 1.1
2852     if (@{$self->{char}}) {
2853 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2854 wakaba 1.1 } else {
2855 wakaba 1.76 $self->{set_next_char}->($self);
2856 wakaba 1.1 }
2857    
2858     redo A;
2859     }
2860 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_STATE) {
2861 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2862     $self->{next_char} == 0x000A or # LF
2863     $self->{next_char} == 0x000B or # VT
2864     $self->{next_char} == 0x000C or # FF
2865     $self->{next_char} == 0x0020) { # SP
2866 wakaba 1.77
2867     $Whatpm::HTML::Debug::cp_pass->(155) if $Whatpm::HTML::Debug::cp_pass;
2868     BEGIN {
2869     $Whatpm::HTML::Debug::cp->{155} = 1;
2870     }
2871    
2872 wakaba 1.59 $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
2873 wakaba 1.1
2874     if (@{$self->{char}}) {
2875 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2876 wakaba 1.1 } else {
2877 wakaba 1.76 $self->{set_next_char}->($self);
2878 wakaba 1.1 }
2879    
2880     redo A;
2881     } else {
2882 wakaba 1.77
2883     $Whatpm::HTML::Debug::cp_pass->(156) if $Whatpm::HTML::Debug::cp_pass;
2884     BEGIN {
2885     $Whatpm::HTML::Debug::cp->{156} = 1;
2886     }
2887    
2888 wakaba 1.3 $self->{parse_error}-> (type => 'no space before DOCTYPE name');
2889 wakaba 1.59 $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
2890 wakaba 1.1 ## reconsume
2891     redo A;
2892     }
2893 wakaba 1.59 } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {
2894 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2895     $self->{next_char} == 0x000A or # LF
2896     $self->{next_char} == 0x000B or # VT
2897     $self->{next_char} == 0x000C or # FF
2898     $self->{next_char} == 0x0020) { # SP
2899 wakaba 1.77
2900     $Whatpm::HTML::Debug::cp_pass->(157) if $Whatpm::HTML::Debug::cp_pass;
2901     BEGIN {
2902     $Whatpm::HTML::Debug::cp->{157} = 1;
2903     }
2904    
2905 wakaba 1.1 ## Stay in the state
2906    
2907     if (@{$self->{char}}) {
2908 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2909 wakaba 1.1 } else {
2910 wakaba 1.76 $self->{set_next_char}->($self);
2911 wakaba 1.1 }
2912    
2913     redo A;
2914 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2915 wakaba 1.77
2916     $Whatpm::HTML::Debug::cp_pass->(158) if $Whatpm::HTML::Debug::cp_pass;
2917     BEGIN {
2918     $Whatpm::HTML::Debug::cp->{158} = 1;
2919     }
2920    
2921 wakaba 1.18 $self->{parse_error}-> (type => 'no DOCTYPE name');
2922 wakaba 1.59 $self->{state} = DATA_STATE;
2923 wakaba 1.18
2924     if (@{$self->{char}}) {
2925 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2926 wakaba 1.18 } else {
2927 wakaba 1.76 $self->{set_next_char}->($self);
2928 wakaba 1.18 }
2929    
2930    
2931 wakaba 1.75 return ({type => DOCTYPE_TOKEN, quirks => 1});
2932 wakaba 1.18
2933     redo A;
2934 wakaba 1.77 } elsif ($self->{next_char} == -1) {
2935    
2936     $Whatpm::HTML::Debug::cp_pass->(159) if $Whatpm::HTML::Debug::cp_pass;
2937     BEGIN {
2938     $Whatpm::HTML::Debug::cp->{159} = 1;
2939     }
2940    
2941 wakaba 1.18 $self->{parse_error}-> (type => 'no DOCTYPE name');
2942 wakaba 1.59 $self->{state} = DATA_STATE;
2943 wakaba 1.18 ## reconsume
2944    
2945 wakaba 1.75 return ({type => DOCTYPE_TOKEN, quirks => 1});
2946 wakaba 1.18
2947     redo A;
2948     } else {
2949 wakaba 1.77
2950     $Whatpm::HTML::Debug::cp_pass->(160) if $Whatpm::HTML::Debug::cp_pass;
2951     BEGIN {
2952     $Whatpm::HTML::Debug::cp->{160} = 1;
2953     }
2954    
2955 wakaba 1.18 $self->{current_token}
2956 wakaba 1.57 = {type => DOCTYPE_TOKEN,
2957 wakaba 1.76 name => chr ($self->{next_char}),
2958 wakaba 1.75 #quirks => 0,
2959     };
2960 wakaba 1.4 ## ISSUE: "Set the token's name name to the" in the spec
2961 wakaba 1.59 $self->{state} = DOCTYPE_NAME_STATE;
2962 wakaba 1.1
2963     if (@{$self->{char}}) {
2964 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2965 wakaba 1.1 } else {
2966 wakaba 1.76 $self->{set_next_char}->($self);
2967 wakaba 1.1 }
2968    
2969     redo A;
2970 wakaba 1.18 }
2971 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_NAME_STATE) {
2972 wakaba 1.18 ## ISSUE: Redundant "First," in the spec.
2973 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
2974     $self->{next_char} == 0x000A or # LF
2975     $self->{next_char} == 0x000B or # VT
2976     $self->{next_char} == 0x000C or # FF
2977     $self->{next_char} == 0x0020) { # SP
2978 wakaba 1.77
2979     $Whatpm::HTML::Debug::cp_pass->(161) if $Whatpm::HTML::Debug::cp_pass;
2980     BEGIN {
2981     $Whatpm::HTML::Debug::cp->{161} = 1;
2982     }
2983    
2984 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_NAME_STATE;
2985 wakaba 1.18
2986     if (@{$self->{char}}) {
2987 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
2988 wakaba 1.18 } else {
2989 wakaba 1.76 $self->{set_next_char}->($self);
2990 wakaba 1.18 }
2991    
2992     redo A;
2993 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
2994 wakaba 1.77
2995     $Whatpm::HTML::Debug::cp_pass->(162) if $Whatpm::HTML::Debug::cp_pass;
2996     BEGIN {
2997     $Whatpm::HTML::Debug::cp->{162} = 1;
2998     }
2999    
3000 wakaba 1.59 $self->{state} = DATA_STATE;
3001 wakaba 1.1
3002     if (@{$self->{char}}) {
3003 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3004 wakaba 1.1 } else {
3005 wakaba 1.76 $self->{set_next_char}->($self);
3006 wakaba 1.1 }
3007    
3008    
3009 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3010 wakaba 1.1
3011     redo A;
3012 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3013 wakaba 1.77
3014     $Whatpm::HTML::Debug::cp_pass->(163) if $Whatpm::HTML::Debug::cp_pass;
3015     BEGIN {
3016     $Whatpm::HTML::Debug::cp->{163} = 1;
3017     }
3018    
3019 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3020 wakaba 1.59 $self->{state} = DATA_STATE;
3021 wakaba 1.1 ## reconsume
3022    
3023 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3024 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3025 wakaba 1.1
3026     redo A;
3027     } else {
3028 wakaba 1.77
3029     $Whatpm::HTML::Debug::cp_pass->(164) if $Whatpm::HTML::Debug::cp_pass;
3030     BEGIN {
3031     $Whatpm::HTML::Debug::cp->{164} = 1;
3032     }
3033    
3034 wakaba 1.18 $self->{current_token}->{name}
3035 wakaba 1.76 .= chr ($self->{next_char}); # DOCTYPE
3036 wakaba 1.18 ## Stay in the state
3037 wakaba 1.1
3038     if (@{$self->{char}}) {
3039 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3040 wakaba 1.1 } else {
3041 wakaba 1.76 $self->{set_next_char}->($self);
3042 wakaba 1.1 }
3043    
3044     redo A;
3045     }
3046 wakaba 1.59 } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {
3047 wakaba 1.76 if ($self->{next_char} == 0x0009 or # HT
3048     $self->{next_char} == 0x000A or # LF
3049     $self->{next_char} == 0x000B or # VT
3050     $self->{next_char} == 0x000C or # FF
3051     $self->{next_char} == 0x0020) { # SP
3052 wakaba 1.77
3053     $Whatpm::HTML::Debug::cp_pass->(165) if $Whatpm::HTML::Debug::cp_pass;
3054     BEGIN {
3055     $Whatpm::HTML::Debug::cp->{165} = 1;
3056     }
3057    
3058 wakaba 1.18 ## Stay in the state
3059 wakaba 1.1
3060     if (@{$self->{char}}) {
3061 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3062 wakaba 1.1 } else {
3063 wakaba 1.76 $self->{set_next_char}->($self);
3064 wakaba 1.1 }
3065    
3066     redo A;
3067 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3068 wakaba 1.77
3069     $Whatpm::HTML::Debug::cp_pass->(166) if $Whatpm::HTML::Debug::cp_pass;
3070     BEGIN {
3071     $Whatpm::HTML::Debug::cp->{166} = 1;
3072     }
3073    
3074 wakaba 1.59 $self->{state} = DATA_STATE;
3075 wakaba 1.1
3076     if (@{$self->{char}}) {
3077 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3078 wakaba 1.1 } else {
3079 wakaba 1.76 $self->{set_next_char}->($self);
3080 wakaba 1.1 }
3081    
3082    
3083     return ($self->{current_token}); # DOCTYPE
3084    
3085     redo A;
3086 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3087 wakaba 1.77
3088     $Whatpm::HTML::Debug::cp_pass->(167) if $Whatpm::HTML::Debug::cp_pass;
3089     BEGIN {
3090     $Whatpm::HTML::Debug::cp->{167} = 1;
3091     }
3092    
3093 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3094 wakaba 1.59 $self->{state} = DATA_STATE;
3095 wakaba 1.18 ## reconsume
3096    
3097 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3098 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3099    
3100     redo A;
3101 wakaba 1.76 } elsif ($self->{next_char} == 0x0050 or # P
3102     $self->{next_char} == 0x0070) { # p
3103 wakaba 1.18
3104     if (@{$self->{char}}) {
3105 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3106 wakaba 1.18 } else {
3107 wakaba 1.76 $self->{set_next_char}->($self);
3108 wakaba 1.18 }
3109    
3110 wakaba 1.76 if ($self->{next_char} == 0x0055 or # U
3111     $self->{next_char} == 0x0075) { # u
3112 wakaba 1.18
3113     if (@{$self->{char}}) {
3114 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3115 wakaba 1.18 } else {
3116 wakaba 1.76 $self->{set_next_char}->($self);
3117 wakaba 1.18 }
3118    
3119 wakaba 1.76 if ($self->{next_char} == 0x0042 or # B
3120     $self->{next_char} == 0x0062) { # b
3121 wakaba 1.18
3122     if (@{$self->{char}}) {
3123 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3124 wakaba 1.18 } else {
3125 wakaba 1.76 $self->{set_next_char}->($self);
3126 wakaba 1.18 }
3127    
3128 wakaba 1.76 if ($self->{next_char} == 0x004C or # L
3129     $self->{next_char} == 0x006C) { # l
3130 wakaba 1.18
3131     if (@{$self->{char}}) {
3132 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3133 wakaba 1.18 } else {
3134 wakaba 1.76 $self->{set_next_char}->($self);
3135 wakaba 1.18 }
3136    
3137 wakaba 1.76 if ($self->{next_char} == 0x0049 or # I
3138     $self->{next_char} == 0x0069) { # i
3139 wakaba 1.18
3140     if (@{$self->{char}}) {
3141 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3142 wakaba 1.18 } else {
3143 wakaba 1.76 $self->{set_next_char}->($self);
3144 wakaba 1.18 }
3145    
3146 wakaba 1.76 if ($self->{next_char} == 0x0043 or # C
3147     $self->{next_char} == 0x0063) { # c
3148 wakaba 1.77
3149     $Whatpm::HTML::Debug::cp_pass->(168) if $Whatpm::HTML::Debug::cp_pass;
3150     BEGIN {
3151     $Whatpm::HTML::Debug::cp->{168} = 1;
3152     }
3153    
3154 wakaba 1.59 $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
3155 wakaba 1.18
3156     if (@{$self->{char}}) {
3157 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3158 wakaba 1.18 } else {
3159 wakaba 1.76 $self->{set_next_char}->($self);
3160 wakaba 1.18 }
3161    
3162     redo A;
3163 wakaba 1.77 } else {
3164    
3165     $Whatpm::HTML::Debug::cp_pass->(169) if $Whatpm::HTML::Debug::cp_pass;
3166     BEGIN {
3167     $Whatpm::HTML::Debug::cp->{169} = 1;
3168     }
3169    
3170 wakaba 1.18 }
3171 wakaba 1.77 } else {
3172    
3173     $Whatpm::HTML::Debug::cp_pass->(170) if $Whatpm::HTML::Debug::cp_pass;
3174     BEGIN {
3175     $Whatpm::HTML::Debug::cp->{170} = 1;
3176     }
3177    
3178 wakaba 1.18 }
3179 wakaba 1.77 } else {
3180    
3181     $Whatpm::HTML::Debug::cp_pass->(171) if $Whatpm::HTML::Debug::cp_pass;
3182     BEGIN {
3183     $Whatpm::HTML::Debug::cp->{171} = 1;
3184     }
3185    
3186 wakaba 1.18 }
3187 wakaba 1.77 } else {
3188    
3189     $Whatpm::HTML::Debug::cp_pass->(172) if $Whatpm::HTML::Debug::cp_pass;
3190     BEGIN {
3191     $Whatpm::HTML::Debug::cp->{172} = 1;
3192     }
3193    
3194 wakaba 1.18 }
3195 wakaba 1.77 } else {
3196    
3197     $Whatpm::HTML::Debug::cp_pass->(173) if $Whatpm::HTML::Debug::cp_pass;
3198     BEGIN {
3199     $Whatpm::HTML::Debug::cp->{173} = 1;
3200     }
3201    
3202 wakaba 1.18 }
3203    
3204     #
3205 wakaba 1.76 } elsif ($self->{next_char} == 0x0053 or # S
3206     $self->{next_char} == 0x0073) { # s
3207 wakaba 1.18
3208     if (@{$self->{char}}) {
3209 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3210 wakaba 1.18 } else {
3211 wakaba 1.76 $self->{set_next_char}->($self);
3212 wakaba 1.18 }
3213    
3214 wakaba 1.76 if ($self->{next_char} == 0x0059 or # Y
3215     $self->{next_char} == 0x0079) { # y
3216 wakaba 1.18
3217     if (@{$self->{char}}) {
3218 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3219 wakaba 1.18 } else {
3220 wakaba 1.76 $self->{set_next_char}->($self);
3221 wakaba 1.18 }
3222    
3223 wakaba 1.76 if ($self->{next_char} == 0x0053 or # S
3224     $self->{next_char} == 0x0073) { # s
3225 wakaba 1.18
3226     if (@{$self->{char}}) {
3227 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3228 wakaba 1.18 } else {
3229 wakaba 1.76 $self->{set_next_char}->($self);
3230 wakaba 1.18 }
3231    
3232 wakaba 1.76 if ($self->{next_char} == 0x0054 or # T
3233     $self->{next_char} == 0x0074) { # t
3234 wakaba 1.18
3235     if (@{$self->{char}}) {
3236 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3237 wakaba 1.18 } else {
3238 wakaba 1.76 $self->{set_next_char}->($self);
3239 wakaba 1.18 }
3240    
3241 wakaba 1.76 if ($self->{next_char} == 0x0045 or # E
3242     $self->{next_char} == 0x0065) { # e
3243 wakaba 1.18
3244     if (@{$self->{char}}) {
3245 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3246 wakaba 1.18 } else {
3247 wakaba 1.76 $self->{set_next_char}->($self);
3248 wakaba 1.18 }
3249    
3250 wakaba 1.76 if ($self->{next_char} == 0x004D or # M
3251     $self->{next_char} == 0x006D) { # m
3252 wakaba 1.77
3253     $Whatpm::HTML::Debug::cp_pass->(174) if $Whatpm::HTML::Debug::cp_pass;
3254     BEGIN {
3255     $Whatpm::HTML::Debug::cp->{174} = 1;
3256     }
3257    
3258 wakaba 1.59 $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
3259 wakaba 1.18
3260     if (@{$self->{char}}) {
3261 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3262 wakaba 1.18 } else {
3263 wakaba 1.76 $self->{set_next_char}->($self);
3264 wakaba 1.18 }
3265    
3266     redo A;
3267 wakaba 1.77 } else {
3268    
3269     $Whatpm::HTML::Debug::cp_pass->(175) if $Whatpm::HTML::Debug::cp_pass;
3270     BEGIN {
3271     $Whatpm::HTML::Debug::cp->{175} = 1;
3272     }
3273    
3274 wakaba 1.18 }
3275 wakaba 1.77 } else {
3276    
3277     $Whatpm::HTML::Debug::cp_pass->(176) if $Whatpm::HTML::Debug::cp_pass;
3278     BEGIN {
3279     $Whatpm::HTML::Debug::cp->{176} = 1;
3280     }
3281    
3282 wakaba 1.18 }
3283 wakaba 1.77 } else {
3284    
3285     $Whatpm::HTML::Debug::cp_pass->(177) if $Whatpm::HTML::Debug::cp_pass;
3286     BEGIN {
3287     $Whatpm::HTML::Debug::cp->{177} = 1;
3288     }
3289    
3290 wakaba 1.18 }
3291 wakaba 1.77 } else {
3292    
3293     $Whatpm::HTML::Debug::cp_pass->(178) if $Whatpm::HTML::Debug::cp_pass;
3294     BEGIN {
3295     $Whatpm::HTML::Debug::cp->{178} = 1;
3296     }
3297    
3298 wakaba 1.18 }
3299 wakaba 1.77 } else {
3300    
3301     $Whatpm::HTML::Debug::cp_pass->(179) if $Whatpm::HTML::Debug::cp_pass;
3302     BEGIN {
3303     $Whatpm::HTML::Debug::cp->{179} = 1;
3304     }
3305    
3306 wakaba 1.18 }
3307    
3308     #
3309     } else {
3310    
3311 wakaba 1.77 $Whatpm::HTML::Debug::cp_pass->(180) if $Whatpm::HTML::Debug::cp_pass;
3312     BEGIN {
3313     $Whatpm::HTML::Debug::cp->{180} = 1;
3314     }
3315    
3316    
3317 wakaba 1.18 if (@{$self->{char}}) {
3318 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3319 wakaba 1.18 } else {
3320 wakaba 1.76 $self->{set_next_char}->($self);
3321 wakaba 1.18 }
3322    
3323     #
3324     }
3325    
3326     $self->{parse_error}-> (type => 'string after DOCTYPE name');
3327 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3328 wakaba 1.73
3329 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
3330 wakaba 1.18 # next-input-character is already done
3331     redo A;
3332 wakaba 1.59 } elsif ($self->{state} == BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {
3333 wakaba 1.18 if ({
3334     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
3335     #0x000D => 1, # HT, LF, VT, FF, SP, CR
3336 wakaba 1.76 }->{$self->{next_char}}) {
3337 wakaba 1.77
3338     $Whatpm::HTML::Debug::cp_pass->(181) if $Whatpm::HTML::Debug::cp_pass;
3339     BEGIN {
3340     $Whatpm::HTML::Debug::cp->{181} = 1;
3341     }
3342    
3343 wakaba 1.1 ## Stay in the state
3344    
3345     if (@{$self->{char}}) {
3346 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3347 wakaba 1.1 } else {
3348 wakaba 1.76 $self->{set_next_char}->($self);
3349 wakaba 1.1 }
3350    
3351     redo A;
3352 wakaba 1.76 } elsif ($self->{next_char} eq 0x0022) { # "
3353 wakaba 1.77
3354     $Whatpm::HTML::Debug::cp_pass->(182) if $Whatpm::HTML::Debug::cp_pass;
3355     BEGIN {
3356     $Whatpm::HTML::Debug::cp->{182} = 1;
3357     }
3358    
3359 wakaba 1.18 $self->{current_token}->{public_identifier} = ''; # DOCTYPE
3360 wakaba 1.59 $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;
3361 wakaba 1.18
3362     if (@{$self->{char}}) {
3363 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3364 wakaba 1.18 } else {
3365 wakaba 1.76 $self->{set_next_char}->($self);
3366 wakaba 1.18 }
3367    
3368     redo A;
3369 wakaba 1.76 } elsif ($self->{next_char} eq 0x0027) { # '
3370 wakaba 1.77
3371     $Whatpm::HTML::Debug::cp_pass->(183) if $Whatpm::HTML::Debug::cp_pass;
3372     BEGIN {
3373     $Whatpm::HTML::Debug::cp->{183} = 1;
3374     }
3375    
3376 wakaba 1.18 $self->{current_token}->{public_identifier} = ''; # DOCTYPE
3377 wakaba 1.59 $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;
3378 wakaba 1.18
3379     if (@{$self->{char}}) {
3380 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3381 wakaba 1.18 } else {
3382 wakaba 1.76 $self->{set_next_char}->($self);
3383 wakaba 1.18 }
3384    
3385     redo A;
3386 wakaba 1.76 } elsif ($self->{next_char} eq 0x003E) { # >
3387 wakaba 1.77
3388     $Whatpm::HTML::Debug::cp_pass->(184) if $Whatpm::HTML::Debug::cp_pass;
3389     BEGIN {
3390     $Whatpm::HTML::Debug::cp->{184} = 1;
3391     }
3392    
3393 wakaba 1.18 $self->{parse_error}-> (type => 'no PUBLIC literal');
3394    
3395 wakaba 1.59 $self->{state} = DATA_STATE;
3396 wakaba 1.18
3397     if (@{$self->{char}}) {
3398 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3399 wakaba 1.18 } else {
3400 wakaba 1.76 $self->{set_next_char}->($self);
3401 wakaba 1.18 }
3402    
3403    
3404 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3405 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3406    
3407     redo A;
3408 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3409 wakaba 1.77
3410     $Whatpm::HTML::Debug::cp_pass->(185) if $Whatpm::HTML::Debug::cp_pass;
3411     BEGIN {
3412     $Whatpm::HTML::Debug::cp->{185} = 1;
3413     }
3414    
3415 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3416 wakaba 1.18
3417 wakaba 1.59 $self->{state} = DATA_STATE;
3418 wakaba 1.1 ## reconsume
3419    
3420 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3421 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3422 wakaba 1.1
3423     redo A;
3424     } else {
3425 wakaba 1.77
3426     $Whatpm::HTML::Debug::cp_pass->(186) if $Whatpm::HTML::Debug::cp_pass;
3427     BEGIN {
3428     $Whatpm::HTML::Debug::cp->{186} = 1;
3429     }
3430    
3431 wakaba 1.18 $self->{parse_error}-> (type => 'string after PUBLIC');
3432 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3433 wakaba 1.73
3434 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
3435 wakaba 1.18
3436     if (@{$self->{char}}) {
3437 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3438 wakaba 1.18 } else {
3439 wakaba 1.76 $self->{set_next_char}->($self);
3440 wakaba 1.18 }
3441    
3442     redo A;
3443     }
3444 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE) {
3445 wakaba 1.76 if ($self->{next_char} == 0x0022) { # "
3446 wakaba 1.77
3447     $Whatpm::HTML::Debug::cp_pass->(187) if $Whatpm::HTML::Debug::cp_pass;
3448     BEGIN {
3449     $Whatpm::HTML::Debug::cp->{187} = 1;
3450     }
3451    
3452 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
3453 wakaba 1.18
3454     if (@{$self->{char}}) {
3455 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3456 wakaba 1.18 } else {
3457 wakaba 1.76 $self->{set_next_char}->($self);
3458 wakaba 1.18 }
3459    
3460     redo A;
3461 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3462 wakaba 1.77
3463     $Whatpm::HTML::Debug::cp_pass->(188) if $Whatpm::HTML::Debug::cp_pass;
3464     BEGIN {
3465     $Whatpm::HTML::Debug::cp->{188} = 1;
3466     }
3467    
3468 wakaba 1.70 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3469    
3470     $self->{state} = DATA_STATE;
3471    
3472     if (@{$self->{char}}) {
3473 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3474 wakaba 1.70 } else {
3475 wakaba 1.76 $self->{set_next_char}->($self);
3476 wakaba 1.70 }
3477    
3478    
3479 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3480 wakaba 1.70 return ($self->{current_token}); # DOCTYPE
3481    
3482     redo A;
3483 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3484 wakaba 1.77
3485     $Whatpm::HTML::Debug::cp_pass->(189) if $Whatpm::HTML::Debug::cp_pass;
3486     BEGIN {
3487     $Whatpm::HTML::Debug::cp->{189} = 1;
3488     }
3489    
3490 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3491    
3492 wakaba 1.59 $self->{state} = DATA_STATE;
3493 wakaba 1.18 ## reconsume
3494    
3495 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3496 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3497    
3498     redo A;
3499     } else {
3500 wakaba 1.77
3501     $Whatpm::HTML::Debug::cp_pass->(190) if $Whatpm::HTML::Debug::cp_pass;
3502     BEGIN {
3503     $Whatpm::HTML::Debug::cp->{190} = 1;
3504     }
3505    
3506 wakaba 1.18 $self->{current_token}->{public_identifier} # DOCTYPE
3507 wakaba 1.76 .= chr $self->{next_char};
3508 wakaba 1.18 ## Stay in the state
3509    
3510     if (@{$self->{char}}) {
3511 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3512 wakaba 1.18 } else {
3513 wakaba 1.76 $self->{set_next_char}->($self);
3514 wakaba 1.18 }
3515    
3516     redo A;
3517     }
3518 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE) {
3519 wakaba 1.76 if ($self->{next_char} == 0x0027) { # '
3520 wakaba 1.77
3521     $Whatpm::HTML::Debug::cp_pass->(191) if $Whatpm::HTML::Debug::cp_pass;
3522     BEGIN {
3523     $Whatpm::HTML::Debug::cp->{191} = 1;
3524     }
3525    
3526 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
3527 wakaba 1.18
3528     if (@{$self->{char}}) {
3529 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3530 wakaba 1.18 } else {
3531 wakaba 1.76 $self->{set_next_char}->($self);
3532 wakaba 1.18 }
3533    
3534     redo A;
3535 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3536 wakaba 1.77
3537     $Whatpm::HTML::Debug::cp_pass->(192) if $Whatpm::HTML::Debug::cp_pass;
3538     BEGIN {
3539     $Whatpm::HTML::Debug::cp->{192} = 1;
3540     }
3541    
3542 wakaba 1.70 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3543    
3544     $self->{state} = DATA_STATE;
3545    
3546     if (@{$self->{char}}) {
3547 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3548 wakaba 1.70 } else {
3549 wakaba 1.76 $self->{set_next_char}->($self);
3550 wakaba 1.70 }
3551    
3552    
3553 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3554 wakaba 1.70 return ($self->{current_token}); # DOCTYPE
3555    
3556     redo A;
3557 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3558 wakaba 1.77
3559     $Whatpm::HTML::Debug::cp_pass->(193) if $Whatpm::HTML::Debug::cp_pass;
3560     BEGIN {
3561     $Whatpm::HTML::Debug::cp->{193} = 1;
3562     }
3563    
3564 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3565    
3566 wakaba 1.59 $self->{state} = DATA_STATE;
3567 wakaba 1.18 ## reconsume
3568    
3569 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3570 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3571    
3572     redo A;
3573     } else {
3574 wakaba 1.77
3575     $Whatpm::HTML::Debug::cp_pass->(194) if $Whatpm::HTML::Debug::cp_pass;
3576     BEGIN {
3577     $Whatpm::HTML::Debug::cp->{194} = 1;
3578     }
3579    
3580 wakaba 1.18 $self->{current_token}->{public_identifier} # DOCTYPE
3581 wakaba 1.76 .= chr $self->{next_char};
3582 wakaba 1.18 ## Stay in the state
3583    
3584     if (@{$self->{char}}) {
3585 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3586 wakaba 1.18 } else {
3587 wakaba 1.76 $self->{set_next_char}->($self);
3588 wakaba 1.18 }
3589    
3590     redo A;
3591     }
3592 wakaba 1.59 } elsif ($self->{state} == AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {
3593 wakaba 1.18 if ({
3594     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
3595     #0x000D => 1, # HT, LF, VT, FF, SP, CR
3596 wakaba 1.76 }->{$self->{next_char}}) {
3597 wakaba 1.77
3598     $Whatpm::HTML::Debug::cp_pass->(195) if $Whatpm::HTML::Debug::cp_pass;
3599     BEGIN {
3600     $Whatpm::HTML::Debug::cp->{195} = 1;
3601     }
3602    
3603 wakaba 1.1 ## Stay in the state
3604    
3605     if (@{$self->{char}}) {
3606 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3607 wakaba 1.1 } else {
3608 wakaba 1.76 $self->{set_next_char}->($self);
3609 wakaba 1.1 }
3610    
3611     redo A;
3612 wakaba 1.76 } elsif ($self->{next_char} == 0x0022) { # "
3613 wakaba 1.77
3614     $Whatpm::HTML::Debug::cp_pass->(196) if $Whatpm::HTML::Debug::cp_pass;
3615     BEGIN {
3616     $Whatpm::HTML::Debug::cp->{196} = 1;
3617     }
3618    
3619 wakaba 1.18 $self->{current_token}->{system_identifier} = ''; # DOCTYPE
3620 wakaba 1.59 $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
3621 wakaba 1.18
3622     if (@{$self->{char}}) {
3623 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3624 wakaba 1.18 } else {
3625 wakaba 1.76 $self->{set_next_char}->($self);
3626 wakaba 1.18 }
3627    
3628     redo A;
3629 wakaba 1.76 } elsif ($self->{next_char} == 0x0027) { # '
3630 wakaba 1.77
3631     $Whatpm::HTML::Debug::cp_pass->(197) if $Whatpm::HTML::Debug::cp_pass;
3632     BEGIN {
3633     $Whatpm::HTML::Debug::cp->{197} = 1;
3634     }
3635    
3636 wakaba 1.18 $self->{current_token}->{system_identifier} = ''; # DOCTYPE
3637 wakaba 1.59 $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
3638 wakaba 1.18
3639     if (@{$self->{char}}) {
3640 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3641 wakaba 1.18 } else {
3642 wakaba 1.76 $self->{set_next_char}->($self);
3643 wakaba 1.18 }
3644    
3645     redo A;
3646 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3647 wakaba 1.77
3648     $Whatpm::HTML::Debug::cp_pass->(198) if $Whatpm::HTML::Debug::cp_pass;
3649     BEGIN {
3650     $Whatpm::HTML::Debug::cp->{198} = 1;
3651     }
3652    
3653 wakaba 1.59 $self->{state} = DATA_STATE;
3654 wakaba 1.18
3655     if (@{$self->{char}}) {
3656 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3657 wakaba 1.18 } else {
3658 wakaba 1.76 $self->{set_next_char}->($self);
3659 wakaba 1.18 }
3660    
3661    
3662     return ($self->{current_token}); # DOCTYPE
3663    
3664     redo A;
3665 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3666 wakaba 1.77
3667     $Whatpm::HTML::Debug::cp_pass->(199) if $Whatpm::HTML::Debug::cp_pass;
3668     BEGIN {
3669     $Whatpm::HTML::Debug::cp->{199} = 1;
3670     }
3671    
3672 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3673    
3674 wakaba 1.59 $self->{state} = DATA_STATE;
3675 wakaba 1.26 ## reconsume
3676 wakaba 1.18
3677 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3678 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3679    
3680     redo A;
3681     } else {
3682 wakaba 1.77
3683     $Whatpm::HTML::Debug::cp_pass->(200) if $Whatpm::HTML::Debug::cp_pass;
3684     BEGIN {
3685     $Whatpm::HTML::Debug::cp->{200} = 1;
3686     }
3687    
3688 wakaba 1.18 $self->{parse_error}-> (type => 'string after PUBLIC literal');
3689 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3690 wakaba 1.73
3691 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
3692 wakaba 1.18
3693     if (@{$self->{char}}) {
3694 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3695 wakaba 1.18 } else {
3696 wakaba 1.76 $self->{set_next_char}->($self);
3697 wakaba 1.18 }
3698    
3699     redo A;
3700 wakaba 1.1 }
3701 wakaba 1.59 } elsif ($self->{state} == BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {
3702 wakaba 1.18 if ({
3703     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
3704     #0x000D => 1, # HT, LF, VT, FF, SP, CR
3705 wakaba 1.76 }->{$self->{next_char}}) {
3706 wakaba 1.77
3707     $Whatpm::HTML::Debug::cp_pass->(201) if $Whatpm::HTML::Debug::cp_pass;
3708     BEGIN {
3709     $Whatpm::HTML::Debug::cp->{201} = 1;
3710     }
3711    
3712 wakaba 1.1 ## Stay in the state
3713    
3714     if (@{$self->{char}}) {
3715 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3716 wakaba 1.1 } else {
3717 wakaba 1.76 $self->{set_next_char}->($self);
3718 wakaba 1.1 }
3719    
3720     redo A;
3721 wakaba 1.76 } elsif ($self->{next_char} == 0x0022) { # "
3722 wakaba 1.77
3723     $Whatpm::HTML::Debug::cp_pass->(202) if $Whatpm::HTML::Debug::cp_pass;
3724     BEGIN {
3725     $Whatpm::HTML::Debug::cp->{202} = 1;
3726     }
3727    
3728 wakaba 1.18 $self->{current_token}->{system_identifier} = ''; # DOCTYPE
3729 wakaba 1.59 $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
3730 wakaba 1.18
3731     if (@{$self->{char}}) {
3732 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3733 wakaba 1.18 } else {
3734 wakaba 1.76 $self->{set_next_char}->($self);
3735 wakaba 1.18 }
3736    
3737     redo A;
3738 wakaba 1.76 } elsif ($self->{next_char} == 0x0027) { # '
3739 wakaba 1.77
3740     $Whatpm::HTML::Debug::cp_pass->(203) if $Whatpm::HTML::Debug::cp_pass;
3741     BEGIN {
3742     $Whatpm::HTML::Debug::cp->{203} = 1;
3743     }
3744    
3745 wakaba 1.18 $self->{current_token}->{system_identifier} = ''; # DOCTYPE
3746 wakaba 1.59 $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
3747 wakaba 1.18
3748     if (@{$self->{char}}) {
3749 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3750 wakaba 1.18 } else {
3751 wakaba 1.76 $self->{set_next_char}->($self);
3752 wakaba 1.18 }
3753    
3754     redo A;
3755 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3756 wakaba 1.77
3757     $Whatpm::HTML::Debug::cp_pass->(204) if $Whatpm::HTML::Debug::cp_pass;
3758     BEGIN {
3759     $Whatpm::HTML::Debug::cp->{204} = 1;
3760     }
3761    
3762 wakaba 1.18 $self->{parse_error}-> (type => 'no SYSTEM literal');
3763 wakaba 1.59 $self->{state} = DATA_STATE;
3764 wakaba 1.1
3765     if (@{$self->{char}}) {
3766 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3767 wakaba 1.1 } else {
3768 wakaba 1.76 $self->{set_next_char}->($self);
3769 wakaba 1.1 }
3770    
3771    
3772 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3773 wakaba 1.1 return ($self->{current_token}); # DOCTYPE
3774    
3775     redo A;
3776 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3777 wakaba 1.77
3778     $Whatpm::HTML::Debug::cp_pass->(205) if $Whatpm::HTML::Debug::cp_pass;
3779     BEGIN {
3780     $Whatpm::HTML::Debug::cp->{205} = 1;
3781     }
3782    
3783 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
3784 wakaba 1.18
3785 wakaba 1.59 $self->{state} = DATA_STATE;
3786 wakaba 1.26 ## reconsume
3787 wakaba 1.18
3788 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3789 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3790    
3791     redo A;
3792     } else {
3793 wakaba 1.77
3794     $Whatpm::HTML::Debug::cp_pass->(206) if $Whatpm::HTML::Debug::cp_pass;
3795     BEGIN {
3796     $Whatpm::HTML::Debug::cp->{206} = 1;
3797     }
3798    
3799 wakaba 1.30 $self->{parse_error}-> (type => 'string after SYSTEM');
3800 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3801 wakaba 1.73
3802 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
3803 wakaba 1.18
3804     if (@{$self->{char}}) {
3805 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3806 wakaba 1.18 } else {
3807 wakaba 1.76 $self->{set_next_char}->($self);
3808 wakaba 1.18 }
3809    
3810     redo A;
3811     }
3812 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE) {
3813 wakaba 1.76 if ($self->{next_char} == 0x0022) { # "
3814 wakaba 1.77
3815     $Whatpm::HTML::Debug::cp_pass->(207) if $Whatpm::HTML::Debug::cp_pass;
3816     BEGIN {
3817     $Whatpm::HTML::Debug::cp->{207} = 1;
3818     }
3819    
3820 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
3821 wakaba 1.18
3822     if (@{$self->{char}}) {
3823 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3824 wakaba 1.18 } else {
3825 wakaba 1.76 $self->{set_next_char}->($self);
3826 wakaba 1.18 }
3827    
3828     redo A;
3829 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3830 wakaba 1.77
3831     $Whatpm::HTML::Debug::cp_pass->(208) if $Whatpm::HTML::Debug::cp_pass;
3832     BEGIN {
3833     $Whatpm::HTML::Debug::cp->{208} = 1;
3834     }
3835    
3836 wakaba 1.70 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3837    
3838     $self->{state} = DATA_STATE;
3839    
3840     if (@{$self->{char}}) {
3841 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3842 wakaba 1.70 } else {
3843 wakaba 1.76 $self->{set_next_char}->($self);
3844 wakaba 1.70 }
3845    
3846    
3847 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3848 wakaba 1.70 return ($self->{current_token}); # DOCTYPE
3849    
3850     redo A;
3851 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3852 wakaba 1.77
3853     $Whatpm::HTML::Debug::cp_pass->(209) if $Whatpm::HTML::Debug::cp_pass;
3854     BEGIN {
3855     $Whatpm::HTML::Debug::cp->{209} = 1;
3856     }
3857    
3858 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed SYSTEM literal');
3859    
3860 wakaba 1.59 $self->{state} = DATA_STATE;
3861 wakaba 1.1 ## reconsume
3862    
3863 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3864 wakaba 1.1 return ($self->{current_token}); # DOCTYPE
3865    
3866     redo A;
3867     } else {
3868 wakaba 1.77
3869     $Whatpm::HTML::Debug::cp_pass->(210) if $Whatpm::HTML::Debug::cp_pass;
3870     BEGIN {
3871     $Whatpm::HTML::Debug::cp->{210} = 1;
3872     }
3873    
3874 wakaba 1.18 $self->{current_token}->{system_identifier} # DOCTYPE
3875 wakaba 1.76 .= chr $self->{next_char};
3876 wakaba 1.18 ## Stay in the state
3877    
3878     if (@{$self->{char}}) {
3879 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3880 wakaba 1.18 } else {
3881 wakaba 1.76 $self->{set_next_char}->($self);
3882 wakaba 1.18 }
3883    
3884     redo A;
3885     }
3886 wakaba 1.59 } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE) {
3887 wakaba 1.76 if ($self->{next_char} == 0x0027) { # '
3888 wakaba 1.77
3889     $Whatpm::HTML::Debug::cp_pass->(211) if $Whatpm::HTML::Debug::cp_pass;
3890     BEGIN {
3891     $Whatpm::HTML::Debug::cp->{211} = 1;
3892     }
3893    
3894 wakaba 1.59 $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
3895 wakaba 1.18
3896     if (@{$self->{char}}) {
3897 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3898 wakaba 1.18 } else {
3899 wakaba 1.76 $self->{set_next_char}->($self);
3900 wakaba 1.18 }
3901    
3902     redo A;
3903 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3904 wakaba 1.77
3905     $Whatpm::HTML::Debug::cp_pass->(212) if $Whatpm::HTML::Debug::cp_pass;
3906     BEGIN {
3907     $Whatpm::HTML::Debug::cp->{212} = 1;
3908     }
3909    
3910 wakaba 1.70 $self->{parse_error}-> (type => 'unclosed PUBLIC literal');
3911    
3912     $self->{state} = DATA_STATE;
3913    
3914     if (@{$self->{char}}) {
3915 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3916 wakaba 1.70 } else {
3917 wakaba 1.76 $self->{set_next_char}->($self);
3918 wakaba 1.70 }
3919    
3920    
3921 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3922 wakaba 1.70 return ($self->{current_token}); # DOCTYPE
3923    
3924     redo A;
3925 wakaba 1.76 } elsif ($self->{next_char} == -1) {
3926 wakaba 1.77
3927     $Whatpm::HTML::Debug::cp_pass->(213) if $Whatpm::HTML::Debug::cp_pass;
3928     BEGIN {
3929     $Whatpm::HTML::Debug::cp->{213} = 1;
3930     }
3931    
3932 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed SYSTEM literal');
3933    
3934 wakaba 1.59 $self->{state} = DATA_STATE;
3935 wakaba 1.18 ## reconsume
3936    
3937 wakaba 1.75 $self->{current_token}->{quirks} = 1;
3938 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
3939    
3940     redo A;
3941     } else {
3942 wakaba 1.77
3943     $Whatpm::HTML::Debug::cp_pass->(214) if $Whatpm::HTML::Debug::cp_pass;
3944     BEGIN {
3945     $Whatpm::HTML::Debug::cp->{214} = 1;
3946     }
3947    
3948 wakaba 1.18 $self->{current_token}->{system_identifier} # DOCTYPE
3949 wakaba 1.76 .= chr $self->{next_char};
3950 wakaba 1.18 ## Stay in the state
3951    
3952     if (@{$self->{char}}) {
3953 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3954 wakaba 1.18 } else {
3955 wakaba 1.76 $self->{set_next_char}->($self);
3956 wakaba 1.18 }
3957    
3958     redo A;
3959     }
3960 wakaba 1.59 } elsif ($self->{state} == AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {
3961 wakaba 1.18 if ({
3962     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
3963     #0x000D => 1, # HT, LF, VT, FF, SP, CR
3964 wakaba 1.76 }->{$self->{next_char}}) {
3965 wakaba 1.77
3966     $Whatpm::HTML::Debug::cp_pass->(215) if $Whatpm::HTML::Debug::cp_pass;
3967     BEGIN {
3968     $Whatpm::HTML::Debug::cp->{215} = 1;
3969     }
3970    
3971 wakaba 1.18 ## Stay in the state
3972    
3973     if (@{$self->{char}}) {
3974 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3975 wakaba 1.18 } else {
3976 wakaba 1.76 $self->{set_next_char}->($self);
3977 wakaba 1.18 }
3978    
3979     redo A;
3980 wakaba 1.76 } elsif ($self->{next_char} == 0x003E) { # >
3981 wakaba 1.77
3982     $Whatpm::HTML::Debug::cp_pass->(216) if $Whatpm::HTML::Debug::cp_pass;
3983     BEGIN {
3984     $Whatpm::HTML::Debug::cp->{216} = 1;
3985     }
3986    
3987 wakaba 1.59 $self->{state} = DATA_STATE;
3988 wakaba 1.18
3989     if (@{$self->{char}}) {
3990 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
3991 wakaba 1.18 } else {
3992 wakaba 1.76 $self->{set_next_char}->($self);
3993 wakaba 1.18 }
3994    
3995    
3996     return ($self->{current_token}); # DOCTYPE
3997    
3998     redo A;
3999 wakaba 1.76 } elsif ($self->{next_char} == -1) {
4000 wakaba 1.77
4001     $Whatpm::HTML::Debug::cp_pass->(217) if $Whatpm::HTML::Debug::cp_pass;
4002     BEGIN {
4003     $Whatpm::HTML::Debug::cp->{217} = 1;
4004     }
4005    
4006 wakaba 1.18 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
4007    
4008 wakaba 1.59 $self->{state} = DATA_STATE;
4009 wakaba 1.26 ## reconsume
4010 wakaba 1.18
4011 wakaba 1.75 $self->{current_token}->{quirks} = 1;
4012 wakaba 1.18 return ($self->{current_token}); # DOCTYPE
4013    
4014     redo A;
4015     } else {
4016 wakaba 1.77
4017     $Whatpm::HTML::Debug::cp_pass->(218) if $Whatpm::HTML::Debug::cp_pass;
4018     BEGIN {
4019     $Whatpm::HTML::Debug::cp->{218} = 1;
4020     }
4021    
4022 wakaba 1.18 $self->{parse_error}-> (type => 'string after SYSTEM literal');
4023 wakaba 1.75 #$self->{current_token}->{quirks} = 1;
4024 wakaba 1.73
4025 wakaba 1.59 $self->{state} = BOGUS_DOCTYPE_STATE;
4026 wakaba 1.1
4027     if (@{$self->{char}}) {
4028 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4029 wakaba 1.1 } else {
4030 wakaba 1.76 $self->{set_next_char}->($self);
4031 wakaba 1.1 }
4032    
4033     redo A;
4034     }
4035 wakaba 1.59 } elsif ($self->{state} == BOGUS_DOCTYPE_STATE) {
4036 wakaba 1.76 if ($self->{next_char} == 0x003E) { # >
4037 wakaba 1.77
4038     $Whatpm::HTML::Debug::cp_pass->(219) if $Whatpm::HTML::Debug::cp_pass;
4039     BEGIN {
4040     $Whatpm::HTML::Debug::cp->{219} = 1;
4041     }
4042    
4043 wakaba 1.59 $self->{state} = DATA_STATE;
4044 wakaba 1.1
4045     if (@{$self->{char}}) {
4046 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4047 wakaba 1.1 } else {
4048 wakaba 1.76 $self->{set_next_char}->($self);
4049 wakaba 1.1 }
4050    
4051    
4052     return ($self->{current_token}); # DOCTYPE
4053    
4054     redo A;
4055 wakaba 1.76 } elsif ($self->{next_char} == -1) {
4056 wakaba 1.77
4057     $Whatpm::HTML::Debug::cp_pass->(220) if $Whatpm::HTML::Debug::cp_pass;
4058     BEGIN {
4059     $Whatpm::HTML::Debug::cp->{220} = 1;
4060     }
4061    
4062 wakaba 1.3 $self->{parse_error}-> (type => 'unclosed DOCTYPE');
4063 wakaba 1.59 $self->{state} = DATA_STATE;
4064 wakaba 1.1 ## reconsume
4065    
4066     return ($self->{current_token}); # DOCTYPE
4067    
4068     redo A;
4069     } else {
4070 wakaba 1.77
4071     $Whatpm::HTML::Debug::cp_pass->(221) if $Whatpm::HTML::Debug::cp_pass;
4072     BEGIN {
4073     $Whatpm::HTML::Debug::cp->{221} = 1;
4074     }
4075    
4076 wakaba 1.1 ## Stay in the state
4077    
4078     if (@{$self->{char}}) {
4079 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4080 wakaba 1.1 } else {
4081 wakaba 1.76 $self->{set_next_char}->($self);
4082 wakaba 1.1 }
4083    
4084     redo A;
4085     }
4086     } else {
4087     die "$0: $self->{state}: Unknown state";
4088     }
4089     } # A
4090    
4091     die "$0: _get_next_token: unexpected case";
4092     } # _get_next_token
4093    
4094 wakaba 1.72 sub _tokenize_attempt_to_consume_an_entity ($$$) {
4095     my ($self, $in_attr, $additional) = @_;
4096 wakaba 1.20
4097     if ({
4098     0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, # HT, LF, VT, FF,
4099     0x0020 => 1, 0x003C => 1, 0x0026 => 1, -1 => 1, # SP, <, & # 0x000D # CR
4100 wakaba 1.72 $additional => 1,
4101 wakaba 1.76 }->{$self->{next_char}}) {
4102 wakaba 1.78
4103     $Whatpm::HTML::Debug::cp_pass->(1001) if $Whatpm::HTML::Debug::cp_pass;
4104     BEGIN {
4105     $Whatpm::HTML::Debug::cp->{1001} = 1;
4106     }
4107    
4108 wakaba 1.20 ## Don't consume
4109     ## No error
4110     return undef;
4111 wakaba 1.76 } elsif ($self->{next_char} == 0x0023) { # #
4112 wakaba 1.1
4113     if (@{$self->{char}}) {
4114 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4115 wakaba 1.1 } else {
4116 wakaba 1.76 $self->{set_next_char}->($self);
4117 wakaba 1.1 }
4118    
4119 wakaba 1.76 if ($self->{next_char} == 0x0078 or # x
4120     $self->{next_char} == 0x0058) { # X
4121 wakaba 1.26 my $code;
4122 wakaba 1.1 X: {
4123 wakaba 1.76 my $x_char = $self->{next_char};
4124 wakaba 1.1
4125     if (@{$self->{char}}) {
4126 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4127 wakaba 1.1 } else {
4128 wakaba 1.76 $self->{set_next_char}->($self);
4129 wakaba 1.1 }
4130    
4131 wakaba 1.76 if (0x0030 <= $self->{next_char} and
4132     $self->{next_char} <= 0x0039) { # 0..9
4133 wakaba 1.78
4134     $Whatpm::HTML::Debug::cp_pass->(1002) if $Whatpm::HTML::Debug::cp_pass;
4135     BEGIN {
4136     $Whatpm::HTML::Debug::cp->{1002} = 1;
4137     }
4138    
4139 wakaba 1.26 $code ||= 0;
4140     $code *= 0x10;
4141 wakaba 1.76 $code += $self->{next_char} - 0x0030;
4142 wakaba 1.1 redo X;
4143 wakaba 1.76 } elsif (0x0061 <= $self->{next_char} and
4144     $self->{next_char} <= 0x0066) { # a..f
4145 wakaba 1.78
4146     $Whatpm::HTML::Debug::cp_pass->(1003) if $Whatpm::HTML::Debug::cp_pass;
4147     BEGIN {
4148     $Whatpm::HTML::Debug::cp->{1003} = 1;
4149     }
4150    
4151 wakaba 1.26 $code ||= 0;
4152     $code *= 0x10;
4153 wakaba 1.76 $code += $self->{next_char} - 0x0060 + 9;
4154 wakaba 1.1 redo X;
4155 wakaba 1.76 } elsif (0x0041 <= $self->{next_char} and
4156     $self->{next_char} <= 0x0046) { # A..F
4157 wakaba 1.78
4158     $Whatpm::HTML::Debug::cp_pass->(1004) if $Whatpm::HTML::Debug::cp_pass;
4159     BEGIN {
4160     $Whatpm::HTML::Debug::cp->{1004} = 1;
4161     }
4162    
4163 wakaba 1.26 $code ||= 0;
4164     $code *= 0x10;
4165 wakaba 1.76 $code += $self->{next_char} - 0x0040 + 9;
4166 wakaba 1.1 redo X;
4167 wakaba 1.26 } elsif (not defined $code) { # no hexadecimal digit
4168 wakaba 1.78
4169     $Whatpm::HTML::Debug::cp_pass->(1005) if $Whatpm::HTML::Debug::cp_pass;
4170     BEGIN {
4171     $Whatpm::HTML::Debug::cp->{1005} = 1;
4172     }
4173    
4174 wakaba 1.3 $self->{parse_error}-> (type => 'bare hcro');
4175 wakaba 1.76 unshift @{$self->{char}}, ($x_char, $self->{next_char});
4176     $self->{next_char} = 0x0023; # #
4177 wakaba 1.1 return undef;
4178 wakaba 1.76 } elsif ($self->{next_char} == 0x003B) { # ;
4179 wakaba 1.1
4180 wakaba 1.78 $Whatpm::HTML::Debug::cp_pass->(1006) if $Whatpm::HTML::Debug::cp_pass;
4181     BEGIN {
4182     $Whatpm::HTML::Debug::cp->{1006} = 1;
4183     }
4184    
4185    
4186 wakaba 1.1 if (@{$self->{char}}) {
4187 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4188 wakaba 1.1 } else {
4189 wakaba 1.76 $self->{set_next_char}->($self);
4190 wakaba 1.1 }
4191    
4192     } else {
4193 wakaba 1.78
4194     $Whatpm::HTML::Debug::cp_pass->(1007) if $Whatpm::HTML::Debug::cp_pass;
4195     BEGIN {
4196     $Whatpm::HTML::Debug::cp->{1007} = 1;
4197     }
4198    
4199 wakaba 1.3 $self->{parse_error}-> (type => 'no refc');
4200 wakaba 1.1 }
4201    
4202 wakaba 1.26 if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {
4203 wakaba 1.78
4204     $Whatpm::HTML::Debug::cp_pass->(1008) if $Whatpm::HTML::Debug::cp_pass;
4205     BEGIN {
4206     $Whatpm::HTML::Debug::cp->{1008} = 1;
4207     }
4208    
4209 wakaba 1.26 $self->{parse_error}-> (type => sprintf 'invalid character reference:U+%04X', $code);
4210     $code = 0xFFFD;
4211     } elsif ($code > 0x10FFFF) {
4212 wakaba 1.78
4213     $Whatpm::HTML::Debug::cp_pass->(1009) if $Whatpm::HTML::Debug::cp_pass;
4214     BEGIN {
4215     $Whatpm::HTML::Debug::cp->{1009} = 1;
4216     }
4217    
4218 wakaba 1.26 $self->{parse_error}-> (type => sprintf 'invalid character reference:U-%08X', $code);
4219     $code = 0xFFFD;
4220     } elsif ($code == 0x000D) {
4221 wakaba 1.78
4222     $Whatpm::HTML::Debug::cp_pass->(1010) if $Whatpm::HTML::Debug::cp_pass;
4223     BEGIN {
4224     $Whatpm::HTML::Debug::cp->{1010} = 1;
4225     }
4226    
4227 wakaba 1.26 $self->{parse_error}-> (type => 'CR character reference');
4228     $code = 0x000A;
4229     } elsif (0x80 <= $code and $code <= 0x9F) {
4230 wakaba 1.78
4231     $Whatpm::HTML::Debug::cp_pass->(1011) if $Whatpm::HTML::Debug::cp_pass;
4232     BEGIN {
4233     $Whatpm::HTML::Debug::cp->{1011} = 1;
4234     }
4235    
4236 wakaba 1.30 $self->{parse_error}-> (type => sprintf 'C1 character reference:U+%04X', $code);
4237 wakaba 1.26 $code = $c1_entity_char->{$code};
4238 wakaba 1.1 }
4239    
4240 wakaba 1.68 return {type => CHARACTER_TOKEN, data => chr $code,
4241     has_reference => 1};
4242 wakaba 1.1 } # X
4243 wakaba 1.76 } elsif (0x0030 <= $self->{next_char} and
4244     $self->{next_char} <= 0x0039) { # 0..9
4245     my $code = $self->{next_char} - 0x0030;
4246 wakaba 1.1
4247     if (@{$self->{char}}) {
4248 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4249 wakaba 1.1 } else {
4250 wakaba 1.76 $self->{set_next_char}->($self);
4251 wakaba 1.1 }
4252    
4253    
4254 wakaba 1.76 while (0x0030 <= $self->{next_char} and
4255     $self->{next_char} <= 0x0039) { # 0..9
4256 wakaba 1.78
4257     $Whatpm::HTML::Debug::cp_pass->(1012) if $Whatpm::HTML::Debug::cp_pass;
4258     BEGIN {
4259     $Whatpm::HTML::Debug::cp->{1012} = 1;
4260     }
4261    
4262 wakaba 1.1 $code *= 10;
4263 wakaba 1.76 $code += $self->{next_char} - 0x0030;
4264 wakaba 1.1
4265    
4266     if (@{$self->{char}}) {
4267 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4268 wakaba 1.1 } else {
4269 wakaba 1.76 $self->{set_next_char}->($self);
4270 wakaba 1.1 }
4271    
4272     }
4273    
4274 wakaba 1.76 if ($self->{next_char} == 0x003B) { # ;
4275 wakaba 1.1
4276 wakaba 1.78 $Whatpm::HTML::Debug::cp_pass->(1013) if $Whatpm::HTML::Debug::cp_pass;
4277     BEGIN {
4278     $Whatpm::HTML::Debug::cp->{1013} = 1;
4279     }
4280    
4281    
4282 wakaba 1.1 if (@{$self->{char}}) {
4283 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4284 wakaba 1.1 } else {
4285 wakaba 1.76 $self->{set_next_char}->($self);
4286 wakaba 1.1 }
4287    
4288     } else {
4289 wakaba 1.78
4290     $Whatpm::HTML::Debug::cp_pass->(1014) if $Whatpm::HTML::Debug::cp_pass;
4291     BEGIN {
4292     $Whatpm::HTML::Debug::cp->{1014} = 1;
4293     }
4294    
4295 wakaba 1.3 $self->{parse_error}-> (type => 'no refc');
4296 wakaba 1.1 }
4297    
4298 wakaba 1.26 if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {
4299 wakaba 1.78
4300     $Whatpm::HTML::Debug::cp_pass->(1015) if $Whatpm::HTML::Debug::cp_pass;
4301     BEGIN {
4302     $Whatpm::HTML::Debug::cp->{1015} = 1;
4303     }
4304    
4305 wakaba 1.26 $self->{parse_error}-> (type => sprintf 'invalid character reference:U+%04X', $code);
4306     $code = 0xFFFD;
4307     } elsif ($code > 0x10FFFF) {
4308 wakaba 1.78
4309     $Whatpm::HTML::Debug::cp_pass->(1016) if $Whatpm::HTML::Debug::cp_pass;
4310     BEGIN {
4311     $Whatpm::HTML::Debug::cp->{1016} = 1;
4312     }
4313    
4314 wakaba 1.26 $self->{parse_error}-> (type => sprintf 'invalid character reference:U-%08X', $code);
4315     $code = 0xFFFD;
4316     } elsif ($code == 0x000D) {
4317 wakaba 1.78
4318     $Whatpm::HTML::Debug::cp_pass->(1017) if $Whatpm::HTML::Debug::cp_pass;
4319     BEGIN {
4320     $Whatpm::HTML::Debug::cp->{1017} = 1;
4321     }
4322    
4323 wakaba 1.26 $self->{parse_error}-> (type => 'CR character reference');
4324     $code = 0x000A;
4325 wakaba 1.4 } elsif (0x80 <= $code and $code <= 0x9F) {
4326 wakaba 1.78
4327     $Whatpm::HTML::Debug::cp_pass->(1018) if $Whatpm::HTML::Debug::cp_pass;
4328     BEGIN {
4329     $Whatpm::HTML::Debug::cp->{1018} = 1;
4330     }
4331    
4332 wakaba 1.30 $self->{parse_error}-> (type => sprintf 'C1 character reference:U+%04X', $code);
4333 wakaba 1.4 $code = $c1_entity_char->{$code};
4334 wakaba 1.1 }
4335    
4336 wakaba 1.68 return {type => CHARACTER_TOKEN, data => chr $code, has_reference => 1};
4337 wakaba 1.1 } else {
4338 wakaba 1.78
4339     $Whatpm::HTML::Debug::cp_pass->(1019) if $Whatpm::HTML::Debug::cp_pass;
4340     BEGIN {
4341     $Whatpm::HTML::Debug::cp->{1019} = 1;
4342     }
4343    
4344 wakaba 1.3 $self->{parse_error}-> (type => 'bare nero');
4345 wakaba 1.76 unshift @{$self->{char}}, ($self->{next_char});
4346     $self->{next_char} = 0x0023; # #
4347 wakaba 1.1 return undef;
4348     }
4349 wakaba 1.76 } elsif ((0x0041 <= $self->{next_char} and
4350     $self->{next_char} <= 0x005A) or
4351     (0x0061 <= $self->{next_char} and
4352     $self->{next_char} <= 0x007A)) {
4353     my $entity_name = chr $self->{next_char};
4354 wakaba 1.1
4355     if (@{$self->{char}}) {
4356 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4357 wakaba 1.1 } else {
4358 wakaba 1.76 $self->{set_next_char}->($self);
4359 wakaba 1.1 }
4360    
4361    
4362     my $value = $entity_name;
4363 wakaba 1.37 my $match = 0;
4364 wakaba 1.16 require Whatpm::_NamedEntityList;
4365     our $EntityChar;
4366 wakaba 1.1
4367     while (length $entity_name < 10 and
4368     ## NOTE: Some number greater than the maximum length of entity name
4369 wakaba 1.76 ((0x0041 <= $self->{next_char} and # a
4370     $self->{next_char} <= 0x005A) or # x
4371     (0x0061 <= $self->{next_char} and # a
4372     $self->{next_char} <= 0x007A) or # z
4373     (0x0030 <= $self->{next_char} and # 0
4374     $self->{next_char} <= 0x0039) or # 9
4375     $self->{next_char} == 0x003B)) { # ;
4376     $entity_name .= chr $self->{next_char};
4377 wakaba 1.16 if (defined $EntityChar->{$entity_name}) {
4378 wakaba 1.76 if ($self->{next_char} == 0x003B) { # ;
4379 wakaba 1.78
4380     $Whatpm::HTML::Debug::cp_pass->(1020) if $Whatpm::HTML::Debug::cp_pass;
4381     BEGIN {
4382     $Whatpm::HTML::Debug::cp->{1020} = 1;
4383     }
4384    
4385 wakaba 1.26 $value = $EntityChar->{$entity_name};
4386 wakaba 1.16 $match = 1;
4387    
4388     if (@{$self->{char}}) {
4389 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4390 wakaba 1.16 } else {
4391 wakaba 1.76 $self->{set_next_char}->($self);
4392 wakaba 1.16 }
4393    
4394     last;
4395 wakaba 1.37 } else {
4396 wakaba 1.78
4397     $Whatpm::HTML::Debug::cp_pass->(1021) if $Whatpm::HTML::Debug::cp_pass;
4398     BEGIN {
4399     $Whatpm::HTML::Debug::cp->{1021} = 1;
4400     }
4401    
4402 wakaba 1.26 $value = $EntityChar->{$entity_name};
4403     $match = -1;
4404 wakaba 1.37
4405     if (@{$self->{char}}) {
4406 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4407 wakaba 1.37 } else {
4408 wakaba 1.76 $self->{set_next_char}->($self);
4409 wakaba 1.37 }
4410    
4411 wakaba 1.16 }
4412 wakaba 1.1 } else {
4413 wakaba 1.78
4414     $Whatpm::HTML::Debug::cp_pass->(1022) if $Whatpm::HTML::Debug::cp_pass;
4415     BEGIN {
4416     $Whatpm::HTML::Debug::cp->{1022} = 1;
4417     }
4418    
4419 wakaba 1.76 $value .= chr $self->{next_char};
4420 wakaba 1.37 $match *= 2;
4421    
4422 wakaba 1.1 if (@{$self->{char}}) {
4423 wakaba 1.76 $self->{next_char} = shift @{$self->{char}};
4424 wakaba 1.1 } else {
4425 wakaba 1.76 $self->{set_next_char}->($self);
4426 wakaba 1.1 }
4427    
4428 wakaba 1.37 }
4429 wakaba 1.1 }
4430    
4431 wakaba 1.16 if ($match > 0) {
4432 wakaba 1.78
4433     $Whatpm::HTML::Debug::cp_pass->(1023) if $Whatpm::HTML::Debug::cp_pass;
4434     BEGIN {
4435     $Whatpm::HTML::Debug::cp->{1023} = 1;
4436     }
4437    
4438 wakaba 1.68 return {type => CHARACTER_TOKEN, data => $value, has_reference => 1};
4439 wakaba 1.16 } elsif ($match < 0) {
4440 wakaba 1.30 $self->{parse_error}-> (type => 'no refc');
4441 wakaba 1.37 if ($in_attr and $match < -1) {
4442 wakaba 1.78
4443     $Whatpm::HTML::Debug::cp_pass->(1024) if $Whatpm::HTML::Debug::cp_pass;
4444     BEGIN {
4445     $Whatpm::HTML::Debug::cp->{1024} = 1;
4446     }
4447    
4448 wakaba 1.57 return {type => CHARACTER_TOKEN, data => '&'.$entity_name};
4449 wakaba 1.37 } else {
4450 wakaba 1.78
4451     $Whatpm::HTML::Debug::cp_pass->(1025) if $Whatpm::HTML::Debug::cp_pass;
4452     BEGIN {
4453     $Whatpm::HTML::Debug::cp->{1025} = 1;
4454     }
4455    
4456 wakaba 1.68 return {type => CHARACTER_TOKEN, data => $value, has_reference => 1};
4457 wakaba 1.37 }
4458 wakaba 1.1 } else {
4459 wakaba 1.78
4460     $Whatpm::HTML::Debug::cp_pass->(1026) if $Whatpm::HTML::Debug::cp_pass;
4461     BEGIN {
4462     $Whatpm::HTML::Debug::cp->{1026} = 1;
4463     }
4464    
4465 wakaba 1.3 $self->{parse_error}-> (type => 'bare ero');
4466 wakaba 1.68 ## NOTE: "No characters are consumed" in the spec.
4467 wakaba 1.57 return {type => CHARACTER_TOKEN, data => '&'.$value};
4468 wakaba 1.1 }
4469     } else {
4470 wakaba 1.78
4471     $Whatpm::HTML::Debug::cp_pass->(1027) if $Whatpm::HTML::Debug::cp_pass;
4472     BEGIN {
4473     $Whatpm::HTML::Debug::cp->{1027} = 1;
4474     }
4475    
4476 wakaba 1.1 ## no characters are consumed
4477 wakaba 1.3 $self->{parse_error}-> (type => 'bare ero');
4478 wakaba 1.1 return undef;
4479     }
4480     } # _tokenize_attempt_to_consume_an_entity
4481    
4482     sub _initialize_tree_constructor ($) {
4483     my $self = shift;
4484     ## NOTE: $self->{document} MUST be specified before this method is called
4485     $self->{document}->strict_error_checking (0);
4486     ## TODO: Turn mutation events off # MUST
4487     ## TODO: Turn loose Document option (manakai extension) on
4488 wakaba 1.18 $self->{document}->manakai_is_html (1); # MUST
4489 wakaba 1.1 } # _initialize_tree_constructor
4490    
4491     sub _terminate_tree_constructor ($) {
4492     my $self = shift;
4493     $self->{document}->strict_error_checking (1);
4494     ## TODO: Turn mutation events on
4495     } # _terminate_tree_constructor
4496    
4497     ## ISSUE: Should append_child (for example) in script executed in tree construction stage fire mutation events?
4498    
4499 wakaba 1.3 { # tree construction stage
4500     my $token;
4501    
4502 wakaba 1.1 sub _construct_tree ($) {
4503     my ($self) = @_;
4504    
4505     ## When an interactive UA render the $self->{document} available
4506     ## to the user, or when it begin accepting user input, are
4507     ## not defined.
4508    
4509     ## Append a character: collect it and all subsequent consecutive
4510     ## characters and insert one Text node whose data is concatenation
4511     ## of all those characters. # MUST
4512    
4513     $token = $self->_get_next_token;
4514    
4515 wakaba 1.56 $self->{insertion_mode} = BEFORE_HEAD_IM;
4516 wakaba 1.3 undef $self->{form_element};
4517     undef $self->{head_element};
4518     $self->{open_elements} = [];
4519     undef $self->{inner_html_node};
4520    
4521     $self->_tree_construction_initial; # MUST
4522     $self->_tree_construction_root_element;
4523     $self->_tree_construction_main;
4524     } # _construct_tree
4525    
4526     sub _tree_construction_initial ($) {
4527     my $self = shift;
4528 wakaba 1.18 INITIAL: {
4529 wakaba 1.57 if ($token->{type} == DOCTYPE_TOKEN) {
4530 wakaba 1.18 ## NOTE: Conformance checkers MAY, instead of reporting "not HTML5"
4531     ## error, switch to a conformance checking mode for another
4532     ## language.
4533     my $doctype_name = $token->{name};
4534     $doctype_name = '' unless defined $doctype_name;
4535     $doctype_name =~ tr/a-z/A-Z/;
4536     if (not defined $token->{name} or # <!DOCTYPE>
4537     defined $token->{public_identifier} or
4538     defined $token->{system_identifier}) {
4539 wakaba 1.79
4540     $Whatpm::HTML::Debug::cp_pass->('t1') if $Whatpm::HTML::Debug::cp_pass;
4541     BEGIN {
4542     $Whatpm::HTML::Debug::cp->{'t1'} = 1;
4543     }
4544    
4545 wakaba 1.18 $self->{parse_error}-> (type => 'not HTML5');
4546     } elsif ($doctype_name ne 'HTML') {
4547 wakaba 1.79
4548     $Whatpm::HTML::Debug::cp_pass->('t2') if $Whatpm::HTML::Debug::cp_pass;
4549     BEGIN {
4550     $Whatpm::HTML::Debug::cp->{'t2'} = 1;
4551     }
4552    
4553 wakaba 1.18 ## ISSUE: ASCII case-insensitive? (in fact it does not matter)
4554     $self->{parse_error}-> (type => 'not HTML5');
4555 wakaba 1.79 } else {
4556    
4557     $Whatpm::HTML::Debug::cp_pass->('t3') if $Whatpm::HTML::Debug::cp_pass;
4558     BEGIN {
4559     $Whatpm::HTML::Debug::cp->{'t3'} = 1;
4560     }
4561    
4562 wakaba 1.18 }
4563    
4564     my $doctype = $self->{document}->create_document_type_definition
4565     ($token->{name}); ## ISSUE: If name is missing (e.g. <!DOCTYPE>)?
4566     $doctype->public_id ($token->{public_identifier})
4567     if defined $token->{public_identifier};
4568     $doctype->system_id ($token->{system_identifier})
4569     if defined $token->{system_identifier};
4570     ## NOTE: Other DocumentType attributes are null or empty lists.
4571     ## ISSUE: internalSubset = null??
4572     $self->{document}->append_child ($doctype);
4573    
4574 wakaba 1.75 if ($token->{quirks} or $doctype_name ne 'HTML') {
4575 wakaba 1.79
4576     $Whatpm::HTML::Debug::cp_pass->('t4') if $Whatpm::HTML::Debug::cp_pass;
4577     BEGIN {
4578     $Whatpm::HTML::Debug::cp->{'t4'} = 1;
4579     }
4580    
4581 wakaba 1.18 $self->{document}->manakai_compat_mode ('quirks');
4582     } elsif (defined $token->{public_identifier}) {
4583     my $pubid = $token->{public_identifier};
4584     $pubid =~ tr/a-z/A-z/;
4585     if ({
4586     "+//SILMARIL//DTD HTML PRO V0R11 19970101//EN" => 1,
4587     "-//ADVASOFT LTD//DTD HTML 3.0 ASWEDIT + EXTENSIONS//EN" => 1,
4588     "-//AS//DTD HTML 3.0 ASWEDIT + EXTENSIONS//EN" => 1,
4589     "-//IETF//DTD HTML 2.0 LEVEL 1//EN" => 1,
4590     "-//IETF//DTD HTML 2.0 LEVEL 2//EN" => 1,
4591     "-//IETF//DTD HTML 2.0 STRICT LEVEL 1//EN" => 1,
4592     "-//IETF//DTD HTML 2.0 STRICT LEVEL 2//EN" => 1,
4593     "-//IETF//DTD HTML 2.0 STRICT//EN" => 1,
4594     "-//IETF//DTD HTML 2.0//EN" => 1,
4595     "-//IETF//DTD HTML 2.1E//EN" => 1,
4596     "-//IETF//DTD HTML 3.0//EN" => 1,
4597     "-//IETF//DTD HTML 3.0//EN//" => 1,
4598     "-//IETF//DTD HTML 3.2 FINAL//EN" => 1,
4599     "-//IETF//DTD HTML 3.2//EN" => 1,
4600     "-//IETF//DTD HTML 3//EN" => 1,
4601     "-//IETF//DTD HTML LEVEL 0//EN" => 1,
4602     "-//IETF//DTD HTML LEVEL 0//EN//2.0" => 1,
4603     "-//IETF//DTD HTML LEVEL 1//EN" => 1,
4604     "-//IETF//DTD HTML LEVEL 1//EN//2.0" => 1,
4605     "-//IETF//DTD HTML LEVEL 2//EN" => 1,
4606     "-//IETF//DTD HTML LEVEL 2//EN//2.0" => 1,
4607     "-//IETF//DTD HTML LEVEL 3//EN" => 1,
4608     "-//IETF//DTD HTML LEVEL 3//EN//3.0" => 1,
4609     "-//IETF//DTD HTML STRICT LEVEL 0//EN" => 1,
4610     "-//IETF//DTD HTML STRICT LEVEL 0//EN//2.0" => 1,
4611     "-//IETF//DTD HTML STRICT LEVEL 1//EN" => 1,
4612     "-//IETF//DTD HTML STRICT LEVEL 1//EN//2.0" => 1,
4613     "-//IETF//DTD HTML STRICT LEVEL 2//EN" => 1,
4614     "-//IETF//DTD HTML STRICT LEVEL 2//EN//2.0" => 1,
4615     "-//IETF//DTD HTML STRICT LEVEL 3//EN" => 1,
4616     "-//IETF//DTD HTML STRICT LEVEL 3//EN//3.0" => 1,
4617     "-//IETF//DTD HTML STRICT//EN" => 1,
4618     "-//IETF//DTD HTML STRICT//EN//2.0" => 1,
4619     "-//IETF//DTD HTML STRICT//EN//3.0" => 1,
4620     "-//IETF//DTD HTML//EN" => 1,
4621     "-//IETF//DTD HTML//EN//2.0" => 1,
4622     "-//IETF//DTD HTML//EN//3.0" => 1,
4623     "-//METRIUS//DTD METRIUS PRESENTATIONAL//EN" => 1,
4624     "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 HTML STRICT//EN" => 1,
4625     "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 HTML//EN" => 1,
4626     "-//MICROSOFT//DTD INTERNET EXPLORER 2.0 TABLES//EN" => 1,
4627     "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 HTML STRICT//EN" => 1,
4628     "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 HTML//EN" => 1,
4629     "-//MICROSOFT//DTD INTERNET EXPLORER 3.0 TABLES//EN" => 1,
4630     "-//NETSCAPE COMM. CORP.//DTD HTML//EN" => 1,
4631     "-//NETSCAPE COMM. CORP.//DTD STRICT HTML//EN" => 1,
4632     "-//O'REILLY AND ASSOCIATES//DTD HTML 2.0//EN" => 1,
4633     "-//O'REILLY AND ASSOCIATES//DTD HTML EXTENDED 1.0//EN" => 1,
4634 wakaba 1.72 "-//O'REILLY AND ASSOCIATES//DTD HTML EXTENDED RELAXED 1.0//EN" => 1,
4635     "-//SOFTQUAD SOFTWARE//DTD HOTMETAL PRO 6.0::19990601::EXTENSIONS TO HTML 4.0//EN" => 1,
4636     "-//SOFTQUAD//DTD HOTMETAL PRO 4.0::19971010::EXTENSIONS TO HTML 4.0//EN" => 1,
4637 wakaba 1.18 "-//SPYGLASS//DTD HTML 2.0 EXTENDED//EN" => 1,
4638     "-//SQ//DTD HTML 2.0 HOTMETAL + EXTENSIONS//EN" => 1,
4639     "-//SUN MICROSYSTEMS CORP.//DTD HOTJAVA HTML//EN" => 1,
4640     "-//SUN MICROSYSTEMS CORP.//DTD HOTJAVA STRICT HTML//EN" => 1,
4641     "-//W3C//DTD HTML 3 1995-03-24//EN" => 1,
4642     "-//W3C//DTD HTML 3.2 DRAFT//EN" => 1,
4643     "-//W3C//DTD HTML 3.2 FINAL//EN" => 1,
4644     "-//W3C//DTD HTML 3.2//EN" => 1,
4645     "-//W3C//DTD HTML 3.2S DRAFT//EN" => 1,
4646     "-//W3C//DTD HTML 4.0 FRAMESET//EN" => 1,
4647     "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN" => 1,
4648     "-//W3C//DTD HTML EXPERIMETNAL 19960712//EN" => 1,
4649     "-//W3C//DTD HTML EXPERIMENTAL 970421//EN" => 1,
4650     "-//W3C//DTD W3 HTML//EN" => 1,
4651     "-//W3O//DTD W3 HTML 3.0//EN" => 1,
4652     "-//W3O//DTD W3 HTML 3.0//EN//" => 1,
4653     "-//W3O//DTD W3 HTML STRICT 3.0//EN//" => 1,
4654     "-//WEBTECHS//DTD MOZILLA HTML 2.0//EN" => 1,
4655     "-//WEBTECHS//DTD MOZILLA HTML//EN" => 1,
4656     "-/W3C/DTD HTML 4.0 TRANSITIONAL/EN" => 1,
4657     "HTML" => 1,
4658     }->{$pubid}) {
4659 wakaba 1.79
4660     $Whatpm::HTML::Debug::cp_pass->('t5') if $Whatpm::HTML::Debug::cp_pass;
4661     BEGIN {
4662     $Whatpm::HTML::Debug::cp->{'t5'} = 1;
4663     }
4664    
4665 wakaba 1.18 $self->{document}->manakai_compat_mode ('quirks');
4666     } elsif ($pubid eq "-//W3C//DTD HTML 4.01 FRAMESET//EN" or
4667     $pubid eq "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN") {
4668     if (defined $token->{system_identifier}) {
4669 wakaba 1.79
4670     $Whatpm::HTML::Debug::cp_pass->('t6') if $Whatpm::HTML::Debug::cp_pass;
4671     BEGIN {
4672     $Whatpm::HTML::Debug::cp->{'t6'} = 1;
4673     }
4674    
4675 wakaba 1.18 $self->{document}->manakai_compat_mode ('quirks');
4676     } else {
4677 wakaba 1.79
4678     $Whatpm::HTML::Debug::cp_pass->('t7') if $Whatpm::HTML::Debug::cp_pass;
4679     BEGIN {
4680     $Whatpm::HTML::Debug::cp->{'t7'} = 1;
4681     }
4682    
4683 wakaba 1.18 $self->{document}->manakai_compat_mode ('limited quirks');
4684 wakaba 1.3 }
4685 wakaba 1.80 } elsif ($pubid eq "-//W3C//DTD XHTML 1.0 FRAMESET//EN" or
4686     $pubid eq "-//W3C//DTD XHTML 1.0 TRANSITIONAL//EN") {
4687 wakaba 1.79
4688     $Whatpm::HTML::Debug::cp_pass->('t8') if $Whatpm::HTML::Debug::cp_pass;
4689     BEGIN {
4690     $Whatpm::HTML::Debug::cp->{'t8'} = 1;
4691     }
4692    
4693 wakaba 1.18 $self->{document}->manakai_compat_mode ('limited quirks');
4694 wakaba 1.79 } else {
4695    
4696     $Whatpm::HTML::Debug::cp_pass->('t9') if $Whatpm::HTML::Debug::cp_pass;
4697     BEGIN {
4698     $Whatpm::HTML::Debug::cp->{'t9'} = 1;
4699     }
4700    
4701 wakaba 1.18 }
4702 wakaba 1.79 } else {
4703    
4704     $Whatpm::HTML::Debug::cp_pass->('t10') if $Whatpm::HTML::Debug::cp_pass;
4705     BEGIN {
4706     $Whatpm::HTML::Debug::cp->{'t10'} = 1;
4707     }
4708    
4709 wakaba 1.18 }
4710     if (defined $token->{system_identifier}) {
4711     my $sysid = $token->{system_identifier};
4712     $sysid =~ tr/A-Z/a-z/;
4713     if ($sysid eq "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
4714 wakaba 1.80 ## TODO: Check the spec: PUBLIC "(limited quirks)" "(quirks)"
4715 wakaba 1.18 $self->{document}->manakai_compat_mode ('quirks');
4716 wakaba 1.79
4717     $Whatpm::HTML::Debug::cp_pass->('t11') if $Whatpm::HTML::Debug::cp_pass;
4718     BEGIN {
4719     $Whatpm::HTML::Debug::cp->{'t11'} = 1;
4720     }
4721    
4722     } else {
4723    
4724     $Whatpm::HTML::Debug::cp_pass->('t12') if $Whatpm::HTML::Debug::cp_pass;
4725     BEGIN {
4726     $Whatpm::HTML::Debug::cp->{'t12'} = 1;
4727     }
4728    
4729 wakaba 1.18 }
4730 wakaba 1.79 } else {
4731    
4732     $Whatpm::HTML::Debug::cp_pass->('t13') if $Whatpm::HTML::Debug::cp_pass;
4733     BEGIN {
4734     $Whatpm::HTML::Debug::cp->{'t13'} = 1;
4735     }
4736    
4737 wakaba 1.18 }
4738    
4739     ## Go to the root element phase.
4740     $token = $self->_get_next_token;
4741     return;
4742     } elsif ({
4743 wakaba 1.57 START_TAG_TOKEN, 1,
4744     END_TAG_TOKEN, 1,
4745     END_OF_FILE_TOKEN, 1,
4746 wakaba 1.18 }->{$token->{type}}) {
4747 wakaba 1.79
4748     $Whatpm::HTML::Debug::cp_pass->('t14') if $Whatpm::HTML::Debug::cp_pass;
4749     BEGIN {
4750     $Whatpm::HTML::Debug::cp->{'t14'} = 1;
4751     }
4752    
4753 wakaba 1.18 $self->{parse_error}-> (type => 'no DOCTYPE');
4754     $self->{document}->manakai_compat_mode ('quirks');
4755     ## Go to the root element phase
4756     ## reprocess
4757     return;
4758 wakaba 1.57 } elsif ($token->{type} == CHARACTER_TOKEN) {
4759 wakaba 1.18 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) { # \x0D
4760     ## Ignore the token
4761 wakaba 1.26
4762 wakaba 1.18 unless (length $token->{data}) {
4763 wakaba 1.79
4764     $Whatpm::HTML::Debug::cp_pass->('t15') if $Whatpm::HTML::Debug::cp_pass;
4765     BEGIN {
4766     $Whatpm::HTML::Debug::cp->{'t15'} = 1;
4767     }
4768    
4769 wakaba 1.18 ## Stay in the phase
4770     $token = $self->_get_next_token;
4771     redo INITIAL;
4772 wakaba 1.79 } else {
4773    
4774     $Whatpm::HTML::Debug::cp_pass->('t16') if $Whatpm::HTML::Debug::cp_pass;
4775     BEGIN {
4776     $Whatpm::HTML::Debug::cp->{'t16'} = 1;
4777     }
4778    
4779 wakaba 1.3 }
4780 wakaba 1.79 } else {
4781    
4782     $Whatpm::HTML::Debug::cp_pass->('t17') if $Whatpm::HTML::Debug::cp_pass;
4783     BEGIN {
4784     $Whatpm::HTML::Debug::cp->{'t17'} = 1;
4785     }
4786    
4787 wakaba 1.3 }
4788 wakaba 1.18
4789     $self->{parse_error}-> (type => 'no DOCTYPE');
4790     $self->{document}->manakai_compat_mode ('quirks');
4791     ## Go to the root element phase
4792     ## reprocess
4793     return;
4794 wakaba 1.57 } elsif ($token->{type} == COMMENT_TOKEN) {
4795 wakaba 1.79
4796     $Whatpm::HTML::Debug::cp_pass->('t18') if $Whatpm::HTML::Debug::cp_pass;
4797     BEGIN {
4798     $Whatpm::HTML::Debug::cp->{'t18'} = 1;
4799     }
4800    
4801 wakaba 1.18 my $comment = $self->{document}->create_comment ($token->{data});
4802     $self->{document}->append_child ($comment);
4803    
4804     ## Stay in the phase.
4805     $token = $self->_get_next_token;
4806     redo INITIAL;
4807     } else {
4808 wakaba 1.57 die "$0: $token->{type}: Unknown token type";
4809 wakaba 1.18 }
4810     } # INITIAL
4811 wakaba 1.79
4812     die "$0: _tree_construction_initial: This should be never reached";
4813 wakaba 1.3 } # _tree_construction_initial
4814    
4815     sub _tree_construction_root_element ($) {
4816     my $self = shift;
4817    
4818     B: {
4819 wakaba 1.57 if ($token->{type} == DOCTYPE_TOKEN) {
4820 wakaba 1.79
4821     $Whatpm::HTML::Debug::cp_pass->('t19') if $Whatpm::HTML::Debug::cp_pass;
4822     BEGIN {
4823     $Whatpm::HTML::Debug::cp->{'t19'} = 1;
4824     }
4825    
4826 wakaba 1.3 $self->{parse_error}-> (type => 'in html:#DOCTYPE');
4827     ## Ignore the token
4828     ## Stay in the phase
4829     $token = $self->_get_next_token;
4830     redo B;
4831 wakaba 1.57 } elsif ($token->{type} == COMMENT_TOKEN) {
4832 wakaba 1.79
4833     $Whatpm::HTML::Debug::cp_pass->('t20') if $Whatpm::HTML::Debug::cp_pass;
4834     BEGIN {
4835     $Whatpm::HTML::Debug::cp->{'t20'} = 1;
4836     }
4837    
4838 wakaba 1.3 my $comment = $self->{document}->create_comment ($token->{data});
4839     $self->{document}->append_child ($comment);
4840     ## Stay in the phase
4841     $token = $self->_get_next_token;
4842     redo B;
4843 wakaba 1.57 } elsif ($token->{type} == CHARACTER_TOKEN) {
4844 wakaba 1.26 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) { # \x0D
4845     ## Ignore the token.
4846    
4847 wakaba 1.3 unless (length $token->{data}) {
4848 wakaba 1.79
4849     $Whatpm::HTML::Debug::cp_pass->('t21') if $Whatpm::HTML::Debug::cp_pass;
4850     BEGIN {
4851     $Whatpm::HTML::Debug::cp->{'t21'} = 1;
4852     }
4853    
4854 wakaba 1.3 ## Stay in the phase
4855     $token = $self->_get_next_token;
4856     redo B;
4857 wakaba 1.79 } else {
4858    
4859     $Whatpm::HTML::Debug::cp_pass->('t22') if $Whatpm::HTML::Debug::cp_pass;
4860     BEGIN {
4861     $Whatpm::HTML::Debug::cp->{'t22'} = 1;
4862     }
4863    
4864 wakaba 1.3 }
4865 wakaba 1.79 } else {
4866    
4867     $Whatpm::HTML::Debug::cp_pass->('t23') if $Whatpm::HTML::Debug::cp_pass;
4868     BEGIN {
4869     $Whatpm::HTML::Debug::cp->{'t23'} = 1;
4870     }
4871    
4872 wakaba 1.3 }
4873 wakaba 1.63
4874     $self->{application_cache_selection}->(undef);
4875    
4876     #
4877     } elsif ($token->{type} == START_TAG_TOKEN) {
4878     if ($token->{tag_name} eq 'html' and
4879 wakaba 1.69 $token->{attributes}->{manifest}) {
4880 wakaba 1.79
4881     $Whatpm::HTML::Debug::cp_pass->('t24') if $Whatpm::HTML::Debug::cp_pass;
4882     BEGIN {
4883     $Whatpm::HTML::Debug::cp->{'t24'} = 1;
4884     }
4885    
4886 wakaba 1.63 $self->{application_cache_selection}
4887     ->($token->{attributes}->{manifest}->{value});
4888     ## ISSUE: No relative reference resolution?
4889     } else {
4890 wakaba 1.79
4891     $Whatpm::HTML::Debug::cp_pass->('t25') if $Whatpm::HTML::Debug::cp_pass;
4892     BEGIN {
4893     $Whatpm::HTML::Debug::cp->{'t25'} = 1;
4894     }
4895    
4896 wakaba 1.63 $self->{application_cache_selection}->(undef);
4897     }
4898    
4899     ## ISSUE: There is an issue in the spec
4900 wakaba 1.3 #
4901     } elsif ({
4902 wakaba 1.57 END_TAG_TOKEN, 1,
4903     END_OF_FILE_TOKEN, 1,
4904 wakaba 1.3 }->{$token->{type}}) {
4905 wakaba 1.79
4906     $Whatpm::HTML::Debug::cp_pass->('t26') if $Whatpm::HTML::Debug::cp_pass;
4907     BEGIN {
4908     $Whatpm::HTML::Debug::cp->{'t26'} = 1;
4909     }
4910    
4911 wakaba 1.63 $self->{application_cache_selection}->(undef);
4912    
4913 wakaba 1.3 ## ISSUE: There is an issue in the spec
4914     #
4915     } else {
4916 wakaba 1.57 die "$0: $token->{type}: Unknown token type";
4917 wakaba 1.3 }
4918 wakaba 1.63
4919 wakaba 1.3 my $root_element;
4920     $root_element = $self->{document}->create_element_ns
4921     (q<http://www.w3.org/1999/xhtml>, [undef, 'html']);
4922    
4923     $self->{document}->append_child ($root_element);
4924     push @{$self->{open_elements}}, [$root_element, 'html'];
4925     ## reprocess
4926     #redo B;
4927 wakaba 1.35 return; ## Go to the main phase.
4928 wakaba 1.3 } # B
4929 wakaba 1.79
4930     die "$0: _tree_construction_root_element: This should never be reached";
4931 wakaba 1.3 } # _tree_construction_root_element
4932    
4933     sub _reset_insertion_mode ($) {
4934     my $self = shift;
4935    
4936     ## Step 1
4937     my $last;
4938    
4939     ## Step 2
4940     my $i = -1;
4941     my $node = $self->{open_elements}->[$i];
4942    
4943     ## Step 3
4944     S3: {
4945 wakaba 1.29 ## ISSUE: Oops! "If node is the first node in the stack of open
4946     ## elements, then set last to true. If the context element of the
4947     ## HTML fragment parsing algorithm is neither a td element nor a
4948     ## th element, then set node to the context element. (fragment case)":
4949     ## The second "if" is in the scope of the first "if"!?
4950     if ($self->{open_elements}->[0]->[0] eq $node->[0]) {
4951     $last = 1;
4952     if (defined $self->{inner_html_node}) {
4953     if ($self->{inner_html_node}->[1] eq 'td' or
4954     $self->{inner_html_node}->[1] eq 'th') {
4955 wakaba 1.79
4956     $Whatpm::HTML::Debug::cp_pass->('t27') if $Whatpm::HTML::Debug::cp_pass;
4957     BEGIN {
4958     $Whatpm::HTML::Debug::cp->{'t27'} = 1;
4959     }
4960    
4961 wakaba 1.29 #
4962     } else {
4963 wakaba 1.79
4964     $Whatpm::HTML::Debug::cp_pass->('t28') if $Whatpm::HTML::Debug::cp_pass;
4965     BEGIN {
4966     $Whatpm::HTML::Debug::cp->{'t28'} = 1;
4967     }
4968    
4969 wakaba 1.29 $node = $self->{inner_html_node};
4970     }
4971 wakaba 1.3 }
4972     }
4973    
4974     ## Step 4..13
4975     my $new_mode = {
4976 wakaba 1.56 select => IN_SELECT_IM,
4977     td => IN_CELL_IM,
4978     th => IN_CELL_IM,
4979     tr => IN_ROW_IM,
4980     tbody => IN_TABLE_BODY_IM,
4981     thead => IN_TABLE_BODY_IM,
4982     tfoot => IN_TABLE_BODY_IM,
4983     caption => IN_CAPTION_IM,
4984     colgroup => IN_COLUMN_GROUP_IM,
4985     table => IN_TABLE_IM,
4986     head => IN_BODY_IM, # not in head!
4987     body => IN_BODY_IM,
4988     frameset => IN_FRAMESET_IM,
4989 wakaba 1.3 }->{$node->[1]};
4990     $self->{insertion_mode} = $new_mode and return if defined $new_mode;
4991    
4992     ## Step 14
4993     if ($node->[1] eq 'html') {
4994     unless (defined $self->{head_element}) {
4995 wakaba 1.79
4996     $Whatpm::HTML::Debug::cp_pass->('t29') if $Whatpm::HTML::Debug::cp_pass;
4997     BEGIN {
4998     $Whatpm::HTML::Debug::cp->{'t29'} = 1;
4999     }
5000    
5001 wakaba 1.56 $self->{insertion_mode} = BEFORE_HEAD_IM;
5002 wakaba 1.3 } else {
5003 wakaba 1.81 ## ISSUE: Can this state be reached?
5004 wakaba 1.79
5005     $Whatpm::HTML::Debug::cp_pass->('t30') if $Whatpm::HTML::Debug::cp_pass;
5006     BEGIN {
5007     $Whatpm::HTML::Debug::cp->{'t30'} = 1;
5008     }
5009    
5010 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
5011 wakaba 1.3 }
5012     return;
5013 wakaba 1.79 } else {
5014    
5015     $Whatpm::HTML::Debug::cp_pass->('t31') if $Whatpm::HTML::Debug::cp_pass;
5016     BEGIN {
5017     $Whatpm::HTML::Debug::cp->{'t31'} = 1;
5018     }
5019    
5020 wakaba 1.3 }
5021    
5022     ## Step 15
5023 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM and return if $last;
5024 wakaba 1.3
5025     ## Step 16
5026     $i--;
5027     $node = $self->{open_elements}->[$i];
5028    
5029     ## Step 17
5030     redo S3;
5031     } # S3
5032 wakaba 1.79
5033     die "$0: _reset_insertion_mode: This line should never be reached";
5034 wakaba 1.3 } # _reset_insertion_mode
5035    
5036     sub _tree_construction_main ($) {
5037     my $self = shift;
5038    
5039 wakaba 1.1 my $active_formatting_elements = [];
5040    
5041     my $reconstruct_active_formatting_elements = sub { # MUST
5042     my $insert = shift;
5043    
5044     ## Step 1
5045     return unless @$active_formatting_elements;
5046    
5047     ## Step 3
5048     my $i = -1;
5049     my $entry = $active_formatting_elements->[$i];
5050    
5051     ## Step 2
5052     return if $entry->[0] eq '#marker';
5053 wakaba 1.3 for (@{$self->{open_elements}}) {
5054 wakaba 1.1 if ($entry->[0] eq $_->[0]) {
5055 wakaba 1.79
5056     $Whatpm::HTML::Debug::cp_pass->('t32') if $Whatpm::HTML::Debug::cp_pass;
5057     BEGIN {
5058     $Whatpm::HTML::Debug::cp->{'t32'} = 1;
5059     }
5060    
5061 wakaba 1.1 return;
5062     }
5063     }
5064    
5065     S4: {
5066     ## Step 4
5067     last S4 if $active_formatting_elements->[0]->[0] eq $entry->[0];
5068    
5069     ## Step 5
5070     $i--;
5071     $entry = $active_formatting_elements->[$i];
5072    
5073     ## Step 6
5074     if ($entry->[0] eq '#marker') {
5075 wakaba 1.79
5076 wakaba 1.81 $Whatpm::HTML::Debug::cp_pass->('t33_1') if $Whatpm::HTML::Debug::cp_pass;
5077 wakaba 1.79 BEGIN {
5078 wakaba 1.81 $Whatpm::HTML::Debug::cp->{'t33_1'} = 1;
5079 wakaba 1.79 }
5080    
5081 wakaba 1.1 #
5082     } else {
5083     my $in_open_elements;
5084 wakaba 1.3 OE: for (@{$self->{open_elements}}) {
5085 wakaba 1.1 if ($entry->[0] eq $_->[0]) {
5086 wakaba 1.79
5087     $Whatpm::HTML::Debug::cp_pass->('t33') if $Whatpm::HTML::Debug::cp_pass;
5088     BEGIN {
5089     $Whatpm::HTML::Debug::cp->{'t33'} = 1;
5090     }
5091    
5092 wakaba 1.1 $in_open_elements = 1;
5093     last OE;
5094     }
5095     }
5096     if ($in_open_elements) {
5097 wakaba 1.79
5098     $Whatpm::HTML::Debug::cp_pass->('t34') if $Whatpm::HTML::Debug::cp_pass;
5099     BEGIN {
5100     $Whatpm::HTML::Debug::cp->{'t34'} = 1;
5101     }
5102    
5103 wakaba 1.1 #
5104     } else {
5105 wakaba 1.81 ## NOTE: <!DOCTYPE HTML><p><b><i><u></p> <p>X
5106 wakaba 1.79
5107     $Whatpm::HTML::Debug::cp_pass->('t35') if $Whatpm::HTML::Debug::cp_pass;
5108     BEGIN {
5109     $Whatpm::HTML::Debug::cp->{'t35'} = 1;
5110     }
5111    
5112 wakaba 1.1 redo S4;
5113     }
5114     }
5115    
5116     ## Step 7
5117     $i++;
5118     $entry = $active_formatting_elements->[$i];
5119     } # S4
5120    
5121     S7: {
5122     ## Step 8
5123     my $clone = [$entry->[0]->clone_node (0), $entry->[1]];
5124    
5125     ## Step 9
5126     $insert->($clone->[0]);
5127 wakaba 1.3 push @{$self->{open_elements}}, $clone;
5128 wakaba 1.1
5129     ## Step 10
5130 wakaba 1.3 $active_formatting_elements->[$i] = $self->{open_elements}->[-1];
5131 wakaba 1.1
5132     ## Step 11
5133     unless ($clone->[0] eq $active_formatting_elements->[-1]->[0]) {
5134 wakaba 1.79
5135     $Whatpm::HTML::Debug::cp_pass->('t36') if $Whatpm::HTML::Debug::cp_pass;
5136     BEGIN {
5137     $Whatpm::HTML::Debug::cp->{'t36'} = 1;
5138     }
5139    
5140 wakaba 1.1 ## Step 7'
5141     $i++;
5142     $entry = $active_formatting_elements->[$i];
5143    
5144     redo S7;
5145     }
5146 wakaba 1.79
5147    
5148     $Whatpm::HTML::Debug::cp_pass->('t37') if $Whatpm::HTML::Debug::cp_pass;
5149     BEGIN {
5150     $Whatpm::HTML::Debug::cp->{'t37'} = 1;
5151     }
5152    
5153 wakaba 1.1 } # S7
5154     }; # $reconstruct_active_formatting_elements
5155    
5156     my $clear_up_to_marker = sub {
5157     for (reverse 0..$#$active_formatting_elements) {
5158     if ($active_formatting_elements->[$_]->[0] eq '#marker') {
5159 wakaba 1.79
5160     $Whatpm::HTML::Debug::cp_pass->('t38') if $Whatpm::HTML::Debug::cp_pass;
5161     BEGIN {
5162     $Whatpm::HTML::Debug::cp->{'t38'} = 1;
5163     }
5164    
5165 wakaba 1.1 splice @$active_formatting_elements, $_;
5166     return;
5167     }
5168     }
5169 wakaba 1.79
5170    
5171     $Whatpm::HTML::Debug::cp_pass->('t39') if $Whatpm::HTML::Debug::cp_pass;
5172     BEGIN {
5173     $Whatpm::HTML::Debug::cp->{'t39'} = 1;
5174     }
5175    
5176 wakaba 1.1 }; # $clear_up_to_marker
5177    
5178 wakaba 1.25 my $parse_rcdata = sub ($$) {
5179     my ($content_model_flag, $insert) = @_;
5180    
5181     ## Step 1
5182     my $start_tag_name = $token->{tag_name};
5183     my $el;
5184    
5185     $el = $self->{document}->create_element_ns
5186     (q<http://www.w3.org/1999/xhtml>, [undef, $start_tag_name]);
5187 wakaba 1.1
5188 wakaba 1.6 for my $attr_name (keys %{ $token->{attributes}}) {
5189 wakaba 1.25 $el->set_attribute_ns (undef, [undef, $attr_name],
5190 wakaba 1.6 $token->{attributes} ->{$attr_name}->{value});
5191     }
5192    
5193 wakaba 1.25
5194     ## Step 2
5195     $insert->($el); # /context node/->append_child ($el)
5196    
5197     ## Step 3
5198 wakaba 1.41 $self->{content_model} = $content_model_flag; # CDATA or RCDATA
5199 wakaba 1.13 delete $self->{escape}; # MUST
5200 wakaba 1.25
5201     ## Step 4
5202 wakaba 1.1 my $text = '';
5203     $token = $self->_get_next_token;
5204 wakaba 1.57 while ($token->{type} == CHARACTER_TOKEN) { # or until stop tokenizing
5205 wakaba 1.79
5206     $Whatpm::HTML::Debug::cp_pass->('t40') if $Whatpm::HTML::Debug::cp_pass;
5207     BEGIN {
5208     $Whatpm::HTML::Debug::cp->{'t40'} = 1;
5209     }
5210    
5211 wakaba 1.1 $text .= $token->{data};
5212     $token = $self->_get_next_token;
5213 wakaba 1.25 }
5214    
5215     ## Step 5
5216 wakaba 1.1 if (length $text) {
5217 wakaba 1.79
5218     $Whatpm::HTML::Debug::cp_pass->('t41') if $Whatpm::HTML::Debug::cp_pass;
5219     BEGIN {
5220     $Whatpm::HTML::Debug::cp->{'t41'} = 1;
5221     }
5222    
5223 wakaba 1.25 my $text = $self->{document}->create_text_node ($text);
5224     $el->append_child ($text);
5225 wakaba 1.1 }
5226 wakaba 1.25
5227     ## Step 6
5228 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL;
5229 wakaba 1.25
5230     ## Step 7
5231 wakaba 1.79 if ($token->{type} == END_TAG_TOKEN and
5232     $token->{tag_name} eq $start_tag_name) {
5233    
5234     $Whatpm::HTML::Debug::cp_pass->('t42') if $Whatpm::HTML::Debug::cp_pass;
5235     BEGIN {
5236     $Whatpm::HTML::Debug::cp->{'t42'} = 1;
5237     }
5238    
5239 wakaba 1.1 ## Ignore the token
5240 wakaba 1.41 } elsif ($content_model_flag == CDATA_CONTENT_MODEL) {
5241 wakaba 1.79
5242     $Whatpm::HTML::Debug::cp_pass->('t43') if $Whatpm::HTML::Debug::cp_pass;
5243     BEGIN {
5244     $Whatpm::HTML::Debug::cp->{'t43'} = 1;
5245     }
5246    
5247 wakaba 1.41 $self->{parse_error}-> (type => 'in CDATA:#'.$token->{type});
5248     } elsif ($content_model_flag == RCDATA_CONTENT_MODEL) {
5249 wakaba 1.79
5250     $Whatpm::HTML::Debug::cp_pass->('t44') if $Whatpm::HTML::Debug::cp_pass;
5251     BEGIN {
5252     $Whatpm::HTML::Debug::cp->{'t44'} = 1;
5253     }
5254    
5255 wakaba 1.41 $self->{parse_error}-> (type => 'in RCDATA:#'.$token->{type});
5256 wakaba 1.1 } else {
5257 wakaba 1.41 die "$0: $content_model_flag in parse_rcdata";
5258 wakaba 1.1 }
5259     $token = $self->_get_next_token;
5260 wakaba 1.25 }; # $parse_rcdata
5261 wakaba 1.1
5262 wakaba 1.25 my $script_start_tag = sub ($) {
5263     my $insert = $_[0];
5264 wakaba 1.1 my $script_el;
5265    
5266     $script_el = $self->{document}->create_element_ns
5267     (q<http://www.w3.org/1999/xhtml>, [undef, 'script']);
5268    
5269     for my $attr_name (keys %{ $token->{attributes}}) {
5270     $script_el->set_attribute_ns (undef, [undef, $attr_name],
5271     $token->{attributes} ->{$attr_name}->{value});
5272     }
5273    
5274     ## TODO: mark as "parser-inserted"
5275    
5276 wakaba 1.41 $self->{content_model} = CDATA_CONTENT_MODEL;
5277 wakaba 1.13 delete $self->{escape}; # MUST
5278 wakaba 1.1
5279     my $text = '';
5280     $token = $self->_get_next_token;
5281 wakaba 1.57 while ($token->{type} == CHARACTER_TOKEN) {
5282 wakaba 1.79
5283     $Whatpm::HTML::Debug::cp_pass->('t45') if $Whatpm::HTML::Debug::cp_pass;
5284     BEGIN {
5285     $Whatpm::HTML::Debug::cp->{'t45'} = 1;
5286     }
5287    
5288 wakaba 1.1 $text .= $token->{data};
5289     $token = $self->_get_next_token;
5290     } # stop if non-character token or tokenizer stops tokenising
5291     if (length $text) {
5292 wakaba 1.79
5293     $Whatpm::HTML::Debug::cp_pass->('t46') if $Whatpm::HTML::Debug::cp_pass;
5294     BEGIN {
5295     $Whatpm::HTML::Debug::cp->{'t46'} = 1;
5296     }
5297    
5298 wakaba 1.1 $script_el->manakai_append_text ($text);
5299     }
5300    
5301 wakaba 1.41 $self->{content_model} = PCDATA_CONTENT_MODEL;
5302 wakaba 1.1
5303 wakaba 1.57 if ($token->{type} == END_TAG_TOKEN and
5304 wakaba 1.1 $token->{tag_name} eq 'script') {
5305 wakaba 1.79
5306     $Whatpm::HTML::Debug::cp_pass->('t47') if $Whatpm::HTML::Debug::cp_pass;
5307     BEGIN {
5308     $Whatpm::HTML::Debug::cp->{'t47'} = 1;
5309     }
5310    
5311 wakaba 1.1 ## Ignore the token
5312     } else {
5313 wakaba 1.79
5314     $Whatpm::HTML::Debug::cp_pass->('t48') if $Whatpm::HTML::Debug::cp_pass;
5315     BEGIN {
5316     $Whatpm::HTML::Debug::cp->{'t48'} = 1;
5317     }
5318    
5319 wakaba 1.3 $self->{parse_error}-> (type => 'in CDATA:#'.$token->{type});
5320 wakaba 1.1 ## ISSUE: And ignore?
5321     ## TODO: mark as "already executed"
5322     }
5323    
5324 wakaba 1.3 if (defined $self->{inner_html_node}) {
5325 wakaba 1.79
5326     $Whatpm::HTML::Debug::cp_pass->('t49') if $Whatpm::HTML::Debug::cp_pass;
5327     BEGIN {
5328     $Whatpm::HTML::Debug::cp->{'t49'} = 1;
5329     }
5330    
5331 wakaba 1.3 ## TODO: mark as "already executed"
5332     } else {
5333 wakaba 1.79
5334     $Whatpm::HTML::Debug::cp_pass->('t50') if $Whatpm::HTML::Debug::cp_pass;
5335     BEGIN {
5336     $Whatpm::HTML::Debug::cp->{'t50'} = 1;
5337     }
5338    
5339 wakaba 1.1 ## TODO: $old_insertion_point = current insertion point
5340     ## TODO: insertion point = just before the next input character
5341 wakaba 1.25
5342     $insert->($script_el);
5343 wakaba 1.1
5344     ## TODO: insertion point = $old_insertion_point (might be "undefined")
5345    
5346     ## TODO: if there is a script that will execute as soon as the parser resume, then...
5347     }
5348    
5349     $token = $self->_get_next_token;
5350     }; # $script_start_tag
5351    
5352     my $formatting_end_tag = sub {
5353     my $tag_name = shift;
5354    
5355     FET: {
5356     ## Step 1
5357     my $formatting_element;
5358     my $formatting_element_i_in_active;
5359     AFE: for (reverse 0..$#$active_formatting_elements) {
5360     if ($active_formatting_elements->[$_]->[1] eq $tag_name) {
5361 wakaba 1.79
5362     $Whatpm::HTML::Debug::cp_pass->('t51') if $Whatpm::HTML::Debug::cp_pass;
5363     BEGIN {
5364     $Whatpm::HTML::Debug::cp->{'t51'} = 1;
5365     }
5366    
5367 wakaba 1.1 $formatting_element = $active_formatting_elements->[$_];
5368     $formatting_element_i_in_active = $_;
5369     last AFE;
5370     } elsif ($active_formatting_elements->[$_]->[0] eq '#marker') {
5371 wakaba 1.79
5372     $Whatpm::HTML::Debug::cp_pass->('t52') if $Whatpm::HTML::Debug::cp_pass;
5373     BEGIN {
5374     $Whatpm::HTML::Debug::cp->{'t52'} = 1;
5375     }
5376    
5377 wakaba 1.1 last AFE;
5378     }
5379     } # AFE
5380     unless (defined $formatting_element) {
5381 wakaba 1.79
5382     $Whatpm::HTML::Debug::cp_pass->('t53') if $Whatpm::HTML::Debug::cp_pass;
5383     BEGIN {
5384     $Whatpm::HTML::Debug::cp->{'t53'} = 1;
5385     }
5386    
5387 wakaba 1.3 $self->{parse_error}-> (type => 'unmatched end tag:'.$tag_name);
5388 wakaba 1.1 ## Ignore the token
5389     $token = $self->_get_next_token;
5390     return;
5391     }
5392     ## has an element in scope
5393     my $in_scope = 1;
5394     my $formatting_element_i_in_open;
5395 wakaba 1.3 INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5396     my $node = $self->{open_elements}->[$_];
5397 wakaba 1.1 if ($node->[0] eq $formatting_element->[0]) {
5398     if ($in_scope) {
5399 wakaba 1.79
5400     $Whatpm::HTML::Debug::cp_pass->('t54') if $Whatpm::HTML::Debug::cp_pass;
5401     BEGIN {
5402     $Whatpm::HTML::Debug::cp->{'t54'} = 1;
5403     }
5404    
5405 wakaba 1.1 $formatting_element_i_in_open = $_;
5406     last INSCOPE;
5407     } else { # in open elements but not in scope
5408 wakaba 1.79
5409     $Whatpm::HTML::Debug::cp_pass->('t55') if $Whatpm::HTML::Debug::cp_pass;
5410     BEGIN {
5411     $Whatpm::HTML::Debug::cp->{'t55'} = 1;
5412     }
5413    
5414 wakaba 1.4 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
5415 wakaba 1.1 ## Ignore the token
5416     $token = $self->_get_next_token;
5417     return;
5418     }
5419     } elsif ({
5420     table => 1, caption => 1, td => 1, th => 1,
5421     button => 1, marquee => 1, object => 1, html => 1,
5422     }->{$node->[1]}) {
5423 wakaba 1.79
5424     $Whatpm::HTML::Debug::cp_pass->('t56') if $Whatpm::HTML::Debug::cp_pass;
5425     BEGIN {
5426     $Whatpm::HTML::Debug::cp->{'t56'} = 1;
5427     }
5428    
5429 wakaba 1.1 $in_scope = 0;
5430     }
5431     } # INSCOPE
5432     unless (defined $formatting_element_i_in_open) {
5433 wakaba 1.79
5434     $Whatpm::HTML::Debug::cp_pass->('t57') if $Whatpm::HTML::Debug::cp_pass;
5435     BEGIN {
5436     $Whatpm::HTML::Debug::cp->{'t57'} = 1;
5437     }
5438    
5439 wakaba 1.4 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
5440 wakaba 1.1 pop @$active_formatting_elements; # $formatting_element
5441     $token = $self->_get_next_token; ## TODO: ok?
5442     return;
5443     }
5444 wakaba 1.3 if (not $self->{open_elements}->[-1]->[0] eq $formatting_element->[0]) {
5445 wakaba 1.79
5446     $Whatpm::HTML::Debug::cp_pass->('t58') if $Whatpm::HTML::Debug::cp_pass;
5447     BEGIN {
5448     $Whatpm::HTML::Debug::cp->{'t58'} = 1;
5449     }
5450    
5451 wakaba 1.4 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5452 wakaba 1.1 }
5453    
5454     ## Step 2
5455     my $furthest_block;
5456     my $furthest_block_i_in_open;
5457 wakaba 1.3 OE: for (reverse 0..$#{$self->{open_elements}}) {
5458     my $node = $self->{open_elements}->[$_];
5459 wakaba 1.1 if (not $formatting_category->{$node->[1]} and
5460     #not $phrasing_category->{$node->[1]} and
5461     ($special_category->{$node->[1]} or
5462     $scoping_category->{$node->[1]})) {
5463 wakaba 1.79
5464     $Whatpm::HTML::Debug::cp_pass->('t59') if $Whatpm::HTML::Debug::cp_pass;
5465     BEGIN {
5466     $Whatpm::HTML::Debug::cp->{'t59'} = 1;
5467     }
5468    
5469 wakaba 1.1 $furthest_block = $node;
5470     $furthest_block_i_in_open = $_;
5471     } elsif ($node->[0] eq $formatting_element->[0]) {
5472 wakaba 1.79
5473     $Whatpm::HTML::Debug::cp_pass->('t60') if $Whatpm::HTML::Debug::cp_pass;
5474     BEGIN {
5475     $Whatpm::HTML::Debug::cp->{'t60'} = 1;
5476     }
5477    
5478 wakaba 1.1 last OE;
5479     }
5480     } # OE
5481    
5482     ## Step 3
5483     unless (defined $furthest_block) { # MUST
5484 wakaba 1.79
5485     $Whatpm::HTML::Debug::cp_pass->('t61') if $Whatpm::HTML::Debug::cp_pass;
5486     BEGIN {
5487     $Whatpm::HTML::Debug::cp->{'t61'} = 1;
5488     }
5489    
5490 wakaba 1.3 splice @{$self->{open_elements}}, $formatting_element_i_in_open;
5491 wakaba 1.1 splice @$active_formatting_elements, $formatting_element_i_in_active, 1;
5492     $token = $self->_get_next_token;
5493     return;
5494     }
5495    
5496     ## Step 4
5497 wakaba 1.3 my $common_ancestor_node = $self->{open_elements}->[$formatting_element_i_in_open - 1];
5498 wakaba 1.1
5499     ## Step 5
5500     my $furthest_block_parent = $furthest_block->[0]->parent_node;
5501     if (defined $furthest_block_parent) {
5502 wakaba 1.79
5503     $Whatpm::HTML::Debug::cp_pass->('t62') if $Whatpm::HTML::Debug::cp_pass;
5504     BEGIN {
5505     $Whatpm::HTML::Debug::cp->{'t62'} = 1;
5506     }
5507    
5508 wakaba 1.1 $furthest_block_parent->remove_child ($furthest_block->[0]);
5509     }
5510    
5511     ## Step 6
5512     my $bookmark_prev_el
5513     = $active_formatting_elements->[$formatting_element_i_in_active - 1]
5514     ->[0];
5515    
5516     ## Step 7
5517     my $node = $furthest_block;
5518     my $node_i_in_open = $furthest_block_i_in_open;
5519     my $last_node = $furthest_block;
5520     S7: {
5521     ## Step 1
5522     $node_i_in_open--;
5523 wakaba 1.3 $node = $self->{open_elements}->[$node_i_in_open];
5524 wakaba 1.1
5525     ## Step 2
5526     my $node_i_in_active;
5527     S7S2: {
5528     for (reverse 0..$#$active_formatting_elements) {
5529     if ($active_formatting_elements->[$_]->[0] eq $node->[0]) {
5530 wakaba 1.79
5531     $Whatpm::HTML::Debug::cp_pass->('t63') if $Whatpm::HTML::Debug::cp_pass;
5532     BEGIN {
5533     $Whatpm::HTML::Debug::cp->{'t63'} = 1;
5534     }
5535    
5536 wakaba 1.1 $node_i_in_active = $_;
5537     last S7S2;
5538     }
5539     }
5540 wakaba 1.3 splice @{$self->{open_elements}}, $node_i_in_open, 1;
5541 wakaba 1.1 redo S7;
5542     } # S7S2
5543    
5544     ## Step 3
5545     last S7 if $node->[0] eq $formatting_element->[0];
5546    
5547     ## Step 4
5548     if ($last_node->[0] eq $furthest_block->[0]) {
5549 wakaba 1.79
5550     $Whatpm::HTML::Debug::cp_pass->('t64') if $Whatpm::HTML::Debug::cp_pass;
5551     BEGIN {
5552     $Whatpm::HTML::Debug::cp->{'t64'} = 1;
5553     }
5554    
5555 wakaba 1.1 $bookmark_prev_el = $node->[0];
5556     }
5557    
5558     ## Step 5
5559     if ($node->[0]->has_child_nodes ()) {
5560 wakaba 1.79
5561     $Whatpm::HTML::Debug::cp_pass->('t65') if $Whatpm::HTML::Debug::cp_pass;
5562     BEGIN {
5563     $Whatpm::HTML::Debug::cp->{'t65'} = 1;
5564     }
5565    
5566 wakaba 1.1 my $clone = [$node->[0]->clone_node (0), $node->[1]];
5567     $active_formatting_elements->[$node_i_in_active] = $clone;
5568 wakaba 1.3 $self->{open_elements}->[$node_i_in_open] = $clone;
5569 wakaba 1.1 $node = $clone;
5570     }
5571    
5572     ## Step 6
5573     $node->[0]->append_child ($last_node->[0]);
5574    
5575     ## Step 7
5576     $last_node = $node;
5577    
5578     ## Step 8
5579     redo S7;
5580     } # S7
5581    
5582     ## Step 8
5583     $common_ancestor_node->[0]->append_child ($last_node->[0]);
5584    
5585     ## Step 9
5586     my $clone = [$formatting_element->[0]->clone_node (0),
5587     $formatting_element->[1]];
5588    
5589     ## Step 10
5590     my @cn = @{$furthest_block->[0]->child_nodes};
5591     $clone->[0]->append_child ($_) for @cn;
5592    
5593     ## Step 11
5594     $furthest_block->[0]->append_child ($clone->[0]);
5595    
5596     ## Step 12
5597     my $i;
5598     AFE: for (reverse 0..$#$active_formatting_elements) {
5599     if ($active_formatting_elements->[$_]->[0] eq $formatting_element->[0]) {
5600 wakaba 1.79
5601     $Whatpm::HTML::Debug::cp_pass->('t66') if $Whatpm::HTML::Debug::cp_pass;
5602     BEGIN {
5603     $Whatpm::HTML::Debug::cp->{'t66'} = 1;
5604     }
5605    
5606 wakaba 1.1 splice @$active_formatting_elements, $_, 1;
5607     $i-- and last AFE if defined $i;
5608     } elsif ($active_formatting_elements->[$_]->[0] eq $bookmark_prev_el) {
5609 wakaba 1.79
5610     $Whatpm::HTML::Debug::cp_pass->('t67') if $Whatpm::HTML::Debug::cp_pass;
5611     BEGIN {
5612     $Whatpm::HTML::Debug::cp->{'t67'} = 1;
5613     }
5614    
5615 wakaba 1.1 $i = $_;
5616     }
5617     } # AFE
5618     splice @$active_formatting_elements, $i + 1, 0, $clone;
5619    
5620     ## Step 13
5621     undef $i;
5622 wakaba 1.3 OE: for (reverse 0..$#{$self->{open_elements}}) {
5623     if ($self->{open_elements}->[$_]->[0] eq $formatting_element->[0]) {
5624 wakaba 1.79
5625     $Whatpm::HTML::Debug::cp_pass->('t68') if $Whatpm::HTML::Debug::cp_pass;
5626     BEGIN {
5627     $Whatpm::HTML::Debug::cp->{'t68'} = 1;
5628     }
5629    
5630 wakaba 1.3 splice @{$self->{open_elements}}, $_, 1;
5631 wakaba 1.1 $i-- and last OE if defined $i;
5632 wakaba 1.3 } elsif ($self->{open_elements}->[$_]->[0] eq $furthest_block->[0]) {
5633 wakaba 1.79
5634     $Whatpm::HTML::Debug::cp_pass->('t69') if $Whatpm::HTML::Debug::cp_pass;
5635     BEGIN {
5636     $Whatpm::HTML::Debug::cp->{'t69'} = 1;
5637     }
5638    
5639 wakaba 1.1 $i = $_;
5640     }
5641     } # OE
5642 wakaba 1.3 splice @{$self->{open_elements}}, $i + 1, 1, $clone;
5643 wakaba 1.1
5644     ## Step 14
5645     redo FET;
5646     } # FET
5647     }; # $formatting_end_tag
5648    
5649     my $insert_to_current = sub {
5650 wakaba 1.25 $self->{open_elements}->[-1]->[0]->append_child ($_[0]);
5651 wakaba 1.1 }; # $insert_to_current
5652    
5653     my $insert_to_foster = sub {
5654     my $child = shift;
5655     if ({
5656     table => 1, tbody => 1, tfoot => 1,
5657     thead => 1, tr => 1,
5658 wakaba 1.3 }->{$self->{open_elements}->[-1]->[1]}) {
5659 wakaba 1.1 # MUST
5660     my $foster_parent_element;
5661     my $next_sibling;
5662 wakaba 1.3 OE: for (reverse 0..$#{$self->{open_elements}}) {
5663     if ($self->{open_elements}->[$_]->[1] eq 'table') {
5664     my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
5665 wakaba 1.1 if (defined $parent and $parent->node_type == 1) {
5666 wakaba 1.79
5667     $Whatpm::HTML::Debug::cp_pass->('t70') if $Whatpm::HTML::Debug::cp_pass;
5668     BEGIN {
5669     $Whatpm::HTML::Debug::cp->{'t70'} = 1;
5670     }
5671    
5672 wakaba 1.1 $foster_parent_element = $parent;
5673 wakaba 1.3 $next_sibling = $self->{open_elements}->[$_]->[0];
5674 wakaba 1.1 } else {
5675 wakaba 1.79
5676     $Whatpm::HTML::Debug::cp_pass->('t71') if $Whatpm::HTML::Debug::cp_pass;
5677     BEGIN {
5678     $Whatpm::HTML::Debug::cp->{'t71'} = 1;
5679     }
5680    
5681 wakaba 1.1 $foster_parent_element
5682 wakaba 1.3 = $self->{open_elements}->[$_ - 1]->[0];
5683 wakaba 1.1 }
5684     last OE;
5685     }
5686     } # OE
5687 wakaba 1.3 $foster_parent_element = $self->{open_elements}->[0]->[0]
5688 wakaba 1.1 unless defined $foster_parent_element;
5689     $foster_parent_element->insert_before
5690     ($child, $next_sibling);
5691     } else {
5692 wakaba 1.79
5693     $Whatpm::HTML::Debug::cp_pass->('t72') if $Whatpm::HTML::Debug::cp_pass;
5694     BEGIN {
5695     $Whatpm::HTML::Debug::cp->{'t72'} = 1;
5696     }
5697    
5698 wakaba 1.3 $self->{open_elements}->[-1]->[0]->append_child ($child);
5699 wakaba 1.1 }
5700     }; # $insert_to_foster
5701    
5702 wakaba 1.54 my $insert;
5703    
5704     B: {
5705 wakaba 1.57 if ($token->{type} == DOCTYPE_TOKEN) {
5706 wakaba 1.79
5707     $Whatpm::HTML::Debug::cp_pass->('t73') if $Whatpm::HTML::Debug::cp_pass;
5708     BEGIN {
5709     $Whatpm::HTML::Debug::cp->{'t73'} = 1;
5710     }
5711    
5712 wakaba 1.54 $self->{parse_error}-> (type => 'DOCTYPE in the middle');
5713     ## Ignore the token
5714     ## Stay in the phase
5715     $token = $self->_get_next_token;
5716     redo B;
5717 wakaba 1.57 } elsif ($token->{type} == END_OF_FILE_TOKEN) {
5718 wakaba 1.58 if ($self->{insertion_mode} & AFTER_HTML_IMS) {
5719 wakaba 1.79
5720     $Whatpm::HTML::Debug::cp_pass->('t74') if $Whatpm::HTML::Debug::cp_pass;
5721     BEGIN {
5722     $Whatpm::HTML::Debug::cp->{'t74'} = 1;
5723     }
5724    
5725 wakaba 1.54 #
5726     } else {
5727     ## Generate implied end tags
5728     if ({
5729     dd => 1, dt => 1, li => 1, p => 1, td => 1, th => 1, tr => 1,
5730     tbody => 1, tfoot=> 1, thead => 1,
5731     }->{$self->{open_elements}->[-1]->[1]}) {
5732 wakaba 1.79
5733     $Whatpm::HTML::Debug::cp_pass->('t75') if $Whatpm::HTML::Debug::cp_pass;
5734     BEGIN {
5735     $Whatpm::HTML::Debug::cp->{'t75'} = 1;
5736     }
5737    
5738 wakaba 1.54 unshift @{$self->{token}}, $token;
5739 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => $self->{open_elements}->[-1]->[1]};
5740 wakaba 1.54 redo B;
5741     }
5742 wakaba 1.1
5743 wakaba 1.54 if (@{$self->{open_elements}} > 2 or
5744     (@{$self->{open_elements}} == 2 and $self->{open_elements}->[1]->[1] ne 'body')) {
5745 wakaba 1.79
5746     $Whatpm::HTML::Debug::cp_pass->('t76') if $Whatpm::HTML::Debug::cp_pass;
5747     BEGIN {
5748     $Whatpm::HTML::Debug::cp->{'t76'} = 1;
5749     }
5750    
5751 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5752     } elsif (defined $self->{inner_html_node} and
5753     @{$self->{open_elements}} > 1 and
5754     $self->{open_elements}->[1]->[1] ne 'body') {
5755 wakaba 1.81 ## ISSUE: This case is never reached.
5756 wakaba 1.79
5757     $Whatpm::HTML::Debug::cp_pass->('t77') if $Whatpm::HTML::Debug::cp_pass;
5758     BEGIN {
5759     $Whatpm::HTML::Debug::cp->{'t77'} = 1;
5760     }
5761    
5762 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5763 wakaba 1.79 } else {
5764    
5765     $Whatpm::HTML::Debug::cp_pass->('t78') if $Whatpm::HTML::Debug::cp_pass;
5766     BEGIN {
5767     $Whatpm::HTML::Debug::cp->{'t78'} = 1;
5768     }
5769    
5770 wakaba 1.54 }
5771    
5772     ## ISSUE: There is an issue in the spec.
5773     }
5774    
5775     ## Stop parsing
5776     last B;
5777 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN and
5778 wakaba 1.54 $token->{tag_name} eq 'html') {
5779 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
5780 wakaba 1.79
5781     $Whatpm::HTML::Debug::cp_pass->('t79') if $Whatpm::HTML::Debug::cp_pass;
5782     BEGIN {
5783     $Whatpm::HTML::Debug::cp->{'t79'} = 1;
5784     }
5785    
5786 wakaba 1.54 ## Turn into the main phase
5787     $self->{parse_error}-> (type => 'after html:html');
5788 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
5789     } elsif ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
5790 wakaba 1.79
5791     $Whatpm::HTML::Debug::cp_pass->('t80') if $Whatpm::HTML::Debug::cp_pass;
5792     BEGIN {
5793     $Whatpm::HTML::Debug::cp->{'t80'} = 1;
5794     }
5795    
5796 wakaba 1.54 ## Turn into the main phase
5797     $self->{parse_error}-> (type => 'after html:html');
5798 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
5799 wakaba 1.79 } else {
5800    
5801     $Whatpm::HTML::Debug::cp_pass->('t81') if $Whatpm::HTML::Debug::cp_pass;
5802     BEGIN {
5803     $Whatpm::HTML::Debug::cp->{'t81'} = 1;
5804     }
5805    
5806 wakaba 1.54 }
5807    
5808     ## ISSUE: "aa<html>" is not a parse error.
5809     ## ISSUE: "<html>" in fragment is not a parse error.
5810     unless ($token->{first_start_tag}) {
5811 wakaba 1.79
5812     $Whatpm::HTML::Debug::cp_pass->('t82') if $Whatpm::HTML::Debug::cp_pass;
5813     BEGIN {
5814     $Whatpm::HTML::Debug::cp->{'t82'} = 1;
5815     }
5816    
5817 wakaba 1.54 $self->{parse_error}-> (type => 'not first start tag');
5818 wakaba 1.79 } else {
5819    
5820     $Whatpm::HTML::Debug::cp_pass->('t83') if $Whatpm::HTML::Debug::cp_pass;
5821     BEGIN {
5822     $Whatpm::HTML::Debug::cp->{'t83'} = 1;
5823     }
5824    
5825 wakaba 1.54 }
5826     my $top_el = $self->{open_elements}->[0]->[0];
5827     for my $attr_name (keys %{$token->{attributes}}) {
5828     unless ($top_el->has_attribute_ns (undef, $attr_name)) {
5829 wakaba 1.79
5830     $Whatpm::HTML::Debug::cp_pass->('t84') if $Whatpm::HTML::Debug::cp_pass;
5831     BEGIN {
5832     $Whatpm::HTML::Debug::cp->{'t84'} = 1;
5833     }
5834    
5835 wakaba 1.54 $top_el->set_attribute_ns
5836     (undef, [undef, $attr_name],
5837     $token->{attributes}->{$attr_name}->{value});
5838     }
5839     }
5840     $token = $self->_get_next_token;
5841     redo B;
5842 wakaba 1.57 } elsif ($token->{type} == COMMENT_TOKEN) {
5843 wakaba 1.54 my $comment = $self->{document}->create_comment ($token->{data});
5844 wakaba 1.58 if ($self->{insertion_mode} & AFTER_HTML_IMS) {
5845 wakaba 1.79
5846     $Whatpm::HTML::Debug::cp_pass->('t85') if $Whatpm::HTML::Debug::cp_pass;
5847     BEGIN {
5848     $Whatpm::HTML::Debug::cp->{'t85'} = 1;
5849     }
5850    
5851 wakaba 1.54 $self->{document}->append_child ($comment);
5852 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_BODY_IM) {
5853 wakaba 1.79
5854     $Whatpm::HTML::Debug::cp_pass->('t86') if $Whatpm::HTML::Debug::cp_pass;
5855     BEGIN {
5856     $Whatpm::HTML::Debug::cp->{'t86'} = 1;
5857     }
5858    
5859 wakaba 1.54 $self->{open_elements}->[0]->[0]->append_child ($comment);
5860     } else {
5861 wakaba 1.79
5862     $Whatpm::HTML::Debug::cp_pass->('t87') if $Whatpm::HTML::Debug::cp_pass;
5863     BEGIN {
5864     $Whatpm::HTML::Debug::cp->{'t87'} = 1;
5865     }
5866    
5867 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($comment);
5868     }
5869     $token = $self->_get_next_token;
5870     redo B;
5871 wakaba 1.58 } elsif ($self->{insertion_mode} & HEAD_IMS) {
5872 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
5873 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
5874     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
5875     unless (length $token->{data}) {
5876 wakaba 1.79
5877     $Whatpm::HTML::Debug::cp_pass->('t88') if $Whatpm::HTML::Debug::cp_pass;
5878     BEGIN {
5879     $Whatpm::HTML::Debug::cp->{'t88'} = 1;
5880     }
5881    
5882 wakaba 1.54 $token = $self->_get_next_token;
5883     redo B;
5884     }
5885     }
5886    
5887 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
5888 wakaba 1.79
5889     $Whatpm::HTML::Debug::cp_pass->('t89') if $Whatpm::HTML::Debug::cp_pass;
5890     BEGIN {
5891     $Whatpm::HTML::Debug::cp->{'t89'} = 1;
5892     }
5893    
5894 wakaba 1.54 ## As if <head>
5895    
5896     $self->{head_element} = $self->{document}->create_element_ns
5897     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
5898    
5899     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
5900     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
5901    
5902     ## Reprocess in the "in head" insertion mode...
5903     pop @{$self->{open_elements}};
5904    
5905     ## Reprocess in the "after head" insertion mode...
5906 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
5907 wakaba 1.79
5908     $Whatpm::HTML::Debug::cp_pass->('t90') if $Whatpm::HTML::Debug::cp_pass;
5909     BEGIN {
5910     $Whatpm::HTML::Debug::cp->{'t90'} = 1;
5911     }
5912    
5913 wakaba 1.54 ## As if </noscript>
5914     pop @{$self->{open_elements}};
5915     $self->{parse_error}-> (type => 'in noscript:#character');
5916    
5917     ## Reprocess in the "in head" insertion mode...
5918     ## As if </head>
5919     pop @{$self->{open_elements}};
5920    
5921     ## Reprocess in the "after head" insertion mode...
5922 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
5923 wakaba 1.79
5924     $Whatpm::HTML::Debug::cp_pass->('t91') if $Whatpm::HTML::Debug::cp_pass;
5925     BEGIN {
5926     $Whatpm::HTML::Debug::cp->{'t91'} = 1;
5927     }
5928    
5929 wakaba 1.54 pop @{$self->{open_elements}};
5930    
5931     ## Reprocess in the "after head" insertion mode...
5932 wakaba 1.79 } else {
5933    
5934     $Whatpm::HTML::Debug::cp_pass->('t92') if $Whatpm::HTML::Debug::cp_pass;
5935     BEGIN {
5936     $Whatpm::HTML::Debug::cp->{'t92'} = 1;
5937     }
5938    
5939 wakaba 1.54 }
5940    
5941     ## "after head" insertion mode
5942     ## As if <body>
5943    
5944     {
5945     my $el;
5946    
5947     $el = $self->{document}->create_element_ns
5948     (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
5949    
5950     $self->{open_elements}->[-1]->[0]->append_child ($el);
5951     push @{$self->{open_elements}}, [$el, 'body'];
5952     }
5953    
5954 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
5955 wakaba 1.54 ## reprocess
5956     redo B;
5957 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
5958 wakaba 1.54 if ($token->{tag_name} eq 'head') {
5959 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
5960 wakaba 1.54
5961 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t93') if $Whatpm::HTML::Debug::cp_pass;
5962     BEGIN {
5963     $Whatpm::HTML::Debug::cp->{'t93'} = 1;
5964     }
5965    
5966    
5967 wakaba 1.54 $self->{head_element} = $self->{document}->create_element_ns
5968     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
5969    
5970     for my $attr_name (keys %{ $token->{attributes}}) {
5971     $self->{head_element}->set_attribute_ns (undef, [undef, $attr_name],
5972     $token->{attributes} ->{$attr_name}->{value});
5973     }
5974    
5975     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
5976     push @{$self->{open_elements}}, [$self->{head_element}, $token->{tag_name}];
5977 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
5978 wakaba 1.54 $token = $self->_get_next_token;
5979     redo B;
5980 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
5981 wakaba 1.79
5982     $Whatpm::HTML::Debug::cp_pass->('t94') if $Whatpm::HTML::Debug::cp_pass;
5983     BEGIN {
5984     $Whatpm::HTML::Debug::cp->{'t94'} = 1;
5985     }
5986    
5987 wakaba 1.56 #
5988     } else {
5989 wakaba 1.79
5990     $Whatpm::HTML::Debug::cp_pass->('t95') if $Whatpm::HTML::Debug::cp_pass;
5991     BEGIN {
5992     $Whatpm::HTML::Debug::cp->{'t95'} = 1;
5993     }
5994    
5995 wakaba 1.54 $self->{parse_error}-> (type => 'in head:head'); # or in head noscript
5996     ## Ignore the token
5997     $token = $self->_get_next_token;
5998     redo B;
5999     }
6000 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6001 wakaba 1.79
6002     $Whatpm::HTML::Debug::cp_pass->('t96') if $Whatpm::HTML::Debug::cp_pass;
6003     BEGIN {
6004     $Whatpm::HTML::Debug::cp->{'t96'} = 1;
6005     }
6006    
6007 wakaba 1.54 ## As if <head>
6008    
6009     $self->{head_element} = $self->{document}->create_element_ns
6010     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6011    
6012     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6013     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6014    
6015 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6016 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6017 wakaba 1.79 } else {
6018    
6019     $Whatpm::HTML::Debug::cp_pass->('t97') if $Whatpm::HTML::Debug::cp_pass;
6020     BEGIN {
6021     $Whatpm::HTML::Debug::cp->{'t97'} = 1;
6022     }
6023    
6024 wakaba 1.54 }
6025    
6026     if ($token->{tag_name} eq 'base') {
6027 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6028 wakaba 1.79
6029     $Whatpm::HTML::Debug::cp_pass->('t98') if $Whatpm::HTML::Debug::cp_pass;
6030     BEGIN {
6031     $Whatpm::HTML::Debug::cp->{'t98'} = 1;
6032     }
6033    
6034 wakaba 1.54 ## As if </noscript>
6035     pop @{$self->{open_elements}};
6036     $self->{parse_error}-> (type => 'in noscript:base');
6037    
6038 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6039 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6040 wakaba 1.79 } else {
6041    
6042     $Whatpm::HTML::Debug::cp_pass->('t99') if $Whatpm::HTML::Debug::cp_pass;
6043     BEGIN {
6044     $Whatpm::HTML::Debug::cp->{'t99'} = 1;
6045     }
6046    
6047 wakaba 1.54 }
6048    
6049     ## NOTE: There is a "as if in head" code clone.
6050 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6051 wakaba 1.79
6052     $Whatpm::HTML::Debug::cp_pass->('t100') if $Whatpm::HTML::Debug::cp_pass;
6053     BEGIN {
6054     $Whatpm::HTML::Debug::cp->{'t100'} = 1;
6055     }
6056    
6057 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6058     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6059 wakaba 1.79 } else {
6060    
6061     $Whatpm::HTML::Debug::cp_pass->('t101') if $Whatpm::HTML::Debug::cp_pass;
6062     BEGIN {
6063     $Whatpm::HTML::Debug::cp->{'t101'} = 1;
6064     }
6065    
6066 wakaba 1.54 }
6067    
6068     {
6069     my $el;
6070    
6071     $el = $self->{document}->create_element_ns
6072     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6073    
6074     for my $attr_name (keys %{ $token->{attributes}}) {
6075     $el->set_attribute_ns (undef, [undef, $attr_name],
6076     $token->{attributes} ->{$attr_name}->{value});
6077     }
6078    
6079     $self->{open_elements}->[-1]->[0]->append_child ($el);
6080     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6081     }
6082    
6083     pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6084     pop @{$self->{open_elements}}
6085 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6086 wakaba 1.54 $token = $self->_get_next_token;
6087     redo B;
6088     } elsif ($token->{tag_name} eq 'link') {
6089     ## NOTE: There is a "as if in head" code clone.
6090 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6091 wakaba 1.79
6092     $Whatpm::HTML::Debug::cp_pass->('t102') if $Whatpm::HTML::Debug::cp_pass;
6093     BEGIN {
6094     $Whatpm::HTML::Debug::cp->{'t102'} = 1;
6095     }
6096    
6097 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6098     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6099 wakaba 1.79 } else {
6100    
6101     $Whatpm::HTML::Debug::cp_pass->('t103') if $Whatpm::HTML::Debug::cp_pass;
6102     BEGIN {
6103     $Whatpm::HTML::Debug::cp->{'t103'} = 1;
6104     }
6105    
6106 wakaba 1.54 }
6107    
6108 wakaba 1.25 {
6109     my $el;
6110    
6111 wakaba 1.1 $el = $self->{document}->create_element_ns
6112     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6113    
6114 wakaba 1.25 for my $attr_name (keys %{ $token->{attributes}}) {
6115 wakaba 1.1 $el->set_attribute_ns (undef, [undef, $attr_name],
6116 wakaba 1.25 $token->{attributes} ->{$attr_name}->{value});
6117 wakaba 1.1 }
6118    
6119 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6120 wakaba 1.25 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6121     }
6122    
6123 wakaba 1.54 pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6124     pop @{$self->{open_elements}}
6125 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6126 wakaba 1.54 $token = $self->_get_next_token;
6127     redo B;
6128     } elsif ($token->{tag_name} eq 'meta') {
6129     ## NOTE: There is a "as if in head" code clone.
6130 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6131 wakaba 1.79
6132     $Whatpm::HTML::Debug::cp_pass->('t104') if $Whatpm::HTML::Debug::cp_pass;
6133     BEGIN {
6134     $Whatpm::HTML::Debug::cp->{'t104'} = 1;
6135     }
6136    
6137 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6138     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6139 wakaba 1.79 } else {
6140    
6141     $Whatpm::HTML::Debug::cp_pass->('t105') if $Whatpm::HTML::Debug::cp_pass;
6142     BEGIN {
6143     $Whatpm::HTML::Debug::cp->{'t105'} = 1;
6144     }
6145    
6146 wakaba 1.54 }
6147    
6148 wakaba 1.34 {
6149     my $el;
6150    
6151     $el = $self->{document}->create_element_ns
6152     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6153    
6154     for my $attr_name (keys %{ $token->{attributes}}) {
6155     $el->set_attribute_ns (undef, [undef, $attr_name],
6156     $token->{attributes} ->{$attr_name}->{value});
6157     }
6158    
6159 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6160 wakaba 1.34 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6161     }
6162    
6163 wakaba 1.68 my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
6164 wakaba 1.34
6165 wakaba 1.54 unless ($self->{confident}) {
6166     if ($token->{attributes}->{charset}) { ## TODO: And if supported
6167 wakaba 1.79
6168     $Whatpm::HTML::Debug::cp_pass->('t106') if $Whatpm::HTML::Debug::cp_pass;
6169     BEGIN {
6170     $Whatpm::HTML::Debug::cp->{'t106'} = 1;
6171     }
6172    
6173 wakaba 1.65 $self->{change_encoding}
6174     ->($self, $token->{attributes}->{charset}->{value});
6175 wakaba 1.68
6176     $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
6177     ->set_user_data (manakai_has_reference =>
6178     $token->{attributes}->{charset}
6179     ->{has_reference});
6180 wakaba 1.65 } elsif ($token->{attributes}->{content}) {
6181 wakaba 1.54 ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.
6182 wakaba 1.65 if ($token->{attributes}->{content}->{value}
6183 wakaba 1.71 =~ /\A[^;]*;[\x09-\x0D\x20]*[Cc][Hh][Aa][Rr][Ss][Ee][Tt]
6184     [\x09-\x0D\x20]*=
6185 wakaba 1.54 [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
6186     ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
6187 wakaba 1.79
6188     $Whatpm::HTML::Debug::cp_pass->('t107') if $Whatpm::HTML::Debug::cp_pass;
6189     BEGIN {
6190     $Whatpm::HTML::Debug::cp->{'t107'} = 1;
6191     }
6192    
6193 wakaba 1.65 $self->{change_encoding}
6194     ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);
6195 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
6196     ->set_user_data (manakai_has_reference =>
6197     $token->{attributes}->{content}
6198     ->{has_reference});
6199 wakaba 1.79 } else {
6200    
6201     $Whatpm::HTML::Debug::cp_pass->('t108') if $Whatpm::HTML::Debug::cp_pass;
6202     BEGIN {
6203     $Whatpm::HTML::Debug::cp->{'t108'} = 1;
6204     }
6205    
6206 wakaba 1.65 }
6207 wakaba 1.54 }
6208 wakaba 1.68 } else {
6209     if ($token->{attributes}->{charset}) {
6210 wakaba 1.79
6211     $Whatpm::HTML::Debug::cp_pass->('t109') if $Whatpm::HTML::Debug::cp_pass;
6212     BEGIN {
6213     $Whatpm::HTML::Debug::cp->{'t109'} = 1;
6214     }
6215    
6216 wakaba 1.68 $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
6217     ->set_user_data (manakai_has_reference =>
6218     $token->{attributes}->{charset}
6219     ->{has_reference});
6220     }
6221 wakaba 1.69 if ($token->{attributes}->{content}) {
6222 wakaba 1.79
6223     $Whatpm::HTML::Debug::cp_pass->('t110') if $Whatpm::HTML::Debug::cp_pass;
6224     BEGIN {
6225     $Whatpm::HTML::Debug::cp->{'t110'} = 1;
6226     }
6227    
6228 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
6229     ->set_user_data (manakai_has_reference =>
6230     $token->{attributes}->{content}
6231     ->{has_reference});
6232     }
6233 wakaba 1.54 }
6234 wakaba 1.34
6235 wakaba 1.54 pop @{$self->{open_elements}}
6236 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6237 wakaba 1.54 $token = $self->_get_next_token;
6238     redo B;
6239     } elsif ($token->{tag_name} eq 'title') {
6240 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6241 wakaba 1.79
6242     $Whatpm::HTML::Debug::cp_pass->('t111') if $Whatpm::HTML::Debug::cp_pass;
6243     BEGIN {
6244     $Whatpm::HTML::Debug::cp->{'t111'} = 1;
6245     }
6246    
6247 wakaba 1.54 ## As if </noscript>
6248     pop @{$self->{open_elements}};
6249     $self->{parse_error}-> (type => 'in noscript:title');
6250 wakaba 1.1
6251 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6252 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6253 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
6254 wakaba 1.79
6255     $Whatpm::HTML::Debug::cp_pass->('t112') if $Whatpm::HTML::Debug::cp_pass;
6256     BEGIN {
6257     $Whatpm::HTML::Debug::cp->{'t112'} = 1;
6258     }
6259    
6260 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6261     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6262 wakaba 1.79 } else {
6263    
6264     $Whatpm::HTML::Debug::cp_pass->('t113') if $Whatpm::HTML::Debug::cp_pass;
6265     BEGIN {
6266     $Whatpm::HTML::Debug::cp->{'t113'} = 1;
6267     }
6268    
6269 wakaba 1.54 }
6270    
6271     ## NOTE: There is a "as if in head" code clone.
6272     my $parent = defined $self->{head_element} ? $self->{head_element}
6273     : $self->{open_elements}->[-1]->[0];
6274     $parse_rcdata->(RCDATA_CONTENT_MODEL,
6275     sub { $parent->append_child ($_[0]) });
6276     pop @{$self->{open_elements}}
6277 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6278 wakaba 1.54 redo B;
6279     } elsif ($token->{tag_name} eq 'style') {
6280     ## NOTE: Or (scripting is enabled and tag_name eq 'noscript' and
6281 wakaba 1.56 ## insertion mode IN_HEAD_IM)
6282 wakaba 1.54 ## NOTE: There is a "as if in head" code clone.
6283 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6284 wakaba 1.79
6285     $Whatpm::HTML::Debug::cp_pass->('t114') if $Whatpm::HTML::Debug::cp_pass;
6286     BEGIN {
6287     $Whatpm::HTML::Debug::cp->{'t114'} = 1;
6288     }
6289    
6290 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6291     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6292 wakaba 1.79 } else {
6293    
6294     $Whatpm::HTML::Debug::cp_pass->('t115') if $Whatpm::HTML::Debug::cp_pass;
6295     BEGIN {
6296     $Whatpm::HTML::Debug::cp->{'t115'} = 1;
6297     }
6298    
6299 wakaba 1.54 }
6300     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert_to_current);
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 'noscript') {
6305 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_IM) {
6306 wakaba 1.79
6307     $Whatpm::HTML::Debug::cp_pass->('t116') if $Whatpm::HTML::Debug::cp_pass;
6308     BEGIN {
6309     $Whatpm::HTML::Debug::cp->{'t116'} = 1;
6310     }
6311    
6312 wakaba 1.54 ## NOTE: and scripting is disalbed
6313    
6314 wakaba 1.1 {
6315     my $el;
6316    
6317     $el = $self->{document}->create_element_ns
6318     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6319    
6320     for my $attr_name (keys %{ $token->{attributes}}) {
6321     $el->set_attribute_ns (undef, [undef, $attr_name],
6322     $token->{attributes} ->{$attr_name}->{value});
6323     }
6324    
6325 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6326 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6327 wakaba 1.1 }
6328    
6329 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_NOSCRIPT_IM;
6330 wakaba 1.54 $token = $self->_get_next_token;
6331     redo B;
6332 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6333 wakaba 1.79
6334     $Whatpm::HTML::Debug::cp_pass->('t117') if $Whatpm::HTML::Debug::cp_pass;
6335     BEGIN {
6336     $Whatpm::HTML::Debug::cp->{'t117'} = 1;
6337     }
6338    
6339 wakaba 1.54 $self->{parse_error}-> (type => 'in noscript:noscript');
6340     ## Ignore the token
6341     $token = $self->_get_next_token;
6342     redo B;
6343     } else {
6344 wakaba 1.79
6345     $Whatpm::HTML::Debug::cp_pass->('t118') if $Whatpm::HTML::Debug::cp_pass;
6346     BEGIN {
6347     $Whatpm::HTML::Debug::cp->{'t118'} = 1;
6348     }
6349    
6350 wakaba 1.54 #
6351     }
6352     } elsif ($token->{tag_name} eq 'script') {
6353 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6354 wakaba 1.79
6355     $Whatpm::HTML::Debug::cp_pass->('t119') if $Whatpm::HTML::Debug::cp_pass;
6356     BEGIN {
6357     $Whatpm::HTML::Debug::cp->{'t119'} = 1;
6358     }
6359    
6360 wakaba 1.54 ## As if </noscript>
6361     pop @{$self->{open_elements}};
6362     $self->{parse_error}-> (type => 'in noscript:script');
6363    
6364 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6365 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6366 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
6367 wakaba 1.79
6368     $Whatpm::HTML::Debug::cp_pass->('t120') if $Whatpm::HTML::Debug::cp_pass;
6369     BEGIN {
6370     $Whatpm::HTML::Debug::cp->{'t120'} = 1;
6371     }
6372    
6373 wakaba 1.54 $self->{parse_error}-> (type => 'after head:'.$token->{tag_name});
6374     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6375 wakaba 1.79 } else {
6376    
6377     $Whatpm::HTML::Debug::cp_pass->('t121') if $Whatpm::HTML::Debug::cp_pass;
6378     BEGIN {
6379     $Whatpm::HTML::Debug::cp->{'t121'} = 1;
6380     }
6381    
6382 wakaba 1.54 }
6383    
6384     ## NOTE: There is a "as if in head" code clone.
6385     $script_start_tag->($insert_to_current);
6386     pop @{$self->{open_elements}}
6387 wakaba 1.56 if $self->{insertion_mode} == AFTER_HEAD_IM;
6388 wakaba 1.54 redo B;
6389     } elsif ($token->{tag_name} eq 'body' or
6390     $token->{tag_name} eq 'frameset') {
6391 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6392 wakaba 1.79
6393     $Whatpm::HTML::Debug::cp_pass->('t122') if $Whatpm::HTML::Debug::cp_pass;
6394     BEGIN {
6395     $Whatpm::HTML::Debug::cp->{'t122'} = 1;
6396     }
6397    
6398 wakaba 1.54 ## As if </noscript>
6399     pop @{$self->{open_elements}};
6400     $self->{parse_error}-> (type => 'in noscript:'.$token->{tag_name});
6401    
6402     ## Reprocess in the "in head" insertion mode...
6403     ## As if </head>
6404     pop @{$self->{open_elements}};
6405    
6406     ## Reprocess in the "after head" insertion mode...
6407 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6408 wakaba 1.79
6409     $Whatpm::HTML::Debug::cp_pass->('t124') if $Whatpm::HTML::Debug::cp_pass;
6410     BEGIN {
6411     $Whatpm::HTML::Debug::cp->{'t124'} = 1;
6412     }
6413    
6414 wakaba 1.54 pop @{$self->{open_elements}};
6415    
6416     ## Reprocess in the "after head" insertion mode...
6417 wakaba 1.79 } else {
6418    
6419     $Whatpm::HTML::Debug::cp_pass->('t125') if $Whatpm::HTML::Debug::cp_pass;
6420     BEGIN {
6421     $Whatpm::HTML::Debug::cp->{'t125'} = 1;
6422     }
6423    
6424 wakaba 1.54 }
6425    
6426     ## "after head" insertion mode
6427    
6428 wakaba 1.1 {
6429     my $el;
6430    
6431     $el = $self->{document}->create_element_ns
6432     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
6433    
6434     for my $attr_name (keys %{ $token->{attributes}}) {
6435     $el->set_attribute_ns (undef, [undef, $attr_name],
6436     $token->{attributes} ->{$attr_name}->{value});
6437     }
6438    
6439 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6440 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
6441 wakaba 1.1 }
6442    
6443 wakaba 1.56 if ($token->{tag_name} eq 'body') {
6444 wakaba 1.79
6445     $Whatpm::HTML::Debug::cp_pass->('t126') if $Whatpm::HTML::Debug::cp_pass;
6446     BEGIN {
6447     $Whatpm::HTML::Debug::cp->{'t126'} = 1;
6448     }
6449    
6450 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6451     } elsif ($token->{tag_name} eq 'frameset') {
6452 wakaba 1.79
6453     $Whatpm::HTML::Debug::cp_pass->('t127') if $Whatpm::HTML::Debug::cp_pass;
6454     BEGIN {
6455     $Whatpm::HTML::Debug::cp->{'t127'} = 1;
6456     }
6457    
6458 wakaba 1.56 $self->{insertion_mode} = IN_FRAMESET_IM;
6459     } else {
6460     die "$0: tag name: $self->{tag_name}";
6461     }
6462 wakaba 1.54 $token = $self->_get_next_token;
6463     redo B;
6464     } else {
6465 wakaba 1.79
6466     $Whatpm::HTML::Debug::cp_pass->('t128') if $Whatpm::HTML::Debug::cp_pass;
6467     BEGIN {
6468     $Whatpm::HTML::Debug::cp->{'t128'} = 1;
6469     }
6470    
6471 wakaba 1.54 #
6472 wakaba 1.8 }
6473 wakaba 1.54
6474 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6475 wakaba 1.79
6476     $Whatpm::HTML::Debug::cp_pass->('t129') if $Whatpm::HTML::Debug::cp_pass;
6477     BEGIN {
6478     $Whatpm::HTML::Debug::cp->{'t129'} = 1;
6479     }
6480    
6481 wakaba 1.54 ## As if </noscript>
6482     pop @{$self->{open_elements}};
6483     $self->{parse_error}-> (type => 'in noscript:/'.$token->{tag_name});
6484    
6485     ## Reprocess in the "in head" insertion mode...
6486     ## As if </head>
6487     pop @{$self->{open_elements}};
6488    
6489     ## Reprocess in the "after head" insertion mode...
6490 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6491 wakaba 1.79
6492     $Whatpm::HTML::Debug::cp_pass->('t130') if $Whatpm::HTML::Debug::cp_pass;
6493     BEGIN {
6494     $Whatpm::HTML::Debug::cp->{'t130'} = 1;
6495     }
6496    
6497 wakaba 1.54 ## As if </head>
6498     pop @{$self->{open_elements}};
6499    
6500     ## Reprocess in the "after head" insertion mode...
6501 wakaba 1.79 } else {
6502    
6503     $Whatpm::HTML::Debug::cp_pass->('t131') if $Whatpm::HTML::Debug::cp_pass;
6504     BEGIN {
6505     $Whatpm::HTML::Debug::cp->{'t131'} = 1;
6506     }
6507    
6508 wakaba 1.54 }
6509    
6510     ## "after head" insertion mode
6511     ## As if <body>
6512    
6513 wakaba 1.1 {
6514     my $el;
6515    
6516     $el = $self->{document}->create_element_ns
6517 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
6518 wakaba 1.1
6519 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6520     push @{$self->{open_elements}}, [$el, 'body'];
6521 wakaba 1.1 }
6522    
6523 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6524 wakaba 1.54 ## reprocess
6525     redo B;
6526 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
6527 wakaba 1.54 if ($token->{tag_name} eq 'head') {
6528 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6529 wakaba 1.79
6530     $Whatpm::HTML::Debug::cp_pass->('t132') if $Whatpm::HTML::Debug::cp_pass;
6531     BEGIN {
6532     $Whatpm::HTML::Debug::cp->{'t132'} = 1;
6533     }
6534    
6535 wakaba 1.54 ## As if <head>
6536    
6537     $self->{head_element} = $self->{document}->create_element_ns
6538     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6539    
6540     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6541     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6542    
6543     ## Reprocess in the "in head" insertion mode...
6544     pop @{$self->{open_elements}};
6545 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6546 wakaba 1.54 $token = $self->_get_next_token;
6547     redo B;
6548 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6549 wakaba 1.79
6550     $Whatpm::HTML::Debug::cp_pass->('t133') if $Whatpm::HTML::Debug::cp_pass;
6551     BEGIN {
6552     $Whatpm::HTML::Debug::cp->{'t133'} = 1;
6553     }
6554    
6555 wakaba 1.54 ## As if </noscript>
6556     pop @{$self->{open_elements}};
6557     $self->{parse_error}-> (type => 'in noscript:script');
6558    
6559     ## Reprocess in the "in head" insertion mode...
6560     pop @{$self->{open_elements}};
6561 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6562 wakaba 1.54 $token = $self->_get_next_token;
6563     redo B;
6564 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6565 wakaba 1.79
6566     $Whatpm::HTML::Debug::cp_pass->('t134') if $Whatpm::HTML::Debug::cp_pass;
6567     BEGIN {
6568     $Whatpm::HTML::Debug::cp->{'t134'} = 1;
6569     }
6570    
6571 wakaba 1.54 pop @{$self->{open_elements}};
6572 wakaba 1.56 $self->{insertion_mode} = AFTER_HEAD_IM;
6573 wakaba 1.54 $token = $self->_get_next_token;
6574     redo B;
6575     } else {
6576 wakaba 1.79
6577     $Whatpm::HTML::Debug::cp_pass->('t135') if $Whatpm::HTML::Debug::cp_pass;
6578     BEGIN {
6579     $Whatpm::HTML::Debug::cp->{'t135'} = 1;
6580     }
6581    
6582 wakaba 1.54 #
6583     }
6584     } elsif ($token->{tag_name} eq 'noscript') {
6585 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6586 wakaba 1.79
6587     $Whatpm::HTML::Debug::cp_pass->('t136') if $Whatpm::HTML::Debug::cp_pass;
6588     BEGIN {
6589     $Whatpm::HTML::Debug::cp->{'t136'} = 1;
6590     }
6591    
6592 wakaba 1.54 pop @{$self->{open_elements}};
6593 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6594 wakaba 1.54 $token = $self->_get_next_token;
6595     redo B;
6596 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6597 wakaba 1.79
6598     $Whatpm::HTML::Debug::cp_pass->('t137') if $Whatpm::HTML::Debug::cp_pass;
6599     BEGIN {
6600     $Whatpm::HTML::Debug::cp->{'t137'} = 1;
6601     }
6602    
6603 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:noscript');
6604     ## Ignore the token ## ISSUE: An issue in the spec.
6605     $token = $self->_get_next_token;
6606     redo B;
6607     } else {
6608 wakaba 1.79
6609     $Whatpm::HTML::Debug::cp_pass->('t138') if $Whatpm::HTML::Debug::cp_pass;
6610     BEGIN {
6611     $Whatpm::HTML::Debug::cp->{'t138'} = 1;
6612     }
6613    
6614 wakaba 1.54 #
6615     }
6616     } elsif ({
6617     body => 1, html => 1,
6618     }->{$token->{tag_name}}) {
6619 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6620 wakaba 1.79
6621     $Whatpm::HTML::Debug::cp_pass->('t139') if $Whatpm::HTML::Debug::cp_pass;
6622     BEGIN {
6623     $Whatpm::HTML::Debug::cp->{'t139'} = 1;
6624     }
6625    
6626 wakaba 1.54 ## As if <head>
6627    
6628     $self->{head_element} = $self->{document}->create_element_ns
6629     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6630    
6631     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6632     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6633    
6634 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6635 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6636 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6637 wakaba 1.79
6638     $Whatpm::HTML::Debug::cp_pass->('t140') if $Whatpm::HTML::Debug::cp_pass;
6639     BEGIN {
6640     $Whatpm::HTML::Debug::cp->{'t140'} = 1;
6641     }
6642    
6643 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6644     ## Ignore the token
6645     $token = $self->_get_next_token;
6646     redo B;
6647 wakaba 1.79 } else {
6648    
6649     $Whatpm::HTML::Debug::cp_pass->('t141') if $Whatpm::HTML::Debug::cp_pass;
6650     BEGIN {
6651     $Whatpm::HTML::Debug::cp->{'t141'} = 1;
6652     }
6653    
6654 wakaba 1.54 }
6655    
6656     #
6657     } elsif ({
6658     p => 1, br => 1,
6659     }->{$token->{tag_name}}) {
6660 wakaba 1.56 if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6661 wakaba 1.79
6662     $Whatpm::HTML::Debug::cp_pass->('t142') if $Whatpm::HTML::Debug::cp_pass;
6663     BEGIN {
6664     $Whatpm::HTML::Debug::cp->{'t142'} = 1;
6665     }
6666    
6667 wakaba 1.54 ## As if <head>
6668    
6669     $self->{head_element} = $self->{document}->create_element_ns
6670     (q<http://www.w3.org/1999/xhtml>, [undef, 'head']);
6671    
6672     $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
6673     push @{$self->{open_elements}}, [$self->{head_element}, 'head'];
6674    
6675 wakaba 1.56 $self->{insertion_mode} = IN_HEAD_IM;
6676 wakaba 1.54 ## Reprocess in the "in head" insertion mode...
6677 wakaba 1.79 } else {
6678    
6679     $Whatpm::HTML::Debug::cp_pass->('t143') if $Whatpm::HTML::Debug::cp_pass;
6680     BEGIN {
6681     $Whatpm::HTML::Debug::cp->{'t143'} = 1;
6682     }
6683    
6684 wakaba 1.54 }
6685    
6686     #
6687     } else {
6688 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HEAD_IM) {
6689 wakaba 1.79
6690     $Whatpm::HTML::Debug::cp_pass->('t144') if $Whatpm::HTML::Debug::cp_pass;
6691     BEGIN {
6692     $Whatpm::HTML::Debug::cp->{'t144'} = 1;
6693     }
6694    
6695 wakaba 1.56 #
6696     } else {
6697 wakaba 1.79
6698     $Whatpm::HTML::Debug::cp_pass->('t145') if $Whatpm::HTML::Debug::cp_pass;
6699     BEGIN {
6700     $Whatpm::HTML::Debug::cp->{'t145'} = 1;
6701     }
6702    
6703 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6704     ## Ignore the token
6705     $token = $self->_get_next_token;
6706     redo B;
6707     }
6708     }
6709    
6710 wakaba 1.56 if ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
6711 wakaba 1.79
6712     $Whatpm::HTML::Debug::cp_pass->('t146') if $Whatpm::HTML::Debug::cp_pass;
6713     BEGIN {
6714     $Whatpm::HTML::Debug::cp->{'t146'} = 1;
6715     }
6716    
6717 wakaba 1.54 ## As if </noscript>
6718     pop @{$self->{open_elements}};
6719     $self->{parse_error}-> (type => 'in noscript:/'.$token->{tag_name});
6720    
6721     ## Reprocess in the "in head" insertion mode...
6722     ## As if </head>
6723     pop @{$self->{open_elements}};
6724    
6725     ## Reprocess in the "after head" insertion mode...
6726 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
6727 wakaba 1.79
6728     $Whatpm::HTML::Debug::cp_pass->('t147') if $Whatpm::HTML::Debug::cp_pass;
6729     BEGIN {
6730     $Whatpm::HTML::Debug::cp->{'t147'} = 1;
6731     }
6732    
6733 wakaba 1.54 ## As if </head>
6734     pop @{$self->{open_elements}};
6735    
6736     ## Reprocess in the "after head" insertion mode...
6737 wakaba 1.56 } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
6738 wakaba 1.79
6739     $Whatpm::HTML::Debug::cp_pass->('t148') if $Whatpm::HTML::Debug::cp_pass;
6740     BEGIN {
6741     $Whatpm::HTML::Debug::cp->{'t148'} = 1;
6742     }
6743    
6744 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6745     ## Ignore the token ## ISSUE: An issue in the spec.
6746     $token = $self->_get_next_token;
6747     redo B;
6748 wakaba 1.79 } else {
6749    
6750     $Whatpm::HTML::Debug::cp_pass->('t149') if $Whatpm::HTML::Debug::cp_pass;
6751     BEGIN {
6752     $Whatpm::HTML::Debug::cp->{'t149'} = 1;
6753     }
6754    
6755 wakaba 1.8 }
6756 wakaba 1.54
6757     ## "after head" insertion mode
6758     ## As if <body>
6759    
6760 wakaba 1.1 {
6761     my $el;
6762    
6763     $el = $self->{document}->create_element_ns
6764 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'body']);
6765 wakaba 1.1
6766 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
6767     push @{$self->{open_elements}}, [$el, 'body'];
6768 wakaba 1.1 }
6769    
6770 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
6771 wakaba 1.54 ## reprocess
6772     redo B;
6773     } else {
6774     die "$0: $token->{type}: Unknown token type";
6775 wakaba 1.1 }
6776 wakaba 1.54
6777     ## ISSUE: An issue in the spec.
6778 wakaba 1.58 } elsif ($self->{insertion_mode} & BODY_IMS) {
6779 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
6780 wakaba 1.79
6781     $Whatpm::HTML::Debug::cp_pass->('t150') if $Whatpm::HTML::Debug::cp_pass;
6782     BEGIN {
6783     $Whatpm::HTML::Debug::cp->{'t150'} = 1;
6784     }
6785    
6786 wakaba 1.54 ## NOTE: There is a code clone of "character in body".
6787     $reconstruct_active_formatting_elements->($insert_to_current);
6788    
6789     $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
6790    
6791     $token = $self->_get_next_token;
6792     redo B;
6793 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
6794 wakaba 1.54 if ({
6795     caption => 1, col => 1, colgroup => 1, tbody => 1,
6796     td => 1, tfoot => 1, th => 1, thead => 1, tr => 1,
6797     }->{$token->{tag_name}}) {
6798 wakaba 1.56 if ($self->{insertion_mode} == IN_CELL_IM) {
6799 wakaba 1.54 ## have an element in table scope
6800     my $tn;
6801     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6802     my $node = $self->{open_elements}->[$_];
6803     if ($node->[1] eq 'td' or $node->[1] eq 'th') {
6804 wakaba 1.79
6805     $Whatpm::HTML::Debug::cp_pass->('t151') if $Whatpm::HTML::Debug::cp_pass;
6806     BEGIN {
6807     $Whatpm::HTML::Debug::cp->{'t151'} = 1;
6808     }
6809    
6810 wakaba 1.54 $tn = $node->[1];
6811     last INSCOPE;
6812     } elsif ({
6813     table => 1, html => 1,
6814     }->{$node->[1]}) {
6815 wakaba 1.79
6816     $Whatpm::HTML::Debug::cp_pass->('t152') if $Whatpm::HTML::Debug::cp_pass;
6817     BEGIN {
6818     $Whatpm::HTML::Debug::cp->{'t152'} = 1;
6819     }
6820    
6821 wakaba 1.54 last INSCOPE;
6822     }
6823     } # INSCOPE
6824     unless (defined $tn) {
6825 wakaba 1.79
6826     $Whatpm::HTML::Debug::cp_pass->('t153') if $Whatpm::HTML::Debug::cp_pass;
6827     BEGIN {
6828     $Whatpm::HTML::Debug::cp->{'t153'} = 1;
6829     }
6830    
6831 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6832     ## Ignore the token
6833     $token = $self->_get_next_token;
6834     redo B;
6835     }
6836    
6837 wakaba 1.79
6838     $Whatpm::HTML::Debug::cp_pass->('t154') if $Whatpm::HTML::Debug::cp_pass;
6839     BEGIN {
6840     $Whatpm::HTML::Debug::cp->{'t154'} = 1;
6841     }
6842    
6843 wakaba 1.54 ## Close the cell
6844     unshift @{$self->{token}}, $token; # <?>
6845 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => $tn};
6846 wakaba 1.54 redo B;
6847 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {
6848 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:caption');
6849    
6850     ## As if </caption>
6851     ## have a table element in table scope
6852     my $i;
6853     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6854     my $node = $self->{open_elements}->[$_];
6855     if ($node->[1] eq 'caption') {
6856 wakaba 1.79
6857     $Whatpm::HTML::Debug::cp_pass->('t155') if $Whatpm::HTML::Debug::cp_pass;
6858     BEGIN {
6859     $Whatpm::HTML::Debug::cp->{'t155'} = 1;
6860     }
6861    
6862 wakaba 1.54 $i = $_;
6863     last INSCOPE;
6864     } elsif ({
6865     table => 1, html => 1,
6866     }->{$node->[1]}) {
6867 wakaba 1.79
6868     $Whatpm::HTML::Debug::cp_pass->('t156') if $Whatpm::HTML::Debug::cp_pass;
6869     BEGIN {
6870     $Whatpm::HTML::Debug::cp->{'t156'} = 1;
6871     }
6872    
6873 wakaba 1.54 last INSCOPE;
6874     }
6875     } # INSCOPE
6876     unless (defined $i) {
6877 wakaba 1.79
6878     $Whatpm::HTML::Debug::cp_pass->('t157') if $Whatpm::HTML::Debug::cp_pass;
6879     BEGIN {
6880     $Whatpm::HTML::Debug::cp->{'t157'} = 1;
6881     }
6882    
6883 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:caption');
6884     ## Ignore the token
6885     $token = $self->_get_next_token;
6886     redo B;
6887     }
6888    
6889     ## generate implied end tags
6890     if ({
6891     dd => 1, dt => 1, li => 1, p => 1,
6892     td => 1, th => 1, tr => 1,
6893     tbody => 1, tfoot=> 1, thead => 1,
6894     }->{$self->{open_elements}->[-1]->[1]}) {
6895 wakaba 1.79
6896     $Whatpm::HTML::Debug::cp_pass->('t158') if $Whatpm::HTML::Debug::cp_pass;
6897     BEGIN {
6898     $Whatpm::HTML::Debug::cp->{'t158'} = 1;
6899     }
6900    
6901 wakaba 1.54 unshift @{$self->{token}}, $token; # <?>
6902 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'caption'};
6903 wakaba 1.54 unshift @{$self->{token}}, $token;
6904 wakaba 1.57 $token = {type => END_TAG_TOKEN,
6905 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
6906     redo B;
6907     }
6908    
6909     if ($self->{open_elements}->[-1]->[1] ne 'caption') {
6910 wakaba 1.79
6911     $Whatpm::HTML::Debug::cp_pass->('t159') if $Whatpm::HTML::Debug::cp_pass;
6912     BEGIN {
6913     $Whatpm::HTML::Debug::cp->{'t159'} = 1;
6914     }
6915    
6916 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
6917 wakaba 1.79 } else {
6918    
6919     $Whatpm::HTML::Debug::cp_pass->('t160') if $Whatpm::HTML::Debug::cp_pass;
6920     BEGIN {
6921     $Whatpm::HTML::Debug::cp->{'t160'} = 1;
6922     }
6923    
6924 wakaba 1.54 }
6925    
6926     splice @{$self->{open_elements}}, $i;
6927    
6928     $clear_up_to_marker->();
6929    
6930 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
6931 wakaba 1.54
6932     ## reprocess
6933     redo B;
6934     } else {
6935 wakaba 1.79
6936     $Whatpm::HTML::Debug::cp_pass->('t161') if $Whatpm::HTML::Debug::cp_pass;
6937     BEGIN {
6938     $Whatpm::HTML::Debug::cp->{'t161'} = 1;
6939     }
6940    
6941 wakaba 1.54 #
6942     }
6943     } else {
6944 wakaba 1.79
6945     $Whatpm::HTML::Debug::cp_pass->('t162') if $Whatpm::HTML::Debug::cp_pass;
6946     BEGIN {
6947     $Whatpm::HTML::Debug::cp->{'t162'} = 1;
6948     }
6949    
6950 wakaba 1.54 #
6951     }
6952 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
6953 wakaba 1.54 if ($token->{tag_name} eq 'td' or $token->{tag_name} eq 'th') {
6954 wakaba 1.56 if ($self->{insertion_mode} == IN_CELL_IM) {
6955 wakaba 1.54 ## have an element in table scope
6956     my $i;
6957     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6958     my $node = $self->{open_elements}->[$_];
6959     if ($node->[1] eq $token->{tag_name}) {
6960 wakaba 1.79
6961     $Whatpm::HTML::Debug::cp_pass->('t163') if $Whatpm::HTML::Debug::cp_pass;
6962     BEGIN {
6963     $Whatpm::HTML::Debug::cp->{'t163'} = 1;
6964     }
6965    
6966 wakaba 1.54 $i = $_;
6967     last INSCOPE;
6968     } elsif ({
6969     table => 1, html => 1,
6970     }->{$node->[1]}) {
6971 wakaba 1.79
6972     $Whatpm::HTML::Debug::cp_pass->('t164') if $Whatpm::HTML::Debug::cp_pass;
6973     BEGIN {
6974     $Whatpm::HTML::Debug::cp->{'t164'} = 1;
6975     }
6976    
6977 wakaba 1.54 last INSCOPE;
6978     }
6979     } # INSCOPE
6980     unless (defined $i) {
6981 wakaba 1.79
6982     $Whatpm::HTML::Debug::cp_pass->('t165') if $Whatpm::HTML::Debug::cp_pass;
6983     BEGIN {
6984     $Whatpm::HTML::Debug::cp->{'t165'} = 1;
6985     }
6986    
6987 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
6988     ## Ignore the token
6989     $token = $self->_get_next_token;
6990     redo B;
6991     }
6992    
6993     ## generate implied end tags
6994     if ({
6995     dd => 1, dt => 1, li => 1, p => 1,
6996     td => ($token->{tag_name} eq 'th'),
6997     th => ($token->{tag_name} eq 'td'),
6998     tr => 1,
6999     tbody => 1, tfoot=> 1, thead => 1,
7000     }->{$self->{open_elements}->[-1]->[1]}) {
7001 wakaba 1.79
7002     $Whatpm::HTML::Debug::cp_pass->('t166') if $Whatpm::HTML::Debug::cp_pass;
7003     BEGIN {
7004     $Whatpm::HTML::Debug::cp->{'t166'} = 1;
7005     }
7006    
7007 wakaba 1.54 unshift @{$self->{token}}, $token;
7008 wakaba 1.57 $token = {type => END_TAG_TOKEN,
7009 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
7010     redo B;
7011     }
7012    
7013     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
7014 wakaba 1.79
7015     $Whatpm::HTML::Debug::cp_pass->('t167') if $Whatpm::HTML::Debug::cp_pass;
7016     BEGIN {
7017     $Whatpm::HTML::Debug::cp->{'t167'} = 1;
7018     }
7019    
7020 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7021 wakaba 1.79 } else {
7022    
7023     $Whatpm::HTML::Debug::cp_pass->('t168') if $Whatpm::HTML::Debug::cp_pass;
7024     BEGIN {
7025     $Whatpm::HTML::Debug::cp->{'t168'} = 1;
7026     }
7027    
7028 wakaba 1.54 }
7029    
7030     splice @{$self->{open_elements}}, $i;
7031    
7032     $clear_up_to_marker->();
7033    
7034 wakaba 1.56 $self->{insertion_mode} = IN_ROW_IM;
7035 wakaba 1.54
7036     $token = $self->_get_next_token;
7037     redo B;
7038 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {
7039 wakaba 1.79
7040     $Whatpm::HTML::Debug::cp_pass->('t169') if $Whatpm::HTML::Debug::cp_pass;
7041     BEGIN {
7042     $Whatpm::HTML::Debug::cp->{'t169'} = 1;
7043     }
7044    
7045 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7046     ## Ignore the token
7047     $token = $self->_get_next_token;
7048     redo B;
7049     } else {
7050 wakaba 1.79
7051     $Whatpm::HTML::Debug::cp_pass->('t170') if $Whatpm::HTML::Debug::cp_pass;
7052     BEGIN {
7053     $Whatpm::HTML::Debug::cp->{'t170'} = 1;
7054     }
7055    
7056 wakaba 1.54 #
7057     }
7058     } elsif ($token->{tag_name} eq 'caption') {
7059 wakaba 1.56 if ($self->{insertion_mode} == IN_CAPTION_IM) {
7060 wakaba 1.54 ## have a table element in table scope
7061     my $i;
7062     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7063     my $node = $self->{open_elements}->[$_];
7064     if ($node->[1] eq $token->{tag_name}) {
7065 wakaba 1.79
7066     $Whatpm::HTML::Debug::cp_pass->('t171') if $Whatpm::HTML::Debug::cp_pass;
7067     BEGIN {
7068     $Whatpm::HTML::Debug::cp->{'t171'} = 1;
7069     }
7070    
7071 wakaba 1.54 $i = $_;
7072     last INSCOPE;
7073     } elsif ({
7074     table => 1, html => 1,
7075     }->{$node->[1]}) {
7076 wakaba 1.79
7077     $Whatpm::HTML::Debug::cp_pass->('t172') if $Whatpm::HTML::Debug::cp_pass;
7078     BEGIN {
7079     $Whatpm::HTML::Debug::cp->{'t172'} = 1;
7080     }
7081    
7082 wakaba 1.54 last INSCOPE;
7083     }
7084     } # INSCOPE
7085     unless (defined $i) {
7086 wakaba 1.79
7087     $Whatpm::HTML::Debug::cp_pass->('t173') if $Whatpm::HTML::Debug::cp_pass;
7088     BEGIN {
7089     $Whatpm::HTML::Debug::cp->{'t173'} = 1;
7090     }
7091    
7092 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7093     ## Ignore the token
7094     $token = $self->_get_next_token;
7095     redo B;
7096     }
7097    
7098     ## generate implied end tags
7099     if ({
7100     dd => 1, dt => 1, li => 1, p => 1,
7101     td => 1, th => 1, tr => 1,
7102     tbody => 1, tfoot=> 1, thead => 1,
7103     }->{$self->{open_elements}->[-1]->[1]}) {
7104 wakaba 1.79
7105     $Whatpm::HTML::Debug::cp_pass->('t174') if $Whatpm::HTML::Debug::cp_pass;
7106     BEGIN {
7107     $Whatpm::HTML::Debug::cp->{'t174'} = 1;
7108     }
7109    
7110 wakaba 1.54 unshift @{$self->{token}}, $token;
7111 wakaba 1.57 $token = {type => END_TAG_TOKEN,
7112 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
7113     redo B;
7114     }
7115    
7116     if ($self->{open_elements}->[-1]->[1] ne 'caption') {
7117 wakaba 1.79
7118     $Whatpm::HTML::Debug::cp_pass->('t175') if $Whatpm::HTML::Debug::cp_pass;
7119     BEGIN {
7120     $Whatpm::HTML::Debug::cp->{'t175'} = 1;
7121     }
7122    
7123 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7124 wakaba 1.79 } else {
7125    
7126     $Whatpm::HTML::Debug::cp_pass->('t176') if $Whatpm::HTML::Debug::cp_pass;
7127     BEGIN {
7128     $Whatpm::HTML::Debug::cp->{'t176'} = 1;
7129     }
7130    
7131 wakaba 1.54 }
7132    
7133     splice @{$self->{open_elements}}, $i;
7134    
7135     $clear_up_to_marker->();
7136    
7137 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7138 wakaba 1.54
7139     $token = $self->_get_next_token;
7140     redo B;
7141 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_CELL_IM) {
7142 wakaba 1.79
7143     $Whatpm::HTML::Debug::cp_pass->('t177') if $Whatpm::HTML::Debug::cp_pass;
7144     BEGIN {
7145     $Whatpm::HTML::Debug::cp->{'t177'} = 1;
7146     }
7147    
7148 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7149     ## Ignore the token
7150     $token = $self->_get_next_token;
7151     redo B;
7152     } else {
7153 wakaba 1.79
7154     $Whatpm::HTML::Debug::cp_pass->('t178') if $Whatpm::HTML::Debug::cp_pass;
7155     BEGIN {
7156     $Whatpm::HTML::Debug::cp->{'t178'} = 1;
7157     }
7158    
7159 wakaba 1.54 #
7160 wakaba 1.1 }
7161 wakaba 1.54 } elsif ({
7162     table => 1, tbody => 1, tfoot => 1,
7163     thead => 1, tr => 1,
7164     }->{$token->{tag_name}} and
7165 wakaba 1.56 $self->{insertion_mode} == IN_CELL_IM) {
7166 wakaba 1.54 ## have an element in table scope
7167     my $i;
7168     my $tn;
7169     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7170     my $node = $self->{open_elements}->[$_];
7171     if ($node->[1] eq $token->{tag_name}) {
7172 wakaba 1.79
7173     $Whatpm::HTML::Debug::cp_pass->('t179') if $Whatpm::HTML::Debug::cp_pass;
7174     BEGIN {
7175     $Whatpm::HTML::Debug::cp->{'t179'} = 1;
7176     }
7177    
7178 wakaba 1.54 $i = $_;
7179     last INSCOPE;
7180     } elsif ($node->[1] eq 'td' or $node->[1] eq 'th') {
7181 wakaba 1.79
7182     $Whatpm::HTML::Debug::cp_pass->('t180') if $Whatpm::HTML::Debug::cp_pass;
7183     BEGIN {
7184     $Whatpm::HTML::Debug::cp->{'t180'} = 1;
7185     }
7186    
7187 wakaba 1.54 $tn = $node->[1];
7188     ## NOTE: There is exactly one |td| or |th| element
7189     ## in scope in the stack of open elements by definition.
7190     } elsif ({
7191     table => 1, html => 1,
7192     }->{$node->[1]}) {
7193 wakaba 1.79
7194     $Whatpm::HTML::Debug::cp_pass->('t181') if $Whatpm::HTML::Debug::cp_pass;
7195     BEGIN {
7196     $Whatpm::HTML::Debug::cp->{'t181'} = 1;
7197     }
7198    
7199 wakaba 1.54 last INSCOPE;
7200     }
7201     } # INSCOPE
7202     unless (defined $i) {
7203 wakaba 1.79
7204     $Whatpm::HTML::Debug::cp_pass->('t182') if $Whatpm::HTML::Debug::cp_pass;
7205     BEGIN {
7206     $Whatpm::HTML::Debug::cp->{'t182'} = 1;
7207     }
7208    
7209 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7210     ## Ignore the token
7211     $token = $self->_get_next_token;
7212     redo B;
7213 wakaba 1.79 } else {
7214    
7215     $Whatpm::HTML::Debug::cp_pass->('t183') if $Whatpm::HTML::Debug::cp_pass;
7216     BEGIN {
7217     $Whatpm::HTML::Debug::cp->{'t183'} = 1;
7218     }
7219    
7220 wakaba 1.1 }
7221    
7222 wakaba 1.54 ## Close the cell
7223     unshift @{$self->{token}}, $token; # </?>
7224 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => $tn};
7225 wakaba 1.54 redo B;
7226     } elsif ($token->{tag_name} eq 'table' and
7227 wakaba 1.56 $self->{insertion_mode} == IN_CAPTION_IM) {
7228 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:caption');
7229 wakaba 1.31
7230 wakaba 1.54 ## As if </caption>
7231     ## have a table element in table scope
7232     my $i;
7233     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7234     my $node = $self->{open_elements}->[$_];
7235     if ($node->[1] eq 'caption') {
7236 wakaba 1.79
7237     $Whatpm::HTML::Debug::cp_pass->('t184') if $Whatpm::HTML::Debug::cp_pass;
7238     BEGIN {
7239     $Whatpm::HTML::Debug::cp->{'t184'} = 1;
7240     }
7241    
7242 wakaba 1.54 $i = $_;
7243     last INSCOPE;
7244     } elsif ({
7245     table => 1, html => 1,
7246     }->{$node->[1]}) {
7247 wakaba 1.79
7248     $Whatpm::HTML::Debug::cp_pass->('t185') if $Whatpm::HTML::Debug::cp_pass;
7249     BEGIN {
7250     $Whatpm::HTML::Debug::cp->{'t185'} = 1;
7251     }
7252    
7253 wakaba 1.54 last INSCOPE;
7254     }
7255     } # INSCOPE
7256     unless (defined $i) {
7257 wakaba 1.79
7258     $Whatpm::HTML::Debug::cp_pass->('t186') if $Whatpm::HTML::Debug::cp_pass;
7259     BEGIN {
7260     $Whatpm::HTML::Debug::cp->{'t186'} = 1;
7261     }
7262    
7263 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:caption');
7264     ## Ignore the token
7265     $token = $self->_get_next_token;
7266     redo B;
7267     }
7268    
7269     ## generate implied end tags
7270     if ({
7271     dd => 1, dt => 1, li => 1, p => 1,
7272     td => 1, th => 1, tr => 1,
7273     tbody => 1, tfoot=> 1, thead => 1,
7274     }->{$self->{open_elements}->[-1]->[1]}) {
7275 wakaba 1.79
7276     $Whatpm::HTML::Debug::cp_pass->('t187') if $Whatpm::HTML::Debug::cp_pass;
7277     BEGIN {
7278     $Whatpm::HTML::Debug::cp->{'t187'} = 1;
7279     }
7280    
7281 wakaba 1.54 unshift @{$self->{token}}, $token; # </table>
7282 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'caption'};
7283 wakaba 1.54 unshift @{$self->{token}}, $token;
7284 wakaba 1.57 $token = {type => END_TAG_TOKEN,
7285 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
7286     redo B;
7287     }
7288 wakaba 1.20
7289 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] ne 'caption') {
7290 wakaba 1.79
7291     $Whatpm::HTML::Debug::cp_pass->('t188') if $Whatpm::HTML::Debug::cp_pass;
7292     BEGIN {
7293     $Whatpm::HTML::Debug::cp->{'t188'} = 1;
7294     }
7295    
7296 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7297 wakaba 1.79 } else {
7298    
7299     $Whatpm::HTML::Debug::cp_pass->('t189') if $Whatpm::HTML::Debug::cp_pass;
7300     BEGIN {
7301     $Whatpm::HTML::Debug::cp->{'t189'} = 1;
7302     }
7303    
7304 wakaba 1.54 }
7305 wakaba 1.12
7306 wakaba 1.54 splice @{$self->{open_elements}}, $i;
7307 wakaba 1.31
7308 wakaba 1.54 $clear_up_to_marker->();
7309 wakaba 1.1
7310 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7311 wakaba 1.3
7312 wakaba 1.54 ## reprocess
7313     redo B;
7314     } elsif ({
7315     body => 1, col => 1, colgroup => 1, html => 1,
7316     }->{$token->{tag_name}}) {
7317 wakaba 1.58 if ($self->{insertion_mode} & BODY_TABLE_IMS) {
7318 wakaba 1.79
7319     $Whatpm::HTML::Debug::cp_pass->('t190') if $Whatpm::HTML::Debug::cp_pass;
7320     BEGIN {
7321     $Whatpm::HTML::Debug::cp->{'t190'} = 1;
7322     }
7323    
7324 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7325     ## Ignore the token
7326     $token = $self->_get_next_token;
7327     redo B;
7328     } else {
7329 wakaba 1.79
7330     $Whatpm::HTML::Debug::cp_pass->('t191') if $Whatpm::HTML::Debug::cp_pass;
7331     BEGIN {
7332     $Whatpm::HTML::Debug::cp->{'t191'} = 1;
7333     }
7334    
7335 wakaba 1.54 #
7336     }
7337     } elsif ({
7338     tbody => 1, tfoot => 1,
7339     thead => 1, tr => 1,
7340     }->{$token->{tag_name}} and
7341 wakaba 1.56 $self->{insertion_mode} == IN_CAPTION_IM) {
7342 wakaba 1.79
7343     $Whatpm::HTML::Debug::cp_pass->('t192') if $Whatpm::HTML::Debug::cp_pass;
7344     BEGIN {
7345     $Whatpm::HTML::Debug::cp->{'t192'} = 1;
7346     }
7347    
7348 wakaba 1.25 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7349 wakaba 1.1 ## Ignore the token
7350     $token = $self->_get_next_token;
7351 wakaba 1.54 redo B;
7352     } else {
7353 wakaba 1.79
7354     $Whatpm::HTML::Debug::cp_pass->('t193') if $Whatpm::HTML::Debug::cp_pass;
7355     BEGIN {
7356     $Whatpm::HTML::Debug::cp->{'t193'} = 1;
7357     }
7358    
7359 wakaba 1.54 #
7360 wakaba 1.1 }
7361 wakaba 1.54 } else {
7362     die "$0: $token->{type}: Unknown token type";
7363 wakaba 1.1 }
7364    
7365 wakaba 1.54 $insert = $insert_to_current;
7366     #
7367 wakaba 1.58 } elsif ($self->{insertion_mode} & TABLE_IMS) {
7368 wakaba 1.60 if ($token->{type} == CHARACTER_TOKEN) {
7369 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
7370     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
7371    
7372     unless (length $token->{data}) {
7373 wakaba 1.79
7374     $Whatpm::HTML::Debug::cp_pass->('t194') if $Whatpm::HTML::Debug::cp_pass;
7375     BEGIN {
7376     $Whatpm::HTML::Debug::cp->{'t194'} = 1;
7377     }
7378    
7379 wakaba 1.54 $token = $self->_get_next_token;
7380     redo B;
7381 wakaba 1.79 } else {
7382    
7383     $Whatpm::HTML::Debug::cp_pass->('t195') if $Whatpm::HTML::Debug::cp_pass;
7384     BEGIN {
7385     $Whatpm::HTML::Debug::cp->{'t195'} = 1;
7386     }
7387    
7388 wakaba 1.54 }
7389     }
7390 wakaba 1.1
7391 wakaba 1.54 $self->{parse_error}-> (type => 'in table:#character');
7392 wakaba 1.1
7393 wakaba 1.54 ## As if in body, but insert into foster parent element
7394     ## ISSUE: Spec says that "whenever a node would be inserted
7395     ## into the current node" while characters might not be
7396     ## result in a new Text node.
7397     $reconstruct_active_formatting_elements->($insert_to_foster);
7398    
7399     if ({
7400     table => 1, tbody => 1, tfoot => 1,
7401     thead => 1, tr => 1,
7402     }->{$self->{open_elements}->[-1]->[1]}) {
7403     # MUST
7404     my $foster_parent_element;
7405     my $next_sibling;
7406     my $prev_sibling;
7407     OE: for (reverse 0..$#{$self->{open_elements}}) {
7408     if ($self->{open_elements}->[$_]->[1] eq 'table') {
7409     my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
7410     if (defined $parent and $parent->node_type == 1) {
7411 wakaba 1.79
7412     $Whatpm::HTML::Debug::cp_pass->('t196') if $Whatpm::HTML::Debug::cp_pass;
7413     BEGIN {
7414     $Whatpm::HTML::Debug::cp->{'t196'} = 1;
7415     }
7416    
7417 wakaba 1.54 $foster_parent_element = $parent;
7418     $next_sibling = $self->{open_elements}->[$_]->[0];
7419     $prev_sibling = $next_sibling->previous_sibling;
7420     } else {
7421 wakaba 1.79
7422     $Whatpm::HTML::Debug::cp_pass->('t197') if $Whatpm::HTML::Debug::cp_pass;
7423     BEGIN {
7424     $Whatpm::HTML::Debug::cp->{'t197'} = 1;
7425     }
7426    
7427 wakaba 1.54 $foster_parent_element = $self->{open_elements}->[$_ - 1]->[0];
7428     $prev_sibling = $foster_parent_element->last_child;
7429     }
7430     last OE;
7431     }
7432     } # OE
7433     $foster_parent_element = $self->{open_elements}->[0]->[0] and
7434     $prev_sibling = $foster_parent_element->last_child
7435     unless defined $foster_parent_element;
7436     if (defined $prev_sibling and
7437     $prev_sibling->node_type == 3) {
7438 wakaba 1.79
7439     $Whatpm::HTML::Debug::cp_pass->('t198') if $Whatpm::HTML::Debug::cp_pass;
7440     BEGIN {
7441     $Whatpm::HTML::Debug::cp->{'t198'} = 1;
7442     }
7443    
7444 wakaba 1.54 $prev_sibling->manakai_append_text ($token->{data});
7445     } else {
7446 wakaba 1.79
7447     $Whatpm::HTML::Debug::cp_pass->('t199') if $Whatpm::HTML::Debug::cp_pass;
7448     BEGIN {
7449     $Whatpm::HTML::Debug::cp->{'t199'} = 1;
7450     }
7451    
7452 wakaba 1.54 $foster_parent_element->insert_before
7453     ($self->{document}->create_text_node ($token->{data}),
7454     $next_sibling);
7455     }
7456     } else {
7457 wakaba 1.79
7458     $Whatpm::HTML::Debug::cp_pass->('t200') if $Whatpm::HTML::Debug::cp_pass;
7459     BEGIN {
7460     $Whatpm::HTML::Debug::cp->{'t200'} = 1;
7461     }
7462    
7463 wakaba 1.54 $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
7464     }
7465    
7466 wakaba 1.52 $token = $self->_get_next_token;
7467 wakaba 1.1 redo B;
7468 wakaba 1.60 } elsif ($token->{type} == START_TAG_TOKEN) {
7469 wakaba 1.54 if ({
7470 wakaba 1.56 tr => ($self->{insertion_mode} != IN_ROW_IM),
7471 wakaba 1.54 th => 1, td => 1,
7472     }->{$token->{tag_name}}) {
7473 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_IM) {
7474 wakaba 1.54 ## Clear back to table context
7475     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7476     $self->{open_elements}->[-1]->[1] ne 'html') {
7477 wakaba 1.79
7478     $Whatpm::HTML::Debug::cp_pass->('t201') if $Whatpm::HTML::Debug::cp_pass;
7479     BEGIN {
7480     $Whatpm::HTML::Debug::cp->{'t201'} = 1;
7481     }
7482    
7483 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7484     pop @{$self->{open_elements}};
7485     }
7486    
7487    
7488     {
7489     my $el;
7490    
7491     $el = $self->{document}->create_element_ns
7492     (q<http://www.w3.org/1999/xhtml>, [undef, 'tbody']);
7493    
7494     $self->{open_elements}->[-1]->[0]->append_child ($el);
7495     push @{$self->{open_elements}}, [$el, 'tbody'];
7496     }
7497    
7498 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
7499 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
7500     }
7501    
7502 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
7503 wakaba 1.54 unless ($token->{tag_name} eq 'tr') {
7504 wakaba 1.79
7505     $Whatpm::HTML::Debug::cp_pass->('t202') if $Whatpm::HTML::Debug::cp_pass;
7506     BEGIN {
7507     $Whatpm::HTML::Debug::cp->{'t202'} = 1;
7508     }
7509    
7510 wakaba 1.54 $self->{parse_error}-> (type => 'missing start tag:tr');
7511     }
7512    
7513     ## Clear back to table body context
7514     while (not {
7515     tbody => 1, tfoot => 1, thead => 1, html => 1,
7516     }->{$self->{open_elements}->[-1]->[1]}) {
7517 wakaba 1.79
7518     $Whatpm::HTML::Debug::cp_pass->('t203') if $Whatpm::HTML::Debug::cp_pass;
7519     BEGIN {
7520     $Whatpm::HTML::Debug::cp->{'t203'} = 1;
7521     }
7522    
7523 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7524     pop @{$self->{open_elements}};
7525     }
7526    
7527 wakaba 1.56 $self->{insertion_mode} = IN_ROW_IM;
7528 wakaba 1.54 if ($token->{tag_name} eq 'tr') {
7529    
7530 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t204') if $Whatpm::HTML::Debug::cp_pass;
7531     BEGIN {
7532     $Whatpm::HTML::Debug::cp->{'t204'} = 1;
7533     }
7534    
7535    
7536 wakaba 1.54 {
7537     my $el;
7538    
7539     $el = $self->{document}->create_element_ns
7540     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7541    
7542     for my $attr_name (keys %{ $token->{attributes}}) {
7543     $el->set_attribute_ns (undef, [undef, $attr_name],
7544     $token->{attributes} ->{$attr_name}->{value});
7545 wakaba 1.1 }
7546 wakaba 1.54
7547     $self->{open_elements}->[-1]->[0]->append_child ($el);
7548     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7549     }
7550    
7551     $token = $self->_get_next_token;
7552     redo B;
7553     } else {
7554    
7555 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t205') if $Whatpm::HTML::Debug::cp_pass;
7556     BEGIN {
7557     $Whatpm::HTML::Debug::cp->{'t205'} = 1;
7558     }
7559    
7560    
7561 wakaba 1.54 {
7562     my $el;
7563    
7564     $el = $self->{document}->create_element_ns
7565     (q<http://www.w3.org/1999/xhtml>, [undef, 'tr']);
7566    
7567     $self->{open_elements}->[-1]->[0]->append_child ($el);
7568     push @{$self->{open_elements}}, [$el, 'tr'];
7569     }
7570    
7571     ## reprocess in the "in row" insertion mode
7572     }
7573 wakaba 1.79 } else {
7574    
7575     $Whatpm::HTML::Debug::cp_pass->('t206') if $Whatpm::HTML::Debug::cp_pass;
7576     BEGIN {
7577     $Whatpm::HTML::Debug::cp->{'t206'} = 1;
7578     }
7579    
7580 wakaba 1.54 }
7581 wakaba 1.52
7582 wakaba 1.54 ## Clear back to table row context
7583     while (not {
7584     tr => 1, html => 1,
7585     }->{$self->{open_elements}->[-1]->[1]}) {
7586 wakaba 1.79
7587     $Whatpm::HTML::Debug::cp_pass->('t207') if $Whatpm::HTML::Debug::cp_pass;
7588     BEGIN {
7589     $Whatpm::HTML::Debug::cp->{'t207'} = 1;
7590     }
7591    
7592 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7593     pop @{$self->{open_elements}};
7594     }
7595    
7596    
7597     {
7598     my $el;
7599    
7600     $el = $self->{document}->create_element_ns
7601     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7602 wakaba 1.1
7603 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
7604     $el->set_attribute_ns (undef, [undef, $attr_name],
7605     $token->{attributes} ->{$attr_name}->{value});
7606     }
7607    
7608     $self->{open_elements}->[-1]->[0]->append_child ($el);
7609     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7610     }
7611    
7612 wakaba 1.56 $self->{insertion_mode} = IN_CELL_IM;
7613 wakaba 1.54
7614     push @$active_formatting_elements, ['#marker', ''];
7615    
7616     $token = $self->_get_next_token;
7617     redo B;
7618     } elsif ({
7619     caption => 1, col => 1, colgroup => 1,
7620     tbody => 1, tfoot => 1, thead => 1,
7621 wakaba 1.56 tr => 1, # $self->{insertion_mode} == IN_ROW_IM
7622 wakaba 1.54 }->{$token->{tag_name}}) {
7623 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
7624 wakaba 1.54 ## As if </tr>
7625     ## have an element in table scope
7626     my $i;
7627     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7628     my $node = $self->{open_elements}->[$_];
7629     if ($node->[1] eq 'tr') {
7630 wakaba 1.79
7631     $Whatpm::HTML::Debug::cp_pass->('t208') if $Whatpm::HTML::Debug::cp_pass;
7632     BEGIN {
7633     $Whatpm::HTML::Debug::cp->{'t208'} = 1;
7634     }
7635    
7636 wakaba 1.54 $i = $_;
7637     last INSCOPE;
7638     } elsif ({
7639     table => 1, html => 1,
7640     }->{$node->[1]}) {
7641 wakaba 1.79
7642     $Whatpm::HTML::Debug::cp_pass->('t209') if $Whatpm::HTML::Debug::cp_pass;
7643     BEGIN {
7644     $Whatpm::HTML::Debug::cp->{'t209'} = 1;
7645     }
7646    
7647 wakaba 1.54 last INSCOPE;
7648     }
7649     } # INSCOPE
7650 wakaba 1.79 unless (defined $i) {
7651    
7652     $Whatpm::HTML::Debug::cp_pass->('t210') if $Whatpm::HTML::Debug::cp_pass;
7653     BEGIN {
7654     $Whatpm::HTML::Debug::cp->{'t210'} = 1;
7655     }
7656    
7657     $self->{parse_error}-> (type => 'unmacthed end tag:'.$token->{tag_name});
7658 wakaba 1.54 ## Ignore the token
7659     $token = $self->_get_next_token;
7660     redo B;
7661     }
7662    
7663     ## Clear back to table row context
7664     while (not {
7665     tr => 1, html => 1,
7666     }->{$self->{open_elements}->[-1]->[1]}) {
7667 wakaba 1.79
7668     $Whatpm::HTML::Debug::cp_pass->('t211') if $Whatpm::HTML::Debug::cp_pass;
7669     BEGIN {
7670     $Whatpm::HTML::Debug::cp->{'t211'} = 1;
7671     }
7672    
7673 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7674     pop @{$self->{open_elements}};
7675     }
7676    
7677     pop @{$self->{open_elements}}; # tr
7678 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
7679 wakaba 1.54 if ($token->{tag_name} eq 'tr') {
7680 wakaba 1.79
7681     $Whatpm::HTML::Debug::cp_pass->('t212') if $Whatpm::HTML::Debug::cp_pass;
7682     BEGIN {
7683     $Whatpm::HTML::Debug::cp->{'t212'} = 1;
7684     }
7685    
7686 wakaba 1.54 ## reprocess
7687     redo B;
7688     } else {
7689 wakaba 1.79
7690     $Whatpm::HTML::Debug::cp_pass->('t213') if $Whatpm::HTML::Debug::cp_pass;
7691     BEGIN {
7692     $Whatpm::HTML::Debug::cp->{'t213'} = 1;
7693     }
7694    
7695 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
7696     }
7697     }
7698 wakaba 1.52
7699 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
7700 wakaba 1.54 ## have an element in table scope
7701     my $i;
7702     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7703     my $node = $self->{open_elements}->[$_];
7704     if ({
7705     tbody => 1, thead => 1, tfoot => 1,
7706     }->{$node->[1]}) {
7707 wakaba 1.79
7708     $Whatpm::HTML::Debug::cp_pass->('t214') if $Whatpm::HTML::Debug::cp_pass;
7709     BEGIN {
7710     $Whatpm::HTML::Debug::cp->{'t214'} = 1;
7711     }
7712    
7713 wakaba 1.54 $i = $_;
7714     last INSCOPE;
7715     } elsif ({
7716     table => 1, html => 1,
7717     }->{$node->[1]}) {
7718 wakaba 1.79
7719     $Whatpm::HTML::Debug::cp_pass->('t215') if $Whatpm::HTML::Debug::cp_pass;
7720     BEGIN {
7721     $Whatpm::HTML::Debug::cp->{'t215'} = 1;
7722     }
7723    
7724 wakaba 1.54 last INSCOPE;
7725     }
7726     } # INSCOPE
7727     unless (defined $i) {
7728 wakaba 1.79
7729     $Whatpm::HTML::Debug::cp_pass->('t216') if $Whatpm::HTML::Debug::cp_pass;
7730     BEGIN {
7731     $Whatpm::HTML::Debug::cp->{'t216'} = 1;
7732     }
7733    
7734 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7735     ## Ignore the token
7736     $token = $self->_get_next_token;
7737     redo B;
7738     }
7739 wakaba 1.52
7740 wakaba 1.54 ## Clear back to table body context
7741     while (not {
7742     tbody => 1, tfoot => 1, thead => 1, html => 1,
7743     }->{$self->{open_elements}->[-1]->[1]}) {
7744 wakaba 1.79
7745     $Whatpm::HTML::Debug::cp_pass->('t217') if $Whatpm::HTML::Debug::cp_pass;
7746     BEGIN {
7747     $Whatpm::HTML::Debug::cp->{'t217'} = 1;
7748     }
7749    
7750 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7751     pop @{$self->{open_elements}};
7752     }
7753    
7754     ## As if <{current node}>
7755     ## have an element in table scope
7756     ## true by definition
7757    
7758     ## Clear back to table body context
7759     ## nop by definition
7760    
7761     pop @{$self->{open_elements}};
7762 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
7763 wakaba 1.54 ## reprocess in "in table" insertion mode...
7764 wakaba 1.79 } else {
7765    
7766     $Whatpm::HTML::Debug::cp_pass->('t218') if $Whatpm::HTML::Debug::cp_pass;
7767     BEGIN {
7768     $Whatpm::HTML::Debug::cp->{'t218'} = 1;
7769     }
7770    
7771 wakaba 1.54 }
7772 wakaba 1.51
7773 wakaba 1.54 if ($token->{tag_name} eq 'col') {
7774     ## Clear back to table context
7775     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7776     $self->{open_elements}->[-1]->[1] ne 'html') {
7777 wakaba 1.79
7778     $Whatpm::HTML::Debug::cp_pass->('t219') if $Whatpm::HTML::Debug::cp_pass;
7779     BEGIN {
7780     $Whatpm::HTML::Debug::cp->{'t219'} = 1;
7781     }
7782    
7783 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7784     pop @{$self->{open_elements}};
7785     }
7786    
7787    
7788 wakaba 1.51 {
7789     my $el;
7790    
7791     $el = $self->{document}->create_element_ns
7792 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'colgroup']);
7793 wakaba 1.51
7794     $self->{open_elements}->[-1]->[0]->append_child ($el);
7795 wakaba 1.54 push @{$self->{open_elements}}, [$el, 'colgroup'];
7796 wakaba 1.51 }
7797    
7798 wakaba 1.56 $self->{insertion_mode} = IN_COLUMN_GROUP_IM;
7799 wakaba 1.54 ## reprocess
7800     redo B;
7801     } elsif ({
7802     caption => 1,
7803     colgroup => 1,
7804     tbody => 1, tfoot => 1, thead => 1,
7805     }->{$token->{tag_name}}) {
7806     ## Clear back to table context
7807     while ($self->{open_elements}->[-1]->[1] ne 'table' and
7808     $self->{open_elements}->[-1]->[1] ne 'html') {
7809 wakaba 1.79
7810     $Whatpm::HTML::Debug::cp_pass->('t220') if $Whatpm::HTML::Debug::cp_pass;
7811     BEGIN {
7812     $Whatpm::HTML::Debug::cp->{'t220'} = 1;
7813     }
7814    
7815 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7816     pop @{$self->{open_elements}};
7817     }
7818    
7819     push @$active_formatting_elements, ['#marker', '']
7820     if $token->{tag_name} eq 'caption';
7821    
7822 wakaba 1.52
7823 wakaba 1.54 {
7824     my $el;
7825    
7826     $el = $self->{document}->create_element_ns
7827 wakaba 1.52 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
7828    
7829 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
7830     $el->set_attribute_ns (undef, [undef, $attr_name],
7831     $token->{attributes} ->{$attr_name}->{value});
7832 wakaba 1.52 }
7833    
7834 wakaba 1.54 $self->{open_elements}->[-1]->[0]->append_child ($el);
7835     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
7836     }
7837    
7838     $self->{insertion_mode} = {
7839 wakaba 1.56 caption => IN_CAPTION_IM,
7840     colgroup => IN_COLUMN_GROUP_IM,
7841     tbody => IN_TABLE_BODY_IM,
7842     tfoot => IN_TABLE_BODY_IM,
7843     thead => IN_TABLE_BODY_IM,
7844 wakaba 1.54 }->{$token->{tag_name}};
7845 wakaba 1.52 $token = $self->_get_next_token;
7846     redo B;
7847 wakaba 1.54 } else {
7848     die "$0: in table: <>: $token->{tag_name}";
7849     }
7850     } elsif ($token->{tag_name} eq 'table') {
7851     $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7852    
7853     ## As if </table>
7854     ## have a table element in table scope
7855     my $i;
7856     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7857     my $node = $self->{open_elements}->[$_];
7858     if ($node->[1] eq 'table') {
7859 wakaba 1.79
7860     $Whatpm::HTML::Debug::cp_pass->('t221') if $Whatpm::HTML::Debug::cp_pass;
7861     BEGIN {
7862     $Whatpm::HTML::Debug::cp->{'t221'} = 1;
7863     }
7864    
7865 wakaba 1.54 $i = $_;
7866     last INSCOPE;
7867     } elsif ({
7868     table => 1, html => 1,
7869     }->{$node->[1]}) {
7870 wakaba 1.79
7871     $Whatpm::HTML::Debug::cp_pass->('t222') if $Whatpm::HTML::Debug::cp_pass;
7872     BEGIN {
7873     $Whatpm::HTML::Debug::cp->{'t222'} = 1;
7874     }
7875    
7876 wakaba 1.54 last INSCOPE;
7877     }
7878     } # INSCOPE
7879     unless (defined $i) {
7880 wakaba 1.79
7881     $Whatpm::HTML::Debug::cp_pass->('t223') if $Whatpm::HTML::Debug::cp_pass;
7882     BEGIN {
7883     $Whatpm::HTML::Debug::cp->{'t223'} = 1;
7884     }
7885    
7886 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:table');
7887     ## Ignore tokens </table><table>
7888 wakaba 1.52 $token = $self->_get_next_token;
7889     redo B;
7890     }
7891    
7892 wakaba 1.54 ## generate implied end tags
7893     if ({
7894     dd => 1, dt => 1, li => 1, p => 1,
7895     td => 1, th => 1, tr => 1,
7896     tbody => 1, tfoot=> 1, thead => 1,
7897     }->{$self->{open_elements}->[-1]->[1]}) {
7898 wakaba 1.79
7899     $Whatpm::HTML::Debug::cp_pass->('t224') if $Whatpm::HTML::Debug::cp_pass;
7900     BEGIN {
7901     $Whatpm::HTML::Debug::cp->{'t224'} = 1;
7902     }
7903    
7904 wakaba 1.54 unshift @{$self->{token}}, $token; # <table>
7905 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'table'};
7906 wakaba 1.54 unshift @{$self->{token}}, $token;
7907 wakaba 1.57 $token = {type => END_TAG_TOKEN,
7908 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
7909     redo B;
7910     }
7911    
7912     if ($self->{open_elements}->[-1]->[1] ne 'table') {
7913 wakaba 1.79
7914     $Whatpm::HTML::Debug::cp_pass->('t225') if $Whatpm::HTML::Debug::cp_pass;
7915     BEGIN {
7916     $Whatpm::HTML::Debug::cp->{'t225'} = 1;
7917     }
7918    
7919 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
7920 wakaba 1.79 } else {
7921    
7922     $Whatpm::HTML::Debug::cp_pass->('t226') if $Whatpm::HTML::Debug::cp_pass;
7923     BEGIN {
7924     $Whatpm::HTML::Debug::cp->{'t226'} = 1;
7925     }
7926    
7927 wakaba 1.54 }
7928    
7929     splice @{$self->{open_elements}}, $i;
7930    
7931     $self->_reset_insertion_mode;
7932 wakaba 1.52
7933 wakaba 1.54 ## reprocess
7934     redo B;
7935 wakaba 1.60 } else {
7936 wakaba 1.79
7937     $Whatpm::HTML::Debug::cp_pass->('t227') if $Whatpm::HTML::Debug::cp_pass;
7938     BEGIN {
7939     $Whatpm::HTML::Debug::cp->{'t227'} = 1;
7940     }
7941    
7942 wakaba 1.60 $self->{parse_error}-> (type => 'in table:'.$token->{tag_name});
7943    
7944     $insert = $insert_to_foster;
7945     #
7946     }
7947     } elsif ($token->{type} == END_TAG_TOKEN) {
7948 wakaba 1.54 if ($token->{tag_name} eq 'tr' and
7949 wakaba 1.56 $self->{insertion_mode} == IN_ROW_IM) {
7950 wakaba 1.54 ## have an element in table scope
7951     my $i;
7952     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
7953     my $node = $self->{open_elements}->[$_];
7954     if ($node->[1] eq $token->{tag_name}) {
7955 wakaba 1.79
7956     $Whatpm::HTML::Debug::cp_pass->('t228') if $Whatpm::HTML::Debug::cp_pass;
7957     BEGIN {
7958     $Whatpm::HTML::Debug::cp->{'t228'} = 1;
7959     }
7960    
7961 wakaba 1.54 $i = $_;
7962     last INSCOPE;
7963     } elsif ({
7964     table => 1, html => 1,
7965     }->{$node->[1]}) {
7966 wakaba 1.79
7967     $Whatpm::HTML::Debug::cp_pass->('t229') if $Whatpm::HTML::Debug::cp_pass;
7968     BEGIN {
7969     $Whatpm::HTML::Debug::cp->{'t229'} = 1;
7970     }
7971    
7972 wakaba 1.54 last INSCOPE;
7973     }
7974     } # INSCOPE
7975     unless (defined $i) {
7976 wakaba 1.79
7977     $Whatpm::HTML::Debug::cp_pass->('t230') if $Whatpm::HTML::Debug::cp_pass;
7978     BEGIN {
7979     $Whatpm::HTML::Debug::cp->{'t230'} = 1;
7980     }
7981    
7982 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
7983     ## Ignore the token
7984     $token = $self->_get_next_token;
7985     redo B;
7986 wakaba 1.79 } else {
7987    
7988     $Whatpm::HTML::Debug::cp_pass->('t232') if $Whatpm::HTML::Debug::cp_pass;
7989     BEGIN {
7990     $Whatpm::HTML::Debug::cp->{'t232'} = 1;
7991     }
7992    
7993 wakaba 1.54 }
7994    
7995     ## Clear back to table row context
7996     while (not {
7997     tr => 1, html => 1,
7998     }->{$self->{open_elements}->[-1]->[1]}) {
7999 wakaba 1.79
8000     $Whatpm::HTML::Debug::cp_pass->('t231') if $Whatpm::HTML::Debug::cp_pass;
8001     BEGIN {
8002     $Whatpm::HTML::Debug::cp->{'t231'} = 1;
8003     }
8004    
8005 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8006     pop @{$self->{open_elements}};
8007     }
8008    
8009     pop @{$self->{open_elements}}; # tr
8010 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8011 wakaba 1.54 $token = $self->_get_next_token;
8012     redo B;
8013     } elsif ($token->{tag_name} eq 'table') {
8014 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
8015 wakaba 1.54 ## As if </tr>
8016     ## have an element in table scope
8017     my $i;
8018     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8019     my $node = $self->{open_elements}->[$_];
8020     if ($node->[1] eq 'tr') {
8021 wakaba 1.79
8022     $Whatpm::HTML::Debug::cp_pass->('t233') if $Whatpm::HTML::Debug::cp_pass;
8023     BEGIN {
8024     $Whatpm::HTML::Debug::cp->{'t233'} = 1;
8025     }
8026    
8027 wakaba 1.54 $i = $_;
8028     last INSCOPE;
8029     } elsif ({
8030     table => 1, html => 1,
8031     }->{$node->[1]}) {
8032 wakaba 1.79
8033     $Whatpm::HTML::Debug::cp_pass->('t234') if $Whatpm::HTML::Debug::cp_pass;
8034     BEGIN {
8035     $Whatpm::HTML::Debug::cp->{'t234'} = 1;
8036     }
8037    
8038 wakaba 1.54 last INSCOPE;
8039     }
8040     } # INSCOPE
8041     unless (defined $i) {
8042 wakaba 1.79
8043     $Whatpm::HTML::Debug::cp_pass->('t235') if $Whatpm::HTML::Debug::cp_pass;
8044     BEGIN {
8045     $Whatpm::HTML::Debug::cp->{'t235'} = 1;
8046     }
8047    
8048 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{type});
8049     ## Ignore the token
8050     $token = $self->_get_next_token;
8051     redo B;
8052     }
8053    
8054     ## Clear back to table row context
8055     while (not {
8056     tr => 1, html => 1,
8057     }->{$self->{open_elements}->[-1]->[1]}) {
8058 wakaba 1.79
8059     $Whatpm::HTML::Debug::cp_pass->('t236') if $Whatpm::HTML::Debug::cp_pass;
8060     BEGIN {
8061     $Whatpm::HTML::Debug::cp->{'t236'} = 1;
8062     }
8063    
8064 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8065     pop @{$self->{open_elements}};
8066     }
8067    
8068     pop @{$self->{open_elements}}; # tr
8069 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8070 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
8071     }
8072    
8073 wakaba 1.56 if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
8074 wakaba 1.54 ## have an element in table scope
8075     my $i;
8076     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8077     my $node = $self->{open_elements}->[$_];
8078     if ({
8079     tbody => 1, thead => 1, tfoot => 1,
8080     }->{$node->[1]}) {
8081 wakaba 1.79
8082     $Whatpm::HTML::Debug::cp_pass->('t237') if $Whatpm::HTML::Debug::cp_pass;
8083     BEGIN {
8084     $Whatpm::HTML::Debug::cp->{'t237'} = 1;
8085     }
8086    
8087 wakaba 1.54 $i = $_;
8088     last INSCOPE;
8089     } elsif ({
8090     table => 1, html => 1,
8091     }->{$node->[1]}) {
8092 wakaba 1.79
8093     $Whatpm::HTML::Debug::cp_pass->('t238') if $Whatpm::HTML::Debug::cp_pass;
8094     BEGIN {
8095     $Whatpm::HTML::Debug::cp->{'t238'} = 1;
8096     }
8097    
8098 wakaba 1.54 last INSCOPE;
8099     }
8100     } # INSCOPE
8101     unless (defined $i) {
8102 wakaba 1.79
8103     $Whatpm::HTML::Debug::cp_pass->('t239') if $Whatpm::HTML::Debug::cp_pass;
8104     BEGIN {
8105     $Whatpm::HTML::Debug::cp->{'t239'} = 1;
8106     }
8107    
8108 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8109     ## Ignore the token
8110     $token = $self->_get_next_token;
8111     redo B;
8112     }
8113    
8114     ## Clear back to table body context
8115     while (not {
8116     tbody => 1, tfoot => 1, thead => 1, html => 1,
8117     }->{$self->{open_elements}->[-1]->[1]}) {
8118 wakaba 1.79
8119     $Whatpm::HTML::Debug::cp_pass->('t240') if $Whatpm::HTML::Debug::cp_pass;
8120     BEGIN {
8121     $Whatpm::HTML::Debug::cp->{'t240'} = 1;
8122     }
8123    
8124 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8125     pop @{$self->{open_elements}};
8126     }
8127    
8128     ## As if <{current node}>
8129     ## have an element in table scope
8130     ## true by definition
8131    
8132     ## Clear back to table body context
8133     ## nop by definition
8134    
8135     pop @{$self->{open_elements}};
8136 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8137 wakaba 1.54 ## reprocess in the "in table" insertion mode...
8138     }
8139 wakaba 1.52
8140 wakaba 1.54 ## have a table element in table scope
8141     my $i;
8142     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8143     my $node = $self->{open_elements}->[$_];
8144     if ($node->[1] eq $token->{tag_name}) {
8145 wakaba 1.79
8146     $Whatpm::HTML::Debug::cp_pass->('t241') if $Whatpm::HTML::Debug::cp_pass;
8147     BEGIN {
8148     $Whatpm::HTML::Debug::cp->{'t241'} = 1;
8149     }
8150    
8151 wakaba 1.54 $i = $_;
8152     last INSCOPE;
8153     } elsif ({
8154     table => 1, html => 1,
8155     }->{$node->[1]}) {
8156 wakaba 1.79
8157     $Whatpm::HTML::Debug::cp_pass->('t242') if $Whatpm::HTML::Debug::cp_pass;
8158     BEGIN {
8159     $Whatpm::HTML::Debug::cp->{'t242'} = 1;
8160     }
8161    
8162 wakaba 1.54 last INSCOPE;
8163     }
8164     } # INSCOPE
8165     unless (defined $i) {
8166 wakaba 1.79
8167     $Whatpm::HTML::Debug::cp_pass->('t243') if $Whatpm::HTML::Debug::cp_pass;
8168     BEGIN {
8169     $Whatpm::HTML::Debug::cp->{'t243'} = 1;
8170     }
8171    
8172 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8173     ## Ignore the token
8174     $token = $self->_get_next_token;
8175     redo B;
8176 wakaba 1.51 }
8177    
8178 wakaba 1.54 ## generate implied end tags
8179     if ({
8180     dd => 1, dt => 1, li => 1, p => 1,
8181     td => 1, th => 1, tr => 1,
8182     tbody => 1, tfoot=> 1, thead => 1,
8183     }->{$self->{open_elements}->[-1]->[1]}) {
8184 wakaba 1.79
8185     $Whatpm::HTML::Debug::cp_pass->('t244') if $Whatpm::HTML::Debug::cp_pass;
8186     BEGIN {
8187     $Whatpm::HTML::Debug::cp->{'t244'} = 1;
8188     }
8189    
8190 wakaba 1.54 unshift @{$self->{token}}, $token;
8191 wakaba 1.57 $token = {type => END_TAG_TOKEN,
8192 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
8193     redo B;
8194 wakaba 1.51 }
8195    
8196 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] ne 'table') {
8197 wakaba 1.79
8198     $Whatpm::HTML::Debug::cp_pass->('t245') if $Whatpm::HTML::Debug::cp_pass;
8199     BEGIN {
8200     $Whatpm::HTML::Debug::cp->{'t245'} = 1;
8201     }
8202    
8203 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8204 wakaba 1.79 } else {
8205    
8206     $Whatpm::HTML::Debug::cp_pass->('t246') if $Whatpm::HTML::Debug::cp_pass;
8207     BEGIN {
8208     $Whatpm::HTML::Debug::cp->{'t246'} = 1;
8209     }
8210    
8211     }
8212 wakaba 1.54
8213     splice @{$self->{open_elements}}, $i;
8214    
8215     $self->_reset_insertion_mode;
8216 wakaba 1.1
8217     $token = $self->_get_next_token;
8218 wakaba 1.25 redo B;
8219 wakaba 1.54 } elsif ({
8220     tbody => 1, tfoot => 1, thead => 1,
8221     }->{$token->{tag_name}} and
8222 wakaba 1.58 $self->{insertion_mode} & ROW_IMS) {
8223 wakaba 1.56 if ($self->{insertion_mode} == IN_ROW_IM) {
8224 wakaba 1.54 ## have an element in table scope
8225     my $i;
8226     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8227     my $node = $self->{open_elements}->[$_];
8228     if ($node->[1] eq $token->{tag_name}) {
8229 wakaba 1.79
8230     $Whatpm::HTML::Debug::cp_pass->('t247') if $Whatpm::HTML::Debug::cp_pass;
8231     BEGIN {
8232     $Whatpm::HTML::Debug::cp->{'t247'} = 1;
8233     }
8234    
8235 wakaba 1.54 $i = $_;
8236     last INSCOPE;
8237     } elsif ({
8238     table => 1, html => 1,
8239     }->{$node->[1]}) {
8240 wakaba 1.79
8241     $Whatpm::HTML::Debug::cp_pass->('t248') if $Whatpm::HTML::Debug::cp_pass;
8242     BEGIN {
8243     $Whatpm::HTML::Debug::cp->{'t248'} = 1;
8244     }
8245    
8246 wakaba 1.54 last INSCOPE;
8247     }
8248     } # INSCOPE
8249     unless (defined $i) {
8250 wakaba 1.79
8251     $Whatpm::HTML::Debug::cp_pass->('t249') if $Whatpm::HTML::Debug::cp_pass;
8252     BEGIN {
8253     $Whatpm::HTML::Debug::cp->{'t249'} = 1;
8254     }
8255    
8256 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8257     ## Ignore the token
8258     $token = $self->_get_next_token;
8259     redo B;
8260     }
8261    
8262     ## As if </tr>
8263     ## have an element in table scope
8264     my $i;
8265     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8266     my $node = $self->{open_elements}->[$_];
8267     if ($node->[1] eq 'tr') {
8268 wakaba 1.79
8269     $Whatpm::HTML::Debug::cp_pass->('t250') if $Whatpm::HTML::Debug::cp_pass;
8270     BEGIN {
8271     $Whatpm::HTML::Debug::cp->{'t250'} = 1;
8272     }
8273    
8274 wakaba 1.54 $i = $_;
8275     last INSCOPE;
8276     } elsif ({
8277     table => 1, html => 1,
8278     }->{$node->[1]}) {
8279 wakaba 1.79
8280     $Whatpm::HTML::Debug::cp_pass->('t251') if $Whatpm::HTML::Debug::cp_pass;
8281     BEGIN {
8282     $Whatpm::HTML::Debug::cp->{'t251'} = 1;
8283     }
8284    
8285 wakaba 1.54 last INSCOPE;
8286     }
8287     } # INSCOPE
8288     unless (defined $i) {
8289 wakaba 1.79
8290     $Whatpm::HTML::Debug::cp_pass->('t252') if $Whatpm::HTML::Debug::cp_pass;
8291     BEGIN {
8292     $Whatpm::HTML::Debug::cp->{'t252'} = 1;
8293     }
8294    
8295 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:tr');
8296     ## Ignore the token
8297     $token = $self->_get_next_token;
8298     redo B;
8299     }
8300    
8301     ## Clear back to table row context
8302     while (not {
8303     tr => 1, html => 1,
8304     }->{$self->{open_elements}->[-1]->[1]}) {
8305 wakaba 1.79
8306     $Whatpm::HTML::Debug::cp_pass->('t253') if $Whatpm::HTML::Debug::cp_pass;
8307     BEGIN {
8308     $Whatpm::HTML::Debug::cp->{'t253'} = 1;
8309     }
8310    
8311 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8312     pop @{$self->{open_elements}};
8313     }
8314    
8315     pop @{$self->{open_elements}}; # tr
8316 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_BODY_IM;
8317 wakaba 1.54 ## reprocess in the "in table body" insertion mode...
8318 wakaba 1.34 }
8319    
8320 wakaba 1.54 ## have an element in table scope
8321     my $i;
8322     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8323     my $node = $self->{open_elements}->[$_];
8324     if ($node->[1] eq $token->{tag_name}) {
8325 wakaba 1.79
8326     $Whatpm::HTML::Debug::cp_pass->('t254') if $Whatpm::HTML::Debug::cp_pass;
8327     BEGIN {
8328     $Whatpm::HTML::Debug::cp->{'t254'} = 1;
8329     }
8330    
8331 wakaba 1.54 $i = $_;
8332     last INSCOPE;
8333     } elsif ({
8334     table => 1, html => 1,
8335     }->{$node->[1]}) {
8336 wakaba 1.79
8337     $Whatpm::HTML::Debug::cp_pass->('t255') if $Whatpm::HTML::Debug::cp_pass;
8338     BEGIN {
8339     $Whatpm::HTML::Debug::cp->{'t255'} = 1;
8340     }
8341    
8342 wakaba 1.54 last INSCOPE;
8343 wakaba 1.34 }
8344 wakaba 1.54 } # INSCOPE
8345     unless (defined $i) {
8346 wakaba 1.79
8347     $Whatpm::HTML::Debug::cp_pass->('t256') if $Whatpm::HTML::Debug::cp_pass;
8348     BEGIN {
8349     $Whatpm::HTML::Debug::cp->{'t256'} = 1;
8350     }
8351    
8352 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8353     ## Ignore the token
8354     $token = $self->_get_next_token;
8355     redo B;
8356 wakaba 1.34 }
8357    
8358 wakaba 1.54 ## Clear back to table body context
8359     while (not {
8360     tbody => 1, tfoot => 1, thead => 1, html => 1,
8361     }->{$self->{open_elements}->[-1]->[1]}) {
8362 wakaba 1.79
8363     $Whatpm::HTML::Debug::cp_pass->('t257') if $Whatpm::HTML::Debug::cp_pass;
8364     BEGIN {
8365     $Whatpm::HTML::Debug::cp->{'t257'} = 1;
8366     }
8367    
8368 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
8369 wakaba 1.51 pop @{$self->{open_elements}};
8370 wakaba 1.25 }
8371 wakaba 1.51
8372 wakaba 1.54 pop @{$self->{open_elements}};
8373 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8374 wakaba 1.54 $token = $self->_get_next_token;
8375     redo B;
8376     } elsif ({
8377     body => 1, caption => 1, col => 1, colgroup => 1,
8378     html => 1, td => 1, th => 1,
8379 wakaba 1.56 tr => 1, # $self->{insertion_mode} == IN_ROW_IM
8380     tbody => 1, tfoot => 1, thead => 1, # $self->{insertion_mode} == IN_TABLE_IM
8381 wakaba 1.54 }->{$token->{tag_name}}) {
8382 wakaba 1.79
8383     $Whatpm::HTML::Debug::cp_pass->('t258') if $Whatpm::HTML::Debug::cp_pass;
8384     BEGIN {
8385     $Whatpm::HTML::Debug::cp->{'t258'} = 1;
8386     }
8387    
8388 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8389     ## Ignore the token
8390     $token = $self->_get_next_token;
8391 wakaba 1.1 redo B;
8392 wakaba 1.60 } else {
8393 wakaba 1.79
8394     $Whatpm::HTML::Debug::cp_pass->('t259') if $Whatpm::HTML::Debug::cp_pass;
8395     BEGIN {
8396     $Whatpm::HTML::Debug::cp->{'t259'} = 1;
8397     }
8398    
8399 wakaba 1.60 $self->{parse_error}-> (type => 'in table:/'.$token->{tag_name});
8400 wakaba 1.54
8401 wakaba 1.60 $insert = $insert_to_foster;
8402     #
8403     }
8404     } else {
8405     die "$0: $token->{type}: Unknown token type";
8406     }
8407 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_COLUMN_GROUP_IM) {
8408 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
8409 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
8410     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
8411     unless (length $token->{data}) {
8412 wakaba 1.79
8413     $Whatpm::HTML::Debug::cp_pass->('t260') if $Whatpm::HTML::Debug::cp_pass;
8414     BEGIN {
8415     $Whatpm::HTML::Debug::cp->{'t260'} = 1;
8416     }
8417    
8418 wakaba 1.54 $token = $self->_get_next_token;
8419     redo B;
8420 wakaba 1.25 }
8421 wakaba 1.54 }
8422    
8423 wakaba 1.79
8424     $Whatpm::HTML::Debug::cp_pass->('t261') if $Whatpm::HTML::Debug::cp_pass;
8425     BEGIN {
8426     $Whatpm::HTML::Debug::cp->{'t261'} = 1;
8427     }
8428    
8429 wakaba 1.54 #
8430 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
8431 wakaba 1.54 if ($token->{tag_name} eq 'col') {
8432    
8433 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t262') if $Whatpm::HTML::Debug::cp_pass;
8434     BEGIN {
8435     $Whatpm::HTML::Debug::cp->{'t262'} = 1;
8436     }
8437    
8438    
8439 wakaba 1.25 {
8440     my $el;
8441    
8442 wakaba 1.1 $el = $self->{document}->create_element_ns
8443     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8444    
8445 wakaba 1.25 for my $attr_name (keys %{ $token->{attributes}}) {
8446 wakaba 1.1 $el->set_attribute_ns (undef, [undef, $attr_name],
8447 wakaba 1.25 $token->{attributes} ->{$attr_name}->{value});
8448 wakaba 1.1 }
8449    
8450 wakaba 1.25 $self->{open_elements}->[-1]->[0]->append_child ($el);
8451     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8452     }
8453    
8454 wakaba 1.54 pop @{$self->{open_elements}};
8455     $token = $self->_get_next_token;
8456     redo B;
8457     } else {
8458 wakaba 1.79
8459     $Whatpm::HTML::Debug::cp_pass->('t263') if $Whatpm::HTML::Debug::cp_pass;
8460     BEGIN {
8461     $Whatpm::HTML::Debug::cp->{'t263'} = 1;
8462     }
8463    
8464 wakaba 1.54 #
8465     }
8466 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
8467 wakaba 1.54 if ($token->{tag_name} eq 'colgroup') {
8468     if ($self->{open_elements}->[-1]->[1] eq 'html') {
8469 wakaba 1.79
8470     $Whatpm::HTML::Debug::cp_pass->('t264') if $Whatpm::HTML::Debug::cp_pass;
8471     BEGIN {
8472     $Whatpm::HTML::Debug::cp->{'t264'} = 1;
8473     }
8474    
8475 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:colgroup');
8476 wakaba 1.25 ## Ignore the token
8477 wakaba 1.42 $token = $self->_get_next_token;
8478 wakaba 1.25 redo B;
8479 wakaba 1.24 } else {
8480 wakaba 1.79
8481     $Whatpm::HTML::Debug::cp_pass->('t265') if $Whatpm::HTML::Debug::cp_pass;
8482     BEGIN {
8483     $Whatpm::HTML::Debug::cp->{'t265'} = 1;
8484     }
8485    
8486 wakaba 1.54 pop @{$self->{open_elements}}; # colgroup
8487 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8488 wakaba 1.54 $token = $self->_get_next_token;
8489     redo B;
8490 wakaba 1.25 }
8491 wakaba 1.54 } elsif ($token->{tag_name} eq 'col') {
8492 wakaba 1.79
8493     $Whatpm::HTML::Debug::cp_pass->('t266') if $Whatpm::HTML::Debug::cp_pass;
8494     BEGIN {
8495     $Whatpm::HTML::Debug::cp->{'t266'} = 1;
8496     }
8497    
8498 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:col');
8499     ## Ignore the token
8500     $token = $self->_get_next_token;
8501     redo B;
8502     } else {
8503 wakaba 1.79
8504     $Whatpm::HTML::Debug::cp_pass->('t267') if $Whatpm::HTML::Debug::cp_pass;
8505     BEGIN {
8506     $Whatpm::HTML::Debug::cp->{'t267'} = 1;
8507     }
8508    
8509 wakaba 1.54 #
8510     }
8511     } else {
8512 wakaba 1.79
8513     $Whatpm::HTML::Debug::cp_pass->('t268') if $Whatpm::HTML::Debug::cp_pass;
8514     BEGIN {
8515     $Whatpm::HTML::Debug::cp->{'t268'} = 1;
8516     }
8517    
8518 wakaba 1.54 #
8519     }
8520 wakaba 1.51
8521 wakaba 1.54 ## As if </colgroup>
8522     if ($self->{open_elements}->[-1]->[1] eq 'html') {
8523 wakaba 1.79
8524     $Whatpm::HTML::Debug::cp_pass->('t269') if $Whatpm::HTML::Debug::cp_pass;
8525     BEGIN {
8526     $Whatpm::HTML::Debug::cp->{'t269'} = 1;
8527     }
8528    
8529 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:colgroup');
8530     ## Ignore the token
8531     $token = $self->_get_next_token;
8532     redo B;
8533     } else {
8534 wakaba 1.79
8535     $Whatpm::HTML::Debug::cp_pass->('t270') if $Whatpm::HTML::Debug::cp_pass;
8536     BEGIN {
8537     $Whatpm::HTML::Debug::cp->{'t270'} = 1;
8538     }
8539    
8540 wakaba 1.54 pop @{$self->{open_elements}}; # colgroup
8541 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
8542 wakaba 1.54 ## reprocess
8543     redo B;
8544     }
8545 wakaba 1.56 } elsif ($self->{insertion_mode} == IN_SELECT_IM) {
8546 wakaba 1.60 if ($token->{type} == CHARACTER_TOKEN) {
8547 wakaba 1.79
8548     $Whatpm::HTML::Debug::cp_pass->('t271') if $Whatpm::HTML::Debug::cp_pass;
8549     BEGIN {
8550     $Whatpm::HTML::Debug::cp->{'t271'} = 1;
8551     }
8552    
8553 wakaba 1.60 $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
8554     $token = $self->_get_next_token;
8555     redo B;
8556     } elsif ($token->{type} == START_TAG_TOKEN) {
8557 wakaba 1.54 if ($token->{tag_name} eq 'option') {
8558     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8559 wakaba 1.79
8560     $Whatpm::HTML::Debug::cp_pass->('t272') if $Whatpm::HTML::Debug::cp_pass;
8561     BEGIN {
8562     $Whatpm::HTML::Debug::cp->{'t272'} = 1;
8563     }
8564    
8565 wakaba 1.54 ## As if </option>
8566 wakaba 1.51 pop @{$self->{open_elements}};
8567 wakaba 1.79 } else {
8568    
8569     $Whatpm::HTML::Debug::cp_pass->('t273') if $Whatpm::HTML::Debug::cp_pass;
8570     BEGIN {
8571     $Whatpm::HTML::Debug::cp->{'t273'} = 1;
8572     }
8573    
8574 wakaba 1.51 }
8575    
8576 wakaba 1.1
8577     {
8578     my $el;
8579    
8580     $el = $self->{document}->create_element_ns
8581 wakaba 1.51 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8582 wakaba 1.1
8583     for my $attr_name (keys %{ $token->{attributes}}) {
8584     $el->set_attribute_ns (undef, [undef, $attr_name],
8585     $token->{attributes} ->{$attr_name}->{value});
8586     }
8587    
8588 wakaba 1.3 $self->{open_elements}->[-1]->[0]->append_child ($el);
8589 wakaba 1.51 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8590 wakaba 1.1 }
8591    
8592     $token = $self->_get_next_token;
8593     redo B;
8594 wakaba 1.54 } elsif ($token->{tag_name} eq 'optgroup') {
8595     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8596 wakaba 1.79
8597     $Whatpm::HTML::Debug::cp_pass->('t274') if $Whatpm::HTML::Debug::cp_pass;
8598     BEGIN {
8599     $Whatpm::HTML::Debug::cp->{'t274'} = 1;
8600     }
8601    
8602 wakaba 1.54 ## As if </option>
8603 wakaba 1.51 pop @{$self->{open_elements}};
8604 wakaba 1.79 } else {
8605    
8606     $Whatpm::HTML::Debug::cp_pass->('t275') if $Whatpm::HTML::Debug::cp_pass;
8607     BEGIN {
8608     $Whatpm::HTML::Debug::cp->{'t275'} = 1;
8609     }
8610    
8611 wakaba 1.51 }
8612 wakaba 1.54
8613     if ($self->{open_elements}->[-1]->[1] eq 'optgroup') {
8614 wakaba 1.79
8615     $Whatpm::HTML::Debug::cp_pass->('t276') if $Whatpm::HTML::Debug::cp_pass;
8616     BEGIN {
8617     $Whatpm::HTML::Debug::cp->{'t276'} = 1;
8618     }
8619    
8620 wakaba 1.54 ## As if </optgroup>
8621 wakaba 1.51 pop @{$self->{open_elements}};
8622 wakaba 1.79 } else {
8623    
8624     $Whatpm::HTML::Debug::cp_pass->('t277') if $Whatpm::HTML::Debug::cp_pass;
8625     BEGIN {
8626     $Whatpm::HTML::Debug::cp->{'t277'} = 1;
8627     }
8628    
8629 wakaba 1.51 }
8630    
8631    
8632 wakaba 1.1 {
8633     my $el;
8634    
8635     $el = $self->{document}->create_element_ns
8636 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
8637 wakaba 1.1
8638 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
8639     $el->set_attribute_ns (undef, [undef, $attr_name],
8640     $token->{attributes} ->{$attr_name}->{value});
8641     }
8642    
8643 wakaba 1.3 $self->{open_elements}->[-1]->[0]->append_child ($el);
8644 wakaba 1.54 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
8645 wakaba 1.1 }
8646    
8647 wakaba 1.54 $token = $self->_get_next_token;
8648     redo B;
8649     } elsif ($token->{tag_name} eq 'select') {
8650     $self->{parse_error}-> (type => 'not closed:select');
8651     ## As if </select> instead
8652     ## have an element in table scope
8653     my $i;
8654     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8655     my $node = $self->{open_elements}->[$_];
8656     if ($node->[1] eq $token->{tag_name}) {
8657 wakaba 1.79
8658     $Whatpm::HTML::Debug::cp_pass->('t278') if $Whatpm::HTML::Debug::cp_pass;
8659     BEGIN {
8660     $Whatpm::HTML::Debug::cp->{'t278'} = 1;
8661     }
8662    
8663 wakaba 1.54 $i = $_;
8664     last INSCOPE;
8665     } elsif ({
8666     table => 1, html => 1,
8667     }->{$node->[1]}) {
8668 wakaba 1.79
8669     $Whatpm::HTML::Debug::cp_pass->('t279') if $Whatpm::HTML::Debug::cp_pass;
8670     BEGIN {
8671     $Whatpm::HTML::Debug::cp->{'t279'} = 1;
8672     }
8673    
8674 wakaba 1.54 last INSCOPE;
8675 wakaba 1.44 }
8676 wakaba 1.54 } # INSCOPE
8677     unless (defined $i) {
8678 wakaba 1.79
8679     $Whatpm::HTML::Debug::cp_pass->('t280') if $Whatpm::HTML::Debug::cp_pass;
8680     BEGIN {
8681     $Whatpm::HTML::Debug::cp->{'t280'} = 1;
8682     }
8683    
8684 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:select');
8685     ## Ignore the token
8686     $token = $self->_get_next_token;
8687 wakaba 1.44 redo B;
8688     }
8689 wakaba 1.54
8690 wakaba 1.79
8691     $Whatpm::HTML::Debug::cp_pass->('t281') if $Whatpm::HTML::Debug::cp_pass;
8692     BEGIN {
8693     $Whatpm::HTML::Debug::cp->{'t281'} = 1;
8694     }
8695    
8696 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8697    
8698     $self->_reset_insertion_mode;
8699    
8700     $token = $self->_get_next_token;
8701     redo B;
8702 wakaba 1.60 } else {
8703 wakaba 1.79
8704     $Whatpm::HTML::Debug::cp_pass->('t282') if $Whatpm::HTML::Debug::cp_pass;
8705     BEGIN {
8706     $Whatpm::HTML::Debug::cp->{'t282'} = 1;
8707     }
8708    
8709 wakaba 1.60 $self->{parse_error}-> (type => 'in select:'.$token->{tag_name});
8710     ## Ignore the token
8711     $token = $self->_get_next_token;
8712     redo B;
8713     }
8714     } elsif ($token->{type} == END_TAG_TOKEN) {
8715 wakaba 1.54 if ($token->{tag_name} eq 'optgroup') {
8716     if ($self->{open_elements}->[-1]->[1] eq 'option' and
8717     $self->{open_elements}->[-2]->[1] eq 'optgroup') {
8718 wakaba 1.79
8719     $Whatpm::HTML::Debug::cp_pass->('t283') if $Whatpm::HTML::Debug::cp_pass;
8720     BEGIN {
8721     $Whatpm::HTML::Debug::cp->{'t283'} = 1;
8722     }
8723    
8724 wakaba 1.54 ## As if </option>
8725     splice @{$self->{open_elements}}, -2;
8726     } elsif ($self->{open_elements}->[-1]->[1] eq 'optgroup') {
8727 wakaba 1.79
8728     $Whatpm::HTML::Debug::cp_pass->('t284') if $Whatpm::HTML::Debug::cp_pass;
8729     BEGIN {
8730     $Whatpm::HTML::Debug::cp->{'t284'} = 1;
8731     }
8732    
8733 wakaba 1.54 pop @{$self->{open_elements}};
8734     } else {
8735 wakaba 1.79
8736     $Whatpm::HTML::Debug::cp_pass->('t285') if $Whatpm::HTML::Debug::cp_pass;
8737     BEGIN {
8738     $Whatpm::HTML::Debug::cp->{'t285'} = 1;
8739     }
8740    
8741 wakaba 1.44 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8742 wakaba 1.43 ## Ignore the token
8743 wakaba 1.54 }
8744     $token = $self->_get_next_token;
8745     redo B;
8746     } elsif ($token->{tag_name} eq 'option') {
8747     if ($self->{open_elements}->[-1]->[1] eq 'option') {
8748 wakaba 1.79
8749     $Whatpm::HTML::Debug::cp_pass->('t286') if $Whatpm::HTML::Debug::cp_pass;
8750     BEGIN {
8751     $Whatpm::HTML::Debug::cp->{'t286'} = 1;
8752     }
8753    
8754 wakaba 1.54 pop @{$self->{open_elements}};
8755 wakaba 1.44 } else {
8756 wakaba 1.79
8757     $Whatpm::HTML::Debug::cp_pass->('t287') if $Whatpm::HTML::Debug::cp_pass;
8758     BEGIN {
8759     $Whatpm::HTML::Debug::cp->{'t287'} = 1;
8760     }
8761    
8762 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8763     ## Ignore the token
8764 wakaba 1.43 }
8765 wakaba 1.54 $token = $self->_get_next_token;
8766     redo B;
8767     } elsif ($token->{tag_name} eq 'select') {
8768     ## have an element in table scope
8769     my $i;
8770     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8771     my $node = $self->{open_elements}->[$_];
8772     if ($node->[1] eq $token->{tag_name}) {
8773 wakaba 1.79
8774     $Whatpm::HTML::Debug::cp_pass->('t288') if $Whatpm::HTML::Debug::cp_pass;
8775     BEGIN {
8776     $Whatpm::HTML::Debug::cp->{'t288'} = 1;
8777     }
8778    
8779 wakaba 1.54 $i = $_;
8780     last INSCOPE;
8781     } elsif ({
8782     table => 1, html => 1,
8783     }->{$node->[1]}) {
8784 wakaba 1.79
8785     $Whatpm::HTML::Debug::cp_pass->('t289') if $Whatpm::HTML::Debug::cp_pass;
8786     BEGIN {
8787     $Whatpm::HTML::Debug::cp->{'t289'} = 1;
8788     }
8789    
8790 wakaba 1.54 last INSCOPE;
8791 wakaba 1.44 }
8792 wakaba 1.54 } # INSCOPE
8793     unless (defined $i) {
8794 wakaba 1.79
8795     $Whatpm::HTML::Debug::cp_pass->('t290') if $Whatpm::HTML::Debug::cp_pass;
8796     BEGIN {
8797     $Whatpm::HTML::Debug::cp->{'t290'} = 1;
8798     }
8799    
8800 wakaba 1.44 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8801     ## Ignore the token
8802     $token = $self->_get_next_token;
8803 wakaba 1.43 redo B;
8804     }
8805 wakaba 1.54
8806 wakaba 1.79
8807     $Whatpm::HTML::Debug::cp_pass->('t291') if $Whatpm::HTML::Debug::cp_pass;
8808     BEGIN {
8809     $Whatpm::HTML::Debug::cp->{'t291'} = 1;
8810     }
8811    
8812 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8813    
8814     $self->_reset_insertion_mode;
8815    
8816     $token = $self->_get_next_token;
8817     redo B;
8818 wakaba 1.44 } elsif ({
8819 wakaba 1.54 caption => 1, table => 1, tbody => 1,
8820     tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,
8821     }->{$token->{tag_name}}) {
8822     $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
8823    
8824 wakaba 1.44 ## have an element in table scope
8825 wakaba 1.43 my $i;
8826     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8827     my $node = $self->{open_elements}->[$_];
8828     if ($node->[1] eq $token->{tag_name}) {
8829 wakaba 1.79
8830     $Whatpm::HTML::Debug::cp_pass->('t292') if $Whatpm::HTML::Debug::cp_pass;
8831     BEGIN {
8832     $Whatpm::HTML::Debug::cp->{'t292'} = 1;
8833     }
8834    
8835 wakaba 1.43 $i = $_;
8836     last INSCOPE;
8837     } elsif ({
8838     table => 1, html => 1,
8839     }->{$node->[1]}) {
8840 wakaba 1.79
8841     $Whatpm::HTML::Debug::cp_pass->('t293') if $Whatpm::HTML::Debug::cp_pass;
8842     BEGIN {
8843     $Whatpm::HTML::Debug::cp->{'t293'} = 1;
8844     }
8845    
8846 wakaba 1.43 last INSCOPE;
8847     }
8848     } # INSCOPE
8849     unless (defined $i) {
8850 wakaba 1.79
8851     $Whatpm::HTML::Debug::cp_pass->('t294') if $Whatpm::HTML::Debug::cp_pass;
8852     BEGIN {
8853     $Whatpm::HTML::Debug::cp->{'t294'} = 1;
8854     }
8855    
8856 wakaba 1.43 ## Ignore the token
8857     $token = $self->_get_next_token;
8858     redo B;
8859     }
8860 wakaba 1.54
8861     ## As if </select>
8862     ## have an element in table scope
8863     undef $i;
8864 wakaba 1.43 INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
8865     my $node = $self->{open_elements}->[$_];
8866 wakaba 1.54 if ($node->[1] eq 'select') {
8867 wakaba 1.79
8868     $Whatpm::HTML::Debug::cp_pass->('t295') if $Whatpm::HTML::Debug::cp_pass;
8869     BEGIN {
8870     $Whatpm::HTML::Debug::cp->{'t295'} = 1;
8871     }
8872    
8873 wakaba 1.43 $i = $_;
8874     last INSCOPE;
8875     } elsif ({
8876     table => 1, html => 1,
8877     }->{$node->[1]}) {
8878 wakaba 1.79
8879     $Whatpm::HTML::Debug::cp_pass->('t296') if $Whatpm::HTML::Debug::cp_pass;
8880     BEGIN {
8881     $Whatpm::HTML::Debug::cp->{'t296'} = 1;
8882     }
8883    
8884 wakaba 1.43 last INSCOPE;
8885     }
8886     } # INSCOPE
8887     unless (defined $i) {
8888 wakaba 1.79
8889     $Whatpm::HTML::Debug::cp_pass->('t297') if $Whatpm::HTML::Debug::cp_pass;
8890     BEGIN {
8891     $Whatpm::HTML::Debug::cp->{'t297'} = 1;
8892     }
8893    
8894 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:select');
8895     ## Ignore the </select> token
8896     $token = $self->_get_next_token; ## TODO: ok?
8897 wakaba 1.43 redo B;
8898     }
8899 wakaba 1.54
8900 wakaba 1.79
8901     $Whatpm::HTML::Debug::cp_pass->('t298') if $Whatpm::HTML::Debug::cp_pass;
8902     BEGIN {
8903     $Whatpm::HTML::Debug::cp->{'t298'} = 1;
8904     }
8905    
8906 wakaba 1.54 splice @{$self->{open_elements}}, $i;
8907    
8908     $self->_reset_insertion_mode;
8909    
8910     ## reprocess
8911     redo B;
8912 wakaba 1.60 } else {
8913 wakaba 1.79
8914     $Whatpm::HTML::Debug::cp_pass->('t299') if $Whatpm::HTML::Debug::cp_pass;
8915     BEGIN {
8916     $Whatpm::HTML::Debug::cp->{'t299'} = 1;
8917     }
8918    
8919 wakaba 1.60 $self->{parse_error}-> (type => 'in select:/'.$token->{tag_name});
8920 wakaba 1.54 ## Ignore the token
8921     $token = $self->_get_next_token;
8922     redo B;
8923 wakaba 1.60 }
8924     } else {
8925     die "$0: $token->{type}: Unknown token type";
8926     }
8927 wakaba 1.58 } elsif ($self->{insertion_mode} & BODY_AFTER_IMS) {
8928 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
8929 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
8930     my $data = $1;
8931     ## As if in body
8932     $reconstruct_active_formatting_elements->($insert_to_current);
8933    
8934     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
8935    
8936     unless (length $token->{data}) {
8937 wakaba 1.79
8938     $Whatpm::HTML::Debug::cp_pass->('t300') if $Whatpm::HTML::Debug::cp_pass;
8939     BEGIN {
8940     $Whatpm::HTML::Debug::cp->{'t300'} = 1;
8941     }
8942    
8943 wakaba 1.54 $token = $self->_get_next_token;
8944     redo B;
8945     }
8946     }
8947    
8948 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
8949 wakaba 1.79
8950     $Whatpm::HTML::Debug::cp_pass->('t301') if $Whatpm::HTML::Debug::cp_pass;
8951     BEGIN {
8952     $Whatpm::HTML::Debug::cp->{'t301'} = 1;
8953     }
8954    
8955 wakaba 1.54 $self->{parse_error}-> (type => 'after html:#character');
8956    
8957     ## Reprocess in the "main" phase, "after body" insertion mode...
8958 wakaba 1.79 } else {
8959    
8960     $Whatpm::HTML::Debug::cp_pass->('t302') if $Whatpm::HTML::Debug::cp_pass;
8961     BEGIN {
8962     $Whatpm::HTML::Debug::cp->{'t302'} = 1;
8963     }
8964    
8965 wakaba 1.54 }
8966    
8967     ## "after body" insertion mode
8968     $self->{parse_error}-> (type => 'after body:#character');
8969    
8970 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
8971 wakaba 1.54 ## reprocess
8972     redo B;
8973 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
8974 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
8975 wakaba 1.79
8976     $Whatpm::HTML::Debug::cp_pass->('t303') if $Whatpm::HTML::Debug::cp_pass;
8977     BEGIN {
8978     $Whatpm::HTML::Debug::cp->{'t303'} = 1;
8979     }
8980    
8981 wakaba 1.54 $self->{parse_error}-> (type => 'after html:'.$token->{tag_name});
8982    
8983     ## Reprocess in the "main" phase, "after body" insertion mode...
8984 wakaba 1.79 } else {
8985    
8986     $Whatpm::HTML::Debug::cp_pass->('t304') if $Whatpm::HTML::Debug::cp_pass;
8987     BEGIN {
8988     $Whatpm::HTML::Debug::cp->{'t304'} = 1;
8989     }
8990    
8991 wakaba 1.54 }
8992    
8993     ## "after body" insertion mode
8994     $self->{parse_error}-> (type => 'after body:'.$token->{tag_name});
8995    
8996 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
8997 wakaba 1.54 ## reprocess
8998     redo B;
8999 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
9000 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
9001 wakaba 1.79
9002     $Whatpm::HTML::Debug::cp_pass->('t305') if $Whatpm::HTML::Debug::cp_pass;
9003     BEGIN {
9004     $Whatpm::HTML::Debug::cp->{'t305'} = 1;
9005     }
9006    
9007 wakaba 1.54 $self->{parse_error}-> (type => 'after html:/'.$token->{tag_name});
9008    
9009 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
9010 wakaba 1.54 ## Reprocess in the "main" phase, "after body" insertion mode...
9011 wakaba 1.79 } else {
9012    
9013     $Whatpm::HTML::Debug::cp_pass->('t306') if $Whatpm::HTML::Debug::cp_pass;
9014     BEGIN {
9015     $Whatpm::HTML::Debug::cp->{'t306'} = 1;
9016     }
9017    
9018 wakaba 1.54 }
9019    
9020     ## "after body" insertion mode
9021     if ($token->{tag_name} eq 'html') {
9022     if (defined $self->{inner_html_node}) {
9023 wakaba 1.79
9024     $Whatpm::HTML::Debug::cp_pass->('t307') if $Whatpm::HTML::Debug::cp_pass;
9025     BEGIN {
9026     $Whatpm::HTML::Debug::cp->{'t307'} = 1;
9027     }
9028    
9029 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:html');
9030     ## Ignore the token
9031     $token = $self->_get_next_token;
9032     redo B;
9033     } else {
9034 wakaba 1.79
9035     $Whatpm::HTML::Debug::cp_pass->('t308') if $Whatpm::HTML::Debug::cp_pass;
9036     BEGIN {
9037     $Whatpm::HTML::Debug::cp->{'t308'} = 1;
9038     }
9039    
9040 wakaba 1.56 $self->{insertion_mode} = AFTER_HTML_BODY_IM;
9041 wakaba 1.54 $token = $self->_get_next_token;
9042     redo B;
9043     }
9044     } else {
9045 wakaba 1.79
9046     $Whatpm::HTML::Debug::cp_pass->('t309') if $Whatpm::HTML::Debug::cp_pass;
9047     BEGIN {
9048     $Whatpm::HTML::Debug::cp->{'t309'} = 1;
9049     }
9050    
9051 wakaba 1.54 $self->{parse_error}-> (type => 'after body:/'.$token->{tag_name});
9052    
9053 wakaba 1.56 $self->{insertion_mode} = IN_BODY_IM;
9054 wakaba 1.54 ## reprocess
9055     redo B;
9056     }
9057     } else {
9058     die "$0: $token->{type}: Unknown token type";
9059     }
9060 wakaba 1.58 } elsif ($self->{insertion_mode} & FRAME_IMS) {
9061 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
9062 wakaba 1.54 if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
9063     $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
9064    
9065     unless (length $token->{data}) {
9066 wakaba 1.79
9067     $Whatpm::HTML::Debug::cp_pass->('t310') if $Whatpm::HTML::Debug::cp_pass;
9068     BEGIN {
9069     $Whatpm::HTML::Debug::cp->{'t310'} = 1;
9070     }
9071    
9072 wakaba 1.54 $token = $self->_get_next_token;
9073     redo B;
9074     }
9075     }
9076    
9077     if ($token->{data} =~ s/^[^\x09\x0A\x0B\x0C\x20]+//) {
9078 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9079 wakaba 1.79
9080     $Whatpm::HTML::Debug::cp_pass->('t311') if $Whatpm::HTML::Debug::cp_pass;
9081     BEGIN {
9082     $Whatpm::HTML::Debug::cp->{'t311'} = 1;
9083     }
9084    
9085 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:#character');
9086 wakaba 1.56 } elsif ($self->{insertion_mode} == AFTER_FRAMESET_IM) {
9087 wakaba 1.79
9088     $Whatpm::HTML::Debug::cp_pass->('t312') if $Whatpm::HTML::Debug::cp_pass;
9089     BEGIN {
9090     $Whatpm::HTML::Debug::cp->{'t312'} = 1;
9091     }
9092    
9093 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:#character');
9094     } else { # "after html frameset"
9095 wakaba 1.79
9096     $Whatpm::HTML::Debug::cp_pass->('t313') if $Whatpm::HTML::Debug::cp_pass;
9097     BEGIN {
9098     $Whatpm::HTML::Debug::cp->{'t313'} = 1;
9099     }
9100    
9101 wakaba 1.54 $self->{parse_error}-> (type => 'after html:#character');
9102    
9103 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9104 wakaba 1.54 ## Reprocess in the "main" phase, "after frameset"...
9105     $self->{parse_error}-> (type => 'after frameset:#character');
9106     }
9107    
9108     ## Ignore the token.
9109     if (length $token->{data}) {
9110 wakaba 1.79
9111     $Whatpm::HTML::Debug::cp_pass->('t314') if $Whatpm::HTML::Debug::cp_pass;
9112     BEGIN {
9113     $Whatpm::HTML::Debug::cp->{'t314'} = 1;
9114     }
9115    
9116 wakaba 1.54 ## reprocess the rest of characters
9117     } else {
9118 wakaba 1.79
9119     $Whatpm::HTML::Debug::cp_pass->('t315') if $Whatpm::HTML::Debug::cp_pass;
9120     BEGIN {
9121     $Whatpm::HTML::Debug::cp->{'t315'} = 1;
9122     }
9123    
9124 wakaba 1.54 $token = $self->_get_next_token;
9125     }
9126     redo B;
9127     }
9128    
9129     die qq[$0: Character "$token->{data}"];
9130 wakaba 1.57 } elsif ($token->{type} == START_TAG_TOKEN) {
9131 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
9132 wakaba 1.79
9133     $Whatpm::HTML::Debug::cp_pass->('t316') if $Whatpm::HTML::Debug::cp_pass;
9134     BEGIN {
9135     $Whatpm::HTML::Debug::cp->{'t316'} = 1;
9136     }
9137    
9138 wakaba 1.54 $self->{parse_error}-> (type => 'after html:'.$token->{tag_name});
9139    
9140 wakaba 1.79 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9141     ## Process in the "main" phase, "after frameset" insertion mode...
9142     } else {
9143    
9144     $Whatpm::HTML::Debug::cp_pass->('t317') if $Whatpm::HTML::Debug::cp_pass;
9145     BEGIN {
9146     $Whatpm::HTML::Debug::cp->{'t317'} = 1;
9147     }
9148    
9149     }
9150    
9151 wakaba 1.54 if ($token->{tag_name} eq 'frameset' and
9152 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9153 wakaba 1.54
9154 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t318') if $Whatpm::HTML::Debug::cp_pass;
9155     BEGIN {
9156     $Whatpm::HTML::Debug::cp->{'t318'} = 1;
9157     }
9158    
9159    
9160 wakaba 1.54 {
9161     my $el;
9162    
9163     $el = $self->{document}->create_element_ns
9164     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9165    
9166     for my $attr_name (keys %{ $token->{attributes}}) {
9167     $el->set_attribute_ns (undef, [undef, $attr_name],
9168     $token->{attributes} ->{$attr_name}->{value});
9169     }
9170    
9171     $self->{open_elements}->[-1]->[0]->append_child ($el);
9172     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9173     }
9174    
9175     $token = $self->_get_next_token;
9176     redo B;
9177     } elsif ($token->{tag_name} eq 'frame' and
9178 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9179 wakaba 1.54
9180 wakaba 1.79 $Whatpm::HTML::Debug::cp_pass->('t319') if $Whatpm::HTML::Debug::cp_pass;
9181     BEGIN {
9182     $Whatpm::HTML::Debug::cp->{'t319'} = 1;
9183     }
9184    
9185    
9186 wakaba 1.54 {
9187     my $el;
9188    
9189     $el = $self->{document}->create_element_ns
9190     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9191    
9192     for my $attr_name (keys %{ $token->{attributes}}) {
9193     $el->set_attribute_ns (undef, [undef, $attr_name],
9194     $token->{attributes} ->{$attr_name}->{value});
9195     }
9196    
9197     $self->{open_elements}->[-1]->[0]->append_child ($el);
9198     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9199     }
9200    
9201     pop @{$self->{open_elements}};
9202     $token = $self->_get_next_token;
9203     redo B;
9204     } elsif ($token->{tag_name} eq 'noframes') {
9205 wakaba 1.79
9206     $Whatpm::HTML::Debug::cp_pass->('t320') if $Whatpm::HTML::Debug::cp_pass;
9207     BEGIN {
9208     $Whatpm::HTML::Debug::cp->{'t320'} = 1;
9209     }
9210    
9211 wakaba 1.54 ## NOTE: As if in body.
9212     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert_to_current);
9213     redo B;
9214     } else {
9215 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9216 wakaba 1.79
9217     $Whatpm::HTML::Debug::cp_pass->('t321') if $Whatpm::HTML::Debug::cp_pass;
9218     BEGIN {
9219     $Whatpm::HTML::Debug::cp->{'t321'} = 1;
9220     }
9221    
9222 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:'.$token->{tag_name});
9223     } else {
9224 wakaba 1.79
9225     $Whatpm::HTML::Debug::cp_pass->('t322') if $Whatpm::HTML::Debug::cp_pass;
9226     BEGIN {
9227     $Whatpm::HTML::Debug::cp->{'t322'} = 1;
9228     }
9229    
9230 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:'.$token->{tag_name});
9231     }
9232     ## Ignore the token
9233     $token = $self->_get_next_token;
9234     redo B;
9235     }
9236 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
9237 wakaba 1.56 if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
9238 wakaba 1.79
9239     $Whatpm::HTML::Debug::cp_pass->('t323') if $Whatpm::HTML::Debug::cp_pass;
9240     BEGIN {
9241     $Whatpm::HTML::Debug::cp->{'t323'} = 1;
9242     }
9243    
9244 wakaba 1.54 $self->{parse_error}-> (type => 'after html:/'.$token->{tag_name});
9245    
9246 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9247 wakaba 1.54 ## Process in the "main" phase, "after frameset" insertion mode...
9248 wakaba 1.79 } else {
9249    
9250     $Whatpm::HTML::Debug::cp_pass->('t324') if $Whatpm::HTML::Debug::cp_pass;
9251     BEGIN {
9252     $Whatpm::HTML::Debug::cp->{'t324'} = 1;
9253     }
9254    
9255 wakaba 1.54 }
9256    
9257     if ($token->{tag_name} eq 'frameset' and
9258 wakaba 1.56 $self->{insertion_mode} == IN_FRAMESET_IM) {
9259 wakaba 1.54 if ($self->{open_elements}->[-1]->[1] eq 'html' and
9260     @{$self->{open_elements}} == 1) {
9261 wakaba 1.79
9262     $Whatpm::HTML::Debug::cp_pass->('t325') if $Whatpm::HTML::Debug::cp_pass;
9263     BEGIN {
9264     $Whatpm::HTML::Debug::cp->{'t325'} = 1;
9265     }
9266    
9267 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
9268     ## Ignore the token
9269     $token = $self->_get_next_token;
9270     } else {
9271 wakaba 1.79
9272     $Whatpm::HTML::Debug::cp_pass->('t326') if $Whatpm::HTML::Debug::cp_pass;
9273     BEGIN {
9274     $Whatpm::HTML::Debug::cp->{'t326'} = 1;
9275     }
9276    
9277 wakaba 1.54 pop @{$self->{open_elements}};
9278     $token = $self->_get_next_token;
9279     }
9280 wakaba 1.43
9281 wakaba 1.54 if (not defined $self->{inner_html_node} and
9282     $self->{open_elements}->[-1]->[1] ne 'frameset') {
9283 wakaba 1.79
9284     $Whatpm::HTML::Debug::cp_pass->('t327') if $Whatpm::HTML::Debug::cp_pass;
9285     BEGIN {
9286     $Whatpm::HTML::Debug::cp->{'t327'} = 1;
9287     }
9288    
9289 wakaba 1.56 $self->{insertion_mode} = AFTER_FRAMESET_IM;
9290 wakaba 1.79 } else {
9291    
9292     $Whatpm::HTML::Debug::cp_pass->('t328') if $Whatpm::HTML::Debug::cp_pass;
9293     BEGIN {
9294     $Whatpm::HTML::Debug::cp->{'t328'} = 1;
9295     }
9296    
9297 wakaba 1.54 }
9298     redo B;
9299     } elsif ($token->{tag_name} eq 'html' and
9300 wakaba 1.56 $self->{insertion_mode} == AFTER_FRAMESET_IM) {
9301 wakaba 1.79
9302     $Whatpm::HTML::Debug::cp_pass->('t329') if $Whatpm::HTML::Debug::cp_pass;
9303     BEGIN {
9304     $Whatpm::HTML::Debug::cp->{'t329'} = 1;
9305     }
9306    
9307 wakaba 1.56 $self->{insertion_mode} = AFTER_HTML_FRAMESET_IM;
9308 wakaba 1.54 $token = $self->_get_next_token;
9309     redo B;
9310     } else {
9311 wakaba 1.56 if ($self->{insertion_mode} == IN_FRAMESET_IM) {
9312 wakaba 1.79
9313     $Whatpm::HTML::Debug::cp_pass->('t330') if $Whatpm::HTML::Debug::cp_pass;
9314     BEGIN {
9315     $Whatpm::HTML::Debug::cp->{'t330'} = 1;
9316     }
9317    
9318 wakaba 1.54 $self->{parse_error}-> (type => 'in frameset:/'.$token->{tag_name});
9319     } else {
9320 wakaba 1.79
9321     $Whatpm::HTML::Debug::cp_pass->('t331') if $Whatpm::HTML::Debug::cp_pass;
9322     BEGIN {
9323     $Whatpm::HTML::Debug::cp->{'t331'} = 1;
9324     }
9325    
9326 wakaba 1.54 $self->{parse_error}-> (type => 'after frameset:/'.$token->{tag_name});
9327     }
9328     ## Ignore the token
9329     $token = $self->_get_next_token;
9330     redo B;
9331     }
9332     } else {
9333     die "$0: $token->{type}: Unknown token type";
9334     }
9335 wakaba 1.43
9336 wakaba 1.54 ## ISSUE: An issue in spec here
9337     } else {
9338     die "$0: $self->{insertion_mode}: Unknown insertion mode";
9339     }
9340 wakaba 1.43
9341 wakaba 1.54 ## "in body" insertion mode
9342 wakaba 1.57 if ($token->{type} == START_TAG_TOKEN) {
9343 wakaba 1.54 if ($token->{tag_name} eq 'script') {
9344 wakaba 1.79
9345     $Whatpm::HTML::Debug::cp_pass->('t332') if $Whatpm::HTML::Debug::cp_pass;
9346     BEGIN {
9347     $Whatpm::HTML::Debug::cp->{'t332'} = 1;
9348     }
9349    
9350 wakaba 1.54 ## NOTE: This is an "as if in head" code clone
9351     $script_start_tag->($insert);
9352 wakaba 1.55 redo B;
9353 wakaba 1.54 } elsif ($token->{tag_name} eq 'style') {
9354 wakaba 1.79
9355     $Whatpm::HTML::Debug::cp_pass->('t333') if $Whatpm::HTML::Debug::cp_pass;
9356     BEGIN {
9357     $Whatpm::HTML::Debug::cp->{'t333'} = 1;
9358     }
9359    
9360 wakaba 1.54 ## NOTE: This is an "as if in head" code clone
9361     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
9362 wakaba 1.55 redo B;
9363 wakaba 1.54 } elsif ({
9364     base => 1, link => 1,
9365     }->{$token->{tag_name}}) {
9366 wakaba 1.79
9367     $Whatpm::HTML::Debug::cp_pass->('t334') if $Whatpm::HTML::Debug::cp_pass;
9368     BEGIN {
9369     $Whatpm::HTML::Debug::cp->{'t334'} = 1;
9370     }
9371    
9372 wakaba 1.54 ## NOTE: This is an "as if in head" code clone, only "-t" differs
9373    
9374     {
9375     my $el;
9376    
9377     $el = $self->{document}->create_element_ns
9378     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9379    
9380     for my $attr_name (keys %{ $token->{attributes}}) {
9381     $el->set_attribute_ns (undef, [undef, $attr_name],
9382     $token->{attributes} ->{$attr_name}->{value});
9383     }
9384    
9385     $insert->($el);
9386     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9387     }
9388    
9389     pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
9390     $token = $self->_get_next_token;
9391 wakaba 1.55 redo B;
9392 wakaba 1.54 } elsif ($token->{tag_name} eq 'meta') {
9393     ## NOTE: This is an "as if in head" code clone, only "-t" differs
9394    
9395     {
9396     my $el;
9397    
9398     $el = $self->{document}->create_element_ns
9399     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9400    
9401     for my $attr_name (keys %{ $token->{attributes}}) {
9402     $el->set_attribute_ns (undef, [undef, $attr_name],
9403     $token->{attributes} ->{$attr_name}->{value});
9404     }
9405    
9406     $insert->($el);
9407     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9408     }
9409    
9410 wakaba 1.68 my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
9411 wakaba 1.43
9412 wakaba 1.54 unless ($self->{confident}) {
9413     if ($token->{attributes}->{charset}) { ## TODO: And if supported
9414 wakaba 1.79
9415     $Whatpm::HTML::Debug::cp_pass->('t335') if $Whatpm::HTML::Debug::cp_pass;
9416     BEGIN {
9417     $Whatpm::HTML::Debug::cp->{'t335'} = 1;
9418     }
9419    
9420 wakaba 1.65 $self->{change_encoding}
9421     ->($self, $token->{attributes}->{charset}->{value});
9422 wakaba 1.68
9423     $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
9424     ->set_user_data (manakai_has_reference =>
9425     $token->{attributes}->{charset}
9426     ->{has_reference});
9427 wakaba 1.65 } elsif ($token->{attributes}->{content}) {
9428 wakaba 1.54 ## ISSUE: Algorithm name in the spec was incorrect so that not linked to the definition.
9429 wakaba 1.65 if ($token->{attributes}->{content}->{value}
9430 wakaba 1.71 =~ /\A[^;]*;[\x09-\x0D\x20]*[Cc][Hh][Aa][Rr][Ss][Ee][Tt]
9431     [\x09-\x0D\x20]*=
9432 wakaba 1.54 [\x09-\x0D\x20]*(?>"([^"]*)"|'([^']*)'|
9433     ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
9434 wakaba 1.79
9435     $Whatpm::HTML::Debug::cp_pass->('t336') if $Whatpm::HTML::Debug::cp_pass;
9436     BEGIN {
9437     $Whatpm::HTML::Debug::cp->{'t336'} = 1;
9438     }
9439    
9440 wakaba 1.65 $self->{change_encoding}
9441     ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);
9442 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
9443     ->set_user_data (manakai_has_reference =>
9444     $token->{attributes}->{content}
9445     ->{has_reference});
9446 wakaba 1.65 }
9447 wakaba 1.54 }
9448 wakaba 1.68 } else {
9449     if ($token->{attributes}->{charset}) {
9450 wakaba 1.79
9451     $Whatpm::HTML::Debug::cp_pass->('t337') if $Whatpm::HTML::Debug::cp_pass;
9452     BEGIN {
9453     $Whatpm::HTML::Debug::cp->{'t337'} = 1;
9454     }
9455    
9456 wakaba 1.68 $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
9457     ->set_user_data (manakai_has_reference =>
9458     $token->{attributes}->{charset}
9459     ->{has_reference});
9460     }
9461 wakaba 1.69 if ($token->{attributes}->{content}) {
9462 wakaba 1.79
9463     $Whatpm::HTML::Debug::cp_pass->('t338') if $Whatpm::HTML::Debug::cp_pass;
9464     BEGIN {
9465     $Whatpm::HTML::Debug::cp->{'t338'} = 1;
9466     }
9467    
9468 wakaba 1.69 $meta_el->[0]->get_attribute_node_ns (undef, 'content')
9469     ->set_user_data (manakai_has_reference =>
9470     $token->{attributes}->{content}
9471     ->{has_reference});
9472     }
9473 wakaba 1.54 }
9474 wakaba 1.43
9475 wakaba 1.54 $token = $self->_get_next_token;
9476 wakaba 1.55 redo B;
9477 wakaba 1.54 } elsif ($token->{tag_name} eq 'title') {
9478 wakaba 1.79
9479     $Whatpm::HTML::Debug::cp_pass->('t341') if $Whatpm::HTML::Debug::cp_pass;
9480     BEGIN {
9481     $Whatpm::HTML::Debug::cp->{'t341'} = 1;
9482     }
9483    
9484 wakaba 1.54 $self->{parse_error}-> (type => 'in body:title');
9485     ## NOTE: This is an "as if in head" code clone
9486     $parse_rcdata->(RCDATA_CONTENT_MODEL, sub {
9487     if (defined $self->{head_element}) {
9488 wakaba 1.79
9489     $Whatpm::HTML::Debug::cp_pass->('t339') if $Whatpm::HTML::Debug::cp_pass;
9490     BEGIN {
9491     $Whatpm::HTML::Debug::cp->{'t339'} = 1;
9492     }
9493    
9494 wakaba 1.54 $self->{head_element}->append_child ($_[0]);
9495 wakaba 1.1 } else {
9496 wakaba 1.79
9497     $Whatpm::HTML::Debug::cp_pass->('t340') if $Whatpm::HTML::Debug::cp_pass;
9498     BEGIN {
9499     $Whatpm::HTML::Debug::cp->{'t340'} = 1;
9500     }
9501    
9502 wakaba 1.54 $insert->($_[0]);
9503 wakaba 1.1 }
9504 wakaba 1.54 });
9505 wakaba 1.55 redo B;
9506 wakaba 1.54 } elsif ($token->{tag_name} eq 'body') {
9507     $self->{parse_error}-> (type => 'in body:body');
9508 wakaba 1.1
9509 wakaba 1.54 if (@{$self->{open_elements}} == 1 or
9510     $self->{open_elements}->[1]->[1] ne 'body') {
9511 wakaba 1.79
9512     $Whatpm::HTML::Debug::cp_pass->('t342') if $Whatpm::HTML::Debug::cp_pass;
9513     BEGIN {
9514     $Whatpm::HTML::Debug::cp->{'t342'} = 1;
9515     }
9516    
9517 wakaba 1.54 ## Ignore the token
9518     } else {
9519     my $body_el = $self->{open_elements}->[1]->[0];
9520     for my $attr_name (keys %{$token->{attributes}}) {
9521     unless ($body_el->has_attribute_ns (undef, $attr_name)) {
9522 wakaba 1.79
9523     $Whatpm::HTML::Debug::cp_pass->('t343') if $Whatpm::HTML::Debug::cp_pass;
9524     BEGIN {
9525     $Whatpm::HTML::Debug::cp->{'t343'} = 1;
9526     }
9527    
9528 wakaba 1.54 $body_el->set_attribute_ns
9529     (undef, [undef, $attr_name],
9530     $token->{attributes}->{$attr_name}->{value});
9531 wakaba 1.1 }
9532 wakaba 1.54 }
9533     }
9534     $token = $self->_get_next_token;
9535 wakaba 1.55 redo B;
9536 wakaba 1.54 } elsif ({
9537     address => 1, blockquote => 1, center => 1, dir => 1,
9538     div => 1, dl => 1, fieldset => 1, listing => 1,
9539     menu => 1, ol => 1, p => 1, ul => 1,
9540     pre => 1,
9541     }->{$token->{tag_name}}) {
9542     ## has a p element in scope
9543     INSCOPE: for (reverse @{$self->{open_elements}}) {
9544     if ($_->[1] eq 'p') {
9545 wakaba 1.79
9546     $Whatpm::HTML::Debug::cp_pass->('t344') if $Whatpm::HTML::Debug::cp_pass;
9547     BEGIN {
9548     $Whatpm::HTML::Debug::cp->{'t344'} = 1;
9549     }
9550    
9551 wakaba 1.54 unshift @{$self->{token}}, $token;
9552 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9553 wakaba 1.55 redo B;
9554 wakaba 1.54 } elsif ({
9555     table => 1, caption => 1, td => 1, th => 1,
9556     button => 1, marquee => 1, object => 1, html => 1,
9557     }->{$_->[1]}) {
9558 wakaba 1.79
9559     $Whatpm::HTML::Debug::cp_pass->('t345') if $Whatpm::HTML::Debug::cp_pass;
9560     BEGIN {
9561     $Whatpm::HTML::Debug::cp->{'t345'} = 1;
9562     }
9563    
9564 wakaba 1.54 last INSCOPE;
9565     }
9566     } # INSCOPE
9567    
9568    
9569 wakaba 1.48 {
9570     my $el;
9571    
9572     $el = $self->{document}->create_element_ns
9573 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9574 wakaba 1.48
9575 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9576     $el->set_attribute_ns (undef, [undef, $attr_name],
9577     $token->{attributes} ->{$attr_name}->{value});
9578     }
9579    
9580     $insert->($el);
9581     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9582 wakaba 1.48 }
9583    
9584 wakaba 1.54 if ($token->{tag_name} eq 'pre') {
9585     $token = $self->_get_next_token;
9586 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
9587 wakaba 1.54 $token->{data} =~ s/^\x0A//;
9588     unless (length $token->{data}) {
9589 wakaba 1.79
9590     $Whatpm::HTML::Debug::cp_pass->('t346') if $Whatpm::HTML::Debug::cp_pass;
9591     BEGIN {
9592     $Whatpm::HTML::Debug::cp->{'t346'} = 1;
9593     }
9594    
9595 wakaba 1.54 $token = $self->_get_next_token;
9596 wakaba 1.79 } else {
9597    
9598     $Whatpm::HTML::Debug::cp_pass->('t349') if $Whatpm::HTML::Debug::cp_pass;
9599     BEGIN {
9600     $Whatpm::HTML::Debug::cp->{'t349'} = 1;
9601     }
9602    
9603 wakaba 1.54 }
9604 wakaba 1.79 } else {
9605    
9606     $Whatpm::HTML::Debug::cp_pass->('t348') if $Whatpm::HTML::Debug::cp_pass;
9607     BEGIN {
9608     $Whatpm::HTML::Debug::cp->{'t348'} = 1;
9609     }
9610    
9611 wakaba 1.54 }
9612     } else {
9613 wakaba 1.79
9614     $Whatpm::HTML::Debug::cp_pass->('t347') if $Whatpm::HTML::Debug::cp_pass;
9615     BEGIN {
9616     $Whatpm::HTML::Debug::cp->{'t347'} = 1;
9617     }
9618    
9619 wakaba 1.54 $token = $self->_get_next_token;
9620     }
9621 wakaba 1.55 redo B;
9622 wakaba 1.54 } elsif ($token->{tag_name} eq 'form') {
9623     if (defined $self->{form_element}) {
9624 wakaba 1.79
9625     $Whatpm::HTML::Debug::cp_pass->('t350') if $Whatpm::HTML::Debug::cp_pass;
9626     BEGIN {
9627     $Whatpm::HTML::Debug::cp->{'t350'} = 1;
9628     }
9629    
9630 wakaba 1.54 $self->{parse_error}-> (type => 'in form:form');
9631     ## Ignore the token
9632     $token = $self->_get_next_token;
9633 wakaba 1.55 redo B;
9634 wakaba 1.54 } else {
9635     ## has a p element in scope
9636     INSCOPE: for (reverse @{$self->{open_elements}}) {
9637     if ($_->[1] eq 'p') {
9638 wakaba 1.79
9639     $Whatpm::HTML::Debug::cp_pass->('t351') if $Whatpm::HTML::Debug::cp_pass;
9640     BEGIN {
9641     $Whatpm::HTML::Debug::cp->{'t351'} = 1;
9642     }
9643    
9644 wakaba 1.54 unshift @{$self->{token}}, $token;
9645 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9646 wakaba 1.55 redo B;
9647 wakaba 1.54 } elsif ({
9648     table => 1, caption => 1, td => 1, th => 1,
9649     button => 1, marquee => 1, object => 1, html => 1,
9650     }->{$_->[1]}) {
9651 wakaba 1.79
9652     $Whatpm::HTML::Debug::cp_pass->('t352') if $Whatpm::HTML::Debug::cp_pass;
9653     BEGIN {
9654     $Whatpm::HTML::Debug::cp->{'t352'} = 1;
9655     }
9656    
9657 wakaba 1.54 last INSCOPE;
9658     }
9659     } # INSCOPE
9660    
9661    
9662 wakaba 1.1 {
9663     my $el;
9664    
9665     $el = $self->{document}->create_element_ns
9666     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9667    
9668     for my $attr_name (keys %{ $token->{attributes}}) {
9669     $el->set_attribute_ns (undef, [undef, $attr_name],
9670     $token->{attributes} ->{$attr_name}->{value});
9671     }
9672    
9673 wakaba 1.54 $insert->($el);
9674 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9675 wakaba 1.1 }
9676    
9677 wakaba 1.54 $self->{form_element} = $self->{open_elements}->[-1]->[0];
9678     $token = $self->_get_next_token;
9679 wakaba 1.55 redo B;
9680 wakaba 1.54 }
9681     } elsif ($token->{tag_name} eq 'li') {
9682     ## has a p element in scope
9683     INSCOPE: for (reverse @{$self->{open_elements}}) {
9684     if ($_->[1] eq 'p') {
9685 wakaba 1.79
9686     $Whatpm::HTML::Debug::cp_pass->('t353') if $Whatpm::HTML::Debug::cp_pass;
9687     BEGIN {
9688     $Whatpm::HTML::Debug::cp->{'t353'} = 1;
9689     }
9690    
9691 wakaba 1.54 unshift @{$self->{token}}, $token;
9692 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9693 wakaba 1.55 redo B;
9694 wakaba 1.54 } elsif ({
9695     table => 1, caption => 1, td => 1, th => 1,
9696     button => 1, marquee => 1, object => 1, html => 1,
9697     }->{$_->[1]}) {
9698 wakaba 1.79
9699     $Whatpm::HTML::Debug::cp_pass->('t354') if $Whatpm::HTML::Debug::cp_pass;
9700     BEGIN {
9701     $Whatpm::HTML::Debug::cp->{'t354'} = 1;
9702     }
9703    
9704 wakaba 1.54 last INSCOPE;
9705     }
9706     } # INSCOPE
9707    
9708     ## Step 1
9709     my $i = -1;
9710     my $node = $self->{open_elements}->[$i];
9711     LI: {
9712     ## Step 2
9713     if ($node->[1] eq 'li') {
9714     if ($i != -1) {
9715 wakaba 1.79
9716     $Whatpm::HTML::Debug::cp_pass->('t355') if $Whatpm::HTML::Debug::cp_pass;
9717     BEGIN {
9718     $Whatpm::HTML::Debug::cp->{'t355'} = 1;
9719     }
9720    
9721 wakaba 1.54 $self->{parse_error}-> (type => 'end tag missing:'.
9722     $self->{open_elements}->[-1]->[1]);
9723 wakaba 1.79 } else {
9724    
9725     $Whatpm::HTML::Debug::cp_pass->('t356') if $Whatpm::HTML::Debug::cp_pass;
9726     BEGIN {
9727     $Whatpm::HTML::Debug::cp->{'t356'} = 1;
9728     }
9729    
9730 wakaba 1.54 }
9731     splice @{$self->{open_elements}}, $i;
9732     last LI;
9733 wakaba 1.79 } else {
9734    
9735     $Whatpm::HTML::Debug::cp_pass->('t357') if $Whatpm::HTML::Debug::cp_pass;
9736     BEGIN {
9737     $Whatpm::HTML::Debug::cp->{'t357'} = 1;
9738     }
9739    
9740 wakaba 1.54 }
9741    
9742     ## Step 3
9743     if (not $formatting_category->{$node->[1]} and
9744     #not $phrasing_category->{$node->[1]} and
9745     ($special_category->{$node->[1]} or
9746     $scoping_category->{$node->[1]}) and
9747     $node->[1] ne 'address' and $node->[1] ne 'div') {
9748 wakaba 1.79
9749     $Whatpm::HTML::Debug::cp_pass->('t358') if $Whatpm::HTML::Debug::cp_pass;
9750     BEGIN {
9751     $Whatpm::HTML::Debug::cp->{'t358'} = 1;
9752     }
9753    
9754 wakaba 1.54 last LI;
9755     }
9756    
9757 wakaba 1.79
9758     $Whatpm::HTML::Debug::cp_pass->('t359') if $Whatpm::HTML::Debug::cp_pass;
9759     BEGIN {
9760     $Whatpm::HTML::Debug::cp->{'t359'} = 1;
9761     }
9762    
9763 wakaba 1.54 ## Step 4
9764     $i--;
9765     $node = $self->{open_elements}->[$i];
9766     redo LI;
9767     } # LI
9768    
9769    
9770 wakaba 1.48 {
9771     my $el;
9772    
9773     $el = $self->{document}->create_element_ns
9774 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9775 wakaba 1.48
9776 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9777     $el->set_attribute_ns (undef, [undef, $attr_name],
9778     $token->{attributes} ->{$attr_name}->{value});
9779     }
9780    
9781     $insert->($el);
9782     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9783 wakaba 1.48 }
9784    
9785 wakaba 1.54 $token = $self->_get_next_token;
9786 wakaba 1.55 redo B;
9787 wakaba 1.54 } elsif ($token->{tag_name} eq 'dd' or $token->{tag_name} eq 'dt') {
9788     ## has a p element in scope
9789     INSCOPE: for (reverse @{$self->{open_elements}}) {
9790     if ($_->[1] eq 'p') {
9791 wakaba 1.79
9792     $Whatpm::HTML::Debug::cp_pass->('t360') if $Whatpm::HTML::Debug::cp_pass;
9793     BEGIN {
9794     $Whatpm::HTML::Debug::cp->{'t360'} = 1;
9795     }
9796    
9797 wakaba 1.54 unshift @{$self->{token}}, $token;
9798 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9799 wakaba 1.55 redo B;
9800 wakaba 1.54 } elsif ({
9801     table => 1, caption => 1, td => 1, th => 1,
9802     button => 1, marquee => 1, object => 1, html => 1,
9803     }->{$_->[1]}) {
9804 wakaba 1.79
9805     $Whatpm::HTML::Debug::cp_pass->('t361') if $Whatpm::HTML::Debug::cp_pass;
9806     BEGIN {
9807     $Whatpm::HTML::Debug::cp->{'t361'} = 1;
9808     }
9809    
9810 wakaba 1.54 last INSCOPE;
9811     }
9812     } # INSCOPE
9813    
9814     ## Step 1
9815     my $i = -1;
9816     my $node = $self->{open_elements}->[$i];
9817     LI: {
9818     ## Step 2
9819     if ($node->[1] eq 'dt' or $node->[1] eq 'dd') {
9820     if ($i != -1) {
9821 wakaba 1.79
9822     $Whatpm::HTML::Debug::cp_pass->('t362') if $Whatpm::HTML::Debug::cp_pass;
9823     BEGIN {
9824     $Whatpm::HTML::Debug::cp->{'t362'} = 1;
9825     }
9826    
9827 wakaba 1.54 $self->{parse_error}-> (type => 'end tag missing:'.
9828     $self->{open_elements}->[-1]->[1]);
9829 wakaba 1.79 } else {
9830    
9831     $Whatpm::HTML::Debug::cp_pass->('t363') if $Whatpm::HTML::Debug::cp_pass;
9832     BEGIN {
9833     $Whatpm::HTML::Debug::cp->{'t363'} = 1;
9834     }
9835    
9836 wakaba 1.54 }
9837     splice @{$self->{open_elements}}, $i;
9838     last LI;
9839 wakaba 1.79 } else {
9840    
9841     $Whatpm::HTML::Debug::cp_pass->('t364') if $Whatpm::HTML::Debug::cp_pass;
9842     BEGIN {
9843     $Whatpm::HTML::Debug::cp->{'t364'} = 1;
9844     }
9845    
9846 wakaba 1.54 }
9847    
9848     ## Step 3
9849     if (not $formatting_category->{$node->[1]} and
9850     #not $phrasing_category->{$node->[1]} and
9851     ($special_category->{$node->[1]} or
9852     $scoping_category->{$node->[1]}) and
9853     $node->[1] ne 'address' and $node->[1] ne 'div') {
9854 wakaba 1.79
9855     $Whatpm::HTML::Debug::cp_pass->('t365') if $Whatpm::HTML::Debug::cp_pass;
9856     BEGIN {
9857     $Whatpm::HTML::Debug::cp->{'t365'} = 1;
9858     }
9859    
9860 wakaba 1.54 last LI;
9861     }
9862    
9863 wakaba 1.79
9864     $Whatpm::HTML::Debug::cp_pass->('t366') if $Whatpm::HTML::Debug::cp_pass;
9865     BEGIN {
9866     $Whatpm::HTML::Debug::cp->{'t366'} = 1;
9867     }
9868    
9869 wakaba 1.54 ## Step 4
9870     $i--;
9871     $node = $self->{open_elements}->[$i];
9872     redo LI;
9873     } # LI
9874    
9875    
9876 wakaba 1.49 {
9877     my $el;
9878    
9879     $el = $self->{document}->create_element_ns
9880     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9881    
9882     for my $attr_name (keys %{ $token->{attributes}}) {
9883     $el->set_attribute_ns (undef, [undef, $attr_name],
9884     $token->{attributes} ->{$attr_name}->{value});
9885     }
9886    
9887 wakaba 1.54 $insert->($el);
9888 wakaba 1.49 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9889     }
9890    
9891 wakaba 1.54 $token = $self->_get_next_token;
9892 wakaba 1.55 redo B;
9893 wakaba 1.54 } elsif ($token->{tag_name} eq 'plaintext') {
9894     ## has a p element in scope
9895     INSCOPE: for (reverse @{$self->{open_elements}}) {
9896     if ($_->[1] eq 'p') {
9897 wakaba 1.79
9898     $Whatpm::HTML::Debug::cp_pass->('t367') if $Whatpm::HTML::Debug::cp_pass;
9899     BEGIN {
9900     $Whatpm::HTML::Debug::cp->{'t367'} = 1;
9901     }
9902    
9903 wakaba 1.54 unshift @{$self->{token}}, $token;
9904 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9905 wakaba 1.55 redo B;
9906 wakaba 1.54 } elsif ({
9907     table => 1, caption => 1, td => 1, th => 1,
9908     button => 1, marquee => 1, object => 1, html => 1,
9909     }->{$_->[1]}) {
9910 wakaba 1.79
9911     $Whatpm::HTML::Debug::cp_pass->('t368') if $Whatpm::HTML::Debug::cp_pass;
9912     BEGIN {
9913     $Whatpm::HTML::Debug::cp->{'t368'} = 1;
9914     }
9915    
9916 wakaba 1.54 last INSCOPE;
9917     }
9918     } # INSCOPE
9919    
9920    
9921 wakaba 1.1 {
9922     my $el;
9923    
9924     $el = $self->{document}->create_element_ns
9925 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
9926 wakaba 1.1
9927 wakaba 1.54 for my $attr_name (keys %{ $token->{attributes}}) {
9928     $el->set_attribute_ns (undef, [undef, $attr_name],
9929     $token->{attributes} ->{$attr_name}->{value});
9930     }
9931    
9932     $insert->($el);
9933     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
9934 wakaba 1.1 }
9935    
9936 wakaba 1.54
9937     $self->{content_model} = PLAINTEXT_CONTENT_MODEL;
9938    
9939     $token = $self->_get_next_token;
9940 wakaba 1.55 redo B;
9941 wakaba 1.54 } elsif ({
9942     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
9943     }->{$token->{tag_name}}) {
9944     ## has a p element in scope
9945     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
9946     my $node = $self->{open_elements}->[$_];
9947     if ($node->[1] eq 'p') {
9948 wakaba 1.79
9949     $Whatpm::HTML::Debug::cp_pass->('t369') if $Whatpm::HTML::Debug::cp_pass;
9950     BEGIN {
9951     $Whatpm::HTML::Debug::cp->{'t369'} = 1;
9952     }
9953    
9954 wakaba 1.54 unshift @{$self->{token}}, $token;
9955 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
9956 wakaba 1.55 redo B;
9957 wakaba 1.54 } elsif ({
9958     table => 1, caption => 1, td => 1, th => 1,
9959     button => 1, marquee => 1, object => 1, html => 1,
9960     }->{$node->[1]}) {
9961 wakaba 1.79
9962     $Whatpm::HTML::Debug::cp_pass->('t370') if $Whatpm::HTML::Debug::cp_pass;
9963     BEGIN {
9964     $Whatpm::HTML::Debug::cp->{'t370'} = 1;
9965     }
9966    
9967 wakaba 1.54 last INSCOPE;
9968     }
9969     } # INSCOPE
9970    
9971     ## NOTE: See <http://html5.org/tools/web-apps-tracker?from=925&to=926>
9972     ## has an element in scope
9973     #my $i;
9974     #INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
9975     # my $node = $self->{open_elements}->[$_];
9976     # if ({
9977     # h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
9978     # }->{$node->[1]}) {
9979     # $i = $_;
9980     # last INSCOPE;
9981     # } elsif ({
9982     # table => 1, caption => 1, td => 1, th => 1,
9983     # button => 1, marquee => 1, object => 1, html => 1,
9984     # }->{$node->[1]}) {
9985     # last INSCOPE;
9986     # }
9987     #} # INSCOPE
9988     #
9989     #if (defined $i) {
9990     # !!! parse-error (type => 'in hn:hn');
9991     # splice @{$self->{open_elements}}, $i;
9992     #}
9993    
9994    
9995 wakaba 1.48 {
9996     my $el;
9997    
9998     $el = $self->{document}->create_element_ns
9999     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10000    
10001     for my $attr_name (keys %{ $token->{attributes}}) {
10002     $el->set_attribute_ns (undef, [undef, $attr_name],
10003     $token->{attributes} ->{$attr_name}->{value});
10004     }
10005    
10006 wakaba 1.54 $insert->($el);
10007 wakaba 1.48 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10008     }
10009    
10010 wakaba 1.54
10011     $token = $self->_get_next_token;
10012 wakaba 1.55 redo B;
10013 wakaba 1.54 } elsif ($token->{tag_name} eq 'a') {
10014     AFE: for my $i (reverse 0..$#$active_formatting_elements) {
10015     my $node = $active_formatting_elements->[$i];
10016     if ($node->[1] eq 'a') {
10017 wakaba 1.79
10018     $Whatpm::HTML::Debug::cp_pass->('t371') if $Whatpm::HTML::Debug::cp_pass;
10019     BEGIN {
10020     $Whatpm::HTML::Debug::cp->{'t371'} = 1;
10021     }
10022    
10023 wakaba 1.54 $self->{parse_error}-> (type => 'in a:a');
10024    
10025     unshift @{$self->{token}}, $token;
10026 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'a'};
10027 wakaba 1.54 $formatting_end_tag->($token->{tag_name});
10028    
10029     AFE2: for (reverse 0..$#$active_formatting_elements) {
10030     if ($active_formatting_elements->[$_]->[0] eq $node->[0]) {
10031 wakaba 1.79
10032     $Whatpm::HTML::Debug::cp_pass->('t372') if $Whatpm::HTML::Debug::cp_pass;
10033     BEGIN {
10034     $Whatpm::HTML::Debug::cp->{'t372'} = 1;
10035     }
10036    
10037 wakaba 1.54 splice @$active_formatting_elements, $_, 1;
10038     last AFE2;
10039 wakaba 1.49 }
10040 wakaba 1.54 } # AFE2
10041     OE: for (reverse 0..$#{$self->{open_elements}}) {
10042     if ($self->{open_elements}->[$_]->[0] eq $node->[0]) {
10043 wakaba 1.79
10044     $Whatpm::HTML::Debug::cp_pass->('t373') if $Whatpm::HTML::Debug::cp_pass;
10045     BEGIN {
10046     $Whatpm::HTML::Debug::cp->{'t373'} = 1;
10047     }
10048    
10049 wakaba 1.54 splice @{$self->{open_elements}}, $_, 1;
10050     last OE;
10051 wakaba 1.49 }
10052 wakaba 1.54 } # OE
10053     last AFE;
10054     } elsif ($node->[0] eq '#marker') {
10055 wakaba 1.79
10056     $Whatpm::HTML::Debug::cp_pass->('t374') if $Whatpm::HTML::Debug::cp_pass;
10057     BEGIN {
10058     $Whatpm::HTML::Debug::cp->{'t374'} = 1;
10059     }
10060    
10061 wakaba 1.54 last AFE;
10062     }
10063     } # AFE
10064    
10065     $reconstruct_active_formatting_elements->($insert_to_current);
10066 wakaba 1.49
10067 wakaba 1.54
10068     {
10069     my $el;
10070    
10071     $el = $self->{document}->create_element_ns
10072     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10073    
10074     for my $attr_name (keys %{ $token->{attributes}}) {
10075     $el->set_attribute_ns (undef, [undef, $attr_name],
10076     $token->{attributes} ->{$attr_name}->{value});
10077     }
10078    
10079     $insert->($el);
10080     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10081     }
10082    
10083     push @$active_formatting_elements, $self->{open_elements}->[-1];
10084 wakaba 1.48
10085 wakaba 1.54 $token = $self->_get_next_token;
10086 wakaba 1.55 redo B;
10087 wakaba 1.54 } elsif ({
10088     b => 1, big => 1, em => 1, font => 1, i => 1,
10089     s => 1, small => 1, strile => 1,
10090     strong => 1, tt => 1, u => 1,
10091     }->{$token->{tag_name}}) {
10092 wakaba 1.79
10093     $Whatpm::HTML::Debug::cp_pass->('t375') if $Whatpm::HTML::Debug::cp_pass;
10094     BEGIN {
10095     $Whatpm::HTML::Debug::cp->{'t375'} = 1;
10096     }
10097    
10098 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10099    
10100    
10101     {
10102     my $el;
10103    
10104     $el = $self->{document}->create_element_ns
10105     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10106    
10107     for my $attr_name (keys %{ $token->{attributes}}) {
10108     $el->set_attribute_ns (undef, [undef, $attr_name],
10109     $token->{attributes} ->{$attr_name}->{value});
10110     }
10111    
10112     $insert->($el);
10113     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10114     }
10115    
10116     push @$active_formatting_elements, $self->{open_elements}->[-1];
10117    
10118     $token = $self->_get_next_token;
10119 wakaba 1.55 redo B;
10120 wakaba 1.54 } elsif ($token->{tag_name} eq 'nobr') {
10121     $reconstruct_active_formatting_elements->($insert_to_current);
10122 wakaba 1.1
10123 wakaba 1.54 ## has a |nobr| element in scope
10124     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10125     my $node = $self->{open_elements}->[$_];
10126     if ($node->[1] eq 'nobr') {
10127 wakaba 1.79
10128     $Whatpm::HTML::Debug::cp_pass->('t376') if $Whatpm::HTML::Debug::cp_pass;
10129     BEGIN {
10130     $Whatpm::HTML::Debug::cp->{'t376'} = 1;
10131     }
10132    
10133 wakaba 1.60 $self->{parse_error}-> (type => 'in nobr:nobr');
10134 wakaba 1.54 unshift @{$self->{token}}, $token;
10135 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'nobr'};
10136 wakaba 1.55 redo B;
10137 wakaba 1.54 } elsif ({
10138     table => 1, caption => 1, td => 1, th => 1,
10139     button => 1, marquee => 1, object => 1, html => 1,
10140     }->{$node->[1]}) {
10141 wakaba 1.79
10142     $Whatpm::HTML::Debug::cp_pass->('t377') if $Whatpm::HTML::Debug::cp_pass;
10143     BEGIN {
10144     $Whatpm::HTML::Debug::cp->{'t377'} = 1;
10145     }
10146    
10147 wakaba 1.54 last INSCOPE;
10148     }
10149     } # INSCOPE
10150    
10151    
10152     {
10153     my $el;
10154    
10155     $el = $self->{document}->create_element_ns
10156     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10157    
10158     for my $attr_name (keys %{ $token->{attributes}}) {
10159     $el->set_attribute_ns (undef, [undef, $attr_name],
10160     $token->{attributes} ->{$attr_name}->{value});
10161     }
10162    
10163     $insert->($el);
10164     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10165     }
10166    
10167     push @$active_formatting_elements, $self->{open_elements}->[-1];
10168    
10169     $token = $self->_get_next_token;
10170 wakaba 1.55 redo B;
10171 wakaba 1.54 } elsif ($token->{tag_name} eq 'button') {
10172     ## has a button element in scope
10173     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10174     my $node = $self->{open_elements}->[$_];
10175     if ($node->[1] eq 'button') {
10176 wakaba 1.79
10177     $Whatpm::HTML::Debug::cp_pass->('t378') if $Whatpm::HTML::Debug::cp_pass;
10178     BEGIN {
10179     $Whatpm::HTML::Debug::cp->{'t378'} = 1;
10180     }
10181    
10182 wakaba 1.54 $self->{parse_error}-> (type => 'in button:button');
10183     unshift @{$self->{token}}, $token;
10184 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'button'};
10185 wakaba 1.55 redo B;
10186 wakaba 1.54 } elsif ({
10187     table => 1, caption => 1, td => 1, th => 1,
10188     button => 1, marquee => 1, object => 1, html => 1,
10189     }->{$node->[1]}) {
10190 wakaba 1.79
10191     $Whatpm::HTML::Debug::cp_pass->('t379') if $Whatpm::HTML::Debug::cp_pass;
10192     BEGIN {
10193     $Whatpm::HTML::Debug::cp->{'t379'} = 1;
10194     }
10195    
10196 wakaba 1.54 last INSCOPE;
10197 wakaba 1.1 }
10198 wakaba 1.54 } # INSCOPE
10199    
10200     $reconstruct_active_formatting_elements->($insert_to_current);
10201    
10202    
10203     {
10204     my $el;
10205    
10206     $el = $self->{document}->create_element_ns
10207     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10208    
10209     for my $attr_name (keys %{ $token->{attributes}}) {
10210     $el->set_attribute_ns (undef, [undef, $attr_name],
10211     $token->{attributes} ->{$attr_name}->{value});
10212     }
10213    
10214     $insert->($el);
10215     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10216     }
10217    
10218     push @$active_formatting_elements, ['#marker', ''];
10219 wakaba 1.1
10220 wakaba 1.54 $token = $self->_get_next_token;
10221 wakaba 1.55 redo B;
10222 wakaba 1.54 } elsif ($token->{tag_name} eq 'marquee' or
10223     $token->{tag_name} eq 'object') {
10224 wakaba 1.79
10225     $Whatpm::HTML::Debug::cp_pass->('t380') if $Whatpm::HTML::Debug::cp_pass;
10226     BEGIN {
10227     $Whatpm::HTML::Debug::cp->{'t380'} = 1;
10228     }
10229    
10230 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10231    
10232    
10233 wakaba 1.1 {
10234     my $el;
10235    
10236     $el = $self->{document}->create_element_ns
10237     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10238    
10239     for my $attr_name (keys %{ $token->{attributes}}) {
10240     $el->set_attribute_ns (undef, [undef, $attr_name],
10241     $token->{attributes} ->{$attr_name}->{value});
10242     }
10243    
10244 wakaba 1.54 $insert->($el);
10245 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10246 wakaba 1.1 }
10247    
10248 wakaba 1.54 push @$active_formatting_elements, ['#marker', ''];
10249    
10250     $token = $self->_get_next_token;
10251 wakaba 1.55 redo B;
10252 wakaba 1.54 } elsif ($token->{tag_name} eq 'xmp') {
10253 wakaba 1.79
10254     $Whatpm::HTML::Debug::cp_pass->('t381') if $Whatpm::HTML::Debug::cp_pass;
10255     BEGIN {
10256     $Whatpm::HTML::Debug::cp->{'t381'} = 1;
10257     }
10258    
10259 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10260     $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
10261 wakaba 1.55 redo B;
10262 wakaba 1.54 } elsif ($token->{tag_name} eq 'table') {
10263     ## has a p element in scope
10264     INSCOPE: for (reverse @{$self->{open_elements}}) {
10265     if ($_->[1] eq 'p') {
10266 wakaba 1.79
10267     $Whatpm::HTML::Debug::cp_pass->('t382') if $Whatpm::HTML::Debug::cp_pass;
10268     BEGIN {
10269     $Whatpm::HTML::Debug::cp->{'t382'} = 1;
10270     }
10271    
10272 wakaba 1.54 unshift @{$self->{token}}, $token;
10273 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
10274 wakaba 1.55 redo B;
10275 wakaba 1.54 } elsif ({
10276     table => 1, caption => 1, td => 1, th => 1,
10277     button => 1, marquee => 1, object => 1, html => 1,
10278     }->{$_->[1]}) {
10279 wakaba 1.79
10280     $Whatpm::HTML::Debug::cp_pass->('t383') if $Whatpm::HTML::Debug::cp_pass;
10281     BEGIN {
10282     $Whatpm::HTML::Debug::cp->{'t383'} = 1;
10283     }
10284    
10285 wakaba 1.54 last INSCOPE;
10286 wakaba 1.1 }
10287 wakaba 1.54 } # INSCOPE
10288    
10289    
10290     {
10291     my $el;
10292    
10293     $el = $self->{document}->create_element_ns
10294     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10295    
10296     for my $attr_name (keys %{ $token->{attributes}}) {
10297     $el->set_attribute_ns (undef, [undef, $attr_name],
10298     $token->{attributes} ->{$attr_name}->{value});
10299     }
10300    
10301     $insert->($el);
10302     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10303     }
10304    
10305    
10306 wakaba 1.56 $self->{insertion_mode} = IN_TABLE_IM;
10307 wakaba 1.54
10308     $token = $self->_get_next_token;
10309 wakaba 1.55 redo B;
10310 wakaba 1.54 } elsif ({
10311     area => 1, basefont => 1, bgsound => 1, br => 1,
10312     embed => 1, img => 1, param => 1, spacer => 1, wbr => 1,
10313     image => 1,
10314     }->{$token->{tag_name}}) {
10315     if ($token->{tag_name} eq 'image') {
10316 wakaba 1.79
10317     $Whatpm::HTML::Debug::cp_pass->('t384') if $Whatpm::HTML::Debug::cp_pass;
10318     BEGIN {
10319     $Whatpm::HTML::Debug::cp->{'t384'} = 1;
10320     }
10321    
10322 wakaba 1.54 $self->{parse_error}-> (type => 'image');
10323     $token->{tag_name} = 'img';
10324 wakaba 1.79 } else {
10325    
10326     $Whatpm::HTML::Debug::cp_pass->('t385') if $Whatpm::HTML::Debug::cp_pass;
10327     BEGIN {
10328     $Whatpm::HTML::Debug::cp->{'t385'} = 1;
10329     }
10330    
10331 wakaba 1.54 }
10332 wakaba 1.1
10333 wakaba 1.54 ## NOTE: There is an "as if <br>" code clone.
10334     $reconstruct_active_formatting_elements->($insert_to_current);
10335    
10336    
10337     {
10338     my $el;
10339    
10340     $el = $self->{document}->create_element_ns
10341     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10342    
10343     for my $attr_name (keys %{ $token->{attributes}}) {
10344     $el->set_attribute_ns (undef, [undef, $attr_name],
10345     $token->{attributes} ->{$attr_name}->{value});
10346     }
10347    
10348     $insert->($el);
10349     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10350     }
10351    
10352     pop @{$self->{open_elements}};
10353    
10354     $token = $self->_get_next_token;
10355 wakaba 1.55 redo B;
10356 wakaba 1.54 } elsif ($token->{tag_name} eq 'hr') {
10357     ## has a p element in scope
10358     INSCOPE: for (reverse @{$self->{open_elements}}) {
10359     if ($_->[1] eq 'p') {
10360 wakaba 1.79
10361     $Whatpm::HTML::Debug::cp_pass->('t386') if $Whatpm::HTML::Debug::cp_pass;
10362     BEGIN {
10363     $Whatpm::HTML::Debug::cp->{'t386'} = 1;
10364     }
10365    
10366 wakaba 1.54 unshift @{$self->{token}}, $token;
10367 wakaba 1.57 $token = {type => END_TAG_TOKEN, tag_name => 'p'};
10368 wakaba 1.55 redo B;
10369 wakaba 1.54 } elsif ({
10370     table => 1, caption => 1, td => 1, th => 1,
10371     button => 1, marquee => 1, object => 1, html => 1,
10372     }->{$_->[1]}) {
10373 wakaba 1.79
10374     $Whatpm::HTML::Debug::cp_pass->('t387') if $Whatpm::HTML::Debug::cp_pass;
10375     BEGIN {
10376     $Whatpm::HTML::Debug::cp->{'t387'} = 1;
10377     }
10378    
10379 wakaba 1.54 last INSCOPE;
10380 wakaba 1.1 }
10381 wakaba 1.54 } # INSCOPE
10382    
10383    
10384 wakaba 1.1 {
10385     my $el;
10386    
10387     $el = $self->{document}->create_element_ns
10388     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10389    
10390     for my $attr_name (keys %{ $token->{attributes}}) {
10391     $el->set_attribute_ns (undef, [undef, $attr_name],
10392     $token->{attributes} ->{$attr_name}->{value});
10393     }
10394    
10395 wakaba 1.54 $insert->($el);
10396 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10397 wakaba 1.1 }
10398    
10399 wakaba 1.54 pop @{$self->{open_elements}};
10400    
10401     $token = $self->_get_next_token;
10402 wakaba 1.55 redo B;
10403 wakaba 1.54 } elsif ($token->{tag_name} eq 'input') {
10404 wakaba 1.79
10405     $Whatpm::HTML::Debug::cp_pass->('t388') if $Whatpm::HTML::Debug::cp_pass;
10406     BEGIN {
10407     $Whatpm::HTML::Debug::cp->{'t388'} = 1;
10408     }
10409    
10410 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10411    
10412    
10413 wakaba 1.1 {
10414     my $el;
10415    
10416     $el = $self->{document}->create_element_ns
10417     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10418    
10419     for my $attr_name (keys %{ $token->{attributes}}) {
10420     $el->set_attribute_ns (undef, [undef, $attr_name],
10421     $token->{attributes} ->{$attr_name}->{value});
10422     }
10423    
10424 wakaba 1.54 $insert->($el);
10425 wakaba 1.3 push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10426 wakaba 1.1 }
10427    
10428 wakaba 1.54 ## TODO: associate with $self->{form_element} if defined
10429     pop @{$self->{open_elements}};
10430    
10431     $token = $self->_get_next_token;
10432 wakaba 1.55 redo B;
10433 wakaba 1.54 } elsif ($token->{tag_name} eq 'isindex') {
10434     $self->{parse_error}-> (type => 'isindex');
10435    
10436     if (defined $self->{form_element}) {
10437 wakaba 1.79
10438     $Whatpm::HTML::Debug::cp_pass->('t389') if $Whatpm::HTML::Debug::cp_pass;
10439     BEGIN {
10440     $Whatpm::HTML::Debug::cp->{'t389'} = 1;
10441     }
10442    
10443 wakaba 1.54 ## Ignore the token
10444     $token = $self->_get_next_token;
10445 wakaba 1.55 redo B;
10446 wakaba 1.54 } else {
10447     my $at = $token->{attributes};
10448     my $form_attrs;
10449     $form_attrs->{action} = $at->{action} if $at->{action};
10450     my $prompt_attr = $at->{prompt};
10451     $at->{name} = {name => 'name', value => 'isindex'};
10452     delete $at->{action};
10453     delete $at->{prompt};
10454     my @tokens = (
10455 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'form',
10456 wakaba 1.54 attributes => $form_attrs},
10457 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'hr'},
10458     {type => START_TAG_TOKEN, tag_name => 'p'},
10459     {type => START_TAG_TOKEN, tag_name => 'label'},
10460 wakaba 1.54 );
10461     if ($prompt_attr) {
10462 wakaba 1.79
10463     $Whatpm::HTML::Debug::cp_pass->('t390') if $Whatpm::HTML::Debug::cp_pass;
10464     BEGIN {
10465     $Whatpm::HTML::Debug::cp->{'t390'} = 1;
10466     }
10467    
10468 wakaba 1.57 push @tokens, {type => CHARACTER_TOKEN, data => $prompt_attr->{value}};
10469 wakaba 1.1 } else {
10470 wakaba 1.79
10471     $Whatpm::HTML::Debug::cp_pass->('t391') if $Whatpm::HTML::Debug::cp_pass;
10472     BEGIN {
10473     $Whatpm::HTML::Debug::cp->{'t391'} = 1;
10474     }
10475    
10476 wakaba 1.57 push @tokens, {type => CHARACTER_TOKEN,
10477 wakaba 1.54 data => 'This is a searchable index. Insert your search keywords here: '}; # SHOULD
10478     ## TODO: make this configurable
10479 wakaba 1.1 }
10480 wakaba 1.54 push @tokens,
10481 wakaba 1.57 {type => START_TAG_TOKEN, tag_name => 'input', attributes => $at},
10482     #{type => CHARACTER_TOKEN, data => ''}, # SHOULD
10483     {type => END_TAG_TOKEN, tag_name => 'label'},
10484     {type => END_TAG_TOKEN, tag_name => 'p'},
10485     {type => START_TAG_TOKEN, tag_name => 'hr'},
10486     {type => END_TAG_TOKEN, tag_name => 'form'};
10487 wakaba 1.54 $token = shift @tokens;
10488     unshift @{$self->{token}}, (@tokens);
10489 wakaba 1.55 redo B;
10490 wakaba 1.54 }
10491     } elsif ($token->{tag_name} eq 'textarea') {
10492     my $tag_name = $token->{tag_name};
10493     my $el;
10494    
10495     $el = $self->{document}->create_element_ns
10496     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10497    
10498     for my $attr_name (keys %{ $token->{attributes}}) {
10499     $el->set_attribute_ns (undef, [undef, $attr_name],
10500     $token->{attributes} ->{$attr_name}->{value});
10501     }
10502    
10503    
10504     ## TODO: $self->{form_element} if defined
10505     $self->{content_model} = RCDATA_CONTENT_MODEL;
10506     delete $self->{escape}; # MUST
10507    
10508     $insert->($el);
10509    
10510     my $text = '';
10511     $token = $self->_get_next_token;
10512 wakaba 1.57 if ($token->{type} == CHARACTER_TOKEN) {
10513 wakaba 1.54 $token->{data} =~ s/^\x0A//;
10514 wakaba 1.53 unless (length $token->{data}) {
10515 wakaba 1.79
10516     $Whatpm::HTML::Debug::cp_pass->('t392') if $Whatpm::HTML::Debug::cp_pass;
10517     BEGIN {
10518     $Whatpm::HTML::Debug::cp->{'t392'} = 1;
10519     }
10520    
10521 wakaba 1.53 $token = $self->_get_next_token;
10522 wakaba 1.79 } else {
10523    
10524     $Whatpm::HTML::Debug::cp_pass->('t393') if $Whatpm::HTML::Debug::cp_pass;
10525     BEGIN {
10526     $Whatpm::HTML::Debug::cp->{'t393'} = 1;
10527     }
10528    
10529 wakaba 1.53 }
10530 wakaba 1.79 } else {
10531    
10532     $Whatpm::HTML::Debug::cp_pass->('t394') if $Whatpm::HTML::Debug::cp_pass;
10533     BEGIN {
10534     $Whatpm::HTML::Debug::cp->{'t394'} = 1;
10535     }
10536    
10537 wakaba 1.53 }
10538 wakaba 1.57 while ($token->{type} == CHARACTER_TOKEN) {
10539 wakaba 1.79
10540     $Whatpm::HTML::Debug::cp_pass->('t395') if $Whatpm::HTML::Debug::cp_pass;
10541     BEGIN {
10542     $Whatpm::HTML::Debug::cp->{'t395'} = 1;
10543     }
10544    
10545 wakaba 1.54 $text .= $token->{data};
10546     $token = $self->_get_next_token;
10547     }
10548     if (length $text) {
10549 wakaba 1.79
10550     $Whatpm::HTML::Debug::cp_pass->('t396') if $Whatpm::HTML::Debug::cp_pass;
10551     BEGIN {
10552     $Whatpm::HTML::Debug::cp->{'t396'} = 1;
10553     }
10554    
10555 wakaba 1.54 $el->manakai_append_text ($text);
10556     }
10557    
10558     $self->{content_model} = PCDATA_CONTENT_MODEL;
10559    
10560 wakaba 1.57 if ($token->{type} == END_TAG_TOKEN and
10561 wakaba 1.54 $token->{tag_name} eq $tag_name) {
10562 wakaba 1.79
10563     $Whatpm::HTML::Debug::cp_pass->('t397') if $Whatpm::HTML::Debug::cp_pass;
10564     BEGIN {
10565     $Whatpm::HTML::Debug::cp->{'t397'} = 1;
10566     }
10567    
10568 wakaba 1.54 ## Ignore the token
10569     } else {
10570 wakaba 1.79
10571     $Whatpm::HTML::Debug::cp_pass->('t398') if $Whatpm::HTML::Debug::cp_pass;
10572     BEGIN {
10573     $Whatpm::HTML::Debug::cp->{'t398'} = 1;
10574     }
10575    
10576 wakaba 1.54 $self->{parse_error}-> (type => 'in RCDATA:#'.$token->{type});
10577     }
10578     $token = $self->_get_next_token;
10579 wakaba 1.55 redo B;
10580 wakaba 1.54 } elsif ({
10581     iframe => 1,
10582     noembed => 1,
10583     noframes => 1,
10584     noscript => 0, ## TODO: 1 if scripting is enabled
10585     }->{$token->{tag_name}}) {
10586 wakaba 1.79
10587     $Whatpm::HTML::Debug::cp_pass->('t399') if $Whatpm::HTML::Debug::cp_pass;
10588     BEGIN {
10589     $Whatpm::HTML::Debug::cp->{'t399'} = 1;
10590     }
10591    
10592 wakaba 1.60 ## NOTE: There is an "as if in body" code clone.
10593 wakaba 1.54 $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
10594 wakaba 1.55 redo B;
10595 wakaba 1.54 } elsif ($token->{tag_name} eq 'select') {
10596 wakaba 1.79
10597     $Whatpm::HTML::Debug::cp_pass->('t400') if $Whatpm::HTML::Debug::cp_pass;
10598     BEGIN {
10599     $Whatpm::HTML::Debug::cp->{'t400'} = 1;
10600     }
10601    
10602 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10603    
10604    
10605     {
10606     my $el;
10607    
10608     $el = $self->{document}->create_element_ns
10609     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10610    
10611     for my $attr_name (keys %{ $token->{attributes}}) {
10612     $el->set_attribute_ns (undef, [undef, $attr_name],
10613     $token->{attributes} ->{$attr_name}->{value});
10614     }
10615    
10616     $insert->($el);
10617     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10618     }
10619    
10620    
10621 wakaba 1.56 $self->{insertion_mode} = IN_SELECT_IM;
10622 wakaba 1.54 $token = $self->_get_next_token;
10623 wakaba 1.55 redo B;
10624 wakaba 1.54 } elsif ({
10625     caption => 1, col => 1, colgroup => 1, frame => 1,
10626     frameset => 1, head => 1, option => 1, optgroup => 1,
10627     tbody => 1, td => 1, tfoot => 1, th => 1,
10628     thead => 1, tr => 1,
10629     }->{$token->{tag_name}}) {
10630 wakaba 1.79
10631     $Whatpm::HTML::Debug::cp_pass->('t401') if $Whatpm::HTML::Debug::cp_pass;
10632     BEGIN {
10633     $Whatpm::HTML::Debug::cp->{'t401'} = 1;
10634     }
10635    
10636 wakaba 1.54 $self->{parse_error}-> (type => 'in body:'.$token->{tag_name});
10637     ## Ignore the token
10638     $token = $self->_get_next_token;
10639 wakaba 1.55 redo B;
10640 wakaba 1.54
10641     ## ISSUE: An issue on HTML5 new elements in the spec.
10642     } else {
10643 wakaba 1.79
10644     $Whatpm::HTML::Debug::cp_pass->('t402') if $Whatpm::HTML::Debug::cp_pass;
10645     BEGIN {
10646     $Whatpm::HTML::Debug::cp->{'t402'} = 1;
10647     }
10648    
10649 wakaba 1.54 $reconstruct_active_formatting_elements->($insert_to_current);
10650 wakaba 1.53
10651 wakaba 1.54
10652     {
10653     my $el;
10654    
10655     $el = $self->{document}->create_element_ns
10656     (q<http://www.w3.org/1999/xhtml>, [undef, $token->{tag_name}]);
10657    
10658     for my $attr_name (keys %{ $token->{attributes}}) {
10659     $el->set_attribute_ns (undef, [undef, $attr_name],
10660     $token->{attributes} ->{$attr_name}->{value});
10661 wakaba 1.53 }
10662 wakaba 1.54
10663     $insert->($el);
10664     push @{$self->{open_elements}}, [$el, $token->{tag_name}];
10665     }
10666    
10667 wakaba 1.53
10668 wakaba 1.54 $token = $self->_get_next_token;
10669 wakaba 1.55 redo B;
10670 wakaba 1.54 }
10671 wakaba 1.57 } elsif ($token->{type} == END_TAG_TOKEN) {
10672 wakaba 1.54 if ($token->{tag_name} eq 'body') {
10673     if (@{$self->{open_elements}} > 1 and
10674     $self->{open_elements}->[1]->[1] eq 'body') {
10675     for (@{$self->{open_elements}}) {
10676     unless ({
10677     dd => 1, dt => 1, li => 1, p => 1, td => 1,
10678     th => 1, tr => 1, body => 1, html => 1,
10679     tbody => 1, tfoot => 1, thead => 1,
10680     }->{$_->[1]}) {
10681 wakaba 1.79
10682     $Whatpm::HTML::Debug::cp_pass->('t403') if $Whatpm::HTML::Debug::cp_pass;
10683     BEGIN {
10684     $Whatpm::HTML::Debug::cp->{'t403'} = 1;
10685     }
10686    
10687 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$_->[1]);
10688 wakaba 1.79 } else {
10689    
10690     $Whatpm::HTML::Debug::cp_pass->('t404') if $Whatpm::HTML::Debug::cp_pass;
10691     BEGIN {
10692     $Whatpm::HTML::Debug::cp->{'t404'} = 1;
10693     }
10694    
10695 wakaba 1.54 }
10696     }
10697 wakaba 1.53
10698 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
10699 wakaba 1.54 $token = $self->_get_next_token;
10700 wakaba 1.55 redo B;
10701 wakaba 1.54 } else {
10702 wakaba 1.79
10703     $Whatpm::HTML::Debug::cp_pass->('t405') if $Whatpm::HTML::Debug::cp_pass;
10704     BEGIN {
10705     $Whatpm::HTML::Debug::cp->{'t405'} = 1;
10706     }
10707    
10708 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10709     ## Ignore the token
10710     $token = $self->_get_next_token;
10711 wakaba 1.55 redo B;
10712 wakaba 1.53 }
10713 wakaba 1.54 } elsif ($token->{tag_name} eq 'html') {
10714     if (@{$self->{open_elements}} > 1 and $self->{open_elements}->[1]->[1] eq 'body') {
10715     ## ISSUE: There is an issue in the spec.
10716     if ($self->{open_elements}->[-1]->[1] ne 'body') {
10717 wakaba 1.79
10718     $Whatpm::HTML::Debug::cp_pass->('t406') if $Whatpm::HTML::Debug::cp_pass;
10719     BEGIN {
10720     $Whatpm::HTML::Debug::cp->{'t406'} = 1;
10721     }
10722    
10723 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[1]->[1]);
10724 wakaba 1.79 } else {
10725    
10726     $Whatpm::HTML::Debug::cp_pass->('t407') if $Whatpm::HTML::Debug::cp_pass;
10727     BEGIN {
10728     $Whatpm::HTML::Debug::cp->{'t407'} = 1;
10729     }
10730    
10731 wakaba 1.54 }
10732 wakaba 1.56 $self->{insertion_mode} = AFTER_BODY_IM;
10733 wakaba 1.54 ## reprocess
10734 wakaba 1.55 redo B;
10735 wakaba 1.54 } else {
10736 wakaba 1.79
10737     $Whatpm::HTML::Debug::cp_pass->('t408') if $Whatpm::HTML::Debug::cp_pass;
10738     BEGIN {
10739     $Whatpm::HTML::Debug::cp->{'t408'} = 1;
10740     }
10741    
10742 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10743     ## Ignore the token
10744     $token = $self->_get_next_token;
10745 wakaba 1.55 redo B;
10746 wakaba 1.53 }
10747 wakaba 1.54 } elsif ({
10748     address => 1, blockquote => 1, center => 1, dir => 1,
10749     div => 1, dl => 1, fieldset => 1, listing => 1,
10750     menu => 1, ol => 1, pre => 1, ul => 1,
10751     p => 1,
10752     dd => 1, dt => 1, li => 1,
10753     button => 1, marquee => 1, object => 1,
10754     }->{$token->{tag_name}}) {
10755     ## has an element in scope
10756     my $i;
10757     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10758     my $node = $self->{open_elements}->[$_];
10759     if ($node->[1] eq $token->{tag_name}) {
10760     ## generate implied end tags
10761     if ({
10762     dd => ($token->{tag_name} ne 'dd'),
10763     dt => ($token->{tag_name} ne 'dt'),
10764     li => ($token->{tag_name} ne 'li'),
10765     p => ($token->{tag_name} ne 'p'),
10766     td => 1, th => 1, tr => 1,
10767     tbody => 1, tfoot=> 1, thead => 1,
10768     }->{$self->{open_elements}->[-1]->[1]}) {
10769 wakaba 1.79
10770     $Whatpm::HTML::Debug::cp_pass->('t409') if $Whatpm::HTML::Debug::cp_pass;
10771     BEGIN {
10772     $Whatpm::HTML::Debug::cp->{'t409'} = 1;
10773     }
10774    
10775 wakaba 1.54 unshift @{$self->{token}}, $token;
10776 wakaba 1.57 $token = {type => END_TAG_TOKEN,
10777 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
10778 wakaba 1.55 redo B;
10779 wakaba 1.54 }
10780 wakaba 1.79
10781    
10782     $Whatpm::HTML::Debug::cp_pass->('t410') if $Whatpm::HTML::Debug::cp_pass;
10783     BEGIN {
10784     $Whatpm::HTML::Debug::cp->{'t410'} = 1;
10785     }
10786    
10787 wakaba 1.54 $i = $_;
10788     last INSCOPE unless $token->{tag_name} eq 'p';
10789     } elsif ({
10790     table => 1, caption => 1, td => 1, th => 1,
10791     button => 1, marquee => 1, object => 1, html => 1,
10792     }->{$node->[1]}) {
10793 wakaba 1.79
10794     $Whatpm::HTML::Debug::cp_pass->('t411') if $Whatpm::HTML::Debug::cp_pass;
10795     BEGIN {
10796     $Whatpm::HTML::Debug::cp->{'t411'} = 1;
10797     }
10798    
10799 wakaba 1.54 last INSCOPE;
10800     }
10801     } # INSCOPE
10802    
10803     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
10804     if (defined $i) {
10805 wakaba 1.79
10806     $Whatpm::HTML::Debug::cp_pass->('t412') if $Whatpm::HTML::Debug::cp_pass;
10807     BEGIN {
10808     $Whatpm::HTML::Debug::cp->{'t412'} = 1;
10809     }
10810    
10811 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
10812 wakaba 1.1 } else {
10813 wakaba 1.79
10814     $Whatpm::HTML::Debug::cp_pass->('t413') if $Whatpm::HTML::Debug::cp_pass;
10815     BEGIN {
10816     $Whatpm::HTML::Debug::cp->{'t413'} = 1;
10817     }
10818    
10819 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10820 wakaba 1.1 }
10821 wakaba 1.53 }
10822 wakaba 1.54
10823     if (defined $i) {
10824 wakaba 1.79
10825     $Whatpm::HTML::Debug::cp_pass->('t414') if $Whatpm::HTML::Debug::cp_pass;
10826     BEGIN {
10827     $Whatpm::HTML::Debug::cp->{'t414'} = 1;
10828     }
10829    
10830 wakaba 1.54 splice @{$self->{open_elements}}, $i;
10831     } elsif ($token->{tag_name} eq 'p') {
10832 wakaba 1.79
10833     $Whatpm::HTML::Debug::cp_pass->('t415') if $Whatpm::HTML::Debug::cp_pass;
10834     BEGIN {
10835     $Whatpm::HTML::Debug::cp->{'t415'} = 1;
10836     }
10837    
10838 wakaba 1.54 ## As if <p>, then reprocess the current token
10839     my $el;
10840 wakaba 1.53
10841 wakaba 1.54 $el = $self->{document}->create_element_ns
10842     (q<http://www.w3.org/1999/xhtml>, [undef, 'p']);
10843    
10844     $insert->($el);
10845 wakaba 1.79 } else {
10846    
10847     $Whatpm::HTML::Debug::cp_pass->('t416') if $Whatpm::HTML::Debug::cp_pass;
10848     BEGIN {
10849     $Whatpm::HTML::Debug::cp->{'t416'} = 1;
10850     }
10851    
10852 wakaba 1.54 }
10853     $clear_up_to_marker->()
10854     if {
10855     button => 1, marquee => 1, object => 1,
10856     }->{$token->{tag_name}};
10857     $token = $self->_get_next_token;
10858 wakaba 1.55 redo B;
10859 wakaba 1.54 } elsif ($token->{tag_name} eq 'form') {
10860     ## has an element in scope
10861     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10862     my $node = $self->{open_elements}->[$_];
10863     if ($node->[1] eq $token->{tag_name}) {
10864     ## generate implied end tags
10865     if ({
10866     dd => 1, dt => 1, li => 1, p => 1,
10867     td => 1, th => 1, tr => 1,
10868     tbody => 1, tfoot=> 1, thead => 1,
10869     }->{$self->{open_elements}->[-1]->[1]}) {
10870 wakaba 1.79
10871     $Whatpm::HTML::Debug::cp_pass->('t417') if $Whatpm::HTML::Debug::cp_pass;
10872     BEGIN {
10873     $Whatpm::HTML::Debug::cp->{'t417'} = 1;
10874     }
10875    
10876 wakaba 1.54 unshift @{$self->{token}}, $token;
10877 wakaba 1.57 $token = {type => END_TAG_TOKEN,
10878 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
10879 wakaba 1.55 redo B;
10880 wakaba 1.54 }
10881 wakaba 1.79
10882    
10883     $Whatpm::HTML::Debug::cp_pass->('t418') if $Whatpm::HTML::Debug::cp_pass;
10884     BEGIN {
10885     $Whatpm::HTML::Debug::cp->{'t418'} = 1;
10886     }
10887    
10888 wakaba 1.54 last INSCOPE;
10889     } elsif ({
10890     table => 1, caption => 1, td => 1, th => 1,
10891     button => 1, marquee => 1, object => 1, html => 1,
10892     }->{$node->[1]}) {
10893 wakaba 1.79
10894     $Whatpm::HTML::Debug::cp_pass->('t419') if $Whatpm::HTML::Debug::cp_pass;
10895     BEGIN {
10896     $Whatpm::HTML::Debug::cp->{'t419'} = 1;
10897     }
10898    
10899 wakaba 1.54 last INSCOPE;
10900 wakaba 1.36 }
10901 wakaba 1.54 } # INSCOPE
10902    
10903     if ($self->{open_elements}->[-1]->[1] eq $token->{tag_name}) {
10904 wakaba 1.79
10905     $Whatpm::HTML::Debug::cp_pass->('t420') if $Whatpm::HTML::Debug::cp_pass;
10906     BEGIN {
10907     $Whatpm::HTML::Debug::cp->{'t420'} = 1;
10908     }
10909    
10910 wakaba 1.54 pop @{$self->{open_elements}};
10911     } else {
10912 wakaba 1.79
10913     $Whatpm::HTML::Debug::cp_pass->('t421') if $Whatpm::HTML::Debug::cp_pass;
10914     BEGIN {
10915     $Whatpm::HTML::Debug::cp->{'t421'} = 1;
10916     }
10917    
10918 wakaba 1.60 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10919 wakaba 1.36 }
10920    
10921 wakaba 1.54 undef $self->{form_element};
10922     $token = $self->_get_next_token;
10923 wakaba 1.55 redo B;
10924 wakaba 1.54 } elsif ({
10925     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
10926     }->{$token->{tag_name}}) {
10927     ## has an element in scope
10928     my $i;
10929     INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
10930     my $node = $self->{open_elements}->[$_];
10931     if ({
10932     h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
10933     }->{$node->[1]}) {
10934     ## generate implied end tags
10935     if ({
10936     dd => 1, dt => 1, li => 1, p => 1,
10937     td => 1, th => 1, tr => 1,
10938     tbody => 1, tfoot=> 1, thead => 1,
10939     }->{$self->{open_elements}->[-1]->[1]}) {
10940 wakaba 1.79
10941     $Whatpm::HTML::Debug::cp_pass->('t422') if $Whatpm::HTML::Debug::cp_pass;
10942     BEGIN {
10943     $Whatpm::HTML::Debug::cp->{'t422'} = 1;
10944     }
10945    
10946 wakaba 1.54 unshift @{$self->{token}}, $token;
10947 wakaba 1.57 $token = {type => END_TAG_TOKEN,
10948 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
10949 wakaba 1.55 redo B;
10950 wakaba 1.54 }
10951 wakaba 1.79
10952    
10953     $Whatpm::HTML::Debug::cp_pass->('t423') if $Whatpm::HTML::Debug::cp_pass;
10954     BEGIN {
10955     $Whatpm::HTML::Debug::cp->{'t423'} = 1;
10956     }
10957    
10958 wakaba 1.54 $i = $_;
10959     last INSCOPE;
10960     } elsif ({
10961     table => 1, caption => 1, td => 1, th => 1,
10962     button => 1, marquee => 1, object => 1, html => 1,
10963     }->{$node->[1]}) {
10964 wakaba 1.79
10965     $Whatpm::HTML::Debug::cp_pass->('t424') if $Whatpm::HTML::Debug::cp_pass;
10966     BEGIN {
10967     $Whatpm::HTML::Debug::cp->{'t424'} = 1;
10968     }
10969    
10970 wakaba 1.54 last INSCOPE;
10971 wakaba 1.53 }
10972 wakaba 1.54 } # INSCOPE
10973    
10974     if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
10975 wakaba 1.79
10976     $Whatpm::HTML::Debug::cp_pass->('t425') if $Whatpm::HTML::Debug::cp_pass;
10977     BEGIN {
10978     $Whatpm::HTML::Debug::cp->{'t425'} = 1;
10979     }
10980    
10981 wakaba 1.60 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
10982 wakaba 1.79 } else {
10983    
10984     $Whatpm::HTML::Debug::cp_pass->('t426') if $Whatpm::HTML::Debug::cp_pass;
10985     BEGIN {
10986     $Whatpm::HTML::Debug::cp->{'t426'} = 1;
10987     }
10988    
10989 wakaba 1.53 }
10990    
10991 wakaba 1.54 splice @{$self->{open_elements}}, $i if defined $i;
10992     $token = $self->_get_next_token;
10993 wakaba 1.55 redo B;
10994 wakaba 1.54 } elsif ({
10995     a => 1,
10996     b => 1, big => 1, em => 1, font => 1, i => 1,
10997     nobr => 1, s => 1, small => 1, strile => 1,
10998     strong => 1, tt => 1, u => 1,
10999     }->{$token->{tag_name}}) {
11000 wakaba 1.79
11001     $Whatpm::HTML::Debug::cp_pass->('t427') if $Whatpm::HTML::Debug::cp_pass;
11002     BEGIN {
11003     $Whatpm::HTML::Debug::cp->{'t427'} = 1;
11004     }
11005    
11006 wakaba 1.54 $formatting_end_tag->($token->{tag_name});
11007 wakaba 1.55 redo B;
11008 wakaba 1.54 } elsif ($token->{tag_name} eq 'br') {
11009 wakaba 1.79
11010     $Whatpm::HTML::Debug::cp_pass->('t428') if $Whatpm::HTML::Debug::cp_pass;
11011     BEGIN {
11012     $Whatpm::HTML::Debug::cp->{'t428'} = 1;
11013     }
11014    
11015 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:br');
11016 wakaba 1.53
11017 wakaba 1.54 ## As if <br>
11018     $reconstruct_active_formatting_elements->($insert_to_current);
11019    
11020     my $el;
11021    
11022 wakaba 1.1 $el = $self->{document}->create_element_ns
11023 wakaba 1.54 (q<http://www.w3.org/1999/xhtml>, [undef, 'br']);
11024 wakaba 1.1
11025 wakaba 1.54 $insert->($el);
11026    
11027     ## Ignore the token.
11028     $token = $self->_get_next_token;
11029 wakaba 1.55 redo B;
11030 wakaba 1.54 } elsif ({
11031     caption => 1, col => 1, colgroup => 1, frame => 1,
11032     frameset => 1, head => 1, option => 1, optgroup => 1,
11033     tbody => 1, td => 1, tfoot => 1, th => 1,
11034     thead => 1, tr => 1,
11035     area => 1, basefont => 1, bgsound => 1,
11036     embed => 1, hr => 1, iframe => 1, image => 1,
11037     img => 1, input => 1, isindex => 1, noembed => 1,
11038     noframes => 1, param => 1, select => 1, spacer => 1,
11039     table => 1, textarea => 1, wbr => 1,
11040     noscript => 0, ## TODO: if scripting is enabled
11041     }->{$token->{tag_name}}) {
11042 wakaba 1.79
11043     $Whatpm::HTML::Debug::cp_pass->('t429') if $Whatpm::HTML::Debug::cp_pass;
11044     BEGIN {
11045     $Whatpm::HTML::Debug::cp->{'t429'} = 1;
11046     }
11047    
11048 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
11049     ## Ignore the token
11050     $token = $self->_get_next_token;
11051 wakaba 1.55 redo B;
11052 wakaba 1.54
11053     ## ISSUE: Issue on HTML5 new elements in spec
11054    
11055     } else {
11056     ## Step 1
11057     my $node_i = -1;
11058     my $node = $self->{open_elements}->[$node_i];
11059    
11060     ## Step 2
11061     S2: {
11062     if ($node->[1] eq $token->{tag_name}) {
11063     ## Step 1
11064     ## generate implied end tags
11065     if ({
11066     dd => 1, dt => 1, li => 1, p => 1,
11067     td => 1, th => 1, tr => 1,
11068 wakaba 1.57 tbody => 1, tfoot => 1, thead => 1,
11069 wakaba 1.54 }->{$self->{open_elements}->[-1]->[1]}) {
11070 wakaba 1.79
11071     $Whatpm::HTML::Debug::cp_pass->('t430') if $Whatpm::HTML::Debug::cp_pass;
11072     BEGIN {
11073     $Whatpm::HTML::Debug::cp->{'t430'} = 1;
11074     }
11075    
11076 wakaba 1.54 unshift @{$self->{token}}, $token;
11077 wakaba 1.57 $token = {type => END_TAG_TOKEN,
11078 wakaba 1.54 tag_name => $self->{open_elements}->[-1]->[1]}; # MUST
11079 wakaba 1.55 redo B;
11080 wakaba 1.54 }
11081    
11082     ## Step 2
11083     if ($token->{tag_name} ne $self->{open_elements}->[-1]->[1]) {
11084 wakaba 1.79
11085     $Whatpm::HTML::Debug::cp_pass->('t431') if $Whatpm::HTML::Debug::cp_pass;
11086     BEGIN {
11087     $Whatpm::HTML::Debug::cp->{'t431'} = 1;
11088     }
11089    
11090 wakaba 1.60 ## NOTE: <x><y></x>
11091 wakaba 1.54 $self->{parse_error}-> (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
11092 wakaba 1.79 } else {
11093    
11094     $Whatpm::HTML::Debug::cp_pass->('t432') if $Whatpm::HTML::Debug::cp_pass;
11095     BEGIN {
11096     $Whatpm::HTML::Debug::cp->{'t432'} = 1;
11097     }
11098    
11099 wakaba 1.54 }
11100    
11101     ## Step 3
11102     splice @{$self->{open_elements}}, $node_i;
11103 wakaba 1.53
11104 wakaba 1.36 $token = $self->_get_next_token;
11105 wakaba 1.54 last S2;
11106 wakaba 1.1 } else {
11107 wakaba 1.54 ## Step 3
11108     if (not $formatting_category->{$node->[1]} and
11109     #not $phrasing_category->{$node->[1]} and
11110     ($special_category->{$node->[1]} or
11111     $scoping_category->{$node->[1]})) {
11112 wakaba 1.79
11113     $Whatpm::HTML::Debug::cp_pass->('t433') if $Whatpm::HTML::Debug::cp_pass;
11114     BEGIN {
11115     $Whatpm::HTML::Debug::cp->{'t433'} = 1;
11116     }
11117    
11118 wakaba 1.54 $self->{parse_error}-> (type => 'unmatched end tag:'.$token->{tag_name});
11119     ## Ignore the token
11120     $token = $self->_get_next_token;
11121     last S2;
11122     }
11123 wakaba 1.79
11124    
11125     $Whatpm::HTML::Debug::cp_pass->('t434') if $Whatpm::HTML::Debug::cp_pass;
11126     BEGIN {
11127     $Whatpm::HTML::Debug::cp->{'t434'} = 1;
11128     }
11129    
11130 wakaba 1.1 }
11131 wakaba 1.54
11132     ## Step 4
11133     $node_i--;
11134     $node = $self->{open_elements}->[$node_i];
11135    
11136     ## Step 5;
11137     redo S2;
11138     } # S2
11139 wakaba 1.55 redo B;
11140 wakaba 1.1 }
11141     }
11142 wakaba 1.54 redo B;
11143 wakaba 1.1 } # B
11144    
11145 wakaba 1.53 ## NOTE: The "trailing end" phase in HTML5 is split into
11146     ## two insertion modes: "after html body" and "after html frameset".
11147     ## NOTE: States in the main stage is preserved while
11148     ## the parser stays in the trailing end phase. # MUST
11149    
11150 wakaba 1.1 ## Stop parsing # MUST
11151    
11152     ## TODO: script stuffs
11153 wakaba 1.3 } # _tree_construct_main
11154    
11155     sub set_inner_html ($$$) {
11156     my $class = shift;
11157     my $node = shift;
11158     my $s = \$_[0];
11159     my $onerror = $_[1];
11160    
11161 wakaba 1.65 ## ISSUE: Should {confident} be true?
11162    
11163 wakaba 1.3 my $nt = $node->node_type;
11164     if ($nt == 9) {
11165     # MUST
11166    
11167     ## Step 1 # MUST
11168     ## TODO: If the document has an active parser, ...
11169     ## ISSUE: There is an issue in the spec.
11170    
11171     ## Step 2 # MUST
11172     my @cn = @{$node->child_nodes};
11173     for (@cn) {
11174     $node->remove_child ($_);
11175     }
11176    
11177     ## Step 3, 4, 5 # MUST
11178     $class->parse_string ($$s => $node, $onerror);
11179     } elsif ($nt == 1) {
11180     ## TODO: If non-html element
11181    
11182     ## NOTE: Most of this code is copied from |parse_string|
11183    
11184     ## Step 1 # MUST
11185 wakaba 1.14 my $this_doc = $node->owner_document;
11186     my $doc = $this_doc->implementation->create_document;
11187 wakaba 1.18 $doc->manakai_is_html (1);
11188 wakaba 1.3 my $p = $class->new;
11189     $p->{document} = $doc;
11190    
11191     ## Step 9 # MUST
11192     my $i = 0;
11193     my $line = 1;
11194     my $column = 0;
11195 wakaba 1.76 $p->{set_next_char} = sub {
11196 wakaba 1.3 my $self = shift;
11197 wakaba 1.14
11198 wakaba 1.76 pop @{$self->{prev_char}};
11199     unshift @{$self->{prev_char}}, $self->{next_char};
11200 wakaba 1.14
11201 wakaba 1.76 $self->{next_char} = -1 and return if $i >= length $$s;
11202     $self->{next_char} = ord substr $$s, $i++, 1;
11203 wakaba 1.3 $column++;
11204 wakaba 1.4
11205 wakaba 1.76 if ($self->{next_char} == 0x000A) { # LF
11206 wakaba 1.4 $line++;
11207     $column = 0;
11208 wakaba 1.79
11209     $Whatpm::HTML::Debug::cp_pass->('i1') if $Whatpm::HTML::Debug::cp_pass;
11210     BEGIN {
11211     $Whatpm::HTML::Debug::cp->{'i1'} = 1;
11212     }
11213    
11214 wakaba 1.76 } elsif ($self->{next_char} == 0x000D) { # CR
11215 wakaba 1.15 $i++ if substr ($$s, $i, 1) eq "\x0A";
11216 wakaba 1.76 $self->{next_char} = 0x000A; # LF # MUST
11217 wakaba 1.3 $line++;
11218 wakaba 1.4 $column = 0;
11219 wakaba 1.79
11220     $Whatpm::HTML::Debug::cp_pass->('i2') if $Whatpm::HTML::Debug::cp_pass;
11221     BEGIN {
11222     $Whatpm::HTML::Debug::cp->{'i2'} = 1;
11223     }
11224    
11225 wakaba 1.76 } elsif ($self->{next_char} > 0x10FFFF) {
11226     $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
11227 wakaba 1.79
11228     $Whatpm::HTML::Debug::cp_pass->('i3') if $Whatpm::HTML::Debug::cp_pass;
11229     BEGIN {
11230     $Whatpm::HTML::Debug::cp->{'i3'} = 1;
11231     }
11232    
11233 wakaba 1.76 } elsif ($self->{next_char} == 0x0000) { # NULL
11234 wakaba 1.79
11235     $Whatpm::HTML::Debug::cp_pass->('i4') if $Whatpm::HTML::Debug::cp_pass;
11236     BEGIN {
11237     $Whatpm::HTML::Debug::cp->{'i4'} = 1;
11238     }
11239    
11240 wakaba 1.14 $self->{parse_error}-> (type => 'NULL');
11241 wakaba 1.76 $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
11242 wakaba 1.3 }
11243     };
11244 wakaba 1.76 $p->{prev_char} = [-1, -1, -1];
11245     $p->{next_char} = -1;
11246 wakaba 1.3
11247     my $ponerror = $onerror || sub {
11248     my (%opt) = @_;
11249     warn "Parse error ($opt{type}) at line $opt{line} column $opt{column}\n";
11250     };
11251     $p->{parse_error} = sub {
11252     $ponerror->(@_, line => $line, column => $column);
11253     };
11254    
11255     $p->_initialize_tokenizer;
11256     $p->_initialize_tree_constructor;
11257    
11258     ## Step 2
11259 wakaba 1.71 my $node_ln = $node->manakai_local_name;
11260 wakaba 1.41 $p->{content_model} = {
11261     title => RCDATA_CONTENT_MODEL,
11262     textarea => RCDATA_CONTENT_MODEL,
11263     style => CDATA_CONTENT_MODEL,
11264     script => CDATA_CONTENT_MODEL,
11265     xmp => CDATA_CONTENT_MODEL,
11266     iframe => CDATA_CONTENT_MODEL,
11267     noembed => CDATA_CONTENT_MODEL,
11268     noframes => CDATA_CONTENT_MODEL,
11269     noscript => CDATA_CONTENT_MODEL,
11270     plaintext => PLAINTEXT_CONTENT_MODEL,
11271     }->{$node_ln};
11272     $p->{content_model} = PCDATA_CONTENT_MODEL
11273     unless defined $p->{content_model};
11274     ## ISSUE: What is "the name of the element"? local name?
11275 wakaba 1.3
11276     $p->{inner_html_node} = [$node, $node_ln];
11277    
11278     ## Step 4
11279     my $root = $doc->create_element_ns
11280     ('http://www.w3.org/1999/xhtml', [undef, 'html']);
11281    
11282     ## Step 5 # MUST
11283     $doc->append_child ($root);
11284    
11285     ## Step 6 # MUST
11286     push @{$p->{open_elements}}, [$root, 'html'];
11287    
11288     undef $p->{head_element};
11289    
11290     ## Step 7 # MUST
11291     $p->_reset_insertion_mode;
11292    
11293     ## Step 8 # MUST
11294     my $anode = $node;
11295     AN: while (defined $anode) {
11296     if ($anode->node_type == 1) {
11297     my $nsuri = $anode->namespace_uri;
11298     if (defined $nsuri and $nsuri eq 'http://www.w3.org/1999/xhtml') {
11299 wakaba 1.71 if ($anode->manakai_local_name eq 'form') {
11300 wakaba 1.79
11301     $Whatpm::HTML::Debug::cp_pass->('i5') if $Whatpm::HTML::Debug::cp_pass;
11302     BEGIN {
11303     $Whatpm::HTML::Debug::cp->{'i5'} = 1;
11304     }
11305    
11306 wakaba 1.3 $p->{form_element} = $anode;
11307     last AN;
11308     }
11309     }
11310     }
11311     $anode = $anode->parent_node;
11312     } # AN
11313    
11314     ## Step 3 # MUST
11315     ## Step 10 # MUST
11316     {
11317     my $self = $p;
11318     $token = $self->_get_next_token;
11319     }
11320     $p->_tree_construction_main;
11321    
11322     ## Step 11 # MUST
11323     my @cn = @{$node->child_nodes};
11324     for (@cn) {
11325     $node->remove_child ($_);
11326     }
11327     ## ISSUE: mutation events? read-only?
11328    
11329     ## Step 12 # MUST
11330     @cn = @{$root->child_nodes};
11331     for (@cn) {
11332 wakaba 1.14 $this_doc->adopt_node ($_);
11333 wakaba 1.3 $node->append_child ($_);
11334     }
11335 wakaba 1.14 ## ISSUE: mutation events?
11336 wakaba 1.3
11337     $p->_terminate_tree_constructor;
11338     } else {
11339     die "$0: |set_inner_html| is not defined for node of type $nt";
11340     }
11341     } # set_inner_html
11342    
11343     } # tree construction stage
11344 wakaba 1.1
11345 wakaba 1.65 package Whatpm::HTML::RestartParser;
11346     push our @ISA, 'Error';
11347    
11348 wakaba 1.1 1;
11349 wakaba 1.81 # $Date: 2008/03/04 00:03:13 $

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24