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

Diff of /markup/html/whatpm/Whatpm/HTML.pm.src

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.102 by wakaba, Sun Mar 9 06:29:25 2008 UTC revision 1.124 by wakaba, Sun Apr 6 10:34:11 2008 UTC
# Line 12  use Error qw(:try); Line 12  use Error qw(:try);
12  ## TODO: 1252 parse error (revision 1264)  ## TODO: 1252 parse error (revision 1264)
13  ## TODO: 8859-11 = 874 (revision 1271)  ## TODO: 8859-11 = 874 (revision 1271)
14    
15    sub A_EL () { 0b1 }
16    sub ADDRESS_EL () { 0b10 }
17    sub BODY_EL () { 0b100 }
18    sub BUTTON_EL () { 0b1000 }
19    sub CAPTION_EL () { 0b10000 }
20    sub DD_EL () { 0b100000 }
21    sub DIV_EL () { 0b1000000 }
22    sub DT_EL () { 0b10000000 }
23    sub FORM_EL () { 0b100000000 }
24    sub FORMATTING_EL () { 0b1000000000 }
25    sub FRAMESET_EL () { 0b10000000000 }
26    sub HEADING_EL () { 0b100000000000 }
27    sub HTML_EL () { 0b1000000000000 }
28    sub LI_EL () { 0b10000000000000 }
29    sub NOBR_EL () { 0b100000000000000 }
30    sub OPTION_EL () { 0b1000000000000000 }
31    sub OPTGROUP_EL () { 0b10000000000000000 }
32    sub P_EL () { 0b100000000000000000 }
33    sub SELECT_EL () { 0b1000000000000000000 }
34    sub TABLE_EL () { 0b10000000000000000000 }
35    sub TABLE_CELL_EL () { 0b100000000000000000000 }
36    sub TABLE_ROW_EL () { 0b1000000000000000000000 }
37    sub TABLE_ROW_GROUP_EL () { 0b10000000000000000000000 }
38    sub MISC_SCOPING_EL () { 0b100000000000000000000000 }
39    sub MISC_SPECIAL_EL () { 0b1000000000000000000000000 }
40    
41    sub TABLE_ROWS_EL () {
42      TABLE_EL |
43      TABLE_ROW_EL |
44      TABLE_ROW_GROUP_EL
45    }
46    
47    sub END_TAG_OPTIONAL_EL () {
48      DD_EL |
49      DT_EL |
50      LI_EL |
51      P_EL
52    }
53    
54    sub ALL_END_TAG_OPTIONAL_EL () {
55      END_TAG_OPTIONAL_EL |
56      BODY_EL |
57      HTML_EL |
58      TABLE_CELL_EL |
59      TABLE_ROW_EL |
60      TABLE_ROW_GROUP_EL
61    }
62    
63    sub SCOPING_EL () {
64      BUTTON_EL |
65      CAPTION_EL |
66      HTML_EL |
67      TABLE_EL |
68      TABLE_CELL_EL |
69      MISC_SCOPING_EL
70    }
71    
72    sub TABLE_SCOPING_EL () {
73      HTML_EL |
74      TABLE_EL
75    }
76    
77    sub TABLE_ROWS_SCOPING_EL () {
78      HTML_EL |
79      TABLE_ROW_GROUP_EL
80    }
81    
82    sub TABLE_ROW_SCOPING_EL () {
83      HTML_EL |
84      TABLE_ROW_EL
85    }
86    
87    sub SPECIAL_EL () {
88      ADDRESS_EL |
89      BODY_EL |
90      DIV_EL |
91      END_TAG_OPTIONAL_EL |
92      FORM_EL |
93      FRAMESET_EL |
94      HEADING_EL |
95      OPTION_EL |
96      OPTGROUP_EL |
97      SELECT_EL |
98      TABLE_ROW_EL |
99      TABLE_ROW_GROUP_EL |
100      MISC_SPECIAL_EL
101    }
102    
103    my $el_category = {
104      a => A_EL | FORMATTING_EL,
105      address => ADDRESS_EL,
106      applet => MISC_SCOPING_EL,
107      area => MISC_SPECIAL_EL,
108      b => FORMATTING_EL,
109      base => MISC_SPECIAL_EL,
110      basefont => MISC_SPECIAL_EL,
111      bgsound => MISC_SPECIAL_EL,
112      big => FORMATTING_EL,
113      blockquote => MISC_SPECIAL_EL,
114      body => BODY_EL,
115      br => MISC_SPECIAL_EL,
116      button => BUTTON_EL,
117      caption => CAPTION_EL,
118      center => MISC_SPECIAL_EL,
119      col => MISC_SPECIAL_EL,
120      colgroup => MISC_SPECIAL_EL,
121      dd => DD_EL,
122      dir => MISC_SPECIAL_EL,
123      div => DIV_EL,
124      dl => MISC_SPECIAL_EL,
125      dt => DT_EL,
126      em => FORMATTING_EL,
127      embed => MISC_SPECIAL_EL,
128      fieldset => MISC_SPECIAL_EL,
129      font => FORMATTING_EL,
130      form => FORM_EL,
131      frame => MISC_SPECIAL_EL,
132      frameset => FRAMESET_EL,
133      h1 => HEADING_EL,
134      h2 => HEADING_EL,
135      h3 => HEADING_EL,
136      h4 => HEADING_EL,
137      h5 => HEADING_EL,
138      h6 => HEADING_EL,
139      head => MISC_SPECIAL_EL,
140      hr => MISC_SPECIAL_EL,
141      html => HTML_EL,
142      i => FORMATTING_EL,
143      iframe => MISC_SPECIAL_EL,
144      img => MISC_SPECIAL_EL,
145      input => MISC_SPECIAL_EL,
146      isindex => MISC_SPECIAL_EL,
147      li => LI_EL,
148      link => MISC_SPECIAL_EL,
149      listing => MISC_SPECIAL_EL,
150      marquee => MISC_SCOPING_EL,
151      menu => MISC_SPECIAL_EL,
152      meta => MISC_SPECIAL_EL,
153      nobr => NOBR_EL | FORMATTING_EL,
154      noembed => MISC_SPECIAL_EL,
155      noframes => MISC_SPECIAL_EL,
156      noscript => MISC_SPECIAL_EL,
157      object => MISC_SCOPING_EL,
158      ol => MISC_SPECIAL_EL,
159      optgroup => OPTGROUP_EL,
160      option => OPTION_EL,
161      p => P_EL,
162      param => MISC_SPECIAL_EL,
163      plaintext => MISC_SPECIAL_EL,
164      pre => MISC_SPECIAL_EL,
165      s => FORMATTING_EL,
166      script => MISC_SPECIAL_EL,
167      select => SELECT_EL,
168      small => FORMATTING_EL,
169      spacer => MISC_SPECIAL_EL,
170      strike => FORMATTING_EL,
171      strong => FORMATTING_EL,
172      style => MISC_SPECIAL_EL,
173      table => TABLE_EL,
174      tbody => TABLE_ROW_GROUP_EL,
175      td => TABLE_CELL_EL,
176      textarea => MISC_SPECIAL_EL,
177      tfoot => TABLE_ROW_GROUP_EL,
178      th => TABLE_CELL_EL,
179      thead => TABLE_ROW_GROUP_EL,
180      title => MISC_SPECIAL_EL,
181      tr => TABLE_ROW_EL,
182      tt => FORMATTING_EL,
183      u => FORMATTING_EL,
184      ul => MISC_SPECIAL_EL,
185      wbr => MISC_SPECIAL_EL,
186    };
187    
188  my $permitted_slash_tag_name = {  my $permitted_slash_tag_name = {
189    base => 1,    base => 1,
190    link => 1,    link => 1,
# Line 61  my $c1_entity_char = { Line 234  my $c1_entity_char = {
234    0x9F => 0x0178,    0x9F => 0x0178,
235  }; # $c1_entity_char  }; # $c1_entity_char
236    
 my $special_category = {  
   address => 1, area => 1, base => 1, basefont => 1, bgsound => 1,  
   blockquote => 1, body => 1, br => 1, center => 1, col => 1, colgroup => 1,  
   dd => 1, dir => 1, div => 1, dl => 1, dt => 1, embed => 1, fieldset => 1,  
   form => 1, frame => 1, frameset => 1, h1 => 1, h2 => 1, h3 => 1,  
   h4 => 1, h5 => 1, h6 => 1, head => 1, hr => 1, iframe => 1, image => 1,  
   img => 1, input => 1, isindex => 1, li => 1, link => 1, listing => 1,  
   menu => 1, meta => 1, noembed => 1, noframes => 1, noscript => 1,  
   ol => 1, optgroup => 1, option => 1, p => 1, param => 1, plaintext => 1,  
   pre => 1, script => 1, select => 1, spacer => 1, style => 1, tbody => 1,  
   textarea => 1, tfoot => 1, thead => 1, title => 1, tr => 1, ul => 1, wbr => 1,  
 };  
 my $scoping_category = {  
   button => 1, caption => 1, html => 1, marquee => 1, object => 1,  
   table => 1, td => 1, th => 1,  
 };  
 my $formatting_category = {  
   a => 1, b => 1, big => 1, em => 1, font => 1, i => 1, nobr => 1,  
   s => 1, small => 1, strile => 1, strong => 1, tt => 1, u => 1,  
 };  
 # $phrasing_category: all other elements  
   
237  sub parse_byte_string ($$$$;$) {  sub parse_byte_string ($$$$;$) {
238    my $self = ref $_[0] ? shift : shift->new;    my $self = ref $_[0] ? shift : shift->new;
239    my $charset = shift;    my $charset = shift;
# Line 108  sub parse_byte_string ($$$$;$) { Line 259  sub parse_byte_string ($$$$;$) {
259    $self->{change_encoding} = sub {    $self->{change_encoding} = sub {
260      my $self = shift;      my $self = shift;
261      my $charset = lc shift;      my $charset = lc shift;
262        my $token = shift;
263      ## TODO: if $charset is supported      ## TODO: if $charset is supported
264      ## TODO: normalize charset name      ## TODO: normalize charset name
265    
# Line 126  sub parse_byte_string ($$$$;$) { Line 278  sub parse_byte_string ($$$$;$) {
278      }      }
279    
280      !!!parse-error (type => 'charset label detected:'.$self->{input_encoding}.      !!!parse-error (type => 'charset label detected:'.$self->{input_encoding}.
281          ':'.$charset, level => 'w');          ':'.$charset, level => 'w', token => $token);
282    
283      ## Step 3      ## Step 3
284      # if (can) {      # if (can) {
# Line 177  sub parse_string ($$$;$) { Line 329  sub parse_string ($$$;$) {
329        if defined $self->{input_encoding};        if defined $self->{input_encoding};
330    
331    my $i = 0;    my $i = 0;
332    my $line = 1;    $self->{line_prev} = $self->{line} = 1;
333    my $column = 0;    $self->{column_prev} = $self->{column} = 0;
334    $self->{set_next_char} = sub {    $self->{set_next_char} = sub {
335      my $self = shift;      my $self = shift;
336    
# Line 187  sub parse_string ($$$;$) { Line 339  sub parse_string ($$$;$) {
339    
340      $self->{next_char} = -1 and return if $i >= length $$s;      $self->{next_char} = -1 and return if $i >= length $$s;
341      $self->{next_char} = ord substr $$s, $i++, 1;      $self->{next_char} = ord substr $$s, $i++, 1;
342      $column++;  
343        ($self->{line_prev}, $self->{column_prev})
344            = ($self->{line}, $self->{column});
345        $self->{column}++;
346            
347      if ($self->{next_char} == 0x000A) { # LF      if ($self->{next_char} == 0x000A) { # LF
348        $line++;        $self->{line}++;
349        $column = 0;        $self->{column} = 0;
350      } elsif ($self->{next_char} == 0x000D) { # CR      } elsif ($self->{next_char} == 0x000D) { # CR
351        $i++ if substr ($$s, $i, 1) eq "\x0A";        $i++ if substr ($$s, $i, 1) eq "\x0A";
352        $self->{next_char} = 0x000A; # LF # MUST        $self->{next_char} = 0x000A; # LF # MUST
353        $line++;        $self->{line}++;
354        $column = 0;        $self->{column} = 0;
355      } elsif ($self->{next_char} > 0x10FFFF) {      } elsif ($self->{next_char} > 0x10FFFF) {
356        $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST        $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
357      } elsif ($self->{next_char} == 0x0000) { # NULL      } elsif ($self->{next_char} == 0x0000) { # NULL
# Line 209  sub parse_string ($$$;$) { Line 364  sub parse_string ($$$;$) {
364    
365    my $onerror = $_[2] || sub {    my $onerror = $_[2] || sub {
366      my (%opt) = @_;      my (%opt) = @_;
367      warn "Parse error ($opt{type}) at line $opt{line} column $opt{column}\n";      my $line = $opt{token} ? $opt{token}->{line} : $opt{line};
368        my $column = $opt{token} ? $opt{token}->{column} : $opt{column};
369        warn "Parse error ($opt{type}) at line $line column $column\n";
370    };    };
371    $self->{parse_error} = sub {    $self->{parse_error} = sub {
372      $onerror->(@_, line => $line, column => $column);      $onerror->(line => $self->{line}, column => $self->{column}, @_);
373    };    };
374    
375    $self->_initialize_tokenizer;    $self->_initialize_tokenizer;
# Line 220  sub parse_string ($$$;$) { Line 377  sub parse_string ($$$;$) {
377    $self->_construct_tree;    $self->_construct_tree;
378    $self->_terminate_tree_constructor;    $self->_terminate_tree_constructor;
379    
380      delete $self->{parse_error}; # remove loop
381    
382    return $self->{document};    return $self->{document};
383  } # parse_string  } # parse_string
384    
# Line 449  sub _get_next_token ($) { Line 608  sub _get_next_token ($) {
608          #          #
609        } elsif ($self->{next_char} == -1) {        } elsif ($self->{next_char} == -1) {
610          !!!cp (11);          !!!cp (11);
611          !!!emit ({type => END_OF_FILE_TOKEN});          !!!emit ({type => END_OF_FILE_TOKEN,
612                      line => $self->{line}, column => $self->{column}});
613          last A; ## TODO: ok?          last A; ## TODO: ok?
614        } else {        } else {
615          !!!cp (12);          !!!cp (12);
616        }        }
617        # Anything else        # Anything else
618        my $token = {type => CHARACTER_TOKEN,        my $token = {type => CHARACTER_TOKEN,
619                     data => chr $self->{next_char}};                     data => chr $self->{next_char},
620                       line => $self->{line}, column => $self->{column},
621                      };
622        ## Stay in the data state        ## Stay in the data state
623        !!!next-input-character;        !!!next-input-character;
624    
# Line 465  sub _get_next_token ($) { Line 627  sub _get_next_token ($) {
627        redo A;        redo A;
628      } elsif ($self->{state} == ENTITY_DATA_STATE) {      } elsif ($self->{state} == ENTITY_DATA_STATE) {
629        ## (cannot happen in CDATA state)        ## (cannot happen in CDATA state)
630    
631          my ($l, $c) = ($self->{line_prev}, $self->{column_prev});
632                
633        my $token = $self->_tokenize_attempt_to_consume_an_entity (0, -1);        my $token = $self->_tokenize_attempt_to_consume_an_entity (0, -1);
634    
# Line 473  sub _get_next_token ($) { Line 637  sub _get_next_token ($) {
637    
638        unless (defined $token) {        unless (defined $token) {
639          !!!cp (13);          !!!cp (13);
640          !!!emit ({type => CHARACTER_TOKEN, data => '&'});          !!!emit ({type => CHARACTER_TOKEN, data => '&',
641                      line => $l, column => $c,
642                     });
643        } else {        } else {
644          !!!cp (14);          !!!cp (14);
645          !!!emit ($token);          !!!emit ($token);
# Line 492  sub _get_next_token ($) { Line 658  sub _get_next_token ($) {
658            ## reconsume            ## reconsume
659            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
660    
661            !!!emit ({type => CHARACTER_TOKEN, data => '<'});            !!!emit ({type => CHARACTER_TOKEN, data => '<',
662                        line => $self->{line_prev},
663                        column => $self->{column_prev},
664                       });
665    
666            redo A;            redo A;
667          }          }
# Line 512  sub _get_next_token ($) { Line 681  sub _get_next_token ($) {
681            !!!cp (19);            !!!cp (19);
682            $self->{current_token}            $self->{current_token}
683              = {type => START_TAG_TOKEN,              = {type => START_TAG_TOKEN,
684                 tag_name => chr ($self->{next_char} + 0x0020)};                 tag_name => chr ($self->{next_char} + 0x0020),
685                   line => $self->{line_prev},
686                   column => $self->{column_prev}};
687            $self->{state} = TAG_NAME_STATE;            $self->{state} = TAG_NAME_STATE;
688            !!!next-input-character;            !!!next-input-character;
689            redo A;            redo A;
# Line 520  sub _get_next_token ($) { Line 691  sub _get_next_token ($) {
691                   $self->{next_char} <= 0x007A) { # a..z                   $self->{next_char} <= 0x007A) { # a..z
692            !!!cp (20);            !!!cp (20);
693            $self->{current_token} = {type => START_TAG_TOKEN,            $self->{current_token} = {type => START_TAG_TOKEN,
694                              tag_name => chr ($self->{next_char})};                                      tag_name => chr ($self->{next_char}),
695                                        line => $self->{line_prev},
696                                        column => $self->{column_prev}};
697            $self->{state} = TAG_NAME_STATE;            $self->{state} = TAG_NAME_STATE;
698            !!!next-input-character;            !!!next-input-character;
699            redo A;            redo A;
700          } elsif ($self->{next_char} == 0x003E) { # >          } elsif ($self->{next_char} == 0x003E) { # >
701            !!!cp (21);            !!!cp (21);
702            !!!parse-error (type => 'empty start tag');            !!!parse-error (type => 'empty start tag',
703                              line => $self->{line_prev},
704                              column => $self->{column_prev});
705            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
706            !!!next-input-character;            !!!next-input-character;
707    
708            !!!emit ({type => CHARACTER_TOKEN, data => '<>'});            !!!emit ({type => CHARACTER_TOKEN, data => '<>',
709                        line => $self->{line_prev},
710                        column => $self->{column_prev},
711                       });
712    
713            redo A;            redo A;
714          } elsif ($self->{next_char} == 0x003F) { # ?          } elsif ($self->{next_char} == 0x003F) { # ?
715            !!!cp (22);            !!!cp (22);
716            !!!parse-error (type => 'pio');            !!!parse-error (type => 'pio',
717                              line => $self->{line_prev},
718                              column => $self->{column_prev});
719            $self->{state} = BOGUS_COMMENT_STATE;            $self->{state} = BOGUS_COMMENT_STATE;
720              $self->{current_token} = {type => COMMENT_TOKEN, data => '',
721                                        line => $self->{line_prev},
722                                        column => $self->{column_prev},
723                                       };
724            ## $self->{next_char} is intentionally left as is            ## $self->{next_char} is intentionally left as is
725            redo A;            redo A;
726          } else {          } else {
# Line 545  sub _get_next_token ($) { Line 729  sub _get_next_token ($) {
729            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
730            ## reconsume            ## reconsume
731    
732            !!!emit ({type => CHARACTER_TOKEN, data => '<'});            !!!emit ({type => CHARACTER_TOKEN, data => '<',
733                        line => $self->{line_prev},
734                        column => $self->{column_prev},
735                       });
736    
737            redo A;            redo A;
738          }          }
# Line 553  sub _get_next_token ($) { Line 740  sub _get_next_token ($) {
740          die "$0: $self->{content_model} in tag open";          die "$0: $self->{content_model} in tag open";
741        }        }
742      } elsif ($self->{state} == CLOSE_TAG_OPEN_STATE) {      } elsif ($self->{state} == CLOSE_TAG_OPEN_STATE) {
743          my ($l, $c) = ($self->{line_prev}, $self->{column_prev} - 1); # "<"of"</"
744        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
745          if (defined $self->{last_emitted_start_tag_name}) {          if (defined $self->{last_emitted_start_tag_name}) {
746    
747            ## NOTE: <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>            ## NOTE: <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>
748            my @next_char;            my @next_char;
749            TAGNAME: for (my $i = 0; $i < length $self->{last_emitted_start_tag_name}; $i++) {            TAGNAME: for (my $i = 0; $i < length $self->{last_emitted_start_tag_name}; $i++) {
# Line 571  sub _get_next_token ($) { Line 760  sub _get_next_token ($) {
760                !!!back-next-input-character (@next_char);                !!!back-next-input-character (@next_char);
761                $self->{state} = DATA_STATE;                $self->{state} = DATA_STATE;
762    
763                !!!emit ({type => CHARACTER_TOKEN, data => '</'});                !!!emit ({type => CHARACTER_TOKEN, data => '</',
764                            line => $l, column => $c,
765                           });
766        
767                redo A;                redo A;
768              }              }
# Line 590  sub _get_next_token ($) { Line 781  sub _get_next_token ($) {
781              $self->{next_char} = shift @next_char; # reconsume              $self->{next_char} = shift @next_char; # reconsume
782              !!!back-next-input-character (@next_char);              !!!back-next-input-character (@next_char);
783              $self->{state} = DATA_STATE;              $self->{state} = DATA_STATE;
784              !!!emit ({type => CHARACTER_TOKEN, data => '</'});              !!!emit ({type => CHARACTER_TOKEN, data => '</',
785                          line => $l, column => $c,
786                         });
787              redo A;              redo A;
788            } else {            } else {
789              !!!cp (27);              !!!cp (27);
# Line 603  sub _get_next_token ($) { Line 796  sub _get_next_token ($) {
796            !!!cp (28);            !!!cp (28);
797            # next-input-character is already done            # next-input-character is already done
798            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
799            !!!emit ({type => CHARACTER_TOKEN, data => '</'});            !!!emit ({type => CHARACTER_TOKEN, data => '</',
800                        line => $l, column => $c,
801                       });
802            redo A;            redo A;
803          }          }
804        }        }
# Line 611  sub _get_next_token ($) { Line 806  sub _get_next_token ($) {
806        if (0x0041 <= $self->{next_char} and        if (0x0041 <= $self->{next_char} and
807            $self->{next_char} <= 0x005A) { # A..Z            $self->{next_char} <= 0x005A) { # A..Z
808          !!!cp (29);          !!!cp (29);
809          $self->{current_token} = {type => END_TAG_TOKEN,          $self->{current_token}
810                            tag_name => chr ($self->{next_char} + 0x0020)};              = {type => END_TAG_TOKEN,
811                   tag_name => chr ($self->{next_char} + 0x0020),
812                   line => $l, column => $c};
813          $self->{state} = TAG_NAME_STATE;          $self->{state} = TAG_NAME_STATE;
814          !!!next-input-character;          !!!next-input-character;
815          redo A;          redo A;
# Line 620  sub _get_next_token ($) { Line 817  sub _get_next_token ($) {
817                 $self->{next_char} <= 0x007A) { # a..z                 $self->{next_char} <= 0x007A) { # a..z
818          !!!cp (30);          !!!cp (30);
819          $self->{current_token} = {type => END_TAG_TOKEN,          $self->{current_token} = {type => END_TAG_TOKEN,
820                            tag_name => chr ($self->{next_char})};                                    tag_name => chr ($self->{next_char}),
821                                      line => $l, column => $c};
822          $self->{state} = TAG_NAME_STATE;          $self->{state} = TAG_NAME_STATE;
823          !!!next-input-character;          !!!next-input-character;
824          redo A;          redo A;
825        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{next_char} == 0x003E) { # >
826          !!!cp (31);          !!!cp (31);
827          !!!parse-error (type => 'empty end tag');          !!!parse-error (type => 'empty end tag',
828                            line => $self->{line_prev}, ## "<" in "</>"
829                            column => $self->{column_prev} - 1);
830          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
831          !!!next-input-character;          !!!next-input-character;
832          redo A;          redo A;
# Line 636  sub _get_next_token ($) { Line 836  sub _get_next_token ($) {
836          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
837          # reconsume          # reconsume
838    
839          !!!emit ({type => CHARACTER_TOKEN, data => '</'});          !!!emit ({type => CHARACTER_TOKEN, data => '</',
840                      line => $l, column => $c,
841                     });
842    
843          redo A;          redo A;
844        } else {        } else {
845          !!!cp (33);          !!!cp (33);
846          !!!parse-error (type => 'bogus end tag');          !!!parse-error (type => 'bogus end tag');
847          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_COMMENT_STATE;
848            $self->{current_token} = {type => COMMENT_TOKEN, data => '',
849                                      line => $self->{line_prev}, # "<" of "</"
850                                      column => $self->{column_prev} - 1,
851                                     };
852          ## $self->{next_char} is intentionally left as is          ## $self->{next_char} is intentionally left as is
853          redo A;          redo A;
854        }        }
# Line 659  sub _get_next_token ($) { Line 865  sub _get_next_token ($) {
865        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{next_char} == 0x003E) { # >
866          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
867            !!!cp (35);            !!!cp (35);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
868            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
869          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
870            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 692  sub _get_next_token ($) { Line 896  sub _get_next_token ($) {
896          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
897          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
898            !!!cp (39);            !!!cp (39);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
899            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
900          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
901            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 749  sub _get_next_token ($) { Line 951  sub _get_next_token ($) {
951        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{next_char} == 0x003E) { # >
952          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
953            !!!cp (46);            !!!cp (46);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
954            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
955          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
956            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 772  sub _get_next_token ($) { Line 972  sub _get_next_token ($) {
972        } elsif (0x0041 <= $self->{next_char} and        } elsif (0x0041 <= $self->{next_char} and
973                 $self->{next_char} <= 0x005A) { # A..Z                 $self->{next_char} <= 0x005A) { # A..Z
974          !!!cp (49);          !!!cp (49);
975          $self->{current_attribute} = {name => chr ($self->{next_char} + 0x0020),          $self->{current_attribute}
976                                value => ''};              = {name => chr ($self->{next_char} + 0x0020),
977                   value => '',
978                   line => $self->{line}, column => $self->{column}};
979          $self->{state} = ATTRIBUTE_NAME_STATE;          $self->{state} = ATTRIBUTE_NAME_STATE;
980          !!!next-input-character;          !!!next-input-character;
981          redo A;          redo A;
# Line 796  sub _get_next_token ($) { Line 998  sub _get_next_token ($) {
998          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
999          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1000            !!!cp (52);            !!!cp (52);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1001            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1002          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1003            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 827  sub _get_next_token ($) { Line 1027  sub _get_next_token ($) {
1027          } else {          } else {
1028            !!!cp (56);            !!!cp (56);
1029          }          }
1030          $self->{current_attribute} = {name => chr ($self->{next_char}),          $self->{current_attribute}
1031                                value => ''};              = {name => chr ($self->{next_char}),
1032                   value => '',
1033                   line => $self->{line}, column => $self->{column}};
1034          $self->{state} = ATTRIBUTE_NAME_STATE;          $self->{state} = ATTRIBUTE_NAME_STATE;
1035          !!!next-input-character;          !!!next-input-character;
1036          redo A;          redo A;
# Line 838  sub _get_next_token ($) { Line 1040  sub _get_next_token ($) {
1040          if (exists $self->{current_token}->{attributes} # start tag or end tag          if (exists $self->{current_token}->{attributes} # start tag or end tag
1041              ->{$self->{current_attribute}->{name}}) { # MUST              ->{$self->{current_attribute}->{name}}) { # MUST
1042            !!!cp (57);            !!!cp (57);
1043            !!!parse-error (type => 'duplicate attribute:'.$self->{current_attribute}->{name});            !!!parse-error (type => 'duplicate attribute:'.$self->{current_attribute}->{name}, line => $self->{current_attribute}->{line}, column => $self->{current_attribute}->{column});
1044            ## Discard $self->{current_attribute} # MUST            ## Discard $self->{current_attribute} # MUST
1045          } else {          } else {
1046            !!!cp (58);            !!!cp (58);
# Line 867  sub _get_next_token ($) { Line 1069  sub _get_next_token ($) {
1069          $before_leave->();          $before_leave->();
1070          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1071            !!!cp (61);            !!!cp (61);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1072            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1073          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1074            !!!cp (62);            !!!cp (62);
# Line 913  sub _get_next_token ($) { Line 1113  sub _get_next_token ($) {
1113          $before_leave->();          $before_leave->();
1114          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1115            !!!cp (66);            !!!cp (66);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1116            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1117          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1118            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 965  sub _get_next_token ($) { Line 1163  sub _get_next_token ($) {
1163        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{next_char} == 0x003E) { # >
1164          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1165            !!!cp (73);            !!!cp (73);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1166            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1167          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1168            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 989  sub _get_next_token ($) { Line 1185  sub _get_next_token ($) {
1185        } elsif (0x0041 <= $self->{next_char} and        } elsif (0x0041 <= $self->{next_char} and
1186                 $self->{next_char} <= 0x005A) { # A..Z                 $self->{next_char} <= 0x005A) { # A..Z
1187          !!!cp (76);          !!!cp (76);
1188          $self->{current_attribute} = {name => chr ($self->{next_char} + 0x0020),          $self->{current_attribute}
1189                                value => ''};              = {name => chr ($self->{next_char} + 0x0020),
1190                   value => '',
1191                   line => $self->{line}, column => $self->{column}};
1192          $self->{state} = ATTRIBUTE_NAME_STATE;          $self->{state} = ATTRIBUTE_NAME_STATE;
1193          !!!next-input-character;          !!!next-input-character;
1194          redo A;          redo A;
# Line 1014  sub _get_next_token ($) { Line 1212  sub _get_next_token ($) {
1212          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1213          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1214            !!!cp (79);            !!!cp (79);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1215            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1216          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1217            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 1037  sub _get_next_token ($) { Line 1233  sub _get_next_token ($) {
1233          redo A;          redo A;
1234        } else {        } else {
1235          !!!cp (82);          !!!cp (82);
1236          $self->{current_attribute} = {name => chr ($self->{next_char}),          $self->{current_attribute}
1237                                value => ''};              = {name => chr ($self->{next_char}),
1238                   value => '',
1239                   line => $self->{line}, column => $self->{column}};
1240          $self->{state} = ATTRIBUTE_NAME_STATE;          $self->{state} = ATTRIBUTE_NAME_STATE;
1241          !!!next-input-character;          !!!next-input-character;
1242          redo A;                  redo A;        
# Line 1071  sub _get_next_token ($) { Line 1269  sub _get_next_token ($) {
1269        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{next_char} == 0x003E) { # >
1270          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1271            !!!cp (87);            !!!cp (87);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1272            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1273          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1274            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 1096  sub _get_next_token ($) { Line 1292  sub _get_next_token ($) {
1292          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1293          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1294            !!!cp (90);            !!!cp (90);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1295            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1296          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1297            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 1145  sub _get_next_token ($) { Line 1339  sub _get_next_token ($) {
1339          !!!parse-error (type => 'unclosed attribute value');          !!!parse-error (type => 'unclosed attribute value');
1340          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1341            !!!cp (97);            !!!cp (97);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1342            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1343          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1344            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 1189  sub _get_next_token ($) { Line 1381  sub _get_next_token ($) {
1381          !!!parse-error (type => 'unclosed attribute value');          !!!parse-error (type => 'unclosed attribute value');
1382          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1383            !!!cp (103);            !!!cp (103);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1384            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1385          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1386            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 1236  sub _get_next_token ($) { Line 1426  sub _get_next_token ($) {
1426        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{next_char} == 0x003E) { # >
1427          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1428            !!!cp (109);            !!!cp (109);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1429            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1430          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1431            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 1261  sub _get_next_token ($) { Line 1449  sub _get_next_token ($) {
1449          !!!parse-error (type => 'unclosed tag');          !!!parse-error (type => 'unclosed tag');
1450          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1451            !!!cp (112);            !!!cp (112);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1452            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1453          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1454            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 1333  sub _get_next_token ($) { Line 1519  sub _get_next_token ($) {
1519        } elsif ($self->{next_char} == 0x003E) { # >        } elsif ($self->{next_char} == 0x003E) { # >
1520          if ($self->{current_token}->{type} == START_TAG_TOKEN) {          if ($self->{current_token}->{type} == START_TAG_TOKEN) {
1521            !!!cp (119);            !!!cp (119);
           $self->{current_token}->{first_start_tag}  
               = not defined $self->{last_emitted_start_tag_name};  
1522            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};            $self->{last_emitted_start_tag_name} = $self->{current_token}->{tag_name};
1523          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {          } elsif ($self->{current_token}->{type} == END_TAG_TOKEN) {
1524            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST            $self->{content_model} = PCDATA_CONTENT_MODEL; # MUST
# Line 1379  sub _get_next_token ($) { Line 1563  sub _get_next_token ($) {
1563      } elsif ($self->{state} == BOGUS_COMMENT_STATE) {      } elsif ($self->{state} == BOGUS_COMMENT_STATE) {
1564        ## (only happen if PCDATA state)        ## (only happen if PCDATA state)
1565                
1566        my $token = {type => COMMENT_TOKEN, data => ''};        ## NOTE: Set by the previous state
1567          #my $token = {type => COMMENT_TOKEN, data => ''};
1568    
1569        BC: {        BC: {
1570          if ($self->{next_char} == 0x003E) { # >          if ($self->{next_char} == 0x003E) { # >
# Line 1387  sub _get_next_token ($) { Line 1572  sub _get_next_token ($) {
1572            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
1573            !!!next-input-character;            !!!next-input-character;
1574    
1575            !!!emit ($token);            !!!emit ($self->{current_token}); # comment
1576    
1577            redo A;            redo A;
1578          } elsif ($self->{next_char} == -1) {          } elsif ($self->{next_char} == -1) {
# Line 1395  sub _get_next_token ($) { Line 1580  sub _get_next_token ($) {
1580            $self->{state} = DATA_STATE;            $self->{state} = DATA_STATE;
1581            ## reconsume            ## reconsume
1582    
1583            !!!emit ($token);            !!!emit ($self->{current_token}); # comment
1584    
1585            redo A;            redo A;
1586          } else {          } else {
1587            !!!cp (126);            !!!cp (126);
1588            $token->{data} .= chr ($self->{next_char});            $self->{current_token}->{data} .= chr ($self->{next_char}); # comment
1589            !!!next-input-character;            !!!next-input-character;
1590            redo BC;            redo BC;
1591          }          }
# Line 1410  sub _get_next_token ($) { Line 1595  sub _get_next_token ($) {
1595      } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {      } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {
1596        ## (only happen if PCDATA state)        ## (only happen if PCDATA state)
1597    
1598          my ($l, $c) = ($self->{line_prev}, $self->{column_prev} - 1);
1599    
1600        my @next_char;        my @next_char;
1601        push @next_char, $self->{next_char};        push @next_char, $self->{next_char};
1602                
# Line 1418  sub _get_next_token ($) { Line 1605  sub _get_next_token ($) {
1605          push @next_char, $self->{next_char};          push @next_char, $self->{next_char};
1606          if ($self->{next_char} == 0x002D) { # -          if ($self->{next_char} == 0x002D) { # -
1607            !!!cp (127);            !!!cp (127);
1608            $self->{current_token} = {type => COMMENT_TOKEN, data => ''};            $self->{current_token} = {type => COMMENT_TOKEN, data => '',
1609                                        line => $l, column => $c,
1610                                       };
1611            $self->{state} = COMMENT_START_STATE;            $self->{state} = COMMENT_START_STATE;
1612            !!!next-input-character;            !!!next-input-character;
1613            redo A;            redo A;
# Line 1454  sub _get_next_token ($) { Line 1643  sub _get_next_token ($) {
1643                      !!!cp (129);                      !!!cp (129);
1644                      ## TODO: What a stupid code this is!                      ## TODO: What a stupid code this is!
1645                      $self->{state} = DOCTYPE_STATE;                      $self->{state} = DOCTYPE_STATE;
1646                        $self->{current_token} = {type => DOCTYPE_TOKEN,
1647                                                  quirks => 1,
1648                                                  line => $l, column => $c,
1649                                                 };
1650                      !!!next-input-character;                      !!!next-input-character;
1651                      redo A;                      redo A;
1652                    } else {                    } else {
# Line 1482  sub _get_next_token ($) { Line 1675  sub _get_next_token ($) {
1675        $self->{next_char} = shift @next_char;        $self->{next_char} = shift @next_char;
1676        !!!back-next-input-character (@next_char);        !!!back-next-input-character (@next_char);
1677        $self->{state} = BOGUS_COMMENT_STATE;        $self->{state} = BOGUS_COMMENT_STATE;
1678          $self->{current_token} = {type => COMMENT_TOKEN, data => '',
1679                                    line => $l, column => $c,
1680                                   };
1681        redo A;        redo A;
1682                
1683        ## ISSUE: typos in spec: chacacters, is is a parse error        ## ISSUE: typos in spec: chacacters, is is a parse error
# Line 1605  sub _get_next_token ($) { Line 1801  sub _get_next_token ($) {
1801          redo A;          redo A;
1802        } elsif ($self->{next_char} == 0x002D) { # -        } elsif ($self->{next_char} == 0x002D) { # -
1803          !!!cp (152);          !!!cp (152);
1804          !!!parse-error (type => 'dash in comment');          !!!parse-error (type => 'dash in comment',
1805                            line => $self->{line_prev},
1806                            column => $self->{column_prev});
1807          $self->{current_token}->{data} .= '-'; # comment          $self->{current_token}->{data} .= '-'; # comment
1808          ## Stay in the state          ## Stay in the state
1809          !!!next-input-character;          !!!next-input-character;
# Line 1621  sub _get_next_token ($) { Line 1819  sub _get_next_token ($) {
1819          redo A;          redo A;
1820        } else {        } else {
1821          !!!cp (154);          !!!cp (154);
1822          !!!parse-error (type => 'dash in comment');          !!!parse-error (type => 'dash in comment',
1823                            line => $self->{line_prev},
1824                            column => $self->{column_prev});
1825          $self->{current_token}->{data} .= '--' . chr ($self->{next_char}); # comment          $self->{current_token}->{data} .= '--' . chr ($self->{next_char}); # comment
1826          $self->{state} = COMMENT_STATE;          $self->{state} = COMMENT_STATE;
1827          !!!next-input-character;          !!!next-input-character;
# Line 1660  sub _get_next_token ($) { Line 1860  sub _get_next_token ($) {
1860          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1861          !!!next-input-character;          !!!next-input-character;
1862    
1863          !!!emit ({type => DOCTYPE_TOKEN, quirks => 1});          !!!emit ($self->{current_token}); # DOCTYPE (quirks)
1864    
1865          redo A;          redo A;
1866        } elsif ($self->{next_char} == -1) {        } elsif ($self->{next_char} == -1) {
# Line 1669  sub _get_next_token ($) { Line 1869  sub _get_next_token ($) {
1869          $self->{state} = DATA_STATE;          $self->{state} = DATA_STATE;
1870          ## reconsume          ## reconsume
1871    
1872          !!!emit ({type => DOCTYPE_TOKEN, quirks => 1});          !!!emit ($self->{current_token}); # DOCTYPE (quirks)
1873    
1874          redo A;          redo A;
1875        } else {        } else {
1876          !!!cp (160);          !!!cp (160);
1877          $self->{current_token}          $self->{current_token}->{name} = chr $self->{next_char};
1878              = {type => DOCTYPE_TOKEN,          delete $self->{current_token}->{quirks};
                name => chr ($self->{next_char}),  
                #quirks => 0,  
               };  
1879  ## ISSUE: "Set the token's name name to the" in the spec  ## ISSUE: "Set the token's name name to the" in the spec
1880          $self->{state} = DOCTYPE_NAME_STATE;          $self->{state} = DOCTYPE_NAME_STATE;
1881          !!!next-input-character;          !!!next-input-character;
# Line 2205  sub _get_next_token ($) { Line 2402  sub _get_next_token ($) {
2402  sub _tokenize_attempt_to_consume_an_entity ($$$) {  sub _tokenize_attempt_to_consume_an_entity ($$$) {
2403    my ($self, $in_attr, $additional) = @_;    my ($self, $in_attr, $additional) = @_;
2404    
2405      my ($l, $c) = ($self->{line_prev}, $self->{column_prev});
2406    
2407    if ({    if ({
2408         0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, # HT, LF, VT, FF,         0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, # HT, LF, VT, FF,
2409         0x0020 => 1, 0x003C => 1, 0x0026 => 1, -1 => 1, # SP, <, & # 0x000D # CR         0x0020 => 1, 0x003C => 1, 0x0026 => 1, -1 => 1, # SP, <, & # 0x000D # CR
# Line 2245  sub _tokenize_attempt_to_consume_an_enti Line 2444  sub _tokenize_attempt_to_consume_an_enti
2444            redo X;            redo X;
2445          } elsif (not defined $code) { # no hexadecimal digit          } elsif (not defined $code) { # no hexadecimal digit
2446            !!!cp (1005);            !!!cp (1005);
2447            !!!parse-error (type => 'bare hcro');            !!!parse-error (type => 'bare hcro', line => $l, column => $c);
2448            !!!back-next-input-character ($x_char, $self->{next_char});            !!!back-next-input-character ($x_char, $self->{next_char});
2449            $self->{next_char} = 0x0023; # #            $self->{next_char} = 0x0023; # #
2450            return undef;            return undef;
# Line 2254  sub _tokenize_attempt_to_consume_an_enti Line 2453  sub _tokenize_attempt_to_consume_an_enti
2453            !!!next-input-character;            !!!next-input-character;
2454          } else {          } else {
2455            !!!cp (1007);            !!!cp (1007);
2456            !!!parse-error (type => 'no refc');            !!!parse-error (type => 'no refc', line => $l, column => $c);
2457          }          }
2458    
2459          if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {          if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {
2460            !!!cp (1008);            !!!cp (1008);
2461            !!!parse-error (type => sprintf 'invalid character reference:U+%04X', $code);            !!!parse-error (type => (sprintf 'invalid character reference:U+%04X', $code), line => $l, column => $c);
2462            $code = 0xFFFD;            $code = 0xFFFD;
2463          } elsif ($code > 0x10FFFF) {          } elsif ($code > 0x10FFFF) {
2464            !!!cp (1009);            !!!cp (1009);
2465            !!!parse-error (type => sprintf 'invalid character reference:U-%08X', $code);            !!!parse-error (type => (sprintf 'invalid character reference:U-%08X', $code), line => $l, column => $c);
2466            $code = 0xFFFD;            $code = 0xFFFD;
2467          } elsif ($code == 0x000D) {          } elsif ($code == 0x000D) {
2468            !!!cp (1010);            !!!cp (1010);
2469            !!!parse-error (type => 'CR character reference');            !!!parse-error (type => 'CR character reference', line => $l, column => $c);
2470            $code = 0x000A;            $code = 0x000A;
2471          } elsif (0x80 <= $code and $code <= 0x9F) {          } elsif (0x80 <= $code and $code <= 0x9F) {
2472            !!!cp (1011);            !!!cp (1011);
2473            !!!parse-error (type => sprintf 'C1 character reference:U+%04X', $code);            !!!parse-error (type => (sprintf 'C1 character reference:U+%04X', $code), line => $l, column => $c);
2474            $code = $c1_entity_char->{$code};            $code = $c1_entity_char->{$code};
2475          }          }
2476    
2477          return {type => CHARACTER_TOKEN, data => chr $code,          return {type => CHARACTER_TOKEN, data => chr $code,
2478                  has_reference => 1};                  has_reference => 1,
2479                    line => $l, column => $c,
2480                   };
2481        } # X        } # X
2482      } elsif (0x0030 <= $self->{next_char} and      } elsif (0x0030 <= $self->{next_char} and
2483               $self->{next_char} <= 0x0039) { # 0..9               $self->{next_char} <= 0x0039) { # 0..9
# Line 2297  sub _tokenize_attempt_to_consume_an_enti Line 2498  sub _tokenize_attempt_to_consume_an_enti
2498          !!!next-input-character;          !!!next-input-character;
2499        } else {        } else {
2500          !!!cp (1014);          !!!cp (1014);
2501          !!!parse-error (type => 'no refc');          !!!parse-error (type => 'no refc', line => $l, column => $c);
2502        }        }
2503    
2504        if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {        if ($code == 0 or (0xD800 <= $code and $code <= 0xDFFF)) {
2505          !!!cp (1015);          !!!cp (1015);
2506          !!!parse-error (type => sprintf 'invalid character reference:U+%04X', $code);          !!!parse-error (type => (sprintf 'invalid character reference:U+%04X', $code), line => $l, column => $c);
2507          $code = 0xFFFD;          $code = 0xFFFD;
2508        } elsif ($code > 0x10FFFF) {        } elsif ($code > 0x10FFFF) {
2509          !!!cp (1016);          !!!cp (1016);
2510          !!!parse-error (type => sprintf 'invalid character reference:U-%08X', $code);          !!!parse-error (type => (sprintf 'invalid character reference:U-%08X', $code), line => $l, column => $c);
2511          $code = 0xFFFD;          $code = 0xFFFD;
2512        } elsif ($code == 0x000D) {        } elsif ($code == 0x000D) {
2513          !!!cp (1017);          !!!cp (1017);
2514          !!!parse-error (type => 'CR character reference');          !!!parse-error (type => 'CR character reference', line => $l, column => $c);
2515          $code = 0x000A;          $code = 0x000A;
2516        } elsif (0x80 <= $code and $code <= 0x9F) {        } elsif (0x80 <= $code and $code <= 0x9F) {
2517          !!!cp (1018);          !!!cp (1018);
2518          !!!parse-error (type => sprintf 'C1 character reference:U+%04X', $code);          !!!parse-error (type => (sprintf 'C1 character reference:U+%04X', $code), line => $l, column => $c);
2519          $code = $c1_entity_char->{$code};          $code = $c1_entity_char->{$code};
2520        }        }
2521                
2522        return {type => CHARACTER_TOKEN, data => chr $code, has_reference => 1};        return {type => CHARACTER_TOKEN, data => chr $code, has_reference => 1,
2523                  line => $l, column => $c,
2524                 };
2525      } else {      } else {
2526        !!!cp (1019);        !!!cp (1019);
2527        !!!parse-error (type => 'bare nero');        !!!parse-error (type => 'bare nero', line => $l, column => $c);
2528        !!!back-next-input-character ($self->{next_char});        !!!back-next-input-character ($self->{next_char});
2529        $self->{next_char} = 0x0023; # #        $self->{next_char} = 0x0023; # #
2530        return undef;        return undef;
# Line 2371  sub _tokenize_attempt_to_consume_an_enti Line 2574  sub _tokenize_attempt_to_consume_an_enti
2574            
2575      if ($match > 0) {      if ($match > 0) {
2576        !!!cp (1023);        !!!cp (1023);
2577        return {type => CHARACTER_TOKEN, data => $value, has_reference => 1};        return {type => CHARACTER_TOKEN, data => $value, has_reference => 1,
2578                  line => $l, column => $c,
2579                 };
2580      } elsif ($match < 0) {      } elsif ($match < 0) {
2581        !!!parse-error (type => 'no refc');        !!!parse-error (type => 'no refc', line => $l, column => $c);
2582        if ($in_attr and $match < -1) {        if ($in_attr and $match < -1) {
2583          !!!cp (1024);          !!!cp (1024);
2584          return {type => CHARACTER_TOKEN, data => '&'.$entity_name};          return {type => CHARACTER_TOKEN, data => '&'.$entity_name,
2585                    line => $l, column => $c,
2586                   };
2587        } else {        } else {
2588          !!!cp (1025);          !!!cp (1025);
2589          return {type => CHARACTER_TOKEN, data => $value, has_reference => 1};          return {type => CHARACTER_TOKEN, data => $value, has_reference => 1,
2590                    line => $l, column => $c,
2591                   };
2592        }        }
2593      } else {      } else {
2594        !!!cp (1026);        !!!cp (1026);
2595        !!!parse-error (type => 'bare ero');        !!!parse-error (type => 'bare ero', line => $l, column => $c);
2596        ## NOTE: "No characters are consumed" in the spec.        ## NOTE: "No characters are consumed" in the spec.
2597        return {type => CHARACTER_TOKEN, data => '&'.$value};        return {type => CHARACTER_TOKEN, data => '&'.$value,
2598                  line => $l, column => $c,
2599                 };
2600      }      }
2601    } else {    } else {
2602      !!!cp (1027);      !!!cp (1027);
2603      ## no characters are consumed      ## no characters are consumed
2604      !!!parse-error (type => 'bare ero');      !!!parse-error (type => 'bare ero', line => $l, column => $c);
2605      return undef;      return undef;
2606    }    }
2607  } # _tokenize_attempt_to_consume_an_entity  } # _tokenize_attempt_to_consume_an_entity
# Line 2461  sub _tree_construction_initial ($) { Line 2672  sub _tree_construction_initial ($) {
2672            defined $token->{public_identifier} or            defined $token->{public_identifier} or
2673            defined $token->{system_identifier}) {            defined $token->{system_identifier}) {
2674          !!!cp ('t1');          !!!cp ('t1');
2675          !!!parse-error (type => 'not HTML5');          !!!parse-error (type => 'not HTML5', token => $token);
2676        } elsif ($doctype_name ne 'HTML') {        } elsif ($doctype_name ne 'HTML') {
2677          !!!cp ('t2');          !!!cp ('t2');
2678          ## ISSUE: ASCII case-insensitive? (in fact it does not matter)          ## ISSUE: ASCII case-insensitive? (in fact it does not matter)
2679          !!!parse-error (type => 'not HTML5');          !!!parse-error (type => 'not HTML5', token => $token);
2680        } else {        } else {
2681          !!!cp ('t3');          !!!cp ('t3');
2682        }        }
2683                
2684        my $doctype = $self->{document}->create_document_type_definition        my $doctype = $self->{document}->create_document_type_definition
2685          ($token->{name}); ## ISSUE: If name is missing (e.g. <!DOCTYPE>)?          ($token->{name}); ## ISSUE: If name is missing (e.g. <!DOCTYPE>)?
2686          ## NOTE: Default value for both |public_id| and |system_id| attributes
2687          ## are empty strings, so that we don't set any value in missing cases.
2688        $doctype->public_id ($token->{public_identifier})        $doctype->public_id ($token->{public_identifier})
2689            if defined $token->{public_identifier};            if defined $token->{public_identifier};
2690        $doctype->system_id ($token->{system_identifier})        $doctype->system_id ($token->{system_identifier})
# Line 2604  sub _tree_construction_initial ($) { Line 2817  sub _tree_construction_initial ($) {
2817                END_OF_FILE_TOKEN, 1,                END_OF_FILE_TOKEN, 1,
2818               }->{$token->{type}}) {               }->{$token->{type}}) {
2819        !!!cp ('t14');        !!!cp ('t14');
2820        !!!parse-error (type => 'no DOCTYPE');        !!!parse-error (type => 'no DOCTYPE', token => $token);
2821        $self->{document}->manakai_compat_mode ('quirks');        $self->{document}->manakai_compat_mode ('quirks');
2822        ## Go to the "before html" insertion mode.        ## Go to the "before html" insertion mode.
2823        ## reprocess        ## reprocess
# Line 2625  sub _tree_construction_initial ($) { Line 2838  sub _tree_construction_initial ($) {
2838          !!!cp ('t17');          !!!cp ('t17');
2839        }        }
2840    
2841        !!!parse-error (type => 'no DOCTYPE');        !!!parse-error (type => 'no DOCTYPE', token => $token);
2842        $self->{document}->manakai_compat_mode ('quirks');        $self->{document}->manakai_compat_mode ('quirks');
2843        ## Go to the "before html" insertion mode.        ## Go to the "before html" insertion mode.
2844        ## reprocess        ## reprocess
# Line 2654  sub _tree_construction_root_element ($) Line 2867  sub _tree_construction_root_element ($)
2867    B: {    B: {
2868        if ($token->{type} == DOCTYPE_TOKEN) {        if ($token->{type} == DOCTYPE_TOKEN) {
2869          !!!cp ('t19');          !!!cp ('t19');
2870          !!!parse-error (type => 'in html:#DOCTYPE');          !!!parse-error (type => 'in html:#DOCTYPE', token => $token);
2871          ## Ignore the token          ## Ignore the token
2872          ## Stay in the insertion mode.          ## Stay in the insertion mode.
2873          !!!next-token;          !!!next-token;
# Line 2688  sub _tree_construction_root_element ($) Line 2901  sub _tree_construction_root_element ($)
2901        } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
2902          if ($token->{tag_name} eq 'html') {          if ($token->{tag_name} eq 'html') {
2903            my $root_element;            my $root_element;
2904            !!!create-element ($root_element, $token->{tag_name}, $token->{attributes});            !!!create-element ($root_element, $token->{tag_name}, $token->{attributes}, $token);
2905            $self->{document}->append_child ($root_element);            $self->{document}->append_child ($root_element);
2906            push @{$self->{open_elements}}, [$root_element, 'html'];            push @{$self->{open_elements}},
2907                  [$root_element, $el_category->{html}];
2908    
2909            if ($token->{attributes}->{manifest}) {            if ($token->{attributes}->{manifest}) {
2910              !!!cp ('t24');              !!!cp ('t24');
2911              $self->{application_cache_selection}              $self->{application_cache_selection}
2912                  ->($token->{attributes}->{manifest}->{value});                  ->($token->{attributes}->{manifest}->{value});
2913              ## ISSUE: No relative reference resolution?              ## ISSUE: Spec is unclear on relative references.
2914                ## According to Hixie (#whatwg 2008-03-19), it should be
2915                ## resolved against the base URI of the document in HTML
2916                ## or xml:base of the element in XHTML.
2917            } else {            } else {
2918              !!!cp ('t25');              !!!cp ('t25');
2919              $self->{application_cache_selection}->(undef);              $self->{application_cache_selection}->(undef);
# Line 2718  sub _tree_construction_root_element ($) Line 2935  sub _tree_construction_root_element ($)
2935          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
2936        }        }
2937    
2938      my $root_element; !!!create-element ($root_element, 'html');      my $root_element; !!!create-element ($root_element, 'html',, $token);
2939      $self->{document}->append_child ($root_element);      $self->{document}->append_child ($root_element);
2940      push @{$self->{open_elements}}, [$root_element, 'html'];      push @{$self->{open_elements}}, [$root_element, $el_category->{html}];
2941    
2942      $self->{application_cache_selection}->(undef);      $self->{application_cache_selection}->(undef);
2943    
# Line 2748  sub _reset_insertion_mode ($) { Line 2965  sub _reset_insertion_mode ($) {
2965        if ($self->{open_elements}->[0]->[0] eq $node->[0]) {        if ($self->{open_elements}->[0]->[0] eq $node->[0]) {
2966          $last = 1;          $last = 1;
2967          if (defined $self->{inner_html_node}) {          if (defined $self->{inner_html_node}) {
2968            if ($self->{inner_html_node}->[1] eq 'td' or            if ($self->{inner_html_node}->[1] & TABLE_CELL_EL) {
               $self->{inner_html_node}->[1] eq 'th') {  
2969              !!!cp ('t27');              !!!cp ('t27');
2970              #              #
2971            } else {            } else {
# Line 2776  sub _reset_insertion_mode ($) { Line 2992  sub _reset_insertion_mode ($) {
2992                        head => IN_BODY_IM, # not in head!                        head => IN_BODY_IM, # not in head!
2993                        body => IN_BODY_IM,                        body => IN_BODY_IM,
2994                        frameset => IN_FRAMESET_IM,                        frameset => IN_FRAMESET_IM,
2995                       }->{$node->[1]};                       }->{$node->[0]->manakai_local_name};
2996                         ## TODO: Foreign namespace case OK?
2997        $self->{insertion_mode} = $new_mode and return if defined $new_mode;        $self->{insertion_mode} = $new_mode and return if defined $new_mode;
2998                
2999        ## Step 14        ## Step 14
3000        if ($node->[1] eq 'html') {        if ($node->[1] & HTML_EL) {
3001          unless (defined $self->{head_element}) {          unless (defined $self->{head_element}) {
3002            !!!cp ('t29');            !!!cp ('t29');
3003            $self->{insertion_mode} = BEFORE_HEAD_IM;            $self->{insertion_mode} = BEFORE_HEAD_IM;
# Line 2913  sub _tree_construction_main ($) { Line 3130  sub _tree_construction_main ($) {
3130      ## Step 1      ## Step 1
3131      my $start_tag_name = $token->{tag_name};      my $start_tag_name = $token->{tag_name};
3132      my $el;      my $el;
3133      !!!create-element ($el, $start_tag_name, $token->{attributes});      !!!create-element ($el, $start_tag_name, $token->{attributes}, $token);
3134    
3135      ## Step 2      ## Step 2
3136      $insert->($el);      $insert->($el);
# Line 2950  sub _tree_construction_main ($) { Line 3167  sub _tree_construction_main ($) {
3167        ## NOTE: An end-of-file token.        ## NOTE: An end-of-file token.
3168        if ($content_model_flag == CDATA_CONTENT_MODEL) {        if ($content_model_flag == CDATA_CONTENT_MODEL) {
3169          !!!cp ('t43');          !!!cp ('t43');
3170          !!!parse-error (type => 'in CDATA:#'.$token->{type});          !!!parse-error (type => 'in CDATA:#'.$token->{type}, token => $token);
3171        } elsif ($content_model_flag == RCDATA_CONTENT_MODEL) {        } elsif ($content_model_flag == RCDATA_CONTENT_MODEL) {
3172          !!!cp ('t44');          !!!cp ('t44');
3173          !!!parse-error (type => 'in RCDATA:#'.$token->{type});          !!!parse-error (type => 'in RCDATA:#'.$token->{type}, token => $token);
3174        } else {        } else {
3175          die "$0: $content_model_flag in parse_rcdata";          die "$0: $content_model_flag in parse_rcdata";
3176        }        }
# Line 2963  sub _tree_construction_main ($) { Line 3180  sub _tree_construction_main ($) {
3180    
3181    my $script_start_tag = sub () {    my $script_start_tag = sub () {
3182      my $script_el;      my $script_el;
3183      !!!create-element ($script_el, 'script', $token->{attributes});      !!!create-element ($script_el, 'script', $token->{attributes}, $token);
3184      ## TODO: mark as "parser-inserted"      ## TODO: mark as "parser-inserted"
3185    
3186      $self->{content_model} = CDATA_CONTENT_MODEL;      $self->{content_model} = CDATA_CONTENT_MODEL;
# Line 2989  sub _tree_construction_main ($) { Line 3206  sub _tree_construction_main ($) {
3206        ## Ignore the token        ## Ignore the token
3207      } else {      } else {
3208        !!!cp ('t48');        !!!cp ('t48');
3209        !!!parse-error (type => 'in CDATA:#'.$token->{type});        !!!parse-error (type => 'in CDATA:#'.$token->{type}, token => $token);
3210        ## ISSUE: And ignore?        ## ISSUE: And ignore?
3211        ## TODO: mark as "already executed"        ## TODO: mark as "already executed"
3212      }      }
# Line 3017  sub _tree_construction_main ($) { Line 3234  sub _tree_construction_main ($) {
3234    my $open_tables = [[$self->{open_elements}->[0]->[0]]];    my $open_tables = [[$self->{open_elements}->[0]->[0]]];
3235    
3236    my $formatting_end_tag = sub {    my $formatting_end_tag = sub {
3237      my $tag_name = shift;      my $end_tag_token = shift;
3238        my $tag_name = $end_tag_token->{tag_name};
3239    
3240      ## NOTE: The adoptioon agency algorithm (AAA).      ## NOTE: The adoption agency algorithm (AAA).
3241    
3242      FET: {      FET: {
3243        ## Step 1        ## Step 1
3244        my $formatting_element;        my $formatting_element;
3245        my $formatting_element_i_in_active;        my $formatting_element_i_in_active;
3246        AFE: for (reverse 0..$#$active_formatting_elements) {        AFE: for (reverse 0..$#$active_formatting_elements) {
3247          if ($active_formatting_elements->[$_]->[1] eq $tag_name) {          if ($active_formatting_elements->[$_]->[0] eq '#marker') {
3248              !!!cp ('t52');
3249              last AFE;
3250            } elsif ($active_formatting_elements->[$_]->[0]->manakai_local_name
3251                         eq $tag_name) {
3252            !!!cp ('t51');            !!!cp ('t51');
3253            $formatting_element = $active_formatting_elements->[$_];            $formatting_element = $active_formatting_elements->[$_];
3254            $formatting_element_i_in_active = $_;            $formatting_element_i_in_active = $_;
3255            last AFE;            last AFE;
         } elsif ($active_formatting_elements->[$_]->[0] eq '#marker') {  
           !!!cp ('t52');  
           last AFE;  
3256          }          }
3257        } # AFE        } # AFE
3258        unless (defined $formatting_element) {        unless (defined $formatting_element) {
3259          !!!cp ('t53');          !!!cp ('t53');
3260          !!!parse-error (type => 'unmatched end tag:'.$tag_name);          !!!parse-error (type => 'unmatched end tag:'.$tag_name, token => $end_tag_token);
3261          ## Ignore the token          ## Ignore the token
3262          !!!next-token;          !!!next-token;
3263          return;          return;
# Line 3055  sub _tree_construction_main ($) { Line 3274  sub _tree_construction_main ($) {
3274              last INSCOPE;              last INSCOPE;
3275            } else { # in open elements but not in scope            } else { # in open elements but not in scope
3276              !!!cp ('t55');              !!!cp ('t55');
3277              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name},
3278                                token => $end_tag_token);
3279              ## Ignore the token              ## Ignore the token
3280              !!!next-token;              !!!next-token;
3281              return;              return;
3282            }            }
3283          } elsif ({          } elsif ($node->[1] & SCOPING_EL) {
                   table => 1, caption => 1, td => 1, th => 1,  
                   button => 1, marquee => 1, object => 1, html => 1,  
                  }->{$node->[1]}) {  
3284            !!!cp ('t56');            !!!cp ('t56');
3285            $in_scope = 0;            $in_scope = 0;
3286          }          }
3287        } # INSCOPE        } # INSCOPE
3288        unless (defined $formatting_element_i_in_open) {        unless (defined $formatting_element_i_in_open) {
3289          !!!cp ('t57');          !!!cp ('t57');
3290          !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});          !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name},
3291                            token => $end_tag_token);
3292          pop @$active_formatting_elements; # $formatting_element          pop @$active_formatting_elements; # $formatting_element
3293          !!!next-token; ## TODO: ok?          !!!next-token; ## TODO: ok?
3294          return;          return;
3295        }        }
3296        if (not $self->{open_elements}->[-1]->[0] eq $formatting_element->[0]) {        if (not $self->{open_elements}->[-1]->[0] eq $formatting_element->[0]) {
3297          !!!cp ('t58');          !!!cp ('t58');
3298          !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);          !!!parse-error (type => 'not closed',
3299                            value => $self->{open_elements}->[-1]->[0]
3300                                ->manakai_local_name,
3301                            token => $end_tag_token);
3302        }        }
3303                
3304        ## Step 2        ## Step 2
# Line 3085  sub _tree_construction_main ($) { Line 3306  sub _tree_construction_main ($) {
3306        my $furthest_block_i_in_open;        my $furthest_block_i_in_open;
3307        OE: for (reverse 0..$#{$self->{open_elements}}) {        OE: for (reverse 0..$#{$self->{open_elements}}) {
3308          my $node = $self->{open_elements}->[$_];          my $node = $self->{open_elements}->[$_];
3309          if (not $formatting_category->{$node->[1]} and          if (not ($node->[1] & FORMATTING_EL) and
3310              #not $phrasing_category->{$node->[1]} and              #not $phrasing_category->{$node->[1]} and
3311              ($special_category->{$node->[1]} or              ($node->[1] & SPECIAL_EL or
3312               $scoping_category->{$node->[1]})) {               $node->[1] & SCOPING_EL)) { ## Scoping is redundant, maybe
3313            !!!cp ('t59');            !!!cp ('t59');
3314            $furthest_block = $node;            $furthest_block = $node;
3315            $furthest_block_i_in_open = $_;            $furthest_block_i_in_open = $_;
# Line 3174  sub _tree_construction_main ($) { Line 3395  sub _tree_construction_main ($) {
3395        } # S7          } # S7  
3396                
3397        ## Step 8        ## Step 8
3398        if ({        if ($common_ancestor_node->[1] & TABLE_ROWS_EL) {
            table => 1, tbody => 1, tfoot => 1, thead => 1, tr => 1,  
           }->{$common_ancestor_node->[1]}) {  
3399          my $foster_parent_element;          my $foster_parent_element;
3400          my $next_sibling;          my $next_sibling;
3401                           OE: for (reverse 0..$#{$self->{open_elements}}) {          OE: for (reverse 0..$#{$self->{open_elements}}) {
3402                             if ($self->{open_elements}->[$_]->[1] eq 'table') {            if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {
3403                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
3404                               if (defined $parent and $parent->node_type == 1) {                               if (defined $parent and $parent->node_type == 1) {
3405                                 !!!cp ('t65.1');                                 !!!cp ('t65.1');
# Line 3253  sub _tree_construction_main ($) { Line 3472  sub _tree_construction_main ($) {
3472    
3473    my $insert_to_foster = sub {    my $insert_to_foster = sub {
3474      my $child = shift;      my $child = shift;
3475      if ({      if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {
          table => 1, tbody => 1, tfoot => 1, thead => 1, tr => 1,  
         }->{$self->{open_elements}->[-1]->[1]}) {  
3476        # MUST        # MUST
3477        my $foster_parent_element;        my $foster_parent_element;
3478        my $next_sibling;        my $next_sibling;
3479                           OE: for (reverse 0..$#{$self->{open_elements}}) {        OE: for (reverse 0..$#{$self->{open_elements}}) {
3480                             if ($self->{open_elements}->[$_]->[1] eq 'table') {          if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {
3481                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;                               my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
3482                               if (defined $parent and $parent->node_type == 1) {                               if (defined $parent and $parent->node_type == 1) {
3483                                 !!!cp ('t70');                                 !!!cp ('t70');
# Line 3288  sub _tree_construction_main ($) { Line 3505  sub _tree_construction_main ($) {
3505    B: {    B: {
3506      if ($token->{type} == DOCTYPE_TOKEN) {      if ($token->{type} == DOCTYPE_TOKEN) {
3507        !!!cp ('t73');        !!!cp ('t73');
3508        !!!parse-error (type => 'DOCTYPE in the middle');        !!!parse-error (type => 'DOCTYPE in the middle', token => $token);
3509        ## Ignore the token        ## Ignore the token
3510        ## Stay in the phase        ## Stay in the phase
3511        !!!next-token;        !!!next-token;
3512        redo B;        redo B;
     } elsif ($token->{type} == END_OF_FILE_TOKEN) {  
       if ($self->{insertion_mode} & AFTER_HTML_IMS) {  
         !!!cp ('t74');  
         #  
       } else {  
         ## Generate implied end tags  
         while ({  
                 dd => 1, dt => 1, li => 1, p => 1,  
                }->{$self->{open_elements}->[-1]->[1]}) {  
           !!!cp ('t75');  
           pop @{$self->{open_elements}};  
         }  
           
         if (@{$self->{open_elements}} > 2 or  
             (@{$self->{open_elements}} == 2 and $self->{open_elements}->[1]->[1] ne 'body')) {  
           !!!cp ('t76');  
           !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);  
         } elsif (defined $self->{inner_html_node} and  
                  @{$self->{open_elements}} > 1 and  
                  $self->{open_elements}->[1]->[1] ne 'body') {  
 ## ISSUE: This case is never reached.  
           !!!cp ('t77');  
           !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);  
         } else {  
           !!!cp ('t78');  
         }  
   
         ## ISSUE: There is an issue in the spec.  
       }  
   
       ## Stop parsing  
       last B;  
3513      } elsif ($token->{type} == START_TAG_TOKEN and      } elsif ($token->{type} == START_TAG_TOKEN and
3514               $token->{tag_name} eq 'html') {               $token->{tag_name} eq 'html') {
3515        if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {        if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
3516          !!!cp ('t79');          !!!cp ('t79');
3517          !!!parse-error (type => 'after html:html');          !!!parse-error (type => 'after html:html', token => $token);
3518          $self->{insertion_mode} = AFTER_BODY_IM;          $self->{insertion_mode} = AFTER_BODY_IM;
3519        } elsif ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {        } elsif ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
3520          !!!cp ('t80');          !!!cp ('t80');
3521          !!!parse-error (type => 'after html:html');          !!!parse-error (type => 'after html:html', token => $token);
3522          $self->{insertion_mode} = AFTER_FRAMESET_IM;          $self->{insertion_mode} = AFTER_FRAMESET_IM;
3523        } else {        } else {
3524          !!!cp ('t81');          !!!cp ('t81');
3525        }        }
3526    
3527        !!!cp ('t82');        !!!cp ('t82');
3528        !!!parse-error (type => 'not first start tag');        !!!parse-error (type => 'not first start tag', token => $token);
3529        my $top_el = $self->{open_elements}->[0]->[0];        my $top_el = $self->{open_elements}->[0]->[0];
3530        for my $attr_name (keys %{$token->{attributes}}) {        for my $attr_name (keys %{$token->{attributes}}) {
3531          unless ($top_el->has_attribute_ns (undef, $attr_name)) {          unless ($top_el->has_attribute_ns (undef, $attr_name)) {
# Line 3388  sub _tree_construction_main ($) { Line 3573  sub _tree_construction_main ($) {
3573          if ($self->{insertion_mode} == BEFORE_HEAD_IM) {          if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
3574            !!!cp ('t89');            !!!cp ('t89');
3575            ## As if <head>            ## As if <head>
3576            !!!create-element ($self->{head_element}, 'head');            !!!create-element ($self->{head_element}, 'head',, $token);
3577            $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});            $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
3578            push @{$self->{open_elements}}, [$self->{head_element}, 'head'];            push @{$self->{open_elements}},
3579                  [$self->{head_element}, $el_category->{head}];
3580    
3581            ## Reprocess in the "in head" insertion mode...            ## Reprocess in the "in head" insertion mode...
3582            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
# Line 3400  sub _tree_construction_main ($) { Line 3586  sub _tree_construction_main ($) {
3586            !!!cp ('t90');            !!!cp ('t90');
3587            ## As if </noscript>            ## As if </noscript>
3588            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
3589            !!!parse-error (type => 'in noscript:#character');            !!!parse-error (type => 'in noscript:#character', token => $token);
3590                        
3591            ## Reprocess in the "in head" insertion mode...            ## Reprocess in the "in head" insertion mode...
3592            ## As if </head>            ## As if </head>
# Line 3416  sub _tree_construction_main ($) { Line 3602  sub _tree_construction_main ($) {
3602            !!!cp ('t92');            !!!cp ('t92');
3603          }          }
3604    
3605              ## "after head" insertion mode          ## "after head" insertion mode
3606              ## As if <body>          ## As if <body>
3607              !!!insert-element ('body');          !!!insert-element ('body',, $token);
3608              $self->{insertion_mode} = IN_BODY_IM;          $self->{insertion_mode} = IN_BODY_IM;
3609              ## reprocess          ## reprocess
3610            redo B;
3611          } elsif ($token->{type} == START_TAG_TOKEN) {
3612            if ($token->{tag_name} eq 'head') {
3613              if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
3614                !!!cp ('t93');
3615                !!!create-element ($self->{head_element}, $token->{tag_name}, $token->{attributes}, $token);
3616                $self->{open_elements}->[-1]->[0]->append_child
3617                    ($self->{head_element});
3618                push @{$self->{open_elements}},
3619                    [$self->{head_element}, $el_category->{head}];
3620                $self->{insertion_mode} = IN_HEAD_IM;
3621                !!!next-token;
3622              redo B;              redo B;
           } elsif ($token->{type} == START_TAG_TOKEN) {  
             if ($token->{tag_name} eq 'head') {  
               if ($self->{insertion_mode} == BEFORE_HEAD_IM) {  
                 !!!cp ('t93');  
                 !!!create-element ($self->{head_element}, $token->{tag_name}, $token->{attributes});  
                 $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});  
                 push @{$self->{open_elements}}, [$self->{head_element}, $token->{tag_name}];  
                 $self->{insertion_mode} = IN_HEAD_IM;  
                 !!!next-token;  
                 redo B;  
3623                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
3624                  !!!cp ('t94');                  !!!cp ('t94');
3625                  #                  #
3626                } else {                } else {
3627                  !!!cp ('t95');                  !!!cp ('t95');
3628                  !!!parse-error (type => 'in head:head'); # or in head noscript                  !!!parse-error (type => 'in head:head', token => $token); # or in head noscript
3629                  ## Ignore the token                  ## Ignore the token
3630                  !!!next-token;                  !!!next-token;
3631                  redo B;                  redo B;
# Line 3445  sub _tree_construction_main ($) { Line 3633  sub _tree_construction_main ($) {
3633              } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {              } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
3634                !!!cp ('t96');                !!!cp ('t96');
3635                ## As if <head>                ## As if <head>
3636                !!!create-element ($self->{head_element}, 'head');                !!!create-element ($self->{head_element}, 'head',, $token);
3637                $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});                $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
3638                push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                push @{$self->{open_elements}},
3639                      [$self->{head_element}, $el_category->{head}];
3640    
3641                $self->{insertion_mode} = IN_HEAD_IM;                $self->{insertion_mode} = IN_HEAD_IM;
3642                ## Reprocess in the "in head" insertion mode...                ## Reprocess in the "in head" insertion mode...
# Line 3460  sub _tree_construction_main ($) { Line 3649  sub _tree_construction_main ($) {
3649                  !!!cp ('t98');                  !!!cp ('t98');
3650                  ## As if </noscript>                  ## As if </noscript>
3651                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3652                  !!!parse-error (type => 'in noscript:base');                  !!!parse-error (type => 'in noscript:base', token => $token);
3653                                
3654                  $self->{insertion_mode} = IN_HEAD_IM;                  $self->{insertion_mode} = IN_HEAD_IM;
3655                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
# Line 3471  sub _tree_construction_main ($) { Line 3660  sub _tree_construction_main ($) {
3660                ## NOTE: There is a "as if in head" code clone.                ## NOTE: There is a "as if in head" code clone.
3661                if ($self->{insertion_mode} == AFTER_HEAD_IM) {                if ($self->{insertion_mode} == AFTER_HEAD_IM) {
3662                  !!!cp ('t100');                  !!!cp ('t100');
3663                  !!!parse-error (type => 'after head:'.$token->{tag_name});                  !!!parse-error (type => 'after head:'.$token->{tag_name}, token => $token);
3664                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3665                        [$self->{head_element}, $el_category->{head}];
3666                } else {                } else {
3667                  !!!cp ('t101');                  !!!cp ('t101');
3668                }                }
3669                !!!insert-element ($token->{tag_name}, $token->{attributes});                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3670                pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.                pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
3671                pop @{$self->{open_elements}} # <head>                pop @{$self->{open_elements}} # <head>
3672                    if $self->{insertion_mode} == AFTER_HEAD_IM;                    if $self->{insertion_mode} == AFTER_HEAD_IM;
# Line 3486  sub _tree_construction_main ($) { Line 3676  sub _tree_construction_main ($) {
3676                ## NOTE: There is a "as if in head" code clone.                ## NOTE: There is a "as if in head" code clone.
3677                if ($self->{insertion_mode} == AFTER_HEAD_IM) {                if ($self->{insertion_mode} == AFTER_HEAD_IM) {
3678                  !!!cp ('t102');                  !!!cp ('t102');
3679                  !!!parse-error (type => 'after head:'.$token->{tag_name});                  !!!parse-error (type => 'after head:'.$token->{tag_name}, token => $token);
3680                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3681                        [$self->{head_element}, $el_category->{head}];
3682                } else {                } else {
3683                  !!!cp ('t103');                  !!!cp ('t103');
3684                }                }
3685                !!!insert-element ($token->{tag_name}, $token->{attributes});                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3686                pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.                pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
3687                pop @{$self->{open_elements}} # <head>                pop @{$self->{open_elements}} # <head>
3688                    if $self->{insertion_mode} == AFTER_HEAD_IM;                    if $self->{insertion_mode} == AFTER_HEAD_IM;
# Line 3501  sub _tree_construction_main ($) { Line 3692  sub _tree_construction_main ($) {
3692                ## NOTE: There is a "as if in head" code clone.                ## NOTE: There is a "as if in head" code clone.
3693                if ($self->{insertion_mode} == AFTER_HEAD_IM) {                if ($self->{insertion_mode} == AFTER_HEAD_IM) {
3694                  !!!cp ('t104');                  !!!cp ('t104');
3695                  !!!parse-error (type => 'after head:'.$token->{tag_name});                  !!!parse-error (type => 'after head:'.$token->{tag_name}, token => $token);
3696                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3697                        [$self->{head_element}, $el_category->{head}];
3698                } else {                } else {
3699                  !!!cp ('t105');                  !!!cp ('t105');
3700                }                }
3701                !!!insert-element ($token->{tag_name}, $token->{attributes});                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3702                my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.                my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
3703    
3704                unless ($self->{confident}) {                unless ($self->{confident}) {
3705                  if ($token->{attributes}->{charset}) { ## TODO: And if supported                  if ($token->{attributes}->{charset}) { ## TODO: And if supported
3706                    !!!cp ('t106');                    !!!cp ('t106');
3707                    $self->{change_encoding}                    $self->{change_encoding}
3708                        ->($self, $token->{attributes}->{charset}->{value});                        ->($self, $token->{attributes}->{charset}->{value},
3709                             $token);
3710                                        
3711                    $meta_el->[0]->get_attribute_node_ns (undef, 'charset')                    $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
3712                        ->set_user_data (manakai_has_reference =>                        ->set_user_data (manakai_has_reference =>
# Line 3528  sub _tree_construction_main ($) { Line 3721  sub _tree_construction_main ($) {
3721                            ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {                            ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
3722                      !!!cp ('t107');                      !!!cp ('t107');
3723                      $self->{change_encoding}                      $self->{change_encoding}
3724                          ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);                          ->($self, defined $1 ? $1 : defined $2 ? $2 : $3,
3725                               $token);
3726                      $meta_el->[0]->get_attribute_node_ns (undef, 'content')                      $meta_el->[0]->get_attribute_node_ns (undef, 'content')
3727                          ->set_user_data (manakai_has_reference =>                          ->set_user_data (manakai_has_reference =>
3728                                               $token->{attributes}->{content}                                               $token->{attributes}->{content}
# Line 3563  sub _tree_construction_main ($) { Line 3757  sub _tree_construction_main ($) {
3757                  !!!cp ('t111');                  !!!cp ('t111');
3758                  ## As if </noscript>                  ## As if </noscript>
3759                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3760                  !!!parse-error (type => 'in noscript:title');                  !!!parse-error (type => 'in noscript:title', token => $token);
3761                                
3762                  $self->{insertion_mode} = IN_HEAD_IM;                  $self->{insertion_mode} = IN_HEAD_IM;
3763                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
3764                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
3765                  !!!cp ('t112');                  !!!cp ('t112');
3766                  !!!parse-error (type => 'after head:'.$token->{tag_name});                  !!!parse-error (type => 'after head:'.$token->{tag_name}, token => $token);
3767                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3768                        [$self->{head_element}, $el_category->{head}];
3769                } else {                } else {
3770                  !!!cp ('t113');                  !!!cp ('t113');
3771                }                }
# Line 3588  sub _tree_construction_main ($) { Line 3783  sub _tree_construction_main ($) {
3783                ## NOTE: There is a "as if in head" code clone.                ## NOTE: There is a "as if in head" code clone.
3784                if ($self->{insertion_mode} == AFTER_HEAD_IM) {                if ($self->{insertion_mode} == AFTER_HEAD_IM) {
3785                  !!!cp ('t114');                  !!!cp ('t114');
3786                  !!!parse-error (type => 'after head:'.$token->{tag_name});                  !!!parse-error (type => 'after head:'.$token->{tag_name}, token => $token);
3787                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3788                        [$self->{head_element}, $el_category->{head}];
3789                } else {                } else {
3790                  !!!cp ('t115');                  !!!cp ('t115');
3791                }                }
# Line 3601  sub _tree_construction_main ($) { Line 3797  sub _tree_construction_main ($) {
3797                if ($self->{insertion_mode} == IN_HEAD_IM) {                if ($self->{insertion_mode} == IN_HEAD_IM) {
3798                  !!!cp ('t116');                  !!!cp ('t116');
3799                  ## NOTE: and scripting is disalbed                  ## NOTE: and scripting is disalbed
3800                  !!!insert-element ($token->{tag_name}, $token->{attributes});                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3801                  $self->{insertion_mode} = IN_HEAD_NOSCRIPT_IM;                  $self->{insertion_mode} = IN_HEAD_NOSCRIPT_IM;
3802                  !!!next-token;                  !!!next-token;
3803                  redo B;                  redo B;
3804                } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {                } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
3805                  !!!cp ('t117');                  !!!cp ('t117');
3806                  !!!parse-error (type => 'in noscript:noscript');                  !!!parse-error (type => 'in noscript:noscript', token => $token);
3807                  ## Ignore the token                  ## Ignore the token
3808                  !!!next-token;                  !!!next-token;
3809                  redo B;                  redo B;
# Line 3620  sub _tree_construction_main ($) { Line 3816  sub _tree_construction_main ($) {
3816                  !!!cp ('t119');                  !!!cp ('t119');
3817                  ## As if </noscript>                  ## As if </noscript>
3818                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3819                  !!!parse-error (type => 'in noscript:script');                  !!!parse-error (type => 'in noscript:script', token => $token);
3820                                
3821                  $self->{insertion_mode} = IN_HEAD_IM;                  $self->{insertion_mode} = IN_HEAD_IM;
3822                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
3823                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {                } elsif ($self->{insertion_mode} == AFTER_HEAD_IM) {
3824                  !!!cp ('t120');                  !!!cp ('t120');
3825                  !!!parse-error (type => 'after head:'.$token->{tag_name});                  !!!parse-error (type => 'after head:'.$token->{tag_name}, token => $token);
3826                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3827                        [$self->{head_element}, $el_category->{head}];
3828                } else {                } else {
3829                  !!!cp ('t121');                  !!!cp ('t121');
3830                }                }
# Line 3643  sub _tree_construction_main ($) { Line 3840  sub _tree_construction_main ($) {
3840                  !!!cp ('t122');                  !!!cp ('t122');
3841                  ## As if </noscript>                  ## As if </noscript>
3842                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3843                  !!!parse-error (type => 'in noscript:'.$token->{tag_name});                  !!!parse-error (type => 'in noscript:'.$token->{tag_name}, token => $token);
3844                                    
3845                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
3846                  ## As if </head>                  ## As if </head>
# Line 3660  sub _tree_construction_main ($) { Line 3857  sub _tree_construction_main ($) {
3857                }                }
3858    
3859                ## "after head" insertion mode                ## "after head" insertion mode
3860                !!!insert-element ($token->{tag_name}, $token->{attributes});                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
3861                if ($token->{tag_name} eq 'body') {                if ($token->{tag_name} eq 'body') {
3862                  !!!cp ('t126');                  !!!cp ('t126');
3863                  $self->{insertion_mode} = IN_BODY_IM;                  $self->{insertion_mode} = IN_BODY_IM;
# Line 3681  sub _tree_construction_main ($) { Line 3878  sub _tree_construction_main ($) {
3878                !!!cp ('t129');                !!!cp ('t129');
3879                ## As if </noscript>                ## As if </noscript>
3880                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
3881                !!!parse-error (type => 'in noscript:/'.$token->{tag_name});                !!!parse-error (type => 'in noscript:/'.$token->{tag_name}, token => $token);
3882                                
3883                ## Reprocess in the "in head" insertion mode...                ## Reprocess in the "in head" insertion mode...
3884                ## As if </head>                ## As if </head>
# Line 3700  sub _tree_construction_main ($) { Line 3897  sub _tree_construction_main ($) {
3897    
3898              ## "after head" insertion mode              ## "after head" insertion mode
3899              ## As if <body>              ## As if <body>
3900              !!!insert-element ('body');              !!!insert-element ('body',, $token);
3901              $self->{insertion_mode} = IN_BODY_IM;              $self->{insertion_mode} = IN_BODY_IM;
3902              ## reprocess              ## reprocess
3903              redo B;              redo B;
# Line 3709  sub _tree_construction_main ($) { Line 3906  sub _tree_construction_main ($) {
3906                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
3907                  !!!cp ('t132');                  !!!cp ('t132');
3908                  ## As if <head>                  ## As if <head>
3909                  !!!create-element ($self->{head_element}, 'head');                  !!!create-element ($self->{head_element}, 'head',, $token);
3910                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
3911                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3912                        [$self->{head_element}, $el_category->{head}];
3913    
3914                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
3915                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
# Line 3722  sub _tree_construction_main ($) { Line 3920  sub _tree_construction_main ($) {
3920                  !!!cp ('t133');                  !!!cp ('t133');
3921                  ## As if </noscript>                  ## As if </noscript>
3922                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
3923                  !!!parse-error (type => 'in noscript:/head');                  !!!parse-error (type => 'in noscript:/head', token => $token);
3924                                    
3925                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
3926                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
# Line 3748  sub _tree_construction_main ($) { Line 3946  sub _tree_construction_main ($) {
3946                  redo B;                  redo B;
3947                } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {                } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
3948                  !!!cp ('t137');                  !!!cp ('t137');
3949                  !!!parse-error (type => 'unmatched end tag:noscript');                  !!!parse-error (type => 'unmatched end tag:noscript', token => $token);
3950                  ## Ignore the token ## ISSUE: An issue in the spec.                  ## Ignore the token ## ISSUE: An issue in the spec.
3951                  !!!next-token;                  !!!next-token;
3952                  redo B;                  redo B;
# Line 3762  sub _tree_construction_main ($) { Line 3960  sub _tree_construction_main ($) {
3960                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
3961                  !!!cp ('t139');                  !!!cp ('t139');
3962                  ## As if <head>                  ## As if <head>
3963                  !!!create-element ($self->{head_element}, 'head');                  !!!create-element ($self->{head_element}, 'head',, $token);
3964                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
3965                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3966                        [$self->{head_element}, $el_category->{head}];
3967    
3968                  $self->{insertion_mode} = IN_HEAD_IM;                  $self->{insertion_mode} = IN_HEAD_IM;
3969                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
3970                } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {                } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
3971                  !!!cp ('t140');                  !!!cp ('t140');
3972                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
3973                  ## Ignore the token                  ## Ignore the token
3974                  !!!next-token;                  !!!next-token;
3975                  redo B;                  redo B;
# Line 3785  sub _tree_construction_main ($) { Line 3984  sub _tree_construction_main ($) {
3984                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {                if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
3985                  !!!cp ('t142');                  !!!cp ('t142');
3986                  ## As if <head>                  ## As if <head>
3987                  !!!create-element ($self->{head_element}, 'head');                  !!!create-element ($self->{head_element}, 'head',, $token);
3988                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});                  $self->{open_elements}->[-1]->[0]->append_child ($self->{head_element});
3989                  push @{$self->{open_elements}}, [$self->{head_element}, 'head'];                  push @{$self->{open_elements}},
3990                        [$self->{head_element}, $el_category->{head}];
3991    
3992                  $self->{insertion_mode} = IN_HEAD_IM;                  $self->{insertion_mode} = IN_HEAD_IM;
3993                  ## Reprocess in the "in head" insertion mode...                  ## Reprocess in the "in head" insertion mode...
# Line 3802  sub _tree_construction_main ($) { Line 4002  sub _tree_construction_main ($) {
4002                  #                  #
4003                } else {                } else {
4004                  !!!cp ('t145');                  !!!cp ('t145');
4005                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4006                  ## Ignore the token                  ## Ignore the token
4007                  !!!next-token;                  !!!next-token;
4008                  redo B;                  redo B;
# Line 3813  sub _tree_construction_main ($) { Line 4013  sub _tree_construction_main ($) {
4013                !!!cp ('t146');                !!!cp ('t146');
4014                ## As if </noscript>                ## As if </noscript>
4015                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
4016                !!!parse-error (type => 'in noscript:/'.$token->{tag_name});                !!!parse-error (type => 'in noscript:/'.$token->{tag_name}, token => $token);
4017                                
4018                ## Reprocess in the "in head" insertion mode...                ## Reprocess in the "in head" insertion mode...
4019                ## As if </head>                ## As if </head>
# Line 3829  sub _tree_construction_main ($) { Line 4029  sub _tree_construction_main ($) {
4029              } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {              } elsif ($self->{insertion_mode} == BEFORE_HEAD_IM) {
4030  ## ISSUE: This case cannot be reached?  ## ISSUE: This case cannot be reached?
4031                !!!cp ('t148');                !!!cp ('t148');
4032                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4033                ## Ignore the token ## ISSUE: An issue in the spec.                ## Ignore the token ## ISSUE: An issue in the spec.
4034                !!!next-token;                !!!next-token;
4035                redo B;                redo B;
# Line 3839  sub _tree_construction_main ($) { Line 4039  sub _tree_construction_main ($) {
4039    
4040              ## "after head" insertion mode              ## "after head" insertion mode
4041              ## As if <body>              ## As if <body>
4042              !!!insert-element ('body');              !!!insert-element ('body',, $token);
4043              $self->{insertion_mode} = IN_BODY_IM;              $self->{insertion_mode} = IN_BODY_IM;
4044              ## reprocess              ## reprocess
4045              redo B;              redo B;
4046            } else {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
4047              die "$0: $token->{type}: Unknown token type";          if ($self->{insertion_mode} == BEFORE_HEAD_IM) {
4048            }            !!!cp ('t149.1');
4049    
4050              ## NOTE: As if <head>
4051              !!!create-element ($self->{head_element}, 'head',, $token);
4052              $self->{open_elements}->[-1]->[0]->append_child
4053                  ($self->{head_element});
4054              #push @{$self->{open_elements}},
4055              #    [$self->{head_element}, $el_category->{head}];
4056              #$self->{insertion_mode} = IN_HEAD_IM;
4057              ## NOTE: Reprocess.
4058    
4059              ## NOTE: As if </head>
4060              #pop @{$self->{open_elements}};
4061              #$self->{insertion_mode} = IN_AFTER_HEAD_IM;
4062              ## NOTE: Reprocess.
4063              
4064              #
4065            } elsif ($self->{insertion_mode} == IN_HEAD_IM) {
4066              !!!cp ('t149.2');
4067    
4068              ## NOTE: As if </head>
4069              pop @{$self->{open_elements}};
4070              #$self->{insertion_mode} = IN_AFTER_HEAD_IM;
4071              ## NOTE: Reprocess.
4072    
4073              #
4074            } elsif ($self->{insertion_mode} == IN_HEAD_NOSCRIPT_IM) {
4075              !!!cp ('t149.3');
4076    
4077              !!!parse-error (type => 'in noscript:#eof', token => $token);
4078    
4079              ## As if </noscript>
4080              pop @{$self->{open_elements}};
4081              #$self->{insertion_mode} = IN_HEAD_IM;
4082              ## NOTE: Reprocess.
4083    
4084              ## NOTE: As if </head>
4085              pop @{$self->{open_elements}};
4086              #$self->{insertion_mode} = IN_AFTER_HEAD_IM;
4087              ## NOTE: Reprocess.
4088    
4089              #
4090            } else {
4091              !!!cp ('t149.4');
4092              #
4093            }
4094    
4095            ## NOTE: As if <body>
4096            !!!insert-element ('body',, $token);
4097            $self->{insertion_mode} = IN_BODY_IM;
4098            ## NOTE: Reprocess.
4099            redo B;
4100          } else {
4101            die "$0: $token->{type}: Unknown token type";
4102          }
4103    
4104            ## ISSUE: An issue in the spec.            ## ISSUE: An issue in the spec.
4105      } elsif ($self->{insertion_mode} & BODY_IMS) {      } elsif ($self->{insertion_mode} & BODY_IMS) {
# Line 3865  sub _tree_construction_main ($) { Line 4119  sub _tree_construction_main ($) {
4119                  }->{$token->{tag_name}}) {                  }->{$token->{tag_name}}) {
4120                if ($self->{insertion_mode} == IN_CELL_IM) {                if ($self->{insertion_mode} == IN_CELL_IM) {
4121                  ## have an element in table scope                  ## have an element in table scope
4122                  my $tn;                  for (reverse 0..$#{$self->{open_elements}}) {
                 INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {  
4123                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
4124                    if ($node->[1] eq 'td' or $node->[1] eq 'th') {                    if ($node->[1] & TABLE_CELL_EL) {
4125                      !!!cp ('t151');                      !!!cp ('t151');
4126                      $tn = $node->[1];  
4127                      last INSCOPE;                      ## Close the cell
4128                    } elsif ({                      !!!back-token; # <?>
4129                              table => 1, html => 1,                      $token = {type => END_TAG_TOKEN,
4130                             }->{$node->[1]}) {                                tag_name => $node->[0]->manakai_local_name,
4131                      !!!cp ('t152');                                line => $token->{line},
4132                      last INSCOPE;                                column => $token->{column}};
                   }  
                 } # INSCOPE  
                   unless (defined $tn) {  
                     !!!cp ('t153');  
 ## TODO: This error type is wrong.  
                     !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});  
                     ## Ignore the token  
                     !!!next-token;  
4133                      redo B;                      redo B;
4134                      } elsif ($node->[1] & TABLE_SCOPING_EL) {
4135                        !!!cp ('t152');
4136                        ## ISSUE: This case can never be reached, maybe.
4137                        last;
4138                    }                    }
4139                                    }
4140                  !!!cp ('t154');  
4141                  ## Close the cell                  !!!cp ('t153');
4142                  !!!back-token; # <?>                  !!!parse-error (type => 'start tag not allowed',
4143                  $token = {type => END_TAG_TOKEN, tag_name => $tn};                      value => $token->{tag_name}, token => $token);
4144                    ## Ignore the token
4145                    !!!next-token;
4146                  redo B;                  redo B;
4147                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {
4148                  !!!parse-error (type => 'not closed:caption');                  !!!parse-error (type => 'not closed:caption', token => $token);
4149                                    
4150                  ## As if </caption>                  ## NOTE: As if </caption>.
4151                  ## have a table element in table scope                  ## have a table element in table scope
4152                  my $i;                  my $i;
4153                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: {
4154                    my $node = $self->{open_elements}->[$_];                    for (reverse 0..$#{$self->{open_elements}}) {
4155                    if ($node->[1] eq 'caption') {                      my $node = $self->{open_elements}->[$_];
4156                      !!!cp ('t155');                      if ($node->[1] & CAPTION_EL) {
4157                      $i = $_;                        !!!cp ('t155');
4158                      last INSCOPE;                        $i = $_;
4159                    } elsif ({                        last INSCOPE;
4160                              table => 1, html => 1,                      } elsif ($node->[1] & TABLE_SCOPING_EL) {
4161                             }->{$node->[1]}) {                        !!!cp ('t156');
4162                      !!!cp ('t156');                        last;
4163                      last INSCOPE;                      }
4164                    }                    }
4165    
4166                      !!!cp ('t157');
4167                      !!!parse-error (type => 'start tag not allowed',
4168                                      value => $token->{tag_name}, token => $token);
4169                      ## Ignore the token
4170                      !!!next-token;
4171                      redo B;
4172                  } # INSCOPE                  } # INSCOPE
                   unless (defined $i) {  
                     !!!cp ('t157');  
 ## TODO: this type is wrong.  
                     !!!parse-error (type => 'unmatched end tag:caption');  
                     ## Ignore the token  
                     !!!next-token;  
                     redo B;  
                   }  
4173                                    
4174                  ## generate implied end tags                  ## generate implied end tags
4175                  while ({                  while ($self->{open_elements}->[-1]->[1]
4176                          dd => 1, dt => 1, li => 1, p => 1,                             & END_TAG_OPTIONAL_EL) {
                        }->{$self->{open_elements}->[-1]->[1]}) {  
4177                    !!!cp ('t158');                    !!!cp ('t158');
4178                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
4179                  }                  }
4180    
4181                  if ($self->{open_elements}->[-1]->[1] ne 'caption') {                  unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {
4182                    !!!cp ('t159');                    !!!cp ('t159');
4183                    !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                    !!!parse-error (type => 'not closed',
4184                                      value => $self->{open_elements}->[-1]->[0]
4185                                          ->manakai_local_name,
4186                                      token => $token);
4187                  } else {                  } else {
4188                    !!!cp ('t160');                    !!!cp ('t160');
4189                  }                  }
# Line 3959  sub _tree_construction_main ($) { Line 4211  sub _tree_construction_main ($) {
4211                  my $i;                  my $i;
4212                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4213                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
4214                    if ($node->[1] eq $token->{tag_name}) {                    if ($node->[0]->manakai_local_name eq $token->{tag_name}) {
4215                      !!!cp ('t163');                      !!!cp ('t163');
4216                      $i = $_;                      $i = $_;
4217                      last INSCOPE;                      last INSCOPE;
4218                    } elsif ({                    } elsif ($node->[1] & TABLE_SCOPING_EL) {
                             table => 1, html => 1,  
                            }->{$node->[1]}) {  
4219                      !!!cp ('t164');                      !!!cp ('t164');
4220                      last INSCOPE;                      last INSCOPE;
4221                    }                    }
4222                  } # INSCOPE                  } # INSCOPE
4223                    unless (defined $i) {                    unless (defined $i) {
4224                      !!!cp ('t165');                      !!!cp ('t165');
4225                      !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                      !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4226                      ## Ignore the token                      ## Ignore the token
4227                      !!!next-token;                      !!!next-token;
4228                      redo B;                      redo B;
4229                    }                    }
4230                                    
4231                  ## generate implied end tags                  ## generate implied end tags
4232                  while ({                  while ($self->{open_elements}->[-1]->[1]
4233                          dd => 1, dt => 1, li => 1, p => 1,                             & END_TAG_OPTIONAL_EL) {
                        }->{$self->{open_elements}->[-1]->[1]}) {  
4234                    !!!cp ('t166');                    !!!cp ('t166');
4235                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
4236                  }                  }
4237    
4238                  if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {                  if ($self->{open_elements}->[-1]->[0]->manakai_local_name
4239                            ne $token->{tag_name}) {
4240                    !!!cp ('t167');                    !!!cp ('t167');
4241                    !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                    !!!parse-error (type => 'not closed',
4242                                      value => $self->{open_elements}->[-1]->[0]
4243                                          ->manakai_local_name,
4244                                      token => $token);
4245                  } else {                  } else {
4246                    !!!cp ('t168');                    !!!cp ('t168');
4247                  }                  }
# Line 4003  sub _tree_construction_main ($) { Line 4256  sub _tree_construction_main ($) {
4256                  redo B;                  redo B;
4257                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {                } elsif ($self->{insertion_mode} == IN_CAPTION_IM) {
4258                  !!!cp ('t169');                  !!!cp ('t169');
4259                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4260                  ## Ignore the token                  ## Ignore the token
4261                  !!!next-token;                  !!!next-token;
4262                  redo B;                  redo B;
# Line 4015  sub _tree_construction_main ($) { Line 4268  sub _tree_construction_main ($) {
4268                if ($self->{insertion_mode} == IN_CAPTION_IM) {                if ($self->{insertion_mode} == IN_CAPTION_IM) {
4269                  ## have a table element in table scope                  ## have a table element in table scope
4270                  my $i;                  my $i;
4271                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: {
4272                    my $node = $self->{open_elements}->[$_];                    for (reverse 0..$#{$self->{open_elements}}) {
4273                    if ($node->[1] eq $token->{tag_name}) {                      my $node = $self->{open_elements}->[$_];
4274                      !!!cp ('t171');                      if ($node->[1] & CAPTION_EL) {
4275                      $i = $_;                        !!!cp ('t171');
4276                      last INSCOPE;                        $i = $_;
4277                    } elsif ({                        last INSCOPE;
4278                              table => 1, html => 1,                      } elsif ($node->[1] & TABLE_SCOPING_EL) {
4279                             }->{$node->[1]}) {                        !!!cp ('t172');
4280                      !!!cp ('t172');                        last;
4281                      last INSCOPE;                      }
4282                    }                    }
4283    
4284                      !!!cp ('t173');
4285                      !!!parse-error (type => 'unmatched end tag',
4286                                      value => $token->{tag_name}, token => $token);
4287                      ## Ignore the token
4288                      !!!next-token;
4289                      redo B;
4290                  } # INSCOPE                  } # INSCOPE
                   unless (defined $i) {  
                     !!!cp ('t173');  
                     !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});  
                     ## Ignore the token  
                     !!!next-token;  
                     redo B;  
                   }  
4291                                    
4292                  ## generate implied end tags                  ## generate implied end tags
4293                  while ({                  while ($self->{open_elements}->[-1]->[1]
4294                          dd => 1, dt => 1, li => 1, p => 1,                             & END_TAG_OPTIONAL_EL) {
                        }->{$self->{open_elements}->[-1]->[1]}) {  
4295                    !!!cp ('t174');                    !!!cp ('t174');
4296                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
4297                  }                  }
4298                                    
4299                  if ($self->{open_elements}->[-1]->[1] ne 'caption') {                  unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {
4300                    !!!cp ('t175');                    !!!cp ('t175');
4301                    !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                    !!!parse-error (type => 'not closed',
4302                                      value => $self->{open_elements}->[-1]->[0]
4303                                          ->manakai_local_name,
4304                                      token => $token);
4305                  } else {                  } else {
4306                    !!!cp ('t176');                    !!!cp ('t176');
4307                  }                  }
# Line 4061  sub _tree_construction_main ($) { Line 4316  sub _tree_construction_main ($) {
4316                  redo B;                  redo B;
4317                } elsif ($self->{insertion_mode} == IN_CELL_IM) {                } elsif ($self->{insertion_mode} == IN_CELL_IM) {
4318                  !!!cp ('t177');                  !!!cp ('t177');
4319                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4320                  ## Ignore the token                  ## Ignore the token
4321                  !!!next-token;                  !!!next-token;
4322                  redo B;                  redo B;
# Line 4077  sub _tree_construction_main ($) { Line 4332  sub _tree_construction_main ($) {
4332                ## have an element in table scope                ## have an element in table scope
4333                my $i;                my $i;
4334                my $tn;                my $tn;
4335                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: {
4336                  my $node = $self->{open_elements}->[$_];                  for (reverse 0..$#{$self->{open_elements}}) {
4337                  if ($node->[1] eq $token->{tag_name}) {                    my $node = $self->{open_elements}->[$_];
4338                    !!!cp ('t179');                    if ($node->[0]->manakai_local_name eq $token->{tag_name}) {
4339                    $i = $_;                      !!!cp ('t179');
4340                    last INSCOPE;                      $i = $_;
4341                  } elsif ($node->[1] eq 'td' or $node->[1] eq 'th') {  
4342                    !!!cp ('t180');                      ## Close the cell
4343                    $tn = $node->[1];                      !!!back-token; # </?>
4344                    ## NOTE: There is exactly one |td| or |th| element                      $token = {type => END_TAG_TOKEN, tag_name => $tn,
4345                    ## in scope in the stack of open elements by definition.                                line => $token->{line},
4346                  } elsif ({                                column => $token->{column}};
4347                            table => 1, html => 1,                      redo B;
4348                           }->{$node->[1]}) {                    } elsif ($node->[1] & TABLE_CELL_EL) {
4349                    !!!cp ('t181');                      !!!cp ('t180');
4350                    last INSCOPE;                      $tn = $node->[0]->manakai_local_name;
4351                        ## NOTE: There is exactly one |td| or |th| element
4352                        ## in scope in the stack of open elements by definition.
4353                      } elsif ($node->[1] & TABLE_SCOPING_EL) {
4354                        ## ISSUE: Can this be reached?
4355                        !!!cp ('t181');
4356                        last;
4357                      }
4358                  }                  }
4359                } # INSCOPE  
               unless (defined $i) {  
4360                  !!!cp ('t182');                  !!!cp ('t182');
4361                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag',
4362                        value => $token->{tag_name}, token => $token);
4363                  ## Ignore the token                  ## Ignore the token
4364                  !!!next-token;                  !!!next-token;
4365                  redo B;                  redo B;
4366                } else {                } # INSCOPE
                 !!!cp ('t183');  
               }  
   
               ## Close the cell  
               !!!back-token; # </?>  
               $token = {type => END_TAG_TOKEN, tag_name => $tn};  
               redo B;  
4367              } elsif ($token->{tag_name} eq 'table' and              } elsif ($token->{tag_name} eq 'table' and
4368                       $self->{insertion_mode} == IN_CAPTION_IM) {                       $self->{insertion_mode} == IN_CAPTION_IM) {
4369                !!!parse-error (type => 'not closed:caption');                !!!parse-error (type => 'not closed:caption', token => $token);
4370    
4371                ## As if </caption>                ## As if </caption>
4372                ## have a table element in table scope                ## have a table element in table scope
4373                my $i;                my $i;
4374                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4375                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
4376                  if ($node->[1] eq 'caption') {                  if ($node->[1] & CAPTION_EL) {
4377                    !!!cp ('t184');                    !!!cp ('t184');
4378                    $i = $_;                    $i = $_;
4379                    last INSCOPE;                    last INSCOPE;
4380                  } elsif ({                  } elsif ($node->[1] & TABLE_SCOPING_EL) {
                           table => 1, html => 1,  
                          }->{$node->[1]}) {  
4381                    !!!cp ('t185');                    !!!cp ('t185');
4382                    last INSCOPE;                    last INSCOPE;
4383                  }                  }
4384                } # INSCOPE                } # INSCOPE
4385                unless (defined $i) {                unless (defined $i) {
4386                  !!!cp ('t186');                  !!!cp ('t186');
4387                  !!!parse-error (type => 'unmatched end tag:caption');                  !!!parse-error (type => 'unmatched end tag:caption', token => $token);
4388                  ## Ignore the token                  ## Ignore the token
4389                  !!!next-token;                  !!!next-token;
4390                  redo B;                  redo B;
4391                }                }
4392                                
4393                ## generate implied end tags                ## generate implied end tags
4394                while ({                while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
                       dd => 1, dt => 1, li => 1, p => 1,  
                      }->{$self->{open_elements}->[-1]->[1]}) {  
4395                  !!!cp ('t187');                  !!!cp ('t187');
4396                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
4397                }                }
4398    
4399                if ($self->{open_elements}->[-1]->[1] ne 'caption') {                unless ($self->{open_elements}->[-1]->[1] & CAPTION_EL) {
4400                  !!!cp ('t188');                  !!!cp ('t188');
4401                  !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                  !!!parse-error (type => 'not closed',
4402                                    value => $self->{open_elements}->[-1]->[0]
4403                                        ->manakai_local_name,
4404                                    token => $token);
4405                } else {                } else {
4406                  !!!cp ('t189');                  !!!cp ('t189');
4407                }                }
# Line 4165  sub _tree_construction_main ($) { Line 4419  sub _tree_construction_main ($) {
4419                       }->{$token->{tag_name}}) {                       }->{$token->{tag_name}}) {
4420                if ($self->{insertion_mode} & BODY_TABLE_IMS) {                if ($self->{insertion_mode} & BODY_TABLE_IMS) {
4421                  !!!cp ('t190');                  !!!cp ('t190');
4422                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4423                  ## Ignore the token                  ## Ignore the token
4424                  !!!next-token;                  !!!next-token;
4425                  redo B;                  redo B;
# Line 4179  sub _tree_construction_main ($) { Line 4433  sub _tree_construction_main ($) {
4433                       }->{$token->{tag_name}} and                       }->{$token->{tag_name}} and
4434                       $self->{insertion_mode} == IN_CAPTION_IM) {                       $self->{insertion_mode} == IN_CAPTION_IM) {
4435                !!!cp ('t192');                !!!cp ('t192');
4436                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4437                ## Ignore the token                ## Ignore the token
4438                !!!next-token;                !!!next-token;
4439                redo B;                redo B;
# Line 4187  sub _tree_construction_main ($) { Line 4441  sub _tree_construction_main ($) {
4441                !!!cp ('t193');                !!!cp ('t193');
4442                #                #
4443              }              }
4444          } elsif ($token->{type} == END_OF_FILE_TOKEN) {
4445            for my $entry (@{$self->{open_elements}}) {
4446              unless ($entry->[1] & ALL_END_TAG_OPTIONAL_EL) {
4447                !!!cp ('t75');
4448                !!!parse-error (type => 'in body:#eof', token => $token);
4449                last;
4450              }
4451            }
4452    
4453            ## Stop parsing.
4454            last B;
4455        } else {        } else {
4456          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
4457        }        }
# Line 4208  sub _tree_construction_main ($) { Line 4473  sub _tree_construction_main ($) {
4473            }            }
4474          }          }
4475    
4476              !!!parse-error (type => 'in table:#character');              !!!parse-error (type => 'in table:#character', token => $token);
4477    
4478              ## As if in body, but insert into foster parent element              ## As if in body, but insert into foster parent element
4479              ## ISSUE: Spec says that "whenever a node would be inserted              ## ISSUE: Spec says that "whenever a node would be inserted
# Line 4216  sub _tree_construction_main ($) { Line 4481  sub _tree_construction_main ($) {
4481              ## result in a new Text node.              ## result in a new Text node.
4482              $reconstruct_active_formatting_elements->($insert_to_foster);              $reconstruct_active_formatting_elements->($insert_to_foster);
4483                            
4484              if ({              if ($self->{open_elements}->[-1]->[1] & TABLE_ROWS_EL) {
                  table => 1, tbody => 1, tfoot => 1,  
                  thead => 1, tr => 1,  
                 }->{$self->{open_elements}->[-1]->[1]}) {  
4485                # MUST                # MUST
4486                my $foster_parent_element;                my $foster_parent_element;
4487                my $next_sibling;                my $next_sibling;
4488                my $prev_sibling;                my $prev_sibling;
4489                OE: for (reverse 0..$#{$self->{open_elements}}) {                OE: for (reverse 0..$#{$self->{open_elements}}) {
4490                  if ($self->{open_elements}->[$_]->[1] eq 'table') {                  if ($self->{open_elements}->[$_]->[1] & TABLE_EL) {
4491                    my $parent = $self->{open_elements}->[$_]->[0]->parent_node;                    my $parent = $self->{open_elements}->[$_]->[0]->parent_node;
4492                    if (defined $parent and $parent->node_type == 1) {                    if (defined $parent and $parent->node_type == 1) {
4493                      !!!cp ('t196');                      !!!cp ('t196');
# Line 4268  sub _tree_construction_main ($) { Line 4530  sub _tree_construction_main ($) {
4530                  }->{$token->{tag_name}}) {                  }->{$token->{tag_name}}) {
4531                if ($self->{insertion_mode} == IN_TABLE_IM) {                if ($self->{insertion_mode} == IN_TABLE_IM) {
4532                  ## Clear back to table context                  ## Clear back to table context
4533                  while ($self->{open_elements}->[-1]->[1] ne 'table' and                  while (not ($self->{open_elements}->[-1]->[1]
4534                         $self->{open_elements}->[-1]->[1] ne 'html') {                                  & TABLE_SCOPING_EL)) {
4535                    !!!cp ('t201');                    !!!cp ('t201');
4536                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
4537                  }                  }
4538                                    
4539                  !!!insert-element ('tbody');                  !!!insert-element ('tbody',, $token);
4540                  $self->{insertion_mode} = IN_TABLE_BODY_IM;                  $self->{insertion_mode} = IN_TABLE_BODY_IM;
4541                  ## reprocess in the "in table body" insertion mode...                  ## reprocess in the "in table body" insertion mode...
4542                }                }
# Line 4282  sub _tree_construction_main ($) { Line 4544  sub _tree_construction_main ($) {
4544                if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {                if ($self->{insertion_mode} == IN_TABLE_BODY_IM) {
4545                  unless ($token->{tag_name} eq 'tr') {                  unless ($token->{tag_name} eq 'tr') {
4546                    !!!cp ('t202');                    !!!cp ('t202');
4547                    !!!parse-error (type => 'missing start tag:tr');                    !!!parse-error (type => 'missing start tag:tr', token => $token);
4548                  }                  }
4549                                    
4550                  ## Clear back to table body context                  ## Clear back to table body context
4551                  while (not {                  while (not ($self->{open_elements}->[-1]->[1]
4552                    tbody => 1, tfoot => 1, thead => 1, html => 1,                                  & TABLE_ROWS_SCOPING_EL)) {
                 }->{$self->{open_elements}->[-1]->[1]}) {  
4553                    !!!cp ('t203');                    !!!cp ('t203');
4554                    ## ISSUE: Can this case be reached?                    ## ISSUE: Can this case be reached?
4555                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
# Line 4297  sub _tree_construction_main ($) { Line 4558  sub _tree_construction_main ($) {
4558                  $self->{insertion_mode} = IN_ROW_IM;                  $self->{insertion_mode} = IN_ROW_IM;
4559                  if ($token->{tag_name} eq 'tr') {                  if ($token->{tag_name} eq 'tr') {
4560                    !!!cp ('t204');                    !!!cp ('t204');
4561                    !!!insert-element ($token->{tag_name}, $token->{attributes});                    !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
4562                    !!!next-token;                    !!!next-token;
4563                    redo B;                    redo B;
4564                  } else {                  } else {
4565                    !!!cp ('t205');                    !!!cp ('t205');
4566                    !!!insert-element ('tr');                    !!!insert-element ('tr',, $token);
4567                    ## reprocess in the "in row" insertion mode                    ## reprocess in the "in row" insertion mode
4568                  }                  }
4569                } else {                } else {
# Line 4310  sub _tree_construction_main ($) { Line 4571  sub _tree_construction_main ($) {
4571                }                }
4572    
4573                ## Clear back to table row context                ## Clear back to table row context
4574                while (not {                while (not ($self->{open_elements}->[-1]->[1]
4575                  tr => 1, html => 1,                                & TABLE_ROW_SCOPING_EL)) {
               }->{$self->{open_elements}->[-1]->[1]}) {  
4576                  !!!cp ('t207');                  !!!cp ('t207');
4577                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
4578                }                }
4579                                
4580                !!!insert-element ($token->{tag_name}, $token->{attributes});                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
4581                $self->{insertion_mode} = IN_CELL_IM;                $self->{insertion_mode} = IN_CELL_IM;
4582    
4583                push @$active_formatting_elements, ['#marker', ''];                push @$active_formatting_elements, ['#marker', ''];
# Line 4335  sub _tree_construction_main ($) { Line 4595  sub _tree_construction_main ($) {
4595                  my $i;                  my $i;
4596                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4597                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
4598                    if ($node->[1] eq 'tr') {                    if ($node->[1] & TABLE_ROW_EL) {
4599                      !!!cp ('t208');                      !!!cp ('t208');
4600                      $i = $_;                      $i = $_;
4601                      last INSCOPE;                      last INSCOPE;
4602                    } elsif ({                    } elsif ($node->[1] & TABLE_SCOPING_EL) {
                             html => 1,  
   
                             ## NOTE: This element does not appear here, maybe.  
                             table => 1,  
                            }->{$node->[1]}) {  
4603                      !!!cp ('t209');                      !!!cp ('t209');
4604                      last INSCOPE;                      last INSCOPE;
4605                    }                    }
# Line 4352  sub _tree_construction_main ($) { Line 4607  sub _tree_construction_main ($) {
4607                  unless (defined $i) {                  unless (defined $i) {
4608                   !!!cp ('t210');                   !!!cp ('t210');
4609  ## TODO: This type is wrong.  ## TODO: This type is wrong.
4610                   !!!parse-error (type => 'unmacthed end tag:'.$token->{tag_name});                   !!!parse-error (type => 'unmacthed end tag:'.$token->{tag_name}, token => $token);
4611                    ## Ignore the token                    ## Ignore the token
4612                    !!!next-token;                    !!!next-token;
4613                    redo B;                    redo B;
4614                  }                  }
4615                                    
4616                  ## Clear back to table row context                  ## Clear back to table row context
4617                  while (not {                  while (not ($self->{open_elements}->[-1]->[1]
4618                    tr => 1, html => 1,                                  & TABLE_ROW_SCOPING_EL)) {
                 }->{$self->{open_elements}->[-1]->[1]}) {  
4619                    !!!cp ('t211');                    !!!cp ('t211');
4620                    ## ISSUE: Can this case be reached?                    ## ISSUE: Can this case be reached?
4621                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
# Line 4384  sub _tree_construction_main ($) { Line 4638  sub _tree_construction_main ($) {
4638                  my $i;                  my $i;
4639                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4640                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
4641                    if ({                    if ($node->[1] & TABLE_ROW_GROUP_EL) {
                        tbody => 1, thead => 1, tfoot => 1,  
                       }->{$node->[1]}) {  
4642                      !!!cp ('t214');                      !!!cp ('t214');
4643                      $i = $_;                      $i = $_;
4644                      last INSCOPE;                      last INSCOPE;
4645                    } elsif ({                    } elsif ($node->[1] & TABLE_SCOPING_EL) {
                             table => 1, html => 1,  
                            }->{$node->[1]}) {  
4646                      !!!cp ('t215');                      !!!cp ('t215');
4647                      last INSCOPE;                      last INSCOPE;
4648                    }                    }
# Line 4400  sub _tree_construction_main ($) { Line 4650  sub _tree_construction_main ($) {
4650                  unless (defined $i) {                  unless (defined $i) {
4651                    !!!cp ('t216');                    !!!cp ('t216');
4652  ## TODO: This erorr type ios wrong.  ## TODO: This erorr type ios wrong.
4653                    !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                    !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4654                    ## Ignore the token                    ## Ignore the token
4655                    !!!next-token;                    !!!next-token;
4656                    redo B;                    redo B;
4657                  }                  }
4658    
4659                  ## Clear back to table body context                  ## Clear back to table body context
4660                  while (not {                  while (not ($self->{open_elements}->[-1]->[1]
4661                    tbody => 1, tfoot => 1, thead => 1, html => 1,                                  & TABLE_ROWS_SCOPING_EL)) {
                 }->{$self->{open_elements}->[-1]->[1]}) {  
4662                    !!!cp ('t217');                    !!!cp ('t217');
4663                    ## ISSUE: Can this state be reached?                    ## ISSUE: Can this state be reached?
4664                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
# Line 4431  sub _tree_construction_main ($) { Line 4680  sub _tree_construction_main ($) {
4680    
4681                if ($token->{tag_name} eq 'col') {                if ($token->{tag_name} eq 'col') {
4682                  ## Clear back to table context                  ## Clear back to table context
4683                  while ($self->{open_elements}->[-1]->[1] ne 'table' and                  while (not ($self->{open_elements}->[-1]->[1]
4684                         $self->{open_elements}->[-1]->[1] ne 'html') {                                  & TABLE_SCOPING_EL)) {
4685                    !!!cp ('t219');                    !!!cp ('t219');
4686                    ## ISSUE: Can this state be reached?                    ## ISSUE: Can this state be reached?
4687                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
4688                  }                  }
4689                                    
4690                  !!!insert-element ('colgroup');                  !!!insert-element ('colgroup',, $token);
4691                  $self->{insertion_mode} = IN_COLUMN_GROUP_IM;                  $self->{insertion_mode} = IN_COLUMN_GROUP_IM;
4692                  ## reprocess                  ## reprocess
4693                  redo B;                  redo B;
# Line 4448  sub _tree_construction_main ($) { Line 4697  sub _tree_construction_main ($) {
4697                          tbody => 1, tfoot => 1, thead => 1,                          tbody => 1, tfoot => 1, thead => 1,
4698                         }->{$token->{tag_name}}) {                         }->{$token->{tag_name}}) {
4699                  ## Clear back to table context                  ## Clear back to table context
4700                  while ($self->{open_elements}->[-1]->[1] ne 'table' and                  while (not ($self->{open_elements}->[-1]->[1]
4701                         $self->{open_elements}->[-1]->[1] ne 'html') {                                  & TABLE_SCOPING_EL)) {
4702                    !!!cp ('t220');                    !!!cp ('t220');
4703                    ## ISSUE: Can this state be reached?                    ## ISSUE: Can this state be reached?
4704                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
# Line 4458  sub _tree_construction_main ($) { Line 4707  sub _tree_construction_main ($) {
4707                  push @$active_formatting_elements, ['#marker', '']                  push @$active_formatting_elements, ['#marker', '']
4708                      if $token->{tag_name} eq 'caption';                      if $token->{tag_name} eq 'caption';
4709                                    
4710                  !!!insert-element ($token->{tag_name}, $token->{attributes});                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
4711                  $self->{insertion_mode} = {                  $self->{insertion_mode} = {
4712                                             caption => IN_CAPTION_IM,                                             caption => IN_CAPTION_IM,
4713                                             colgroup => IN_COLUMN_GROUP_IM,                                             colgroup => IN_COLUMN_GROUP_IM,
# Line 4472  sub _tree_construction_main ($) { Line 4721  sub _tree_construction_main ($) {
4721                  die "$0: in table: <>: $token->{tag_name}";                  die "$0: in table: <>: $token->{tag_name}";
4722                }                }
4723              } elsif ($token->{tag_name} eq 'table') {              } elsif ($token->{tag_name} eq 'table') {
4724                !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                !!!parse-error (type => 'not closed',
4725                                  value => $self->{open_elements}->[-1]->[0]
4726                                      ->manakai_local_name,
4727                                  token => $token);
4728    
4729                ## As if </table>                ## As if </table>
4730                ## have a table element in table scope                ## have a table element in table scope
4731                my $i;                my $i;
4732                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4733                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
4734                  if ($node->[1] eq 'table') {                  if ($node->[1] & TABLE_EL) {
4735                    !!!cp ('t221');                    !!!cp ('t221');
4736                    $i = $_;                    $i = $_;
4737                    last INSCOPE;                    last INSCOPE;
4738                  } elsif ({                  } elsif ($node->[1] & TABLE_SCOPING_EL) {
                           #table => 1,  
                           html => 1,  
                          }->{$node->[1]}) {  
4739                    !!!cp ('t222');                    !!!cp ('t222');
4740                    last INSCOPE;                    last INSCOPE;
4741                  }                  }
# Line 4494  sub _tree_construction_main ($) { Line 4743  sub _tree_construction_main ($) {
4743                unless (defined $i) {                unless (defined $i) {
4744                  !!!cp ('t223');                  !!!cp ('t223');
4745  ## TODO: The following is wrong, maybe.  ## TODO: The following is wrong, maybe.
4746                  !!!parse-error (type => 'unmatched end tag:table');                  !!!parse-error (type => 'unmatched end tag:table', token => $token);
4747                  ## Ignore tokens </table><table>                  ## Ignore tokens </table><table>
4748                  !!!next-token;                  !!!next-token;
4749                  redo B;                  redo B;
4750                }                }
4751                                
4752    ## TODO: Followings are removed from the latest spec.
4753                ## generate implied end tags                ## generate implied end tags
4754                while ({                while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
                       dd => 1, dt => 1, li => 1, p => 1,  
                      }->{$self->{open_elements}->[-1]->[1]}) {  
4755                  !!!cp ('t224');                  !!!cp ('t224');
4756                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
4757                }                }
4758    
4759                if ($self->{open_elements}->[-1]->[1] ne 'table') {                unless ($self->{open_elements}->[-1]->[1] & TABLE_EL) {
4760                  !!!cp ('t225');                  !!!cp ('t225');
4761  ## ISSUE: Can this case be reached?                  ## NOTE: |<table><tr><table>|
4762                  !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                  !!!parse-error (type => 'not closed',
4763                                    value => $self->{open_elements}->[-1]->[0]
4764                                        ->manakai_local_name,
4765                                    token => $token);
4766                } else {                } else {
4767                  !!!cp ('t226');                  !!!cp ('t226');
4768                }                }
# Line 4549  sub _tree_construction_main ($) { Line 4800  sub _tree_construction_main ($) {
4800                my $type = lc $token->{attributes}->{type}->{value};                my $type = lc $token->{attributes}->{type}->{value};
4801                if ($type eq 'hidden') {                if ($type eq 'hidden') {
4802                  !!!cp ('t227.3');                  !!!cp ('t227.3');
4803                  !!!parse-error (type => 'in table:'.$token->{tag_name});                  !!!parse-error (type => 'in table:'.$token->{tag_name}, token => $token);
4804    
4805                  !!!insert-element ($token->{tag_name}, $token->{attributes});                  !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
4806    
4807                  ## TODO: form element pointer                  ## TODO: form element pointer
4808    
# Line 4576  sub _tree_construction_main ($) { Line 4827  sub _tree_construction_main ($) {
4827            #            #
4828          }          }
4829    
4830          !!!parse-error (type => 'in table:'.$token->{tag_name});          !!!parse-error (type => 'in table:'.$token->{tag_name}, token => $token);
4831    
4832          $insert = $insert_to_foster;          $insert = $insert_to_foster;
4833          #          #
# Line 4587  sub _tree_construction_main ($) { Line 4838  sub _tree_construction_main ($) {
4838                my $i;                my $i;
4839                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4840                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
4841                  if ($node->[1] eq $token->{tag_name}) {                  if ($node->[1] & TABLE_ROW_EL) {
4842                    !!!cp ('t228');                    !!!cp ('t228');
4843                    $i = $_;                    $i = $_;
4844                    last INSCOPE;                    last INSCOPE;
4845                  } elsif ({                  } elsif ($node->[1] & TABLE_SCOPING_EL) {
                           table => 1, html => 1,  
                          }->{$node->[1]}) {  
4846                    !!!cp ('t229');                    !!!cp ('t229');
4847                    last INSCOPE;                    last INSCOPE;
4848                  }                  }
4849                } # INSCOPE                } # INSCOPE
4850                unless (defined $i) {                unless (defined $i) {
4851                  !!!cp ('t230');                  !!!cp ('t230');
4852                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4853                  ## Ignore the token                  ## Ignore the token
4854                  !!!next-token;                  !!!next-token;
4855                  redo B;                  redo B;
# Line 4609  sub _tree_construction_main ($) { Line 4858  sub _tree_construction_main ($) {
4858                }                }
4859    
4860                ## Clear back to table row context                ## Clear back to table row context
4861                while (not {                while (not ($self->{open_elements}->[-1]->[1]
4862                  tr => 1, html => 1,                                & TABLE_ROW_SCOPING_EL)) {
               }->{$self->{open_elements}->[-1]->[1]}) {  
4863                  !!!cp ('t231');                  !!!cp ('t231');
4864  ## ISSUE: Can this state be reached?  ## ISSUE: Can this state be reached?
4865                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
# Line 4628  sub _tree_construction_main ($) { Line 4876  sub _tree_construction_main ($) {
4876                  my $i;                  my $i;
4877                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4878                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
4879                    if ($node->[1] eq 'tr') {                    if ($node->[1] & TABLE_ROW_EL) {
4880                      !!!cp ('t233');                      !!!cp ('t233');
4881                      $i = $_;                      $i = $_;
4882                      last INSCOPE;                      last INSCOPE;
4883                    } elsif ({                    } elsif ($node->[1] & TABLE_SCOPING_EL) {
                             table => 1, html => 1,  
                            }->{$node->[1]}) {  
4884                      !!!cp ('t234');                      !!!cp ('t234');
4885                      last INSCOPE;                      last INSCOPE;
4886                    }                    }
# Line 4642  sub _tree_construction_main ($) { Line 4888  sub _tree_construction_main ($) {
4888                  unless (defined $i) {                  unless (defined $i) {
4889                    !!!cp ('t235');                    !!!cp ('t235');
4890  ## TODO: The following is wrong.  ## TODO: The following is wrong.
4891                    !!!parse-error (type => 'unmatched end tag:'.$token->{type});                    !!!parse-error (type => 'unmatched end tag:'.$token->{type}, token => $token);
4892                    ## Ignore the token                    ## Ignore the token
4893                    !!!next-token;                    !!!next-token;
4894                    redo B;                    redo B;
4895                  }                  }
4896                                    
4897                  ## Clear back to table row context                  ## Clear back to table row context
4898                  while (not {                  while (not ($self->{open_elements}->[-1]->[1]
4899                    tr => 1, html => 1,                                  & TABLE_ROW_SCOPING_EL)) {
                 }->{$self->{open_elements}->[-1]->[1]}) {  
4900                    !!!cp ('t236');                    !!!cp ('t236');
4901  ## ISSUE: Can this state be reached?  ## ISSUE: Can this state be reached?
4902                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
# Line 4667  sub _tree_construction_main ($) { Line 4912  sub _tree_construction_main ($) {
4912                  my $i;                  my $i;
4913                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4914                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
4915                    if ({                    if ($node->[1] & TABLE_ROW_GROUP_EL) {
                        tbody => 1, thead => 1, tfoot => 1,  
                       }->{$node->[1]}) {  
4916                      !!!cp ('t237');                      !!!cp ('t237');
4917                      $i = $_;                      $i = $_;
4918                      last INSCOPE;                      last INSCOPE;
4919                    } elsif ({                    } elsif ($node->[1] & TABLE_SCOPING_EL) {
                             table => 1, html => 1,  
                            }->{$node->[1]}) {  
4920                      !!!cp ('t238');                      !!!cp ('t238');
4921                      last INSCOPE;                      last INSCOPE;
4922                    }                    }
4923                  } # INSCOPE                  } # INSCOPE
4924                  unless (defined $i) {                  unless (defined $i) {
4925                    !!!cp ('t239');                    !!!cp ('t239');
4926                    !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                    !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4927                    ## Ignore the token                    ## Ignore the token
4928                    !!!next-token;                    !!!next-token;
4929                    redo B;                    redo B;
4930                  }                  }
4931                                    
4932                  ## Clear back to table body context                  ## Clear back to table body context
4933                  while (not {                  while (not ($self->{open_elements}->[-1]->[1]
4934                    tbody => 1, tfoot => 1, thead => 1, html => 1,                                  & TABLE_ROWS_SCOPING_EL)) {
                 }->{$self->{open_elements}->[-1]->[1]}) {  
4935                    !!!cp ('t240');                    !!!cp ('t240');
4936                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
4937                  }                  }
# Line 4717  sub _tree_construction_main ($) { Line 4957  sub _tree_construction_main ($) {
4957                my $i;                my $i;
4958                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4959                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
4960                  if ($node->[1] eq $token->{tag_name}) {                  if ($node->[1] & TABLE_EL) {
4961                    !!!cp ('t241');                    !!!cp ('t241');
4962                    $i = $_;                    $i = $_;
4963                    last INSCOPE;                    last INSCOPE;
4964                  } elsif ({                  } elsif ($node->[1] & TABLE_SCOPING_EL) {
                           table => 1, html => 1,  
                          }->{$node->[1]}) {  
4965                    !!!cp ('t242');                    !!!cp ('t242');
4966                    last INSCOPE;                    last INSCOPE;
4967                  }                  }
4968                } # INSCOPE                } # INSCOPE
4969                unless (defined $i) {                unless (defined $i) {
4970                  !!!cp ('t243');                  !!!cp ('t243');
4971                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
4972                  ## Ignore the token                  ## Ignore the token
4973                  !!!next-token;                  !!!next-token;
4974                  redo B;                  redo B;
# Line 4752  sub _tree_construction_main ($) { Line 4990  sub _tree_construction_main ($) {
4990                  my $i;                  my $i;
4991                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4992                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
4993                    if ($node->[1] eq $token->{tag_name}) {                    if ($node->[0]->manakai_local_name eq $token->{tag_name}) {
4994                      !!!cp ('t247');                      !!!cp ('t247');
4995                      $i = $_;                      $i = $_;
4996                      last INSCOPE;                      last INSCOPE;
4997                    } elsif ({                    } elsif ($node->[1] & TABLE_SCOPING_EL) {
                             table => 1, html => 1,  
                            }->{$node->[1]}) {  
4998                      !!!cp ('t248');                      !!!cp ('t248');
4999                      last INSCOPE;                      last INSCOPE;
5000                    }                    }
5001                  } # INSCOPE                  } # INSCOPE
5002                    unless (defined $i) {                    unless (defined $i) {
5003                      !!!cp ('t249');                      !!!cp ('t249');
5004                      !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                      !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
5005                      ## Ignore the token                      ## Ignore the token
5006                      !!!next-token;                      !!!next-token;
5007                      redo B;                      redo B;
# Line 4776  sub _tree_construction_main ($) { Line 5012  sub _tree_construction_main ($) {
5012                  my $i;                  my $i;
5013                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                  INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5014                    my $node = $self->{open_elements}->[$_];                    my $node = $self->{open_elements}->[$_];
5015                    if ($node->[1] eq 'tr') {                    if ($node->[1] & TABLE_ROW_EL) {
5016                      !!!cp ('t250');                      !!!cp ('t250');
5017                      $i = $_;                      $i = $_;
5018                      last INSCOPE;                      last INSCOPE;
5019                    } elsif ({                    } elsif ($node->[1] & TABLE_SCOPING_EL) {
                             table => 1, html => 1,  
                            }->{$node->[1]}) {  
5020                      !!!cp ('t251');                      !!!cp ('t251');
5021                      last INSCOPE;                      last INSCOPE;
5022                    }                    }
5023                  } # INSCOPE                  } # INSCOPE
5024                    unless (defined $i) {                    unless (defined $i) {
5025                      !!!cp ('t252');                      !!!cp ('t252');
5026                      !!!parse-error (type => 'unmatched end tag:tr');                      !!!parse-error (type => 'unmatched end tag:tr', token => $token);
5027                      ## Ignore the token                      ## Ignore the token
5028                      !!!next-token;                      !!!next-token;
5029                      redo B;                      redo B;
5030                    }                    }
5031                                    
5032                  ## Clear back to table row context                  ## Clear back to table row context
5033                  while (not {                  while (not ($self->{open_elements}->[-1]->[1]
5034                    tr => 1, html => 1,                                  & TABLE_ROW_SCOPING_EL)) {
                 }->{$self->{open_elements}->[-1]->[1]}) {  
5035                    !!!cp ('t253');                    !!!cp ('t253');
5036  ## ISSUE: Can this case be reached?  ## ISSUE: Can this case be reached?
5037                    pop @{$self->{open_elements}};                    pop @{$self->{open_elements}};
# Line 4813  sub _tree_construction_main ($) { Line 5046  sub _tree_construction_main ($) {
5046                my $i;                my $i;
5047                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5048                  my $node = $self->{open_elements}->[$_];                  my $node = $self->{open_elements}->[$_];
5049                  if ($node->[1] eq $token->{tag_name}) {                  if ($node->[0]->manakai_local_name eq $token->{tag_name}) {
5050                    !!!cp ('t254');                    !!!cp ('t254');
5051                    $i = $_;                    $i = $_;
5052                    last INSCOPE;                    last INSCOPE;
5053                  } elsif ({                  } elsif ($node->[1] & TABLE_SCOPING_EL) {
                           table => 1, html => 1,  
                          }->{$node->[1]}) {  
5054                    !!!cp ('t255');                    !!!cp ('t255');
5055                    last INSCOPE;                    last INSCOPE;
5056                  }                  }
5057                } # INSCOPE                } # INSCOPE
5058                unless (defined $i) {                unless (defined $i) {
5059                  !!!cp ('t256');                  !!!cp ('t256');
5060                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
5061                  ## Ignore the token                  ## Ignore the token
5062                  !!!next-token;                  !!!next-token;
5063                  redo B;                  redo B;
5064                }                }
5065    
5066                ## Clear back to table body context                ## Clear back to table body context
5067                while (not {                while (not ($self->{open_elements}->[-1]->[1]
5068                  tbody => 1, tfoot => 1, thead => 1, html => 1,                                & TABLE_ROWS_SCOPING_EL)) {
               }->{$self->{open_elements}->[-1]->[1]}) {  
5069                  !!!cp ('t257');                  !!!cp ('t257');
5070  ## ISSUE: Can this case be reached?  ## ISSUE: Can this case be reached?
5071                  pop @{$self->{open_elements}};                  pop @{$self->{open_elements}};
# Line 4852  sub _tree_construction_main ($) { Line 5082  sub _tree_construction_main ($) {
5082                        tbody => 1, tfoot => 1, thead => 1, # $self->{insertion_mode} == IN_TABLE_IM                        tbody => 1, tfoot => 1, thead => 1, # $self->{insertion_mode} == IN_TABLE_IM
5083                       }->{$token->{tag_name}}) {                       }->{$token->{tag_name}}) {
5084                !!!cp ('t258');                !!!cp ('t258');
5085                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
5086                ## Ignore the token                ## Ignore the token
5087                !!!next-token;                !!!next-token;
5088                redo B;                redo B;
5089          } else {          } else {
5090            !!!cp ('t259');            !!!cp ('t259');
5091            !!!parse-error (type => 'in table:/'.$token->{tag_name});            !!!parse-error (type => 'in table:/'.$token->{tag_name}, token => $token);
5092    
5093            $insert = $insert_to_foster;            $insert = $insert_to_foster;
5094            #            #
5095          }          }
5096          } elsif ($token->{type} == END_OF_FILE_TOKEN) {
5097            unless ($self->{open_elements}->[-1]->[1] & HTML_EL and
5098                    @{$self->{open_elements}} == 1) { # redundant, maybe
5099              !!!parse-error (type => 'in body:#eof', token => $token);
5100              !!!cp ('t259.1');
5101              #
5102            } else {
5103              !!!cp ('t259.2');
5104              #
5105            }
5106    
5107            ## Stop parsing
5108            last B;
5109        } else {        } else {
5110          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
5111        }        }
# Line 4882  sub _tree_construction_main ($) { Line 5125  sub _tree_construction_main ($) {
5125            } elsif ($token->{type} == START_TAG_TOKEN) {            } elsif ($token->{type} == START_TAG_TOKEN) {
5126              if ($token->{tag_name} eq 'col') {              if ($token->{tag_name} eq 'col') {
5127                !!!cp ('t262');                !!!cp ('t262');
5128                !!!insert-element ($token->{tag_name}, $token->{attributes});                !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
5129                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
5130                !!!next-token;                !!!next-token;
5131                redo B;                redo B;
# Line 4892  sub _tree_construction_main ($) { Line 5135  sub _tree_construction_main ($) {
5135              }              }
5136            } elsif ($token->{type} == END_TAG_TOKEN) {            } elsif ($token->{type} == END_TAG_TOKEN) {
5137              if ($token->{tag_name} eq 'colgroup') {              if ($token->{tag_name} eq 'colgroup') {
5138                if ($self->{open_elements}->[-1]->[1] eq 'html') {                if ($self->{open_elements}->[-1]->[1] & HTML_EL) {
5139                  !!!cp ('t264');                  !!!cp ('t264');
5140                  !!!parse-error (type => 'unmatched end tag:colgroup');                  !!!parse-error (type => 'unmatched end tag:colgroup', token => $token);
5141                  ## Ignore the token                  ## Ignore the token
5142                  !!!next-token;                  !!!next-token;
5143                  redo B;                  redo B;
# Line 4907  sub _tree_construction_main ($) { Line 5150  sub _tree_construction_main ($) {
5150                }                }
5151              } elsif ($token->{tag_name} eq 'col') {              } elsif ($token->{tag_name} eq 'col') {
5152                !!!cp ('t266');                !!!cp ('t266');
5153                !!!parse-error (type => 'unmatched end tag:col');                !!!parse-error (type => 'unmatched end tag:col', token => $token);
5154                ## Ignore the token                ## Ignore the token
5155                !!!next-token;                !!!next-token;
5156                redo B;                redo B;
# Line 4915  sub _tree_construction_main ($) { Line 5158  sub _tree_construction_main ($) {
5158                !!!cp ('t267');                !!!cp ('t267');
5159                #                #
5160              }              }
5161            } else {        } elsif ($token->{type} == END_OF_FILE_TOKEN) {
5162              die "$0: $token->{type}: Unknown token type";          if ($self->{open_elements}->[-1]->[1] & HTML_EL and
5163            }              @{$self->{open_elements}} == 1) { # redundant, maybe
5164              !!!cp ('t270.2');
5165              ## Stop parsing.
5166              last B;
5167            } else {
5168              ## NOTE: As if </colgroup>.
5169              !!!cp ('t270.1');
5170              pop @{$self->{open_elements}}; # colgroup
5171              $self->{insertion_mode} = IN_TABLE_IM;
5172              ## Reprocess.
5173              redo B;
5174            }
5175          } else {
5176            die "$0: $token->{type}: Unknown token type";
5177          }
5178    
5179            ## As if </colgroup>            ## As if </colgroup>
5180            if ($self->{open_elements}->[-1]->[1] eq 'html') {            if ($self->{open_elements}->[-1]->[1] & HTML_EL) {
5181              !!!cp ('t269');              !!!cp ('t269');
5182              !!!parse-error (type => 'unmatched end tag:colgroup');  ## TODO: Wrong error type?
5183                !!!parse-error (type => 'unmatched end tag:colgroup', token => $token);
5184              ## Ignore the token              ## Ignore the token
5185              !!!next-token;              !!!next-token;
5186              redo B;              redo B;
# Line 4940  sub _tree_construction_main ($) { Line 5198  sub _tree_construction_main ($) {
5198          !!!next-token;          !!!next-token;
5199          redo B;          redo B;
5200        } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
5201              if ($token->{tag_name} eq 'option') {          if ($token->{tag_name} eq 'option') {
5202                if ($self->{open_elements}->[-1]->[1] eq 'option') {            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {
5203                  !!!cp ('t272');              !!!cp ('t272');
5204                  ## As if </option>              ## As if </option>
5205                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
5206                } else {            } else {
5207                  !!!cp ('t273');              !!!cp ('t273');
5208                }            }
5209    
5210                !!!insert-element ($token->{tag_name}, $token->{attributes});            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
5211                !!!next-token;            !!!next-token;
5212                redo B;            redo B;
5213              } elsif ($token->{tag_name} eq 'optgroup') {          } elsif ($token->{tag_name} eq 'optgroup') {
5214                if ($self->{open_elements}->[-1]->[1] eq 'option') {            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {
5215                  !!!cp ('t274');              !!!cp ('t274');
5216                  ## As if </option>              ## As if </option>
5217                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
5218                } else {            } else {
5219                  !!!cp ('t275');              !!!cp ('t275');
5220                }            }
5221    
5222                if ($self->{open_elements}->[-1]->[1] eq 'optgroup') {            if ($self->{open_elements}->[-1]->[1] & OPTGROUP_EL) {
5223                  !!!cp ('t276');              !!!cp ('t276');
5224                  ## As if </optgroup>              ## As if </optgroup>
5225                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
5226                } else {            } else {
5227                  !!!cp ('t277');              !!!cp ('t277');
5228                }            }
5229    
5230                !!!insert-element ($token->{tag_name}, $token->{attributes});            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
5231                !!!next-token;            !!!next-token;
5232                redo B;            redo B;
5233          } elsif ($token->{tag_name} eq 'select' or          } elsif ($token->{tag_name} eq 'select' or
5234                   $token->{tag_name} eq 'input' or                   $token->{tag_name} eq 'input' or
5235                   ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and                   ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and
# Line 4981  sub _tree_construction_main ($) { Line 5239  sub _tree_construction_main ($) {
5239                     tr => 1, td => 1, th => 1,                     tr => 1, td => 1, th => 1,
5240                    }->{$token->{tag_name}})) {                    }->{$token->{tag_name}})) {
5241            ## TODO: The type below is not good - <select> is replaced by </select>            ## TODO: The type below is not good - <select> is replaced by </select>
5242            !!!parse-error (type => 'not closed:select');            !!!parse-error (type => 'not closed:select', token => $token);
5243            ## NOTE: As if the token were </select> (<select> case) or            ## NOTE: As if the token were </select> (<select> case) or
5244            ## as if there were </select> (otherwise).            ## as if there were </select> (otherwise).
5245                ## have an element in table scope            ## have an element in table scope
5246                my $i;            my $i;
5247                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5248                  my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
5249                  if ($node->[1] eq 'select') {              if ($node->[1] & SELECT_EL) {
5250                    !!!cp ('t278');                !!!cp ('t278');
5251                    $i = $_;                $i = $_;
5252                    last INSCOPE;                last INSCOPE;
5253                  } elsif ({              } elsif ($node->[1] & TABLE_SCOPING_EL) {
5254                            table => 1, html => 1,                !!!cp ('t279');
5255                           }->{$node->[1]}) {                last INSCOPE;
5256                    !!!cp ('t279');              }
5257                    last INSCOPE;            } # INSCOPE
5258                  }            unless (defined $i) {
5259                } # INSCOPE              !!!cp ('t280');
5260                unless (defined $i) {              !!!parse-error (type => 'unmatched end tag:select', token => $token);
5261                  !!!cp ('t280');              ## Ignore the token
5262                  !!!parse-error (type => 'unmatched end tag:select');              !!!next-token;
5263                  ## Ignore the token              redo B;
5264                  !!!next-token;            }
                 redo B;  
               }  
5265                                
5266                !!!cp ('t281');            !!!cp ('t281');
5267                splice @{$self->{open_elements}}, $i;            splice @{$self->{open_elements}}, $i;
5268    
5269                $self->_reset_insertion_mode;            $self->_reset_insertion_mode;
5270    
5271            if ($token->{tag_name} eq 'select') {            if ($token->{tag_name} eq 'select') {
5272              !!!cp ('t281.2');              !!!cp ('t281.2');
# Line 5023  sub _tree_construction_main ($) { Line 5279  sub _tree_construction_main ($) {
5279            }            }
5280          } else {          } else {
5281            !!!cp ('t282');            !!!cp ('t282');
5282            !!!parse-error (type => 'in select:'.$token->{tag_name});            !!!parse-error (type => 'in select:'.$token->{tag_name}, token => $token);
5283            ## Ignore the token            ## Ignore the token
5284            !!!next-token;            !!!next-token;
5285            redo B;            redo B;
5286          }          }
5287        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
5288              if ($token->{tag_name} eq 'optgroup') {          if ($token->{tag_name} eq 'optgroup') {
5289                if ($self->{open_elements}->[-1]->[1] eq 'option' and            if ($self->{open_elements}->[-1]->[1] & OPTION_EL and
5290                    $self->{open_elements}->[-2]->[1] eq 'optgroup') {                $self->{open_elements}->[-2]->[1] & OPTGROUP_EL) {
5291                  !!!cp ('t283');              !!!cp ('t283');
5292                  ## As if </option>              ## As if </option>
5293                  splice @{$self->{open_elements}}, -2;              splice @{$self->{open_elements}}, -2;
5294                } elsif ($self->{open_elements}->[-1]->[1] eq 'optgroup') {            } elsif ($self->{open_elements}->[-1]->[1] & OPTGROUP_EL) {
5295                  !!!cp ('t284');              !!!cp ('t284');
5296                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
5297                } else {            } else {
5298                  !!!cp ('t285');              !!!cp ('t285');
5299                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
5300                  ## Ignore the token              ## Ignore the token
5301                }            }
5302                !!!next-token;            !!!next-token;
5303                redo B;            redo B;
5304              } elsif ($token->{tag_name} eq 'option') {          } elsif ($token->{tag_name} eq 'option') {
5305                if ($self->{open_elements}->[-1]->[1] eq 'option') {            if ($self->{open_elements}->[-1]->[1] & OPTION_EL) {
5306                  !!!cp ('t286');              !!!cp ('t286');
5307                  pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
5308                } else {            } else {
5309                  !!!cp ('t287');              !!!cp ('t287');
5310                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
5311                  ## Ignore the token              ## Ignore the token
5312                }            }
5313                !!!next-token;            !!!next-token;
5314                redo B;            redo B;
5315              } elsif ($token->{tag_name} eq 'select') {          } elsif ($token->{tag_name} eq 'select') {
5316                ## have an element in table scope            ## have an element in table scope
5317                my $i;            my $i;
5318                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5319                  my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
5320                  if ($node->[1] eq $token->{tag_name}) {              if ($node->[1] & SELECT_EL) {
5321                    !!!cp ('t288');                !!!cp ('t288');
5322                    $i = $_;                $i = $_;
5323                    last INSCOPE;                last INSCOPE;
5324                  } elsif ({              } elsif ($node->[1] & TABLE_SCOPING_EL) {
5325                            table => 1, html => 1,                !!!cp ('t289');
5326                           }->{$node->[1]}) {                last INSCOPE;
5327                    !!!cp ('t289');              }
5328                    last INSCOPE;            } # INSCOPE
5329                  }            unless (defined $i) {
5330                } # INSCOPE              !!!cp ('t290');
5331                unless (defined $i) {              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
5332                  !!!cp ('t290');              ## Ignore the token
5333                  !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});              !!!next-token;
5334                  ## Ignore the token              redo B;
5335                  !!!next-token;            }
                 redo B;  
               }  
5336                                
5337                !!!cp ('t291');            !!!cp ('t291');
5338                splice @{$self->{open_elements}}, $i;            splice @{$self->{open_elements}}, $i;
5339    
5340                $self->_reset_insertion_mode;            $self->_reset_insertion_mode;
5341    
5342                !!!next-token;            !!!next-token;
5343                redo B;            redo B;
5344          } elsif ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and          } elsif ($self->{insertion_mode} == IN_SELECT_IN_TABLE_IM and
5345                   {                   {
5346                    caption => 1, table => 1, tbody => 1,                    caption => 1, table => 1, tbody => 1,
5347                    tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,                    tfoot => 1, thead => 1, tr => 1, td => 1, th => 1,
5348                   }->{$token->{tag_name}}) {                   }->{$token->{tag_name}}) {
5349  ## TODO: The following is wrong?  ## TODO: The following is wrong?
5350                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
5351                                
5352                ## have an element in table scope            ## have an element in table scope
5353                my $i;            my $i;
5354                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5355                  my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
5356                  if ($node->[1] eq $token->{tag_name}) {              if ($node->[0]->manakai_local_name eq $token->{tag_name}) {
5357                    !!!cp ('t292');                !!!cp ('t292');
5358                    $i = $_;                $i = $_;
5359                    last INSCOPE;                last INSCOPE;
5360                  } elsif ({              } elsif ($node->[1] & TABLE_SCOPING_EL) {
5361                            table => 1, html => 1,                !!!cp ('t293');
5362                           }->{$node->[1]}) {                last INSCOPE;
5363                    !!!cp ('t293');              }
5364                    last INSCOPE;            } # INSCOPE
5365                  }            unless (defined $i) {
5366                } # INSCOPE              !!!cp ('t294');
5367                unless (defined $i) {              ## Ignore the token
5368                  !!!cp ('t294');              !!!next-token;
5369                  ## Ignore the token              redo B;
5370                  !!!next-token;            }
                 redo B;  
               }  
5371                                
5372                ## As if </select>            ## As if </select>
5373                ## have an element in table scope            ## have an element in table scope
5374                undef $i;            undef $i;
5375                INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {            INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5376                  my $node = $self->{open_elements}->[$_];              my $node = $self->{open_elements}->[$_];
5377                  if ($node->[1] eq 'select') {              if ($node->[1] & SELECT_EL) {
5378                    !!!cp ('t295');                !!!cp ('t295');
5379                    $i = $_;                $i = $_;
5380                    last INSCOPE;                last INSCOPE;
5381                  } elsif ({              } elsif ($node->[1] & TABLE_SCOPING_EL) {
                           table => 1, html => 1,  
                          }->{$node->[1]}) {  
5382  ## ISSUE: Can this state be reached?  ## ISSUE: Can this state be reached?
5383                    !!!cp ('t296');                !!!cp ('t296');
5384                    last INSCOPE;                last INSCOPE;
5385                  }              }
5386                } # INSCOPE            } # INSCOPE
5387                unless (defined $i) {            unless (defined $i) {
5388                  !!!cp ('t297');              !!!cp ('t297');
5389  ## TODO: The following error type is correct?  ## TODO: The following error type is correct?
5390                  !!!parse-error (type => 'unmatched end tag:select');              !!!parse-error (type => 'unmatched end tag:select', token => $token);
5391                  ## Ignore the </select> token              ## Ignore the </select> token
5392                  !!!next-token; ## TODO: ok?              !!!next-token; ## TODO: ok?
5393                  redo B;              redo B;
5394                }            }
5395                                
5396                !!!cp ('t298');            !!!cp ('t298');
5397                splice @{$self->{open_elements}}, $i;            splice @{$self->{open_elements}}, $i;
5398    
5399                $self->_reset_insertion_mode;            $self->_reset_insertion_mode;
5400    
5401                ## reprocess            ## reprocess
5402                redo B;            redo B;
5403          } else {          } else {
5404            !!!cp ('t299');            !!!cp ('t299');
5405            !!!parse-error (type => 'in select:/'.$token->{tag_name});            !!!parse-error (type => 'in select:/'.$token->{tag_name}, token => $token);
5406            ## Ignore the token            ## Ignore the token
5407            !!!next-token;            !!!next-token;
5408            redo B;            redo B;
5409          }          }
5410          } elsif ($token->{type} == END_OF_FILE_TOKEN) {
5411            unless ($self->{open_elements}->[-1]->[1] & HTML_EL and
5412                    @{$self->{open_elements}} == 1) { # redundant, maybe
5413              !!!cp ('t299.1');
5414              !!!parse-error (type => 'in body:#eof', token => $token);
5415            } else {
5416              !!!cp ('t299.2');
5417            }
5418    
5419            ## Stop parsing.
5420            last B;
5421        } else {        } else {
5422          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
5423        }        }
# Line 5178  sub _tree_construction_main ($) { Line 5439  sub _tree_construction_main ($) {
5439                    
5440          if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {          if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
5441            !!!cp ('t301');            !!!cp ('t301');
5442            !!!parse-error (type => 'after html:#character');            !!!parse-error (type => 'after html:#character', token => $token);
5443    
5444            ## Reprocess in the "after body" insertion mode.            ## Reprocess in the "after body" insertion mode.
5445          } else {          } else {
# Line 5186  sub _tree_construction_main ($) { Line 5447  sub _tree_construction_main ($) {
5447          }          }
5448                    
5449          ## "after body" insertion mode          ## "after body" insertion mode
5450          !!!parse-error (type => 'after body:#character');          !!!parse-error (type => 'after body:#character', token => $token);
5451    
5452          $self->{insertion_mode} = IN_BODY_IM;          $self->{insertion_mode} = IN_BODY_IM;
5453          ## reprocess          ## reprocess
# Line 5194  sub _tree_construction_main ($) { Line 5455  sub _tree_construction_main ($) {
5455        } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
5456          if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {          if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
5457            !!!cp ('t303');            !!!cp ('t303');
5458            !!!parse-error (type => 'after html:'.$token->{tag_name});            !!!parse-error (type => 'after html:'.$token->{tag_name}, token => $token);
5459                        
5460            ## Reprocess in the "after body" insertion mode.            ## Reprocess in the "after body" insertion mode.
5461          } else {          } else {
# Line 5202  sub _tree_construction_main ($) { Line 5463  sub _tree_construction_main ($) {
5463          }          }
5464    
5465          ## "after body" insertion mode          ## "after body" insertion mode
5466          !!!parse-error (type => 'after body:'.$token->{tag_name});          !!!parse-error (type => 'after body:'.$token->{tag_name}, token => $token);
5467    
5468          $self->{insertion_mode} = IN_BODY_IM;          $self->{insertion_mode} = IN_BODY_IM;
5469          ## reprocess          ## reprocess
# Line 5210  sub _tree_construction_main ($) { Line 5471  sub _tree_construction_main ($) {
5471        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
5472          if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {          if ($self->{insertion_mode} == AFTER_HTML_BODY_IM) {
5473            !!!cp ('t305');            !!!cp ('t305');
5474            !!!parse-error (type => 'after html:/'.$token->{tag_name});            !!!parse-error (type => 'after html:/'.$token->{tag_name}, token => $token);
5475                        
5476            $self->{insertion_mode} = AFTER_BODY_IM;            $self->{insertion_mode} = AFTER_BODY_IM;
5477            ## Reprocess in the "after body" insertion mode.            ## Reprocess in the "after body" insertion mode.
# Line 5222  sub _tree_construction_main ($) { Line 5483  sub _tree_construction_main ($) {
5483          if ($token->{tag_name} eq 'html') {          if ($token->{tag_name} eq 'html') {
5484            if (defined $self->{inner_html_node}) {            if (defined $self->{inner_html_node}) {
5485              !!!cp ('t307');              !!!cp ('t307');
5486              !!!parse-error (type => 'unmatched end tag:html');              !!!parse-error (type => 'unmatched end tag:html', token => $token);
5487              ## Ignore the token              ## Ignore the token
5488              !!!next-token;              !!!next-token;
5489              redo B;              redo B;
# Line 5234  sub _tree_construction_main ($) { Line 5495  sub _tree_construction_main ($) {
5495            }            }
5496          } else {          } else {
5497            !!!cp ('t309');            !!!cp ('t309');
5498            !!!parse-error (type => 'after body:/'.$token->{tag_name});            !!!parse-error (type => 'after body:/'.$token->{tag_name}, token => $token);
5499    
5500            $self->{insertion_mode} = IN_BODY_IM;            $self->{insertion_mode} = IN_BODY_IM;
5501            ## reprocess            ## reprocess
5502            redo B;            redo B;
5503          }          }
5504          } elsif ($token->{type} == END_OF_FILE_TOKEN) {
5505            !!!cp ('t309.2');
5506            ## Stop parsing
5507            last B;
5508        } else {        } else {
5509          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
5510        }        }
# Line 5258  sub _tree_construction_main ($) { Line 5523  sub _tree_construction_main ($) {
5523          if ($token->{data} =~ s/^[^\x09\x0A\x0B\x0C\x20]+//) {          if ($token->{data} =~ s/^[^\x09\x0A\x0B\x0C\x20]+//) {
5524            if ($self->{insertion_mode} == IN_FRAMESET_IM) {            if ($self->{insertion_mode} == IN_FRAMESET_IM) {
5525              !!!cp ('t311');              !!!cp ('t311');
5526              !!!parse-error (type => 'in frameset:#character');              !!!parse-error (type => 'in frameset:#character', token => $token);
5527            } elsif ($self->{insertion_mode} == AFTER_FRAMESET_IM) {            } elsif ($self->{insertion_mode} == AFTER_FRAMESET_IM) {
5528              !!!cp ('t312');              !!!cp ('t312');
5529              !!!parse-error (type => 'after frameset:#character');              !!!parse-error (type => 'after frameset:#character', token => $token);
5530            } else { # "after html frameset"            } else { # "after html frameset"
5531              !!!cp ('t313');              !!!cp ('t313');
5532              !!!parse-error (type => 'after html:#character');              !!!parse-error (type => 'after html:#character', token => $token);
5533    
5534              $self->{insertion_mode} = AFTER_FRAMESET_IM;              $self->{insertion_mode} = AFTER_FRAMESET_IM;
5535              ## Reprocess in the "after frameset" insertion mode.              ## Reprocess in the "after frameset" insertion mode.
5536              !!!parse-error (type => 'after frameset:#character');              !!!parse-error (type => 'after frameset:#character', token => $token);
5537            }            }
5538                        
5539            ## Ignore the token.            ## Ignore the token.
# Line 5286  sub _tree_construction_main ($) { Line 5551  sub _tree_construction_main ($) {
5551        } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
5552          if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {          if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
5553            !!!cp ('t316');            !!!cp ('t316');
5554            !!!parse-error (type => 'after html:'.$token->{tag_name});            !!!parse-error (type => 'after html:'.$token->{tag_name}, token => $token);
5555    
5556            $self->{insertion_mode} = AFTER_FRAMESET_IM;            $self->{insertion_mode} = AFTER_FRAMESET_IM;
5557            ## Process in the "after frameset" insertion mode.            ## Process in the "after frameset" insertion mode.
# Line 5297  sub _tree_construction_main ($) { Line 5562  sub _tree_construction_main ($) {
5562          if ($token->{tag_name} eq 'frameset' and          if ($token->{tag_name} eq 'frameset' and
5563              $self->{insertion_mode} == IN_FRAMESET_IM) {              $self->{insertion_mode} == IN_FRAMESET_IM) {
5564            !!!cp ('t318');            !!!cp ('t318');
5565            !!!insert-element ($token->{tag_name}, $token->{attributes});            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
5566            !!!next-token;            !!!next-token;
5567            redo B;            redo B;
5568          } elsif ($token->{tag_name} eq 'frame' and          } elsif ($token->{tag_name} eq 'frame' and
5569                   $self->{insertion_mode} == IN_FRAMESET_IM) {                   $self->{insertion_mode} == IN_FRAMESET_IM) {
5570            !!!cp ('t319');            !!!cp ('t319');
5571            !!!insert-element ($token->{tag_name}, $token->{attributes});            !!!insert-element ($token->{tag_name}, $token->{attributes}, $token);
5572            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
5573            !!!next-token;            !!!next-token;
5574            redo B;            redo B;
# Line 5315  sub _tree_construction_main ($) { Line 5580  sub _tree_construction_main ($) {
5580          } else {          } else {
5581            if ($self->{insertion_mode} == IN_FRAMESET_IM) {            if ($self->{insertion_mode} == IN_FRAMESET_IM) {
5582              !!!cp ('t321');              !!!cp ('t321');
5583              !!!parse-error (type => 'in frameset:'.$token->{tag_name});              !!!parse-error (type => 'in frameset:'.$token->{tag_name}, token => $token);
5584            } else {            } else {
5585              !!!cp ('t322');              !!!cp ('t322');
5586              !!!parse-error (type => 'after frameset:'.$token->{tag_name});              !!!parse-error (type => 'after frameset:'.$token->{tag_name}, token => $token);
5587            }            }
5588            ## Ignore the token            ## Ignore the token
5589            !!!next-token;            !!!next-token;
# Line 5327  sub _tree_construction_main ($) { Line 5592  sub _tree_construction_main ($) {
5592        } elsif ($token->{type} == END_TAG_TOKEN) {        } elsif ($token->{type} == END_TAG_TOKEN) {
5593          if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {          if ($self->{insertion_mode} == AFTER_HTML_FRAMESET_IM) {
5594            !!!cp ('t323');            !!!cp ('t323');
5595            !!!parse-error (type => 'after html:/'.$token->{tag_name});            !!!parse-error (type => 'after html:/'.$token->{tag_name}, token => $token);
5596    
5597            $self->{insertion_mode} = AFTER_FRAMESET_IM;            $self->{insertion_mode} = AFTER_FRAMESET_IM;
5598            ## Process in the "after frameset" insertion mode.            ## Process in the "after frameset" insertion mode.
# Line 5337  sub _tree_construction_main ($) { Line 5602  sub _tree_construction_main ($) {
5602    
5603          if ($token->{tag_name} eq 'frameset' and          if ($token->{tag_name} eq 'frameset' and
5604              $self->{insertion_mode} == IN_FRAMESET_IM) {              $self->{insertion_mode} == IN_FRAMESET_IM) {
5605            if ($self->{open_elements}->[-1]->[1] eq 'html' and            if ($self->{open_elements}->[-1]->[1] & HTML_EL and
5606                @{$self->{open_elements}} == 1) {                @{$self->{open_elements}} == 1) {
5607              !!!cp ('t325');              !!!cp ('t325');
5608              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
5609              ## Ignore the token              ## Ignore the token
5610              !!!next-token;              !!!next-token;
5611            } else {            } else {
# Line 5350  sub _tree_construction_main ($) { Line 5615  sub _tree_construction_main ($) {
5615            }            }
5616    
5617            if (not defined $self->{inner_html_node} and            if (not defined $self->{inner_html_node} and
5618                $self->{open_elements}->[-1]->[1] ne 'frameset') {                not ($self->{open_elements}->[-1]->[1] & FRAMESET_EL)) {
5619              !!!cp ('t327');              !!!cp ('t327');
5620              $self->{insertion_mode} = AFTER_FRAMESET_IM;              $self->{insertion_mode} = AFTER_FRAMESET_IM;
5621            } else {            } else {
# Line 5366  sub _tree_construction_main ($) { Line 5631  sub _tree_construction_main ($) {
5631          } else {          } else {
5632            if ($self->{insertion_mode} == IN_FRAMESET_IM) {            if ($self->{insertion_mode} == IN_FRAMESET_IM) {
5633              !!!cp ('t330');              !!!cp ('t330');
5634              !!!parse-error (type => 'in frameset:/'.$token->{tag_name});              !!!parse-error (type => 'in frameset:/'.$token->{tag_name}, token => $token);
5635            } else {            } else {
5636              !!!cp ('t331');              !!!cp ('t331');
5637              !!!parse-error (type => 'after frameset:/'.$token->{tag_name});              !!!parse-error (type => 'after frameset:/'.$token->{tag_name}, token => $token);
5638            }            }
5639            ## Ignore the token            ## Ignore the token
5640            !!!next-token;            !!!next-token;
5641            redo B;            redo B;
5642          }          }
5643          } elsif ($token->{type} == END_OF_FILE_TOKEN) {
5644            unless ($self->{open_elements}->[-1]->[1] & HTML_EL and
5645                    @{$self->{open_elements}} == 1) { # redundant, maybe
5646              !!!cp ('t331.1');
5647              !!!parse-error (type => 'in body:#eof', token => $token);
5648            } else {
5649              !!!cp ('t331.2');
5650            }
5651            
5652            ## Stop parsing
5653            last B;
5654        } else {        } else {
5655          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
5656        }        }
# Line 5401  sub _tree_construction_main ($) { Line 5677  sub _tree_construction_main ($) {
5677                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
5678          !!!cp ('t334');          !!!cp ('t334');
5679          ## NOTE: This is an "as if in head" code clone, only "-t" differs          ## NOTE: This is an "as if in head" code clone, only "-t" differs
5680          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
5681          pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.          pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
5682          !!!next-token;          !!!next-token;
5683          redo B;          redo B;
5684        } elsif ($token->{tag_name} eq 'meta') {        } elsif ($token->{tag_name} eq 'meta') {
5685          ## NOTE: This is an "as if in head" code clone, only "-t" differs          ## NOTE: This is an "as if in head" code clone, only "-t" differs
5686          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
5687          my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.          my $meta_el = pop @{$self->{open_elements}}; ## ISSUE: This step is missing in the spec.
5688    
5689          unless ($self->{confident}) {          unless ($self->{confident}) {
5690            if ($token->{attributes}->{charset}) { ## TODO: And if supported            if ($token->{attributes}->{charset}) { ## TODO: And if supported
5691              !!!cp ('t335');              !!!cp ('t335');
5692              $self->{change_encoding}              $self->{change_encoding}
5693                  ->($self, $token->{attributes}->{charset}->{value});                  ->($self, $token->{attributes}->{charset}->{value}, $token);
5694                            
5695              $meta_el->[0]->get_attribute_node_ns (undef, 'charset')              $meta_el->[0]->get_attribute_node_ns (undef, 'charset')
5696                  ->set_user_data (manakai_has_reference =>                  ->set_user_data (manakai_has_reference =>
# Line 5429  sub _tree_construction_main ($) { Line 5705  sub _tree_construction_main ($) {
5705                      ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {                      ([^"'\x09-\x0D\x20][^\x09-\x0D\x20]*))/x) {
5706                !!!cp ('t336');                !!!cp ('t336');
5707                $self->{change_encoding}                $self->{change_encoding}
5708                    ->($self, defined $1 ? $1 : defined $2 ? $2 : $3);                    ->($self, defined $1 ? $1 : defined $2 ? $2 : $3, $token);
5709                $meta_el->[0]->get_attribute_node_ns (undef, 'content')                $meta_el->[0]->get_attribute_node_ns (undef, 'content')
5710                    ->set_user_data (manakai_has_reference =>                    ->set_user_data (manakai_has_reference =>
5711                                         $token->{attributes}->{content}                                         $token->{attributes}->{content}
# Line 5461  sub _tree_construction_main ($) { Line 5737  sub _tree_construction_main ($) {
5737          $parse_rcdata->(RCDATA_CONTENT_MODEL);          $parse_rcdata->(RCDATA_CONTENT_MODEL);
5738          redo B;          redo B;
5739        } elsif ($token->{tag_name} eq 'body') {        } elsif ($token->{tag_name} eq 'body') {
5740          !!!parse-error (type => 'in body:body');          !!!parse-error (type => 'in body:body', token => $token);
5741                                
5742          if (@{$self->{open_elements}} == 1 or          if (@{$self->{open_elements}} == 1 or
5743              $self->{open_elements}->[1]->[1] ne 'body') {              not ($self->{open_elements}->[1]->[1] & BODY_EL)) {
5744            !!!cp ('t342');            !!!cp ('t342');
5745            ## Ignore the token            ## Ignore the token
5746          } else {          } else {
# Line 5486  sub _tree_construction_main ($) { Line 5762  sub _tree_construction_main ($) {
5762                  h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,                  h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,
5763                  menu => 1, ol => 1, p => 1, ul => 1,                  menu => 1, ol => 1, p => 1, ul => 1,
5764                  pre => 1, listing => 1,                  pre => 1, listing => 1,
5765                    form => 1,
5766                    table => 1,
5767                    hr => 1,
5768                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
5769            if ($token->{tag_name} eq 'form' and defined $self->{form_element}) {
5770              !!!cp ('t350');
5771              !!!parse-error (type => 'in form:form', token => $token);
5772              ## Ignore the token
5773              !!!next-token;
5774              redo B;
5775            }
5776    
5777          ## has a p element in scope          ## has a p element in scope
5778          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
5779            if ($_->[1] eq 'p') {            if ($_->[1] & P_EL) {
5780              !!!cp ('t344');              !!!cp ('t344');
5781              !!!back-token;              !!!back-token;
5782              $token = {type => END_TAG_TOKEN, tag_name => 'p'};              $token = {type => END_TAG_TOKEN, tag_name => 'p',
5783                          line => $token->{line}, column => $token->{column}};
5784              redo B;              redo B;
5785            } elsif ({            } elsif ($_->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$_->[1]}) {  
5786              !!!cp ('t345');              !!!cp ('t345');
5787              last INSCOPE;              last INSCOPE;
5788            }            }
5789          } # INSCOPE          } # INSCOPE
5790                        
5791          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
5792          if ($token->{tag_name} eq 'pre' or $token->{tag_name} eq 'listing') {          if ($token->{tag_name} eq 'pre' or $token->{tag_name} eq 'listing') {
5793            !!!next-token;            !!!next-token;
5794            if ($token->{type} == CHARACTER_TOKEN) {            if ($token->{type} == CHARACTER_TOKEN) {
# Line 5517  sub _tree_construction_main ($) { Line 5802  sub _tree_construction_main ($) {
5802            } else {            } else {
5803              !!!cp ('t348');              !!!cp ('t348');
5804            }            }
5805          } else {          } elsif ($token->{tag_name} eq 'form') {
5806            !!!cp ('t347');            !!!cp ('t347.1');
5807              $self->{form_element} = $self->{open_elements}->[-1]->[0];
5808    
5809            !!!next-token;            !!!next-token;
5810          }          } elsif ($token->{tag_name} eq 'table') {
5811          redo B;            !!!cp ('t382');
5812        } elsif ($token->{tag_name} eq 'form') {            push @{$open_tables}, [$self->{open_elements}->[-1]->[0]];
5813          if (defined $self->{form_element}) {            
5814            !!!cp ('t350');            $self->{insertion_mode} = IN_TABLE_IM;
5815            !!!parse-error (type => 'in form:form');  
5816            ## Ignore the token            !!!next-token;
5817            } elsif ($token->{tag_name} eq 'hr') {
5818              !!!cp ('t386');
5819              pop @{$self->{open_elements}};
5820            
5821            !!!next-token;            !!!next-token;
           redo B;  
5822          } else {          } else {
5823            ## has a p element in scope            !!!cp ('t347');
           INSCOPE: for (reverse @{$self->{open_elements}}) {  
             if ($_->[1] eq 'p') {  
               !!!cp ('t351');  
               !!!back-token;  
               $token = {type => END_TAG_TOKEN, tag_name => 'p'};  
               redo B;  
             } elsif ({  
                       table => 1, caption => 1, td => 1, th => 1,  
                       button => 1, marquee => 1, object => 1, html => 1,  
                      }->{$_->[1]}) {  
               !!!cp ('t352');  
               last INSCOPE;  
             }  
           } # INSCOPE  
               
           !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
           $self->{form_element} = $self->{open_elements}->[-1]->[0];  
5824            !!!next-token;            !!!next-token;
           redo B;  
5825          }          }
5826        } elsif ($token->{tag_name} eq 'li') {          redo B;
5827          } elsif ({li => 1, dt => 1, dd => 1}->{$token->{tag_name}}) {
5828          ## has a p element in scope          ## has a p element in scope
5829          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
5830            if ($_->[1] eq 'p') {            if ($_->[1] & P_EL) {
5831              !!!cp ('t353');              !!!cp ('t353');
5832              !!!back-token;              !!!back-token;
5833              $token = {type => END_TAG_TOKEN, tag_name => 'p'};              $token = {type => END_TAG_TOKEN, tag_name => 'p',
5834                          line => $token->{line}, column => $token->{column}};
5835              redo B;              redo B;
5836            } elsif ({            } elsif ($_->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$_->[1]}) {  
5837              !!!cp ('t354');              !!!cp ('t354');
5838              last INSCOPE;              last INSCOPE;
5839            }            }
# Line 5571  sub _tree_construction_main ($) { Line 5842  sub _tree_construction_main ($) {
5842          ## Step 1          ## Step 1
5843          my $i = -1;          my $i = -1;
5844          my $node = $self->{open_elements}->[$i];          my $node = $self->{open_elements}->[$i];
5845            my $li_or_dtdd = {li => {li => 1},
5846                              dt => {dt => 1, dd => 1},
5847                              dd => {dt => 1, dd => 1}}->{$token->{tag_name}};
5848          LI: {          LI: {
5849            ## Step 2            ## Step 2
5850            if ($node->[1] eq 'li') {            if ($li_or_dtdd->{$node->[0]->manakai_local_name}) {
5851              if ($i != -1) {              if ($i != -1) {
5852                !!!cp ('t355');                !!!cp ('t355');
5853                !!!parse-error (type => 'end tag missing:'.                !!!parse-error (type => 'not closed',
5854                                $self->{open_elements}->[-1]->[1]);                                value => $self->{open_elements}->[-1]->[0]
5855                                      ->manakai_local_name,
5856                                  token => $token);
5857              } else {              } else {
5858                !!!cp ('t356');                !!!cp ('t356');
5859              }              }
# Line 5588  sub _tree_construction_main ($) { Line 5864  sub _tree_construction_main ($) {
5864            }            }
5865                        
5866            ## Step 3            ## Step 3
5867            if (not $formatting_category->{$node->[1]} and            if (not ($node->[1] & FORMATTING_EL) and
5868                #not $phrasing_category->{$node->[1]} and                #not $phrasing_category->{$node->[1]} and
5869                ($special_category->{$node->[1]} or                ($node->[1] & SPECIAL_EL or
5870                 $scoping_category->{$node->[1]}) and                 $node->[1] & SCOPING_EL) and
5871                $node->[1] ne 'address' and $node->[1] ne 'div') {                not ($node->[1] & ADDRESS_EL) and
5872                  not ($node->[1] & DIV_EL)) {
5873              !!!cp ('t358');              !!!cp ('t358');
5874              last LI;              last LI;
5875            }            }
# Line 5604  sub _tree_construction_main ($) { Line 5881  sub _tree_construction_main ($) {
5881            redo LI;            redo LI;
5882          } # LI          } # LI
5883                        
5884          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
         !!!next-token;  
         redo B;  
       } elsif ($token->{tag_name} eq 'dd' or $token->{tag_name} eq 'dt') {  
         ## has a p element in scope  
         INSCOPE: for (reverse @{$self->{open_elements}}) {  
           if ($_->[1] eq 'p') {  
             !!!cp ('t360');  
             !!!back-token;  
             $token = {type => END_TAG_TOKEN, tag_name => 'p'};  
             redo B;  
           } elsif ({  
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$_->[1]}) {  
             !!!cp ('t361');  
             last INSCOPE;  
           }  
         } # INSCOPE  
             
         ## Step 1  
         my $i = -1;  
         my $node = $self->{open_elements}->[$i];  
         LI: {  
           ## Step 2  
           if ($node->[1] eq 'dt' or $node->[1] eq 'dd') {  
             if ($i != -1) {  
               !!!cp ('t362');  
               !!!parse-error (type => 'end tag missing:'.  
                               $self->{open_elements}->[-1]->[1]);  
             } else {  
               !!!cp ('t363');  
             }  
             splice @{$self->{open_elements}}, $i;  
             last LI;  
           } else {  
             !!!cp ('t364');  
           }  
             
           ## Step 3  
           if (not $formatting_category->{$node->[1]} and  
               #not $phrasing_category->{$node->[1]} and  
               ($special_category->{$node->[1]} or  
                $scoping_category->{$node->[1]}) and  
               $node->[1] ne 'address' and $node->[1] ne 'div') {  
             !!!cp ('t365');  
             last LI;  
           }  
             
           !!!cp ('t366');  
           ## Step 4  
           $i--;  
           $node = $self->{open_elements}->[$i];  
           redo LI;  
         } # LI  
             
         !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
5885          !!!next-token;          !!!next-token;
5886          redo B;          redo B;
5887        } elsif ($token->{tag_name} eq 'plaintext') {        } elsif ($token->{tag_name} eq 'plaintext') {
5888          ## has a p element in scope          ## has a p element in scope
5889          INSCOPE: for (reverse @{$self->{open_elements}}) {          INSCOPE: for (reverse @{$self->{open_elements}}) {
5890            if ($_->[1] eq 'p') {            if ($_->[1] & P_EL) {
5891              !!!cp ('t367');              !!!cp ('t367');
5892              !!!back-token;              !!!back-token;
5893              $token = {type => END_TAG_TOKEN, tag_name => 'p'};              $token = {type => END_TAG_TOKEN, tag_name => 'p',
5894                          line => $token->{line}, column => $token->{column}};
5895              redo B;              redo B;
5896            } elsif ({            } elsif ($_->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$_->[1]}) {  
5897              !!!cp ('t368');              !!!cp ('t368');
5898              last INSCOPE;              last INSCOPE;
5899            }            }
5900          } # INSCOPE          } # INSCOPE
5901                        
5902          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
5903                        
5904          $self->{content_model} = PLAINTEXT_CONTENT_MODEL;          $self->{content_model} = PLAINTEXT_CONTENT_MODEL;
5905                        
# Line 5689  sub _tree_construction_main ($) { Line 5908  sub _tree_construction_main ($) {
5908        } elsif ($token->{tag_name} eq 'a') {        } elsif ($token->{tag_name} eq 'a') {
5909          AFE: for my $i (reverse 0..$#$active_formatting_elements) {          AFE: for my $i (reverse 0..$#$active_formatting_elements) {
5910            my $node = $active_formatting_elements->[$i];            my $node = $active_formatting_elements->[$i];
5911            if ($node->[1] eq 'a') {            if ($node->[1] & A_EL) {
5912              !!!cp ('t371');              !!!cp ('t371');
5913              !!!parse-error (type => 'in a:a');              !!!parse-error (type => 'in a:a', token => $token);
5914                            
5915              !!!back-token;              !!!back-token;
5916              $token = {type => END_TAG_TOKEN, tag_name => 'a'};              $token = {type => END_TAG_TOKEN, tag_name => 'a',
5917              $formatting_end_tag->($token->{tag_name});                        line => $token->{line}, column => $token->{column}};
5918                $formatting_end_tag->($token);
5919                            
5920              AFE2: for (reverse 0..$#$active_formatting_elements) {              AFE2: for (reverse 0..$#$active_formatting_elements) {
5921                if ($active_formatting_elements->[$_]->[0] eq $node->[0]) {                if ($active_formatting_elements->[$_]->[0] eq $node->[0]) {
# Line 5720  sub _tree_construction_main ($) { Line 5940  sub _tree_construction_main ($) {
5940                        
5941          $reconstruct_active_formatting_elements->($insert_to_current);          $reconstruct_active_formatting_elements->($insert_to_current);
5942    
5943          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
5944          push @$active_formatting_elements, $self->{open_elements}->[-1];          push @$active_formatting_elements, $self->{open_elements}->[-1];
5945    
5946          !!!next-token;          !!!next-token;
5947          redo B;          redo B;
       } elsif ({  
                 b => 1, big => 1, em => 1, font => 1, i => 1,  
                 s => 1, small => 1, strile => 1,  
                 strong => 1, tt => 1, u => 1,  
                }->{$token->{tag_name}}) {  
         !!!cp ('t375');  
         $reconstruct_active_formatting_elements->($insert_to_current);  
           
         !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
         push @$active_formatting_elements, $self->{open_elements}->[-1];  
           
         !!!next-token;  
         redo B;  
5948        } elsif ($token->{tag_name} eq 'nobr') {        } elsif ($token->{tag_name} eq 'nobr') {
5949          $reconstruct_active_formatting_elements->($insert_to_current);          $reconstruct_active_formatting_elements->($insert_to_current);
5950    
5951          ## has a |nobr| element in scope          ## has a |nobr| element in scope
5952          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5953            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5954            if ($node->[1] eq 'nobr') {            if ($node->[1] & NOBR_EL) {
5955              !!!cp ('t376');              !!!cp ('t376');
5956              !!!parse-error (type => 'in nobr:nobr');              !!!parse-error (type => 'in nobr:nobr', token => $token);
5957              !!!back-token;              !!!back-token;
5958              $token = {type => END_TAG_TOKEN, tag_name => 'nobr'};              $token = {type => END_TAG_TOKEN, tag_name => 'nobr',
5959                          line => $token->{line}, column => $token->{column}};
5960              redo B;              redo B;
5961            } elsif ({            } elsif ($node->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$node->[1]}) {  
5962              !!!cp ('t377');              !!!cp ('t377');
5963              last INSCOPE;              last INSCOPE;
5964            }            }
5965          } # INSCOPE          } # INSCOPE
5966                    
5967          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
5968          push @$active_formatting_elements, $self->{open_elements}->[-1];          push @$active_formatting_elements, $self->{open_elements}->[-1];
5969                    
5970          !!!next-token;          !!!next-token;
# Line 5768  sub _tree_construction_main ($) { Line 5973  sub _tree_construction_main ($) {
5973          ## has a button element in scope          ## has a button element in scope
5974          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
5975            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
5976            if ($node->[1] eq 'button') {            if ($node->[1] & BUTTON_EL) {
5977              !!!cp ('t378');              !!!cp ('t378');
5978              !!!parse-error (type => 'in button:button');              !!!parse-error (type => 'in button:button', token => $token);
5979              !!!back-token;              !!!back-token;
5980              $token = {type => END_TAG_TOKEN, tag_name => 'button'};              $token = {type => END_TAG_TOKEN, tag_name => 'button',
5981                          line => $token->{line}, column => $token->{column}};
5982              redo B;              redo B;
5983            } elsif ({            } elsif ($node->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$node->[1]}) {  
5984              !!!cp ('t379');              !!!cp ('t379');
5985              last INSCOPE;              last INSCOPE;
5986            }            }
# Line 5785  sub _tree_construction_main ($) { Line 5988  sub _tree_construction_main ($) {
5988                        
5989          $reconstruct_active_formatting_elements->($insert_to_current);          $reconstruct_active_formatting_elements->($insert_to_current);
5990                        
5991          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
5992    
5993          ## TODO: associate with $self->{form_element} if defined          ## TODO: associate with $self->{form_element} if defined
5994    
# Line 5793  sub _tree_construction_main ($) { Line 5996  sub _tree_construction_main ($) {
5996    
5997          !!!next-token;          !!!next-token;
5998          redo B;          redo B;
       } elsif ($token->{tag_name} eq 'marquee' or  
                $token->{tag_name} eq 'object') {  
         !!!cp ('t380');  
         $reconstruct_active_formatting_elements->($insert_to_current);  
           
         !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
         push @$active_formatting_elements, ['#marker', ''];  
           
         !!!next-token;  
         redo B;  
       } elsif ($token->{tag_name} eq 'xmp') {  
         !!!cp ('t381');  
         $reconstruct_active_formatting_elements->($insert_to_current);  
         $parse_rcdata->(CDATA_CONTENT_MODEL);  
         redo B;  
       } elsif ($token->{tag_name} eq 'table') {  
         ## has a p element in scope  
         INSCOPE: for (reverse @{$self->{open_elements}}) {  
           if ($_->[1] eq 'p') {  
             !!!cp ('t382');  
             !!!back-token;  
             $token = {type => END_TAG_TOKEN, tag_name => 'p'};  
             redo B;  
           } elsif ({  
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$_->[1]}) {  
             !!!cp ('t383');  
             last INSCOPE;  
           }  
         } # INSCOPE  
             
         !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
         push @{$open_tables}, [$self->{open_elements}->[-1]->[0]];  
   
         $self->{insertion_mode} = IN_TABLE_IM;  
             
         !!!next-token;  
         redo B;  
5999        } elsif ({        } elsif ({
6000                  area => 1, basefont => 1, bgsound => 1, br => 1,                  xmp => 1,
6001                  embed => 1, img => 1, param => 1, spacer => 1, wbr => 1,                  iframe => 1,
6002                  image => 1,                  noembed => 1,
6003                    noframes => 1,
6004                    noscript => 0, ## TODO: 1 if scripting is enabled
6005                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
6006          if ($token->{tag_name} eq 'image') {          if ($token->{tag_name} eq 'xmp') {
6007            !!!cp ('t384');            !!!cp ('t381');
6008            !!!parse-error (type => 'image');            $reconstruct_active_formatting_elements->($insert_to_current);
           $token->{tag_name} = 'img';  
6009          } else {          } else {
6010            !!!cp ('t385');            !!!cp ('t399');
6011          }          }
6012            ## NOTE: There is an "as if in body" code clone.
6013          ## NOTE: There is an "as if <br>" code clone.          $parse_rcdata->(CDATA_CONTENT_MODEL);
         $reconstruct_active_formatting_elements->($insert_to_current);  
           
         !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
         pop @{$self->{open_elements}};  
           
         !!!next-token;  
         redo B;  
       } elsif ($token->{tag_name} eq 'hr') {  
         ## has a p element in scope  
         INSCOPE: for (reverse @{$self->{open_elements}}) {  
           if ($_->[1] eq 'p') {  
             !!!cp ('t386');  
             !!!back-token;  
             $token = {type => END_TAG_TOKEN, tag_name => 'p'};  
             redo B;  
           } elsif ({  
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$_->[1]}) {  
             !!!cp ('t387');  
             last INSCOPE;  
           }  
         } # INSCOPE  
             
         !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
         pop @{$self->{open_elements}};  
             
         !!!next-token;  
         redo B;  
       } elsif ($token->{tag_name} eq 'input') {  
         !!!cp ('t388');  
         $reconstruct_active_formatting_elements->($insert_to_current);  
           
         !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
         ## TODO: associate with $self->{form_element} if defined  
         pop @{$self->{open_elements}};  
           
         !!!next-token;  
6014          redo B;          redo B;
6015        } elsif ($token->{tag_name} eq 'isindex') {        } elsif ($token->{tag_name} eq 'isindex') {
6016          !!!parse-error (type => 'isindex');          !!!parse-error (type => 'isindex', token => $token);
6017                    
6018          if (defined $self->{form_element}) {          if (defined $self->{form_element}) {
6019            !!!cp ('t389');            !!!cp ('t389');
# Line 5903  sub _tree_construction_main ($) { Line 6030  sub _tree_construction_main ($) {
6030            delete $at->{prompt};            delete $at->{prompt};
6031            my @tokens = (            my @tokens = (
6032                          {type => START_TAG_TOKEN, tag_name => 'form',                          {type => START_TAG_TOKEN, tag_name => 'form',
6033                           attributes => $form_attrs},                           attributes => $form_attrs,
6034                          {type => START_TAG_TOKEN, tag_name => 'hr'},                           line => $token->{line}, column => $token->{column}},
6035                          {type => START_TAG_TOKEN, tag_name => 'p'},                          {type => START_TAG_TOKEN, tag_name => 'hr',
6036                          {type => START_TAG_TOKEN, tag_name => 'label'},                           line => $token->{line}, column => $token->{column}},
6037                            {type => START_TAG_TOKEN, tag_name => 'p',
6038                             line => $token->{line}, column => $token->{column}},
6039                            {type => START_TAG_TOKEN, tag_name => 'label',
6040                             line => $token->{line}, column => $token->{column}},
6041                         );                         );
6042            if ($prompt_attr) {            if ($prompt_attr) {
6043              !!!cp ('t390');              !!!cp ('t390');
6044              push @tokens, {type => CHARACTER_TOKEN, data => $prompt_attr->{value}};              push @tokens, {type => CHARACTER_TOKEN, data => $prompt_attr->{value},
6045                               #line => $token->{line}, column => $token->{column},
6046                              };
6047            } else {            } else {
6048              !!!cp ('t391');              !!!cp ('t391');
6049              push @tokens, {type => CHARACTER_TOKEN,              push @tokens, {type => CHARACTER_TOKEN,
6050                             data => 'This is a searchable index. Insert your search keywords here: '}; # SHOULD                             data => 'This is a searchable index. Insert your search keywords here: ',
6051                               #line => $token->{line}, column => $token->{column},
6052                              }; # SHOULD
6053              ## TODO: make this configurable              ## TODO: make this configurable
6054            }            }
6055            push @tokens,            push @tokens,
6056                          {type => START_TAG_TOKEN, tag_name => 'input', attributes => $at},                          {type => START_TAG_TOKEN, tag_name => 'input', attributes => $at,
6057                             line => $token->{line}, column => $token->{column}},
6058                          #{type => CHARACTER_TOKEN, data => ''}, # SHOULD                          #{type => CHARACTER_TOKEN, data => ''}, # SHOULD
6059                          {type => END_TAG_TOKEN, tag_name => 'label'},                          {type => END_TAG_TOKEN, tag_name => 'label',
6060                          {type => END_TAG_TOKEN, tag_name => 'p'},                           line => $token->{line}, column => $token->{column}},
6061                          {type => START_TAG_TOKEN, tag_name => 'hr'},                          {type => END_TAG_TOKEN, tag_name => 'p',
6062                          {type => END_TAG_TOKEN, tag_name => 'form'};                           line => $token->{line}, column => $token->{column}},
6063                            {type => START_TAG_TOKEN, tag_name => 'hr',
6064                             line => $token->{line}, column => $token->{column}},
6065                            {type => END_TAG_TOKEN, tag_name => 'form',
6066                             line => $token->{line}, column => $token->{column}};
6067            $token = shift @tokens;            $token = shift @tokens;
6068            !!!back-token (@tokens);            !!!back-token (@tokens);
6069            redo B;            redo B;
# Line 5931  sub _tree_construction_main ($) { Line 6071  sub _tree_construction_main ($) {
6071        } elsif ($token->{tag_name} eq 'textarea') {        } elsif ($token->{tag_name} eq 'textarea') {
6072          my $tag_name = $token->{tag_name};          my $tag_name = $token->{tag_name};
6073          my $el;          my $el;
6074          !!!create-element ($el, $token->{tag_name}, $token->{attributes});          !!!create-element ($el, $token->{tag_name}, $token->{attributes}, $token);
6075                    
6076          ## TODO: $self->{form_element} if defined          ## TODO: $self->{form_element} if defined
6077          $self->{content_model} = RCDATA_CONTENT_MODEL;          $self->{content_model} = RCDATA_CONTENT_MODEL;
# Line 5970  sub _tree_construction_main ($) { Line 6110  sub _tree_construction_main ($) {
6110            ## Ignore the token            ## Ignore the token
6111          } else {          } else {
6112            !!!cp ('t398');            !!!cp ('t398');
6113            !!!parse-error (type => 'in RCDATA:#'.$token->{type});            !!!parse-error (type => 'in RCDATA:#'.$token->{type}, token => $token);
         }  
         !!!next-token;  
         redo B;  
       } elsif ({  
                 iframe => 1,  
                 noembed => 1,  
                 noframes => 1,  
                 noscript => 0, ## TODO: 1 if scripting is enabled  
                }->{$token->{tag_name}}) {  
         !!!cp ('t399');  
         ## NOTE: There is an "as if in body" code clone.  
         $parse_rcdata->(CDATA_CONTENT_MODEL);  
         redo B;  
       } elsif ($token->{tag_name} eq 'select') {  
         !!!cp ('t400');  
         $reconstruct_active_formatting_elements->($insert_to_current);  
           
         !!!insert-element-t ($token->{tag_name}, $token->{attributes});  
   
         ## TODO: associate with $self->{form_element} if defined  
           
         if ($self->{insertion_mode} & TABLE_IMS or  
             $self->{insertion_mode} & BODY_TABLE_IMS or  
             $self->{insertion_mode} == IN_COLUMN_GROUP_IM) {  
           !!!cp ('t400.1');  
           $self->{insertion_mode} = IN_SELECT_IN_TABLE_IM;  
         } else {  
           !!!cp ('t400.2');  
           $self->{insertion_mode} = IN_SELECT_IM;  
6114          }          }
6115          !!!next-token;          !!!next-token;
6116          redo B;          redo B;
# Line 6010  sub _tree_construction_main ($) { Line 6121  sub _tree_construction_main ($) {
6121                  thead => 1, tr => 1,                  thead => 1, tr => 1,
6122                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
6123          !!!cp ('t401');          !!!cp ('t401');
6124          !!!parse-error (type => 'in body:'.$token->{tag_name});          !!!parse-error (type => 'in body:'.$token->{tag_name}, token => $token);
6125          ## Ignore the token          ## Ignore the token
6126          !!!next-token;          !!!next-token;
6127          redo B;          redo B;
6128                    
6129          ## ISSUE: An issue on HTML5 new elements in the spec.          ## ISSUE: An issue on HTML5 new elements in the spec.
6130        } else {        } else {
6131          !!!cp ('t402');          if ($token->{tag_name} eq 'image') {
6132              !!!cp ('t384');
6133              !!!parse-error (type => 'image', token => $token);
6134              $token->{tag_name} = 'img';
6135            } else {
6136              !!!cp ('t385');
6137            }
6138    
6139            ## NOTE: There is an "as if <br>" code clone.
6140          $reconstruct_active_formatting_elements->($insert_to_current);          $reconstruct_active_formatting_elements->($insert_to_current);
6141                    
6142          !!!insert-element-t ($token->{tag_name}, $token->{attributes});          !!!insert-element-t ($token->{tag_name}, $token->{attributes}, $token);
6143    
6144            if ({
6145                 applet => 1, marquee => 1, object => 1,
6146                }->{$token->{tag_name}}) {
6147              !!!cp ('t380');
6148              push @$active_formatting_elements, ['#marker', ''];
6149            } elsif ({
6150                      b => 1, big => 1, em => 1, font => 1, i => 1,
6151                      s => 1, small => 1, strile => 1,
6152                      strong => 1, tt => 1, u => 1,
6153                     }->{$token->{tag_name}}) {
6154              !!!cp ('t375');
6155              push @$active_formatting_elements, $self->{open_elements}->[-1];
6156            } elsif ($token->{tag_name} eq 'input') {
6157              !!!cp ('t388');
6158              ## TODO: associate with $self->{form_element} if defined
6159              pop @{$self->{open_elements}};
6160            } elsif ({
6161                      area => 1, basefont => 1, bgsound => 1, br => 1,
6162                      embed => 1, img => 1, param => 1, spacer => 1, wbr => 1,
6163                      #image => 1,
6164                     }->{$token->{tag_name}}) {
6165              !!!cp ('t388.1');
6166              pop @{$self->{open_elements}};
6167            } elsif ($token->{tag_name} eq 'select') {
6168              ## TODO: associate with $self->{form_element} if defined
6169            
6170              if ($self->{insertion_mode} & TABLE_IMS or
6171                  $self->{insertion_mode} & BODY_TABLE_IMS or
6172                  $self->{insertion_mode} == IN_COLUMN_GROUP_IM) {
6173                !!!cp ('t400.1');
6174                $self->{insertion_mode} = IN_SELECT_IN_TABLE_IM;
6175              } else {
6176                !!!cp ('t400.2');
6177                $self->{insertion_mode} = IN_SELECT_IM;
6178              }
6179            } else {
6180              !!!cp ('t402');
6181            }
6182                    
6183          !!!next-token;          !!!next-token;
6184          redo B;          redo B;
6185        }        }
6186      } elsif ($token->{type} == END_TAG_TOKEN) {      } elsif ($token->{type} == END_TAG_TOKEN) {
6187        if ($token->{tag_name} eq 'body') {        if ($token->{tag_name} eq 'body') {
6188          if (@{$self->{open_elements}} > 1 and          ## has a |body| element in scope
6189              $self->{open_elements}->[1]->[1] eq 'body') {          my $i;
6190            for (@{$self->{open_elements}}) {          INSCOPE: {
6191              unless ({            for (reverse @{$self->{open_elements}}) {
6192                         dd => 1, dt => 1, li => 1, p => 1, td => 1,              if ($_->[1] & BODY_EL) {
6193                         th => 1, tr => 1, body => 1, html => 1,                !!!cp ('t405');
6194                       tbody => 1, tfoot => 1, thead => 1,                $i = $_;
6195                      }->{$_->[1]}) {                last INSCOPE;
6196                !!!cp ('t403');              } elsif ($_->[1] & SCOPING_EL) {
6197                !!!parse-error (type => 'not closed:'.$_->[1]);                !!!cp ('t405.1');
6198              } else {                last;
               !!!cp ('t404');  
6199              }              }
6200            }            }
6201    
6202            $self->{insertion_mode} = AFTER_BODY_IM;            !!!parse-error (type => 'start tag not allowed',
6203            !!!next-token;                            value => $token->{tag_name}, token => $token);
6204            redo B;            ## NOTE: Ignore the token.
         } else {  
           !!!cp ('t405');  
           !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});  
           ## Ignore the token  
6205            !!!next-token;            !!!next-token;
6206            redo B;            redo B;
6207            } # INSCOPE
6208    
6209            for (@{$self->{open_elements}}) {
6210              unless ($_->[1] & ALL_END_TAG_OPTIONAL_EL) {
6211                !!!cp ('t403');
6212                !!!parse-error (type => 'not closed',
6213                                value => $_->[0]->manakai_local_name,
6214                                token => $token);
6215                last;
6216              } else {
6217                !!!cp ('t404');
6218              }
6219          }          }
6220    
6221            $self->{insertion_mode} = AFTER_BODY_IM;
6222            !!!next-token;
6223            redo B;
6224        } elsif ($token->{tag_name} eq 'html') {        } elsif ($token->{tag_name} eq 'html') {
6225          if (@{$self->{open_elements}} > 1 and $self->{open_elements}->[1]->[1] eq 'body') {          ## TODO: Update this code.  It seems that the code below is not
6226            ## up-to-date, though it has same effect as speced.
6227            if (@{$self->{open_elements}} > 1 and
6228                $self->{open_elements}->[1]->[1] & BODY_EL) {
6229            ## ISSUE: There is an issue in the spec.            ## ISSUE: There is an issue in the spec.
6230            if ($self->{open_elements}->[-1]->[1] ne 'body') {            unless ($self->{open_elements}->[-1]->[1] & BODY_EL) {
6231              !!!cp ('t406');              !!!cp ('t406');
6232              !!!parse-error (type => 'not closed:'.$self->{open_elements}->[1]->[1]);              !!!parse-error (type => 'not closed',
6233                                value => $self->{open_elements}->[1]->[0]
6234                                    ->manakai_local_name,
6235                                token => $token);
6236            } else {            } else {
6237              !!!cp ('t407');              !!!cp ('t407');
6238            }            }
# Line 6066  sub _tree_construction_main ($) { Line 6241  sub _tree_construction_main ($) {
6241            redo B;            redo B;
6242          } else {          } else {
6243            !!!cp ('t408');            !!!cp ('t408');
6244            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
6245            ## Ignore the token            ## Ignore the token
6246            !!!next-token;            !!!next-token;
6247            redo B;            redo B;
# Line 6076  sub _tree_construction_main ($) { Line 6251  sub _tree_construction_main ($) {
6251                  div => 1, dl => 1, fieldset => 1, listing => 1,                  div => 1, dl => 1, fieldset => 1, listing => 1,
6252                  menu => 1, ol => 1, pre => 1, ul => 1,                  menu => 1, ol => 1, pre => 1, ul => 1,
6253                  dd => 1, dt => 1, li => 1,                  dd => 1, dt => 1, li => 1,
6254                  button => 1, marquee => 1, object => 1,                  applet => 1, button => 1, marquee => 1, object => 1,
6255                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
6256          ## has an element in scope          ## has an element in scope
6257          my $i;          my $i;
6258          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6259            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
6260            if ($node->[1] eq $token->{tag_name}) {            if ($node->[0]->manakai_local_name eq $token->{tag_name}) {
6261              !!!cp ('t410');              !!!cp ('t410');
6262              $i = $_;              $i = $_;
6263              last INSCOPE;              last INSCOPE;
6264            } elsif ({            } elsif ($node->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$node->[1]}) {  
6265              !!!cp ('t411');              !!!cp ('t411');
6266              last INSCOPE;              last INSCOPE;
6267            }            }
# Line 6097  sub _tree_construction_main ($) { Line 6269  sub _tree_construction_main ($) {
6269    
6270          unless (defined $i) { # has an element in scope          unless (defined $i) { # has an element in scope
6271            !!!cp ('t413');            !!!cp ('t413');
6272            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
6273          } else {          } else {
6274            ## Step 1. generate implied end tags            ## Step 1. generate implied end tags
6275            while ({            while ({
# Line 6105  sub _tree_construction_main ($) { Line 6277  sub _tree_construction_main ($) {
6277                    dt => ($token->{tag_name} ne 'dt'),                    dt => ($token->{tag_name} ne 'dt'),
6278                    li => ($token->{tag_name} ne 'li'),                    li => ($token->{tag_name} ne 'li'),
6279                    p => 1,                    p => 1,
6280                   }->{$self->{open_elements}->[-1]->[1]}) {                   }->{$self->{open_elements}->[-1]->[0]->manakai_local_name}) {
6281              !!!cp ('t409');              !!!cp ('t409');
6282              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
6283            }            }
6284    
6285            ## Step 2.            ## Step 2.
6286            if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {            if ($self->{open_elements}->[-1]->[0]->manakai_local_name
6287                      ne $token->{tag_name}) {
6288              !!!cp ('t412');              !!!cp ('t412');
6289              !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);              !!!parse-error (type => 'not closed',
6290                                value => $self->{open_elements}->[-1]->[0]
6291                                    ->manakai_local_name,
6292                                token => $token);
6293            } else {            } else {
6294              !!!cp ('t414');              !!!cp ('t414');
6295            }            }
# Line 6124  sub _tree_construction_main ($) { Line 6300  sub _tree_construction_main ($) {
6300            ## Step 4.            ## Step 4.
6301            $clear_up_to_marker->()            $clear_up_to_marker->()
6302                if {                if {
6303                  button => 1, marquee => 1, object => 1,                  applet => 1, button => 1, marquee => 1, object => 1,
6304                }->{$token->{tag_name}};                }->{$token->{tag_name}};
6305          }          }
6306          !!!next-token;          !!!next-token;
# Line 6136  sub _tree_construction_main ($) { Line 6312  sub _tree_construction_main ($) {
6312          my $i;          my $i;
6313          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6314            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
6315            if ($node->[1] eq $token->{tag_name}) {            if ($node->[1] & FORM_EL) {
6316              !!!cp ('t418');              !!!cp ('t418');
6317              $i = $_;              $i = $_;
6318              last INSCOPE;              last INSCOPE;
6319            } elsif ({            } elsif ($node->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$node->[1]}) {  
6320              !!!cp ('t419');              !!!cp ('t419');
6321              last INSCOPE;              last INSCOPE;
6322            }            }
# Line 6151  sub _tree_construction_main ($) { Line 6324  sub _tree_construction_main ($) {
6324    
6325          unless (defined $i) { # has an element in scope          unless (defined $i) { # has an element in scope
6326            !!!cp ('t421');            !!!cp ('t421');
6327            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
6328          } else {          } else {
6329            ## Step 1. generate implied end tags            ## Step 1. generate implied end tags
6330            while ({            while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
                   dd => 1, dt => 1, li => 1, p => 1,  
                  }->{$self->{open_elements}->[-1]->[1]}) {  
6331              !!!cp ('t417');              !!!cp ('t417');
6332              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
6333            }            }
6334                        
6335            ## Step 2.            ## Step 2.
6336            if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {            if ($self->{open_elements}->[-1]->[0]->manakai_local_name
6337                      ne $token->{tag_name}) {
6338              !!!cp ('t417.1');              !!!cp ('t417.1');
6339              !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);              !!!parse-error (type => 'not closed',
6340                                value => $self->{open_elements}->[-1]->[0]
6341                                    ->manakai_local_name,
6342                                token => $token);
6343            } else {            } else {
6344              !!!cp ('t420');              !!!cp ('t420');
6345            }              }  
# Line 6182  sub _tree_construction_main ($) { Line 6357  sub _tree_construction_main ($) {
6357          my $i;          my $i;
6358          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6359            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
6360            if ({            if ($node->[1] & HEADING_EL) {
                h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1, h6 => 1,  
               }->{$node->[1]}) {  
6361              !!!cp ('t423');              !!!cp ('t423');
6362              $i = $_;              $i = $_;
6363              last INSCOPE;              last INSCOPE;
6364            } elsif ({            } elsif ($node->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$node->[1]}) {  
6365              !!!cp ('t424');              !!!cp ('t424');
6366              last INSCOPE;              last INSCOPE;
6367            }            }
# Line 6199  sub _tree_construction_main ($) { Line 6369  sub _tree_construction_main ($) {
6369    
6370          unless (defined $i) { # has an element in scope          unless (defined $i) { # has an element in scope
6371            !!!cp ('t425.1');            !!!cp ('t425.1');
6372            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
6373          } else {          } else {
6374            ## Step 1. generate implied end tags            ## Step 1. generate implied end tags
6375            while ({            while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
                   dd => 1, dt => 1, li => 1, p => 1,  
                  }->{$self->{open_elements}->[-1]->[1]}) {  
6376              !!!cp ('t422');              !!!cp ('t422');
6377              pop @{$self->{open_elements}};              pop @{$self->{open_elements}};
6378            }            }
6379                        
6380            ## Step 2.            ## Step 2.
6381            if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {            if ($self->{open_elements}->[-1]->[0]->manakai_local_name
6382                      ne $token->{tag_name}) {
6383              !!!cp ('t425');              !!!cp ('t425');
6384              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});              !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
6385            } else {            } else {
6386              !!!cp ('t426');              !!!cp ('t426');
6387            }            }
# Line 6228  sub _tree_construction_main ($) { Line 6397  sub _tree_construction_main ($) {
6397          my $i;          my $i;
6398          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
6399            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
6400            if ($node->[1] eq $token->{tag_name}) {            if ($node->[1] & P_EL) {
6401              !!!cp ('t410.1');              !!!cp ('t410.1');
6402              $i = $_;              $i = $_;
6403              last INSCOPE;              last INSCOPE;
6404            } elsif ({            } elsif ($node->[1] & SCOPING_EL) {
                     table => 1, caption => 1, td => 1, th => 1,  
                     button => 1, marquee => 1, object => 1, html => 1,  
                    }->{$node->[1]}) {  
6405              !!!cp ('t411.1');              !!!cp ('t411.1');
6406              last INSCOPE;              last INSCOPE;
6407            }            }
6408          } # INSCOPE          } # INSCOPE
6409    
6410          if (defined $i) {          if (defined $i) {
6411            if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {            if ($self->{open_elements}->[-1]->[0]->manakai_local_name
6412                      ne $token->{tag_name}) {
6413              !!!cp ('t412.1');              !!!cp ('t412.1');
6414              !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);              !!!parse-error (type => 'not closed',
6415                                value => $self->{open_elements}->[-1]->[0]
6416                                    ->manakai_local_name,
6417                                token => $token);
6418            } else {            } else {
6419              !!!cp ('t414.1');              !!!cp ('t414.1');
6420            }            }
# Line 6252  sub _tree_construction_main ($) { Line 6422  sub _tree_construction_main ($) {
6422            splice @{$self->{open_elements}}, $i;            splice @{$self->{open_elements}}, $i;
6423          } else {          } else {
6424            !!!cp ('t413.1');            !!!cp ('t413.1');
6425            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
6426    
6427            !!!cp ('t415.1');            !!!cp ('t415.1');
6428            ## As if <p>, then reprocess the current token            ## As if <p>, then reprocess the current token
6429            my $el;            my $el;
6430            !!!create-element ($el, 'p');            !!!create-element ($el, 'p',, $token);
6431            $insert->($el);            $insert->($el);
6432            ## NOTE: Not inserted into |$self->{open_elements}|.            ## NOTE: Not inserted into |$self->{open_elements}|.
6433          }          }
# Line 6271  sub _tree_construction_main ($) { Line 6441  sub _tree_construction_main ($) {
6441                  strong => 1, tt => 1, u => 1,                  strong => 1, tt => 1, u => 1,
6442                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
6443          !!!cp ('t427');          !!!cp ('t427');
6444          $formatting_end_tag->($token->{tag_name});          $formatting_end_tag->($token);
6445          redo B;          redo B;
6446        } elsif ($token->{tag_name} eq 'br') {        } elsif ($token->{tag_name} eq 'br') {
6447          !!!cp ('t428');          !!!cp ('t428');
6448          !!!parse-error (type => 'unmatched end tag:br');          !!!parse-error (type => 'unmatched end tag:br', token => $token);
6449    
6450          ## As if <br>          ## As if <br>
6451          $reconstruct_active_formatting_elements->($insert_to_current);          $reconstruct_active_formatting_elements->($insert_to_current);
6452                    
6453          my $el;          my $el;
6454          !!!create-element ($el, 'br');          !!!create-element ($el, 'br',, $token);
6455          $insert->($el);          $insert->($el);
6456                    
6457          ## Ignore the token.          ## Ignore the token.
# Line 6300  sub _tree_construction_main ($) { Line 6470  sub _tree_construction_main ($) {
6470                  noscript => 0, ## TODO: if scripting is enabled                  noscript => 0, ## TODO: if scripting is enabled
6471                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
6472          !!!cp ('t429');          !!!cp ('t429');
6473          !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});          !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
6474          ## Ignore the token          ## Ignore the token
6475          !!!next-token;          !!!next-token;
6476          redo B;          redo B;
# Line 6314  sub _tree_construction_main ($) { Line 6484  sub _tree_construction_main ($) {
6484    
6485          ## Step 2          ## Step 2
6486          S2: {          S2: {
6487            if ($node->[1] eq $token->{tag_name}) {            if ($node->[0]->manakai_local_name eq $token->{tag_name}) {
6488              ## Step 1              ## Step 1
6489              ## generate implied end tags              ## generate implied end tags
6490              while ({              while ($self->{open_elements}->[-1]->[1] & END_TAG_OPTIONAL_EL) {
                     dd => 1, dt => 1, li => 1, p => 1,  
                    }->{$self->{open_elements}->[-1]->[1]}) {  
6491                !!!cp ('t430');                !!!cp ('t430');
6492                ## ISSUE: Can this case be reached?                ## ISSUE: Can this case be reached?
6493                pop @{$self->{open_elements}};                pop @{$self->{open_elements}};
6494              }              }
6495                    
6496              ## Step 2              ## Step 2
6497              if ($token->{tag_name} ne $self->{open_elements}->[-1]->[1]) {              if ($self->{open_elements}->[-1]->[0]->manakai_local_name
6498                        ne $token->{tag_name}) {
6499                !!!cp ('t431');                !!!cp ('t431');
6500                ## NOTE: <x><y></x>                ## NOTE: <x><y></x>
6501                !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                !!!parse-error (type => 'not closed',
6502                                  value => $self->{open_elements}->[-1]->[0]
6503                                      ->manakai_local_name,
6504                                  token => $token);
6505              } else {              } else {
6506                !!!cp ('t432');                !!!cp ('t432');
6507              }              }
# Line 6341  sub _tree_construction_main ($) { Line 6513  sub _tree_construction_main ($) {
6513              last S2;              last S2;
6514            } else {            } else {
6515              ## Step 3              ## Step 3
6516              if (not $formatting_category->{$node->[1]} and              if (not ($node->[1] & FORMATTING_EL) and
6517                  #not $phrasing_category->{$node->[1]} and                  #not $phrasing_category->{$node->[1]} and
6518                  ($special_category->{$node->[1]} or                  ($node->[1] & SPECIAL_EL or
6519                   $scoping_category->{$node->[1]})) {                   $node->[1] & SCOPING_EL)) {
6520                !!!cp ('t433');                !!!cp ('t433');
6521                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});                !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name}, token => $token);
6522                ## Ignore the token                ## Ignore the token
6523                !!!next-token;                !!!next-token;
6524                last S2;                last S2;
# Line 6411  sub set_inner_html ($$$) { Line 6583  sub set_inner_html ($$$) {
6583    
6584      ## Step 8 # MUST      ## Step 8 # MUST
6585      my $i = 0;      my $i = 0;
6586      my $line = 1;      $p->{line_prev} = $p->{line} = 1;
6587      my $column = 0;      $p->{column_prev} = $p->{column} = 0;
6588      $p->{set_next_char} = sub {      $p->{set_next_char} = sub {
6589        my $self = shift;        my $self = shift;
6590    
# Line 6421  sub set_inner_html ($$$) { Line 6593  sub set_inner_html ($$$) {
6593    
6594        $self->{next_char} = -1 and return if $i >= length $$s;        $self->{next_char} = -1 and return if $i >= length $$s;
6595        $self->{next_char} = ord substr $$s, $i++, 1;        $self->{next_char} = ord substr $$s, $i++, 1;
6596        $column++;  
6597          ($p->{line_prev}, $p->{column_prev}) = ($p->{line}, $p->{column});
6598          $p->{column}++;
6599    
6600        if ($self->{next_char} == 0x000A) { # LF        if ($self->{next_char} == 0x000A) { # LF
6601          $line++;          $p->{line}++;
6602          $column = 0;          $p->{column} = 0;
6603          !!!cp ('i1');          !!!cp ('i1');
6604        } elsif ($self->{next_char} == 0x000D) { # CR        } elsif ($self->{next_char} == 0x000D) { # CR
6605          $i++ if substr ($$s, $i, 1) eq "\x0A";          $i++ if substr ($$s, $i, 1) eq "\x0A";
6606          $self->{next_char} = 0x000A; # LF # MUST          $self->{next_char} = 0x000A; # LF # MUST
6607          $line++;          $p->{line}++;
6608          $column = 0;          $p->{column} = 0;
6609          !!!cp ('i2');          !!!cp ('i2');
6610        } elsif ($self->{next_char} > 0x10FFFF) {        } elsif ($self->{next_char} > 0x10FFFF) {
6611          $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST          $self->{next_char} = 0xFFFD; # REPLACEMENT CHARACTER # MUST
# Line 6447  sub set_inner_html ($$$) { Line 6621  sub set_inner_html ($$$) {
6621            
6622      my $ponerror = $onerror || sub {      my $ponerror = $onerror || sub {
6623        my (%opt) = @_;        my (%opt) = @_;
6624        warn "Parse error ($opt{type}) at line $opt{line} column $opt{column}\n";        my $line = $opt{line};
6625          my $column = $opt{column};
6626          if (defined $opt{token} and defined $opt{token}->{line}) {
6627            $line = $opt{token}->{line};
6628            $column = $opt{token}->{column};
6629          }
6630          warn "Parse error ($opt{type}) at line $line column $column\n";
6631      };      };
6632      $p->{parse_error} = sub {      $p->{parse_error} = sub {
6633        $ponerror->(@_, line => $line, column => $column);        $ponerror->(line => $p->{line}, column => $p->{column}, @_);
6634      };      };
6635            
6636      $p->_initialize_tokenizer;      $p->_initialize_tokenizer;
# Line 6474  sub set_inner_html ($$$) { Line 6654  sub set_inner_html ($$$) {
6654          unless defined $p->{content_model};          unless defined $p->{content_model};
6655          ## ISSUE: What is "the name of the element"? local name?          ## ISSUE: What is "the name of the element"? local name?
6656    
6657      $p->{inner_html_node} = [$node, $node_ln];      $p->{inner_html_node} = [$node, $el_category->{$node_ln}];
6658          ## TODO: Foreign element OK?
6659    
6660      ## Step 3      ## Step 3
6661      my $root = $doc->create_element_ns      my $root = $doc->create_element_ns
# Line 6484  sub set_inner_html ($$$) { Line 6665  sub set_inner_html ($$$) {
6665      $doc->append_child ($root);      $doc->append_child ($root);
6666    
6667      ## Step 5 # MUST      ## Step 5 # MUST
6668      push @{$p->{open_elements}}, [$root, 'html'];      push @{$p->{open_elements}}, [$root, $el_category->{html}];
6669    
6670      undef $p->{head_element};      undef $p->{head_element};
6671    
# Line 6530  sub set_inner_html ($$$) { Line 6711  sub set_inner_html ($$$) {
6711      ## ISSUE: mutation events?      ## ISSUE: mutation events?
6712    
6713      $p->_terminate_tree_constructor;      $p->_terminate_tree_constructor;
6714    
6715        delete $p->{parse_error}; # delete loop
6716    } else {    } else {
6717      die "$0: |set_inner_html| is not defined for node of type $nt";      die "$0: |set_inner_html| is not defined for node of type $nt";
6718    }    }

Legend:
Removed from v.1.102  
changed lines
  Added in v.1.124

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24