/[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.83 - (hide annotations) (download)
Wed Mar 5 13:07:01 2008 UTC (18 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.82: +48 -17 lines
++ whatpm/t/ChangeLog	5 Mar 2008 13:06:44 -0000
	* HTML-tree.t: Support for \Uhhhhhhhh escapes.  Support for
	dumping PUBLIC and SYSTEM identifiers of DOCTYPE tokens.

	* tree-test-1.dat, tree-test-2.dat: More test data for previously
	uncovered cases are added.  Some error descriptions are revised.

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

++ whatpm/Whatpm/ChangeLog	5 Mar 2008 13:04:50 -0000
	* HTML.pm.src: Since the case t268 should never be reached (no
	other token type, there are), it is replaced by a |die| statement.

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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24