/[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.56 by wakaba, Sat Aug 11 07:19:18 2007 UTC revision 1.60 by wakaba, Sun Oct 14 09:21:46 2007 UTC
# Line 159  sub CDATA_CONTENT_MODEL () { CM_LIMITED_ Line 159  sub CDATA_CONTENT_MODEL () { CM_LIMITED_
159  sub RCDATA_CONTENT_MODEL () { CM_ENTITY | CM_LIMITED_MARKUP }  sub RCDATA_CONTENT_MODEL () { CM_ENTITY | CM_LIMITED_MARKUP }
160  sub PCDATA_CONTENT_MODEL () { CM_ENTITY | CM_FULL_MARKUP }  sub PCDATA_CONTENT_MODEL () { CM_ENTITY | CM_FULL_MARKUP }
161    
162    sub DATA_STATE () { 0 }
163    sub ENTITY_DATA_STATE () { 1 }
164    sub TAG_OPEN_STATE () { 2 }
165    sub CLOSE_TAG_OPEN_STATE () { 3 }
166    sub TAG_NAME_STATE () { 4 }
167    sub BEFORE_ATTRIBUTE_NAME_STATE () { 5 }
168    sub ATTRIBUTE_NAME_STATE () { 6 }
169    sub AFTER_ATTRIBUTE_NAME_STATE () { 7 }
170    sub BEFORE_ATTRIBUTE_VALUE_STATE () { 8 }
171    sub ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE () { 9 }
172    sub ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE () { 10 }
173    sub ATTRIBUTE_VALUE_UNQUOTED_STATE () { 11 }
174    sub ENTITY_IN_ATTRIBUTE_VALUE_STATE () { 12 }
175    sub MARKUP_DECLARATION_OPEN_STATE () { 13 }
176    sub COMMENT_START_STATE () { 14 }
177    sub COMMENT_START_DASH_STATE () { 15 }
178    sub COMMENT_STATE () { 16 }
179    sub COMMENT_END_STATE () { 17 }
180    sub COMMENT_END_DASH_STATE () { 18 }
181    sub BOGUS_COMMENT_STATE () { 19 }
182    sub DOCTYPE_STATE () { 20 }
183    sub BEFORE_DOCTYPE_NAME_STATE () { 21 }
184    sub DOCTYPE_NAME_STATE () { 22 }
185    sub AFTER_DOCTYPE_NAME_STATE () { 23 }
186    sub BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE () { 24 }
187    sub DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE () { 25 }
188    sub DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE () { 26 }
189    sub AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE () { 27 }
190    sub BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE () { 28 }
191    sub DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE () { 29 }
192    sub DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE () { 30 }
193    sub AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE () { 31 }
194    sub BOGUS_DOCTYPE_STATE () { 32 }
195    
196  sub DOCTYPE_TOKEN () { 1 }  sub DOCTYPE_TOKEN () { 1 }
197  sub COMMENT_TOKEN () { 2 }  sub COMMENT_TOKEN () { 2 }
198  sub START_TAG_TOKEN () { 3 }  sub START_TAG_TOKEN () { 3 }
# Line 197  sub IN_COLUMN_GROUP_IM () { 0b10 } Line 231  sub IN_COLUMN_GROUP_IM () { 0b10 }
231    
232  sub _initialize_tokenizer ($) {  sub _initialize_tokenizer ($) {
233    my $self = shift;    my $self = shift;
234    $self->{state} = 'data'; # MUST    $self->{state} = DATA_STATE; # MUST
235    $self->{content_model} = PCDATA_CONTENT_MODEL; # be    $self->{content_model} = PCDATA_CONTENT_MODEL; # be
236    undef $self->{current_token}; # start tag, end tag, comment, or DOCTYPE    undef $self->{current_token}; # start tag, end tag, comment, or DOCTYPE
237    undef $self->{current_attribute};    undef $self->{current_attribute};
# Line 229  sub _initialize_tokenizer ($) { Line 263  sub _initialize_tokenizer ($) {
263  ## has completed loading.  If one has, then it MUST be executed  ## has completed loading.  If one has, then it MUST be executed
264  ## and removed from the list.  ## and removed from the list.
265    
266    ## NOTE: HTML5 "Writing HTML documents" section, applied to
267    ## documents and not to user agents and conformance checkers,
268    ## contains some requirements that are not detected by the
269    ## parsing algorithm:
270    ## - Some requirements on character encoding declarations. ## TODO
271    ## - "Elements MUST NOT contain content that their content model disallows."
272    ##   ... Some are parse error, some are not (will be reported by c.c.).
273    ## - Polytheistic slash SHOULD NOT be used. (Applied only to atheists.) ## TODO
274    ## - Text (in elements, attributes, and comments) SHOULD NOT contain
275    ##   control characters other than space characters. ## TODO: (what is control character? C0, C1 and DEL?  Unicode control character?)
276    
277    ## TODO: HTML5 poses authors two SHOULD-level requirements that cannot
278    ## be detected by the HTML5 parsing algorithm:
279    ## - Text,
280    
281  sub _get_next_token ($) {  sub _get_next_token ($) {
282    my $self = shift;    my $self = shift;
283    if (@{$self->{token}}) {    if (@{$self->{token}}) {
# Line 236  sub _get_next_token ($) { Line 285  sub _get_next_token ($) {
285    }    }
286    
287    A: {    A: {
288      if ($self->{state} eq 'data') {      if ($self->{state} == DATA_STATE) {
289        if ($self->{next_input_character} == 0x0026) { # &        if ($self->{next_input_character} == 0x0026) { # &
290          if ($self->{content_model} & CM_ENTITY) { # PCDATA | RCDATA          if ($self->{content_model} & CM_ENTITY) { # PCDATA | RCDATA
291            $self->{state} = 'entity data';            $self->{state} = ENTITY_DATA_STATE;
292            !!!next-input-character;            !!!next-input-character;
293            redo A;            redo A;
294          } else {          } else {
# Line 261  sub _get_next_token ($) { Line 310  sub _get_next_token ($) {
310          if ($self->{content_model} & CM_FULL_MARKUP or # PCDATA          if ($self->{content_model} & CM_FULL_MARKUP or # PCDATA
311              (($self->{content_model} & CM_LIMITED_MARKUP) and # CDATA | RCDATA              (($self->{content_model} & CM_LIMITED_MARKUP) and # CDATA | RCDATA
312               not $self->{escape})) {               not $self->{escape})) {
313            $self->{state} = 'tag open';            $self->{state} = TAG_OPEN_STATE;
314            !!!next-input-character;            !!!next-input-character;
315            redo A;            redo A;
316          } else {          } else {
# Line 290  sub _get_next_token ($) { Line 339  sub _get_next_token ($) {
339        !!!emit ($token);        !!!emit ($token);
340    
341        redo A;        redo A;
342      } elsif ($self->{state} eq 'entity data') {      } elsif ($self->{state} == ENTITY_DATA_STATE) {
343        ## (cannot happen in CDATA state)        ## (cannot happen in CDATA state)
344                
345        my $token = $self->_tokenize_attempt_to_consume_an_entity (0);        my $token = $self->_tokenize_attempt_to_consume_an_entity (0);
346    
347        $self->{state} = 'data';        $self->{state} = DATA_STATE;
348        # next-input-character is already done        # next-input-character is already done
349    
350        unless (defined $token) {        unless (defined $token) {
# Line 305  sub _get_next_token ($) { Line 354  sub _get_next_token ($) {
354        }        }
355    
356        redo A;        redo A;
357      } elsif ($self->{state} eq 'tag open') {      } elsif ($self->{state} == TAG_OPEN_STATE) {
358        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
359          if ($self->{next_input_character} == 0x002F) { # /          if ($self->{next_input_character} == 0x002F) { # /
360            !!!next-input-character;            !!!next-input-character;
361            $self->{state} = 'close tag open';            $self->{state} = CLOSE_TAG_OPEN_STATE;
362            redo A;            redo A;
363          } else {          } else {
364            ## reconsume            ## reconsume
365            $self->{state} = 'data';            $self->{state} = DATA_STATE;
366    
367            !!!emit ({type => CHARACTER_TOKEN, data => '<'});            !!!emit ({type => CHARACTER_TOKEN, data => '<'});
368    
# Line 321  sub _get_next_token ($) { Line 370  sub _get_next_token ($) {
370          }          }
371        } elsif ($self->{content_model} & CM_FULL_MARKUP) { # PCDATA        } elsif ($self->{content_model} & CM_FULL_MARKUP) { # PCDATA
372          if ($self->{next_input_character} == 0x0021) { # !          if ($self->{next_input_character} == 0x0021) { # !
373            $self->{state} = 'markup declaration open';            $self->{state} = MARKUP_DECLARATION_OPEN_STATE;
374            !!!next-input-character;            !!!next-input-character;
375            redo A;            redo A;
376          } elsif ($self->{next_input_character} == 0x002F) { # /          } elsif ($self->{next_input_character} == 0x002F) { # /
377            $self->{state} = 'close tag open';            $self->{state} = CLOSE_TAG_OPEN_STATE;
378            !!!next-input-character;            !!!next-input-character;
379            redo A;            redo A;
380          } elsif (0x0041 <= $self->{next_input_character} and          } elsif (0x0041 <= $self->{next_input_character} and
# Line 333  sub _get_next_token ($) { Line 382  sub _get_next_token ($) {
382            $self->{current_token}            $self->{current_token}
383              = {type => START_TAG_TOKEN,              = {type => START_TAG_TOKEN,
384                 tag_name => chr ($self->{next_input_character} + 0x0020)};                 tag_name => chr ($self->{next_input_character} + 0x0020)};
385            $self->{state} = 'tag name';            $self->{state} = TAG_NAME_STATE;
386            !!!next-input-character;            !!!next-input-character;
387            redo A;            redo A;
388          } elsif (0x0061 <= $self->{next_input_character} and          } elsif (0x0061 <= $self->{next_input_character} and
389                   $self->{next_input_character} <= 0x007A) { # a..z                   $self->{next_input_character} <= 0x007A) { # a..z
390            $self->{current_token} = {type => START_TAG_TOKEN,            $self->{current_token} = {type => START_TAG_TOKEN,
391                              tag_name => chr ($self->{next_input_character})};                              tag_name => chr ($self->{next_input_character})};
392            $self->{state} = 'tag name';            $self->{state} = TAG_NAME_STATE;
393            !!!next-input-character;            !!!next-input-character;
394            redo A;            redo A;
395          } elsif ($self->{next_input_character} == 0x003E) { # >          } elsif ($self->{next_input_character} == 0x003E) { # >
396            !!!parse-error (type => 'empty start tag');            !!!parse-error (type => 'empty start tag');
397            $self->{state} = 'data';            $self->{state} = DATA_STATE;
398            !!!next-input-character;            !!!next-input-character;
399    
400            !!!emit ({type => CHARACTER_TOKEN, data => '<>'});            !!!emit ({type => CHARACTER_TOKEN, data => '<>'});
# Line 353  sub _get_next_token ($) { Line 402  sub _get_next_token ($) {
402            redo A;            redo A;
403          } elsif ($self->{next_input_character} == 0x003F) { # ?          } elsif ($self->{next_input_character} == 0x003F) { # ?
404            !!!parse-error (type => 'pio');            !!!parse-error (type => 'pio');
405            $self->{state} = 'bogus comment';            $self->{state} = BOGUS_COMMENT_STATE;
406            ## $self->{next_input_character} is intentionally left as is            ## $self->{next_input_character} is intentionally left as is
407            redo A;            redo A;
408          } else {          } else {
409            !!!parse-error (type => 'bare stago');            !!!parse-error (type => 'bare stago');
410            $self->{state} = 'data';            $self->{state} = DATA_STATE;
411            ## reconsume            ## reconsume
412    
413            !!!emit ({type => CHARACTER_TOKEN, data => '<'});            !!!emit ({type => CHARACTER_TOKEN, data => '<'});
# Line 368  sub _get_next_token ($) { Line 417  sub _get_next_token ($) {
417        } else {        } else {
418          die "$0: $self->{content_model} in tag open";          die "$0: $self->{content_model} in tag open";
419        }        }
420      } elsif ($self->{state} eq 'close tag open') {      } elsif ($self->{state} == CLOSE_TAG_OPEN_STATE) {
421        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA        if ($self->{content_model} & CM_LIMITED_MARKUP) { # RCDATA | CDATA
422          if (defined $self->{last_emitted_start_tag_name}) {          if (defined $self->{last_emitted_start_tag_name}) {
423            ## NOTE: <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>            ## NOTE: <http://krijnhoetmer.nl/irc-logs/whatwg/20070626#l-564>
# Line 383  sub _get_next_token ($) { Line 432  sub _get_next_token ($) {
432              } else {              } else {
433                $self->{next_input_character} = shift @next_char; # reconsume                $self->{next_input_character} = shift @next_char; # reconsume
434                !!!back-next-input-character (@next_char);                !!!back-next-input-character (@next_char);
435                $self->{state} = 'data';                $self->{state} = DATA_STATE;
436    
437                !!!emit ({type => CHARACTER_TOKEN, data => '</'});                !!!emit ({type => CHARACTER_TOKEN, data => '</'});
438        
# Line 402  sub _get_next_token ($) { Line 451  sub _get_next_token ($) {
451                    $self->{next_input_character} == -1) {                    $self->{next_input_character} == -1) {
452              $self->{next_input_character} = shift @next_char; # reconsume              $self->{next_input_character} = shift @next_char; # reconsume
453              !!!back-next-input-character (@next_char);              !!!back-next-input-character (@next_char);
454              $self->{state} = 'data';              $self->{state} = DATA_STATE;
455              !!!emit ({type => CHARACTER_TOKEN, data => '</'});              !!!emit ({type => CHARACTER_TOKEN, data => '</'});
456              redo A;              redo A;
457            } else {            } else {
# Line 413  sub _get_next_token ($) { Line 462  sub _get_next_token ($) {
462          } else {          } else {
463            ## No start tag token has ever been emitted            ## No start tag token has ever been emitted
464            # next-input-character is already done            # next-input-character is already done
465            $self->{state} = 'data';            $self->{state} = DATA_STATE;
466            !!!emit ({type => CHARACTER_TOKEN, data => '</'});            !!!emit ({type => CHARACTER_TOKEN, data => '</'});
467            redo A;            redo A;
468          }          }
# Line 423  sub _get_next_token ($) { Line 472  sub _get_next_token ($) {
472            $self->{next_input_character} <= 0x005A) { # A..Z            $self->{next_input_character} <= 0x005A) { # A..Z
473          $self->{current_token} = {type => END_TAG_TOKEN,          $self->{current_token} = {type => END_TAG_TOKEN,
474                            tag_name => chr ($self->{next_input_character} + 0x0020)};                            tag_name => chr ($self->{next_input_character} + 0x0020)};
475          $self->{state} = 'tag name';          $self->{state} = TAG_NAME_STATE;
476          !!!next-input-character;          !!!next-input-character;
477          redo A;          redo A;
478        } elsif (0x0061 <= $self->{next_input_character} and        } elsif (0x0061 <= $self->{next_input_character} and
479                 $self->{next_input_character} <= 0x007A) { # a..z                 $self->{next_input_character} <= 0x007A) { # a..z
480          $self->{current_token} = {type => END_TAG_TOKEN,          $self->{current_token} = {type => END_TAG_TOKEN,
481                            tag_name => chr ($self->{next_input_character})};                            tag_name => chr ($self->{next_input_character})};
482          $self->{state} = 'tag name';          $self->{state} = TAG_NAME_STATE;
483          !!!next-input-character;          !!!next-input-character;
484          redo A;          redo A;
485        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
486          !!!parse-error (type => 'empty end tag');          !!!parse-error (type => 'empty end tag');
487          $self->{state} = 'data';          $self->{state} = DATA_STATE;
488          !!!next-input-character;          !!!next-input-character;
489          redo A;          redo A;
490        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
491          !!!parse-error (type => 'bare etago');          !!!parse-error (type => 'bare etago');
492          $self->{state} = 'data';          $self->{state} = DATA_STATE;
493          # reconsume          # reconsume
494    
495          !!!emit ({type => CHARACTER_TOKEN, data => '</'});          !!!emit ({type => CHARACTER_TOKEN, data => '</'});
# Line 448  sub _get_next_token ($) { Line 497  sub _get_next_token ($) {
497          redo A;          redo A;
498        } else {        } else {
499          !!!parse-error (type => 'bogus end tag');          !!!parse-error (type => 'bogus end tag');
500          $self->{state} = 'bogus comment';          $self->{state} = BOGUS_COMMENT_STATE;
501          ## $self->{next_input_character} is intentionally left as is          ## $self->{next_input_character} is intentionally left as is
502          redo A;          redo A;
503        }        }
504      } elsif ($self->{state} eq 'tag name') {      } elsif ($self->{state} == TAG_NAME_STATE) {
505        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
506            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
507            $self->{next_input_character} == 0x000B or # VT            $self->{next_input_character} == 0x000B or # VT
508            $self->{next_input_character} == 0x000C or # FF            $self->{next_input_character} == 0x000C or # FF
509            $self->{next_input_character} == 0x0020) { # SP            $self->{next_input_character} == 0x0020) { # SP
510          $self->{state} = 'before attribute name';          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
511          !!!next-input-character;          !!!next-input-character;
512          redo A;          redo A;
513        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
# Line 474  sub _get_next_token ($) { Line 523  sub _get_next_token ($) {
523          } else {          } else {
524            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
525          }          }
526          $self->{state} = 'data';          $self->{state} = DATA_STATE;
527          !!!next-input-character;          !!!next-input-character;
528    
529          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 501  sub _get_next_token ($) { Line 550  sub _get_next_token ($) {
550          } else {          } else {
551            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
552          }          }
553          $self->{state} = 'data';          $self->{state} = DATA_STATE;
554          # reconsume          # reconsume
555    
556          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 517  sub _get_next_token ($) { Line 566  sub _get_next_token ($) {
566          } else {          } else {
567            !!!parse-error (type => 'nestc');            !!!parse-error (type => 'nestc');
568          }          }
569          $self->{state} = 'before attribute name';          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
570          # next-input-character is already done          # next-input-character is already done
571          redo A;          redo A;
572        } else {        } else {
# Line 527  sub _get_next_token ($) { Line 576  sub _get_next_token ($) {
576          !!!next-input-character;          !!!next-input-character;
577          redo A;          redo A;
578        }        }
579      } elsif ($self->{state} eq 'before attribute name') {      } elsif ($self->{state} == BEFORE_ATTRIBUTE_NAME_STATE) {
580        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
581            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
582            $self->{next_input_character} == 0x000B or # VT            $self->{next_input_character} == 0x000B or # VT
# Line 549  sub _get_next_token ($) { Line 598  sub _get_next_token ($) {
598          } else {          } else {
599            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
600          }          }
601          $self->{state} = 'data';          $self->{state} = DATA_STATE;
602          !!!next-input-character;          !!!next-input-character;
603    
604          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 559  sub _get_next_token ($) { Line 608  sub _get_next_token ($) {
608                 $self->{next_input_character} <= 0x005A) { # A..Z                 $self->{next_input_character} <= 0x005A) { # A..Z
609          $self->{current_attribute} = {name => chr ($self->{next_input_character} + 0x0020),          $self->{current_attribute} = {name => chr ($self->{next_input_character} + 0x0020),
610                                value => ''};                                value => ''};
611          $self->{state} = 'attribute name';          $self->{state} = ATTRIBUTE_NAME_STATE;
612          !!!next-input-character;          !!!next-input-character;
613          redo A;          redo A;
614        } elsif ($self->{next_input_character} == 0x002F) { # /        } elsif ($self->{next_input_character} == 0x002F) { # /
# Line 589  sub _get_next_token ($) { Line 638  sub _get_next_token ($) {
638          } else {          } else {
639            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
640          }          }
641          $self->{state} = 'data';          $self->{state} = DATA_STATE;
642          # reconsume          # reconsume
643    
644          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 598  sub _get_next_token ($) { Line 647  sub _get_next_token ($) {
647        } else {        } else {
648          $self->{current_attribute} = {name => chr ($self->{next_input_character}),          $self->{current_attribute} = {name => chr ($self->{next_input_character}),
649                                value => ''};                                value => ''};
650          $self->{state} = 'attribute name';          $self->{state} = ATTRIBUTE_NAME_STATE;
651          !!!next-input-character;          !!!next-input-character;
652          redo A;          redo A;
653        }        }
654      } elsif ($self->{state} eq 'attribute name') {      } elsif ($self->{state} == ATTRIBUTE_NAME_STATE) {
655        my $before_leave = sub {        my $before_leave = sub {
656          if (exists $self->{current_token}->{attributes} # start tag or end tag          if (exists $self->{current_token}->{attributes} # start tag or end tag
657              ->{$self->{current_attribute}->{name}}) { # MUST              ->{$self->{current_attribute}->{name}}) { # MUST
# Line 620  sub _get_next_token ($) { Line 669  sub _get_next_token ($) {
669            $self->{next_input_character} == 0x000C or # FF            $self->{next_input_character} == 0x000C or # FF
670            $self->{next_input_character} == 0x0020) { # SP            $self->{next_input_character} == 0x0020) { # SP
671          $before_leave->();          $before_leave->();
672          $self->{state} = 'after attribute name';          $self->{state} = AFTER_ATTRIBUTE_NAME_STATE;
673          !!!next-input-character;          !!!next-input-character;
674          redo A;          redo A;
675        } elsif ($self->{next_input_character} == 0x003D) { # =        } elsif ($self->{next_input_character} == 0x003D) { # =
676          $before_leave->();          $before_leave->();
677          $self->{state} = 'before attribute value';          $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;
678          !!!next-input-character;          !!!next-input-character;
679          redo A;          redo A;
680        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
# Line 642  sub _get_next_token ($) { Line 691  sub _get_next_token ($) {
691          } else {          } else {
692            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
693          }          }
694          $self->{state} = 'data';          $self->{state} = DATA_STATE;
695          !!!next-input-character;          !!!next-input-character;
696    
697          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 665  sub _get_next_token ($) { Line 714  sub _get_next_token ($) {
714          } else {          } else {
715            !!!parse-error (type => 'nestc');            !!!parse-error (type => 'nestc');
716          }          }
717          $self->{state} = 'before attribute name';          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
718          # next-input-character is already done          # next-input-character is already done
719          redo A;          redo A;
720        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
# Line 683  sub _get_next_token ($) { Line 732  sub _get_next_token ($) {
732          } else {          } else {
733            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
734          }          }
735          $self->{state} = 'data';          $self->{state} = DATA_STATE;
736          # reconsume          # reconsume
737    
738          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 695  sub _get_next_token ($) { Line 744  sub _get_next_token ($) {
744          !!!next-input-character;          !!!next-input-character;
745          redo A;          redo A;
746        }        }
747      } elsif ($self->{state} eq 'after attribute name') {      } elsif ($self->{state} == AFTER_ATTRIBUTE_NAME_STATE) {
748        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
749            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
750            $self->{next_input_character} == 0x000B or # VT            $self->{next_input_character} == 0x000B or # VT
# Line 705  sub _get_next_token ($) { Line 754  sub _get_next_token ($) {
754          !!!next-input-character;          !!!next-input-character;
755          redo A;          redo A;
756        } elsif ($self->{next_input_character} == 0x003D) { # =        } elsif ($self->{next_input_character} == 0x003D) { # =
757          $self->{state} = 'before attribute value';          $self->{state} = BEFORE_ATTRIBUTE_VALUE_STATE;
758          !!!next-input-character;          !!!next-input-character;
759          redo A;          redo A;
760        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
# Line 721  sub _get_next_token ($) { Line 770  sub _get_next_token ($) {
770          } else {          } else {
771            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
772          }          }
773          $self->{state} = 'data';          $self->{state} = DATA_STATE;
774          !!!next-input-character;          !!!next-input-character;
775    
776          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 731  sub _get_next_token ($) { Line 780  sub _get_next_token ($) {
780                 $self->{next_input_character} <= 0x005A) { # A..Z                 $self->{next_input_character} <= 0x005A) { # A..Z
781          $self->{current_attribute} = {name => chr ($self->{next_input_character} + 0x0020),          $self->{current_attribute} = {name => chr ($self->{next_input_character} + 0x0020),
782                                value => ''};                                value => ''};
783          $self->{state} = 'attribute name';          $self->{state} = ATTRIBUTE_NAME_STATE;
784          !!!next-input-character;          !!!next-input-character;
785          redo A;          redo A;
786        } elsif ($self->{next_input_character} == 0x002F) { # /        } elsif ($self->{next_input_character} == 0x002F) { # /
# Line 745  sub _get_next_token ($) { Line 794  sub _get_next_token ($) {
794            !!!parse-error (type => 'nestc');            !!!parse-error (type => 'nestc');
795            ## TODO: Different error type for <aa / bb> than <aa/>            ## TODO: Different error type for <aa / bb> than <aa/>
796          }          }
797          $self->{state} = 'before attribute name';          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
798          # next-input-character is already done          # next-input-character is already done
799          redo A;          redo A;
800        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
# Line 762  sub _get_next_token ($) { Line 811  sub _get_next_token ($) {
811          } else {          } else {
812            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
813          }          }
814          $self->{state} = 'data';          $self->{state} = DATA_STATE;
815          # reconsume          # reconsume
816    
817          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 771  sub _get_next_token ($) { Line 820  sub _get_next_token ($) {
820        } else {        } else {
821          $self->{current_attribute} = {name => chr ($self->{next_input_character}),          $self->{current_attribute} = {name => chr ($self->{next_input_character}),
822                                value => ''};                                value => ''};
823          $self->{state} = 'attribute name';          $self->{state} = ATTRIBUTE_NAME_STATE;
824          !!!next-input-character;          !!!next-input-character;
825          redo A;                  redo A;        
826        }        }
827      } elsif ($self->{state} eq 'before attribute value') {      } elsif ($self->{state} == BEFORE_ATTRIBUTE_VALUE_STATE) {
828        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
829            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
830            $self->{next_input_character} == 0x000B or # VT            $self->{next_input_character} == 0x000B or # VT
# Line 785  sub _get_next_token ($) { Line 834  sub _get_next_token ($) {
834          !!!next-input-character;          !!!next-input-character;
835          redo A;          redo A;
836        } elsif ($self->{next_input_character} == 0x0022) { # "        } elsif ($self->{next_input_character} == 0x0022) { # "
837          $self->{state} = 'attribute value (double-quoted)';          $self->{state} = ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE;
838          !!!next-input-character;          !!!next-input-character;
839          redo A;          redo A;
840        } elsif ($self->{next_input_character} == 0x0026) { # &        } elsif ($self->{next_input_character} == 0x0026) { # &
841          $self->{state} = 'attribute value (unquoted)';          $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;
842          ## reconsume          ## reconsume
843          redo A;          redo A;
844        } elsif ($self->{next_input_character} == 0x0027) { # '        } elsif ($self->{next_input_character} == 0x0027) { # '
845          $self->{state} = 'attribute value (single-quoted)';          $self->{state} = ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE;
846          !!!next-input-character;          !!!next-input-character;
847          redo A;          redo A;
848        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
# Line 809  sub _get_next_token ($) { Line 858  sub _get_next_token ($) {
858          } else {          } else {
859            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
860          }          }
861          $self->{state} = 'data';          $self->{state} = DATA_STATE;
862          !!!next-input-character;          !!!next-input-character;
863    
864          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 829  sub _get_next_token ($) { Line 878  sub _get_next_token ($) {
878          } else {          } else {
879            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
880          }          }
881          $self->{state} = 'data';          $self->{state} = DATA_STATE;
882          ## reconsume          ## reconsume
883    
884          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 837  sub _get_next_token ($) { Line 886  sub _get_next_token ($) {
886          redo A;          redo A;
887        } else {        } else {
888          $self->{current_attribute}->{value} .= chr ($self->{next_input_character});          $self->{current_attribute}->{value} .= chr ($self->{next_input_character});
889          $self->{state} = 'attribute value (unquoted)';          $self->{state} = ATTRIBUTE_VALUE_UNQUOTED_STATE;
890          !!!next-input-character;          !!!next-input-character;
891          redo A;          redo A;
892        }        }
893      } elsif ($self->{state} eq 'attribute value (double-quoted)') {      } elsif ($self->{state} == ATTRIBUTE_VALUE_DOUBLE_QUOTED_STATE) {
894        if ($self->{next_input_character} == 0x0022) { # "        if ($self->{next_input_character} == 0x0022) { # "
895          $self->{state} = 'before attribute name';          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
896          !!!next-input-character;          !!!next-input-character;
897          redo A;          redo A;
898        } elsif ($self->{next_input_character} == 0x0026) { # &        } elsif ($self->{next_input_character} == 0x0026) { # &
899          $self->{last_attribute_value_state} = 'attribute value (double-quoted)';          $self->{last_attribute_value_state} = $self->{state};
900          $self->{state} = 'entity in attribute value';          $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
901          !!!next-input-character;          !!!next-input-character;
902          redo A;          redo A;
903        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
# Line 865  sub _get_next_token ($) { Line 914  sub _get_next_token ($) {
914          } else {          } else {
915            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
916          }          }
917          $self->{state} = 'data';          $self->{state} = DATA_STATE;
918          ## reconsume          ## reconsume
919    
920          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 877  sub _get_next_token ($) { Line 926  sub _get_next_token ($) {
926          !!!next-input-character;          !!!next-input-character;
927          redo A;          redo A;
928        }        }
929      } elsif ($self->{state} eq 'attribute value (single-quoted)') {      } elsif ($self->{state} == ATTRIBUTE_VALUE_SINGLE_QUOTED_STATE) {
930        if ($self->{next_input_character} == 0x0027) { # '        if ($self->{next_input_character} == 0x0027) { # '
931          $self->{state} = 'before attribute name';          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
932          !!!next-input-character;          !!!next-input-character;
933          redo A;          redo A;
934        } elsif ($self->{next_input_character} == 0x0026) { # &        } elsif ($self->{next_input_character} == 0x0026) { # &
935          $self->{last_attribute_value_state} = 'attribute value (single-quoted)';          $self->{last_attribute_value_state} = $self->{state};
936          $self->{state} = 'entity in attribute value';          $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
937          !!!next-input-character;          !!!next-input-character;
938          redo A;          redo A;
939        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
# Line 901  sub _get_next_token ($) { Line 950  sub _get_next_token ($) {
950          } else {          } else {
951            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
952          }          }
953          $self->{state} = 'data';          $self->{state} = DATA_STATE;
954          ## reconsume          ## reconsume
955    
956          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 913  sub _get_next_token ($) { Line 962  sub _get_next_token ($) {
962          !!!next-input-character;          !!!next-input-character;
963          redo A;          redo A;
964        }        }
965      } elsif ($self->{state} eq 'attribute value (unquoted)') {      } elsif ($self->{state} == ATTRIBUTE_VALUE_UNQUOTED_STATE) {
966        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
967            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
968            $self->{next_input_character} == 0x000B or # HT            $self->{next_input_character} == 0x000B or # HT
969            $self->{next_input_character} == 0x000C or # FF            $self->{next_input_character} == 0x000C or # FF
970            $self->{next_input_character} == 0x0020) { # SP            $self->{next_input_character} == 0x0020) { # SP
971          $self->{state} = 'before attribute name';          $self->{state} = BEFORE_ATTRIBUTE_NAME_STATE;
972          !!!next-input-character;          !!!next-input-character;
973          redo A;          redo A;
974        } elsif ($self->{next_input_character} == 0x0026) { # &        } elsif ($self->{next_input_character} == 0x0026) { # &
975          $self->{last_attribute_value_state} = 'attribute value (unquoted)';          $self->{last_attribute_value_state} = $self->{state};
976          $self->{state} = 'entity in attribute value';          $self->{state} = ENTITY_IN_ATTRIBUTE_VALUE_STATE;
977          !!!next-input-character;          !!!next-input-character;
978          redo A;          redo A;
979        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
# Line 940  sub _get_next_token ($) { Line 989  sub _get_next_token ($) {
989          } else {          } else {
990            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
991          }          }
992          $self->{state} = 'data';          $self->{state} = DATA_STATE;
993          !!!next-input-character;          !!!next-input-character;
994    
995          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 960  sub _get_next_token ($) { Line 1009  sub _get_next_token ($) {
1009          } else {          } else {
1010            die "$0: $self->{current_token}->{type}: Unknown token type";            die "$0: $self->{current_token}->{type}: Unknown token type";
1011          }          }
1012          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1013          ## reconsume          ## reconsume
1014    
1015          !!!emit ($self->{current_token}); # start tag or end tag          !!!emit ($self->{current_token}); # start tag or end tag
# Line 972  sub _get_next_token ($) { Line 1021  sub _get_next_token ($) {
1021          !!!next-input-character;          !!!next-input-character;
1022          redo A;          redo A;
1023        }        }
1024      } elsif ($self->{state} eq 'entity in attribute value') {      } elsif ($self->{state} == ENTITY_IN_ATTRIBUTE_VALUE_STATE) {
1025        my $token = $self->_tokenize_attempt_to_consume_an_entity (1);        my $token = $self->_tokenize_attempt_to_consume_an_entity (1);
1026    
1027        unless (defined $token) {        unless (defined $token) {
# Line 985  sub _get_next_token ($) { Line 1034  sub _get_next_token ($) {
1034        $self->{state} = $self->{last_attribute_value_state};        $self->{state} = $self->{last_attribute_value_state};
1035        # next-input-character is already done        # next-input-character is already done
1036        redo A;        redo A;
1037      } elsif ($self->{state} eq 'bogus comment') {      } elsif ($self->{state} == BOGUS_COMMENT_STATE) {
1038        ## (only happen if PCDATA state)        ## (only happen if PCDATA state)
1039                
1040        my $token = {type => COMMENT_TOKEN, data => ''};        my $token = {type => COMMENT_TOKEN, data => ''};
1041    
1042        BC: {        BC: {
1043          if ($self->{next_input_character} == 0x003E) { # >          if ($self->{next_input_character} == 0x003E) { # >
1044            $self->{state} = 'data';            $self->{state} = DATA_STATE;
1045            !!!next-input-character;            !!!next-input-character;
1046    
1047            !!!emit ($token);            !!!emit ($token);
1048    
1049            redo A;            redo A;
1050          } elsif ($self->{next_input_character} == -1) {          } elsif ($self->{next_input_character} == -1) {
1051            $self->{state} = 'data';            $self->{state} = DATA_STATE;
1052            ## reconsume            ## reconsume
1053    
1054            !!!emit ($token);            !!!emit ($token);
# Line 1011  sub _get_next_token ($) { Line 1060  sub _get_next_token ($) {
1060            redo BC;            redo BC;
1061          }          }
1062        } # BC        } # BC
1063      } elsif ($self->{state} eq 'markup declaration open') {      } elsif ($self->{state} == MARKUP_DECLARATION_OPEN_STATE) {
1064        ## (only happen if PCDATA state)        ## (only happen if PCDATA state)
1065    
1066        my @next_char;        my @next_char;
# Line 1022  sub _get_next_token ($) { Line 1071  sub _get_next_token ($) {
1071          push @next_char, $self->{next_input_character};          push @next_char, $self->{next_input_character};
1072          if ($self->{next_input_character} == 0x002D) { # -          if ($self->{next_input_character} == 0x002D) { # -
1073            $self->{current_token} = {type => COMMENT_TOKEN, data => ''};            $self->{current_token} = {type => COMMENT_TOKEN, data => ''};
1074            $self->{state} = 'comment start';            $self->{state} = COMMENT_START_STATE;
1075            !!!next-input-character;            !!!next-input-character;
1076            redo A;            redo A;
1077          }          }
# Line 1053  sub _get_next_token ($) { Line 1102  sub _get_next_token ($) {
1102                    if ($self->{next_input_character} == 0x0045 or # E                    if ($self->{next_input_character} == 0x0045 or # E
1103                        $self->{next_input_character} == 0x0065) { # e                        $self->{next_input_character} == 0x0065) { # e
1104                      ## ISSUE: What a stupid code this is!                      ## ISSUE: What a stupid code this is!
1105                      $self->{state} = 'DOCTYPE';                      $self->{state} = DOCTYPE_STATE;
1106                      !!!next-input-character;                      !!!next-input-character;
1107                      redo A;                      redo A;
1108                    }                    }
# Line 1067  sub _get_next_token ($) { Line 1116  sub _get_next_token ($) {
1116        !!!parse-error (type => 'bogus comment');        !!!parse-error (type => 'bogus comment');
1117        $self->{next_input_character} = shift @next_char;        $self->{next_input_character} = shift @next_char;
1118        !!!back-next-input-character (@next_char);        !!!back-next-input-character (@next_char);
1119        $self->{state} = 'bogus comment';        $self->{state} = BOGUS_COMMENT_STATE;
1120        redo A;        redo A;
1121                
1122        ## ISSUE: typos in spec: chacacters, is is a parse error        ## ISSUE: typos in spec: chacacters, is is a parse error
1123        ## ISSUE: spec is somewhat unclear on "is the first character that will be in the comment"; what is "that will be in the comment" is what the algorithm defines, isn't it?        ## ISSUE: spec is somewhat unclear on "is the first character that will be in the comment"; what is "that will be in the comment" is what the algorithm defines, isn't it?
1124      } elsif ($self->{state} eq 'comment start') {      } elsif ($self->{state} == COMMENT_START_STATE) {
1125        if ($self->{next_input_character} == 0x002D) { # -        if ($self->{next_input_character} == 0x002D) { # -
1126          $self->{state} = 'comment start dash';          $self->{state} = COMMENT_START_DASH_STATE;
1127          !!!next-input-character;          !!!next-input-character;
1128          redo A;          redo A;
1129        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
1130          !!!parse-error (type => 'bogus comment');          !!!parse-error (type => 'bogus comment');
1131          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1132          !!!next-input-character;          !!!next-input-character;
1133    
1134          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{current_token}); # comment
# Line 1087  sub _get_next_token ($) { Line 1136  sub _get_next_token ($) {
1136          redo A;          redo A;
1137        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1138          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1139          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1140          ## reconsume          ## reconsume
1141    
1142          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{current_token}); # comment
# Line 1096  sub _get_next_token ($) { Line 1145  sub _get_next_token ($) {
1145        } else {        } else {
1146          $self->{current_token}->{data} # comment          $self->{current_token}->{data} # comment
1147              .= chr ($self->{next_input_character});              .= chr ($self->{next_input_character});
1148          $self->{state} = 'comment';          $self->{state} = COMMENT_STATE;
1149          !!!next-input-character;          !!!next-input-character;
1150          redo A;          redo A;
1151        }        }
1152      } elsif ($self->{state} eq 'comment start dash') {      } elsif ($self->{state} == COMMENT_START_DASH_STATE) {
1153        if ($self->{next_input_character} == 0x002D) { # -        if ($self->{next_input_character} == 0x002D) { # -
1154          $self->{state} = 'comment end';          $self->{state} = COMMENT_END_STATE;
1155          !!!next-input-character;          !!!next-input-character;
1156          redo A;          redo A;
1157        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
1158          !!!parse-error (type => 'bogus comment');          !!!parse-error (type => 'bogus comment');
1159          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1160          !!!next-input-character;          !!!next-input-character;
1161    
1162          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{current_token}); # comment
# Line 1115  sub _get_next_token ($) { Line 1164  sub _get_next_token ($) {
1164          redo A;          redo A;
1165        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1166          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1167          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1168          ## reconsume          ## reconsume
1169    
1170          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{current_token}); # comment
# Line 1124  sub _get_next_token ($) { Line 1173  sub _get_next_token ($) {
1173        } else {        } else {
1174          $self->{current_token}->{data} # comment          $self->{current_token}->{data} # comment
1175              .= '-' . chr ($self->{next_input_character});              .= '-' . chr ($self->{next_input_character});
1176          $self->{state} = 'comment';          $self->{state} = COMMENT_STATE;
1177          !!!next-input-character;          !!!next-input-character;
1178          redo A;          redo A;
1179        }        }
1180      } elsif ($self->{state} eq 'comment') {      } elsif ($self->{state} == COMMENT_STATE) {
1181        if ($self->{next_input_character} == 0x002D) { # -        if ($self->{next_input_character} == 0x002D) { # -
1182          $self->{state} = 'comment end dash';          $self->{state} = COMMENT_END_DASH_STATE;
1183          !!!next-input-character;          !!!next-input-character;
1184          redo A;          redo A;
1185        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1186          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1187          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1188          ## reconsume          ## reconsume
1189    
1190          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{current_token}); # comment
# Line 1147  sub _get_next_token ($) { Line 1196  sub _get_next_token ($) {
1196          !!!next-input-character;          !!!next-input-character;
1197          redo A;          redo A;
1198        }        }
1199      } elsif ($self->{state} eq 'comment end dash') {      } elsif ($self->{state} == COMMENT_END_DASH_STATE) {
1200        if ($self->{next_input_character} == 0x002D) { # -        if ($self->{next_input_character} == 0x002D) { # -
1201          $self->{state} = 'comment end';          $self->{state} = COMMENT_END_STATE;
1202          !!!next-input-character;          !!!next-input-character;
1203          redo A;          redo A;
1204        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1205          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1206          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1207          ## reconsume          ## reconsume
1208    
1209          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{current_token}); # comment
# Line 1162  sub _get_next_token ($) { Line 1211  sub _get_next_token ($) {
1211          redo A;          redo A;
1212        } else {        } else {
1213          $self->{current_token}->{data} .= '-' . chr ($self->{next_input_character}); # comment          $self->{current_token}->{data} .= '-' . chr ($self->{next_input_character}); # comment
1214          $self->{state} = 'comment';          $self->{state} = COMMENT_STATE;
1215          !!!next-input-character;          !!!next-input-character;
1216          redo A;          redo A;
1217        }        }
1218      } elsif ($self->{state} eq 'comment end') {      } elsif ($self->{state} == COMMENT_END_STATE) {
1219        if ($self->{next_input_character} == 0x003E) { # >        if ($self->{next_input_character} == 0x003E) { # >
1220          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1221          !!!next-input-character;          !!!next-input-character;
1222    
1223          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{current_token}); # comment
# Line 1182  sub _get_next_token ($) { Line 1231  sub _get_next_token ($) {
1231          redo A;          redo A;
1232        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1233          !!!parse-error (type => 'unclosed comment');          !!!parse-error (type => 'unclosed comment');
1234          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1235          ## reconsume          ## reconsume
1236    
1237          !!!emit ($self->{current_token}); # comment          !!!emit ($self->{current_token}); # comment
# Line 1191  sub _get_next_token ($) { Line 1240  sub _get_next_token ($) {
1240        } else {        } else {
1241          !!!parse-error (type => 'dash in comment');          !!!parse-error (type => 'dash in comment');
1242          $self->{current_token}->{data} .= '--' . chr ($self->{next_input_character}); # comment          $self->{current_token}->{data} .= '--' . chr ($self->{next_input_character}); # comment
1243          $self->{state} = 'comment';          $self->{state} = COMMENT_STATE;
1244          !!!next-input-character;          !!!next-input-character;
1245          redo A;          redo A;
1246        }        }
1247      } elsif ($self->{state} eq 'DOCTYPE') {      } elsif ($self->{state} == DOCTYPE_STATE) {
1248        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
1249            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
1250            $self->{next_input_character} == 0x000B or # VT            $self->{next_input_character} == 0x000B or # VT
1251            $self->{next_input_character} == 0x000C or # FF            $self->{next_input_character} == 0x000C or # FF
1252            $self->{next_input_character} == 0x0020) { # SP            $self->{next_input_character} == 0x0020) { # SP
1253          $self->{state} = 'before DOCTYPE name';          $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
1254          !!!next-input-character;          !!!next-input-character;
1255          redo A;          redo A;
1256        } else {        } else {
1257          !!!parse-error (type => 'no space before DOCTYPE name');          !!!parse-error (type => 'no space before DOCTYPE name');
1258          $self->{state} = 'before DOCTYPE name';          $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
1259          ## reconsume          ## reconsume
1260          redo A;          redo A;
1261        }        }
1262      } elsif ($self->{state} eq 'before DOCTYPE name') {      } elsif ($self->{state} == BEFORE_DOCTYPE_NAME_STATE) {
1263        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
1264            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
1265            $self->{next_input_character} == 0x000B or # VT            $self->{next_input_character} == 0x000B or # VT
# Line 1221  sub _get_next_token ($) { Line 1270  sub _get_next_token ($) {
1270          redo A;          redo A;
1271        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
1272          !!!parse-error (type => 'no DOCTYPE name');          !!!parse-error (type => 'no DOCTYPE name');
1273          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1274          !!!next-input-character;          !!!next-input-character;
1275    
1276          !!!emit ({type => DOCTYPE_TOKEN}); # incorrect          !!!emit ({type => DOCTYPE_TOKEN}); # incorrect
# Line 1229  sub _get_next_token ($) { Line 1278  sub _get_next_token ($) {
1278          redo A;          redo A;
1279        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1280          !!!parse-error (type => 'no DOCTYPE name');          !!!parse-error (type => 'no DOCTYPE name');
1281          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1282          ## reconsume          ## reconsume
1283    
1284          !!!emit ({type => DOCTYPE_TOKEN}); # incorrect          !!!emit ({type => DOCTYPE_TOKEN}); # incorrect
# Line 1241  sub _get_next_token ($) { Line 1290  sub _get_next_token ($) {
1290                 name => chr ($self->{next_input_character}),                 name => chr ($self->{next_input_character}),
1291                 correct => 1};                 correct => 1};
1292  ## ISSUE: "Set the token's name name to the" in the spec  ## ISSUE: "Set the token's name name to the" in the spec
1293          $self->{state} = 'DOCTYPE name';          $self->{state} = DOCTYPE_NAME_STATE;
1294          !!!next-input-character;          !!!next-input-character;
1295          redo A;          redo A;
1296        }        }
1297      } elsif ($self->{state} eq 'DOCTYPE name') {      } elsif ($self->{state} == DOCTYPE_NAME_STATE) {
1298  ## ISSUE: Redundant "First," in the spec.  ## ISSUE: Redundant "First," in the spec.
1299        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
1300            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
1301            $self->{next_input_character} == 0x000B or # VT            $self->{next_input_character} == 0x000B or # VT
1302            $self->{next_input_character} == 0x000C or # FF            $self->{next_input_character} == 0x000C or # FF
1303            $self->{next_input_character} == 0x0020) { # SP            $self->{next_input_character} == 0x0020) { # SP
1304          $self->{state} = 'after DOCTYPE name';          $self->{state} = AFTER_DOCTYPE_NAME_STATE;
1305          !!!next-input-character;          !!!next-input-character;
1306          redo A;          redo A;
1307        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
1308          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1309          !!!next-input-character;          !!!next-input-character;
1310    
1311          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{current_token}); # DOCTYPE
# Line 1264  sub _get_next_token ($) { Line 1313  sub _get_next_token ($) {
1313          redo A;          redo A;
1314        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1315          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
1316          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1317          ## reconsume          ## reconsume
1318    
1319          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1278  sub _get_next_token ($) { Line 1327  sub _get_next_token ($) {
1327          !!!next-input-character;          !!!next-input-character;
1328          redo A;          redo A;
1329        }        }
1330      } elsif ($self->{state} eq 'after DOCTYPE name') {      } elsif ($self->{state} == AFTER_DOCTYPE_NAME_STATE) {
1331        if ($self->{next_input_character} == 0x0009 or # HT        if ($self->{next_input_character} == 0x0009 or # HT
1332            $self->{next_input_character} == 0x000A or # LF            $self->{next_input_character} == 0x000A or # LF
1333            $self->{next_input_character} == 0x000B or # VT            $self->{next_input_character} == 0x000B or # VT
# Line 1288  sub _get_next_token ($) { Line 1337  sub _get_next_token ($) {
1337          !!!next-input-character;          !!!next-input-character;
1338          redo A;          redo A;
1339        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
1340          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1341          !!!next-input-character;          !!!next-input-character;
1342    
1343          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{current_token}); # DOCTYPE
# Line 1296  sub _get_next_token ($) { Line 1345  sub _get_next_token ($) {
1345          redo A;          redo A;
1346        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1347          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
1348          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1349          ## reconsume          ## reconsume
1350    
1351          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1320  sub _get_next_token ($) { Line 1369  sub _get_next_token ($) {
1369                  !!!next-input-character;                  !!!next-input-character;
1370                  if ($self->{next_input_character} == 0x0043 or # C                  if ($self->{next_input_character} == 0x0043 or # C
1371                      $self->{next_input_character} == 0x0063) { # c                      $self->{next_input_character} == 0x0063) { # c
1372                    $self->{state} = 'before DOCTYPE public identifier';                    $self->{state} = BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
1373                    !!!next-input-character;                    !!!next-input-character;
1374                    redo A;                    redo A;
1375                  }                  }
# Line 1347  sub _get_next_token ($) { Line 1396  sub _get_next_token ($) {
1396                  !!!next-input-character;                  !!!next-input-character;
1397                  if ($self->{next_input_character} == 0x004D or # M                  if ($self->{next_input_character} == 0x004D or # M
1398                      $self->{next_input_character} == 0x006D) { # m                      $self->{next_input_character} == 0x006D) { # m
1399                    $self->{state} = 'before DOCTYPE system identifier';                    $self->{state} = BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
1400                    !!!next-input-character;                    !!!next-input-character;
1401                    redo A;                    redo A;
1402                  }                  }
# Line 1363  sub _get_next_token ($) { Line 1412  sub _get_next_token ($) {
1412        }        }
1413    
1414        !!!parse-error (type => 'string after DOCTYPE name');        !!!parse-error (type => 'string after DOCTYPE name');
1415        $self->{state} = 'bogus DOCTYPE';        $self->{state} = BOGUS_DOCTYPE_STATE;
1416        # next-input-character is already done        # next-input-character is already done
1417        redo A;        redo A;
1418      } elsif ($self->{state} eq 'before DOCTYPE public identifier') {      } elsif ($self->{state} == BEFORE_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {
1419        if ({        if ({
1420              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
1421              #0x000D => 1, # HT, LF, VT, FF, SP, CR              #0x000D => 1, # HT, LF, VT, FF, SP, CR
# Line 1376  sub _get_next_token ($) { Line 1425  sub _get_next_token ($) {
1425          redo A;          redo A;
1426        } elsif ($self->{next_input_character} eq 0x0022) { # "        } elsif ($self->{next_input_character} eq 0x0022) { # "
1427          $self->{current_token}->{public_identifier} = ''; # DOCTYPE          $self->{current_token}->{public_identifier} = ''; # DOCTYPE
1428          $self->{state} = 'DOCTYPE public identifier (double-quoted)';          $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE;
1429          !!!next-input-character;          !!!next-input-character;
1430          redo A;          redo A;
1431        } elsif ($self->{next_input_character} eq 0x0027) { # '        } elsif ($self->{next_input_character} eq 0x0027) { # '
1432          $self->{current_token}->{public_identifier} = ''; # DOCTYPE          $self->{current_token}->{public_identifier} = ''; # DOCTYPE
1433          $self->{state} = 'DOCTYPE public identifier (single-quoted)';          $self->{state} = DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE;
1434          !!!next-input-character;          !!!next-input-character;
1435          redo A;          redo A;
1436        } elsif ($self->{next_input_character} eq 0x003E) { # >        } elsif ($self->{next_input_character} eq 0x003E) { # >
1437          !!!parse-error (type => 'no PUBLIC literal');          !!!parse-error (type => 'no PUBLIC literal');
1438    
1439          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1440          !!!next-input-character;          !!!next-input-character;
1441    
1442          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1397  sub _get_next_token ($) { Line 1446  sub _get_next_token ($) {
1446        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1447          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
1448    
1449          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1450          ## reconsume          ## reconsume
1451    
1452          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1406  sub _get_next_token ($) { Line 1455  sub _get_next_token ($) {
1455          redo A;          redo A;
1456        } else {        } else {
1457          !!!parse-error (type => 'string after PUBLIC');          !!!parse-error (type => 'string after PUBLIC');
1458          $self->{state} = 'bogus DOCTYPE';          $self->{state} = BOGUS_DOCTYPE_STATE;
1459          !!!next-input-character;          !!!next-input-character;
1460          redo A;          redo A;
1461        }        }
1462      } elsif ($self->{state} eq 'DOCTYPE public identifier (double-quoted)') {      } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED_STATE) {
1463        if ($self->{next_input_character} == 0x0022) { # "        if ($self->{next_input_character} == 0x0022) { # "
1464          $self->{state} = 'after DOCTYPE public identifier';          $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
1465          !!!next-input-character;          !!!next-input-character;
1466          redo A;          redo A;
1467        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1468          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
1469    
1470          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1471          ## reconsume          ## reconsume
1472    
1473          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1432  sub _get_next_token ($) { Line 1481  sub _get_next_token ($) {
1481          !!!next-input-character;          !!!next-input-character;
1482          redo A;          redo A;
1483        }        }
1484      } elsif ($self->{state} eq 'DOCTYPE public identifier (single-quoted)') {      } elsif ($self->{state} == DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED_STATE) {
1485        if ($self->{next_input_character} == 0x0027) { # '        if ($self->{next_input_character} == 0x0027) { # '
1486          $self->{state} = 'after DOCTYPE public identifier';          $self->{state} = AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE;
1487          !!!next-input-character;          !!!next-input-character;
1488          redo A;          redo A;
1489        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1490          !!!parse-error (type => 'unclosed PUBLIC literal');          !!!parse-error (type => 'unclosed PUBLIC literal');
1491    
1492          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1493          ## reconsume          ## reconsume
1494    
1495          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1454  sub _get_next_token ($) { Line 1503  sub _get_next_token ($) {
1503          !!!next-input-character;          !!!next-input-character;
1504          redo A;          redo A;
1505        }        }
1506      } elsif ($self->{state} eq 'after DOCTYPE public identifier') {      } elsif ($self->{state} == AFTER_DOCTYPE_PUBLIC_IDENTIFIER_STATE) {
1507        if ({        if ({
1508              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
1509              #0x000D => 1, # HT, LF, VT, FF, SP, CR              #0x000D => 1, # HT, LF, VT, FF, SP, CR
# Line 1464  sub _get_next_token ($) { Line 1513  sub _get_next_token ($) {
1513          redo A;          redo A;
1514        } elsif ($self->{next_input_character} == 0x0022) { # "        } elsif ($self->{next_input_character} == 0x0022) { # "
1515          $self->{current_token}->{system_identifier} = ''; # DOCTYPE          $self->{current_token}->{system_identifier} = ''; # DOCTYPE
1516          $self->{state} = 'DOCTYPE system identifier (double-quoted)';          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
1517          !!!next-input-character;          !!!next-input-character;
1518          redo A;          redo A;
1519        } elsif ($self->{next_input_character} == 0x0027) { # '        } elsif ($self->{next_input_character} == 0x0027) { # '
1520          $self->{current_token}->{system_identifier} = ''; # DOCTYPE          $self->{current_token}->{system_identifier} = ''; # DOCTYPE
1521          $self->{state} = 'DOCTYPE system identifier (single-quoted)';          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
1522          !!!next-input-character;          !!!next-input-character;
1523          redo A;          redo A;
1524        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
1525          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1526          !!!next-input-character;          !!!next-input-character;
1527    
1528          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{current_token}); # DOCTYPE
# Line 1482  sub _get_next_token ($) { Line 1531  sub _get_next_token ($) {
1531        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1532          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
1533    
1534          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1535          ## reconsume          ## reconsume
1536    
1537          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1491  sub _get_next_token ($) { Line 1540  sub _get_next_token ($) {
1540          redo A;          redo A;
1541        } else {        } else {
1542          !!!parse-error (type => 'string after PUBLIC literal');          !!!parse-error (type => 'string after PUBLIC literal');
1543          $self->{state} = 'bogus DOCTYPE';          $self->{state} = BOGUS_DOCTYPE_STATE;
1544          !!!next-input-character;          !!!next-input-character;
1545          redo A;          redo A;
1546        }        }
1547      } elsif ($self->{state} eq 'before DOCTYPE system identifier') {      } elsif ($self->{state} == BEFORE_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {
1548        if ({        if ({
1549              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
1550              #0x000D => 1, # HT, LF, VT, FF, SP, CR              #0x000D => 1, # HT, LF, VT, FF, SP, CR
# Line 1505  sub _get_next_token ($) { Line 1554  sub _get_next_token ($) {
1554          redo A;          redo A;
1555        } elsif ($self->{next_input_character} == 0x0022) { # "        } elsif ($self->{next_input_character} == 0x0022) { # "
1556          $self->{current_token}->{system_identifier} = ''; # DOCTYPE          $self->{current_token}->{system_identifier} = ''; # DOCTYPE
1557          $self->{state} = 'DOCTYPE system identifier (double-quoted)';          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
1558          !!!next-input-character;          !!!next-input-character;
1559          redo A;          redo A;
1560        } elsif ($self->{next_input_character} == 0x0027) { # '        } elsif ($self->{next_input_character} == 0x0027) { # '
1561          $self->{current_token}->{system_identifier} = ''; # DOCTYPE          $self->{current_token}->{system_identifier} = ''; # DOCTYPE
1562          $self->{state} = 'DOCTYPE system identifier (single-quoted)';          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
1563          !!!next-input-character;          !!!next-input-character;
1564          redo A;          redo A;
1565        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
1566          !!!parse-error (type => 'no SYSTEM literal');          !!!parse-error (type => 'no SYSTEM literal');
1567          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1568          !!!next-input-character;          !!!next-input-character;
1569    
1570          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1525  sub _get_next_token ($) { Line 1574  sub _get_next_token ($) {
1574        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1575          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
1576    
1577          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1578          ## reconsume          ## reconsume
1579    
1580          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1534  sub _get_next_token ($) { Line 1583  sub _get_next_token ($) {
1583          redo A;          redo A;
1584        } else {        } else {
1585          !!!parse-error (type => 'string after SYSTEM');          !!!parse-error (type => 'string after SYSTEM');
1586          $self->{state} = 'bogus DOCTYPE';          $self->{state} = BOGUS_DOCTYPE_STATE;
1587          !!!next-input-character;          !!!next-input-character;
1588          redo A;          redo A;
1589        }        }
1590      } elsif ($self->{state} eq 'DOCTYPE system identifier (double-quoted)') {      } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE) {
1591        if ($self->{next_input_character} == 0x0022) { # "        if ($self->{next_input_character} == 0x0022) { # "
1592          $self->{state} = 'after DOCTYPE system identifier';          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
1593          !!!next-input-character;          !!!next-input-character;
1594          redo A;          redo A;
1595        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1596          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
1597    
1598          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1599          ## reconsume          ## reconsume
1600    
1601          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1560  sub _get_next_token ($) { Line 1609  sub _get_next_token ($) {
1609          !!!next-input-character;          !!!next-input-character;
1610          redo A;          redo A;
1611        }        }
1612      } elsif ($self->{state} eq 'DOCTYPE system identifier (single-quoted)') {      } elsif ($self->{state} == DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE) {
1613        if ($self->{next_input_character} == 0x0027) { # '        if ($self->{next_input_character} == 0x0027) { # '
1614          $self->{state} = 'after DOCTYPE system identifier';          $self->{state} = AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE;
1615          !!!next-input-character;          !!!next-input-character;
1616          redo A;          redo A;
1617        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1618          !!!parse-error (type => 'unclosed SYSTEM literal');          !!!parse-error (type => 'unclosed SYSTEM literal');
1619    
1620          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1621          ## reconsume          ## reconsume
1622    
1623          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1582  sub _get_next_token ($) { Line 1631  sub _get_next_token ($) {
1631          !!!next-input-character;          !!!next-input-character;
1632          redo A;          redo A;
1633        }        }
1634      } elsif ($self->{state} eq 'after DOCTYPE system identifier') {      } elsif ($self->{state} == AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {
1635        if ({        if ({
1636              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,              0x0009 => 1, 0x000A => 1, 0x000B => 1, 0x000C => 1, 0x0020 => 1,
1637              #0x000D => 1, # HT, LF, VT, FF, SP, CR              #0x000D => 1, # HT, LF, VT, FF, SP, CR
# Line 1591  sub _get_next_token ($) { Line 1640  sub _get_next_token ($) {
1640          !!!next-input-character;          !!!next-input-character;
1641          redo A;          redo A;
1642        } elsif ($self->{next_input_character} == 0x003E) { # >        } elsif ($self->{next_input_character} == 0x003E) { # >
1643          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1644          !!!next-input-character;          !!!next-input-character;
1645    
1646          !!!emit ($self->{current_token}); # DOCTYPE          !!!emit ($self->{current_token}); # DOCTYPE
# Line 1600  sub _get_next_token ($) { Line 1649  sub _get_next_token ($) {
1649        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1650          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
1651    
1652          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1653          ## reconsume          ## reconsume
1654    
1655          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1609  sub _get_next_token ($) { Line 1658  sub _get_next_token ($) {
1658          redo A;          redo A;
1659        } else {        } else {
1660          !!!parse-error (type => 'string after SYSTEM literal');          !!!parse-error (type => 'string after SYSTEM literal');
1661          $self->{state} = 'bogus DOCTYPE';          $self->{state} = BOGUS_DOCTYPE_STATE;
1662          !!!next-input-character;          !!!next-input-character;
1663          redo A;          redo A;
1664        }        }
1665      } elsif ($self->{state} eq 'bogus DOCTYPE') {      } elsif ($self->{state} == BOGUS_DOCTYPE_STATE) {
1666        if ($self->{next_input_character} == 0x003E) { # >        if ($self->{next_input_character} == 0x003E) { # >
1667          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1668          !!!next-input-character;          !!!next-input-character;
1669    
1670          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 1624  sub _get_next_token ($) { Line 1673  sub _get_next_token ($) {
1673          redo A;          redo A;
1674        } elsif ($self->{next_input_character} == -1) {        } elsif ($self->{next_input_character} == -1) {
1675          !!!parse-error (type => 'unclosed DOCTYPE');          !!!parse-error (type => 'unclosed DOCTYPE');
1676          $self->{state} = 'data';          $self->{state} = DATA_STATE;
1677          ## reconsume          ## reconsume
1678    
1679          delete $self->{current_token}->{correct};          delete $self->{current_token}->{correct};
# Line 2057  sub _tree_construction_root_element ($) Line 2106  sub _tree_construction_root_element ($)
2106        } else {        } else {
2107          die "$0: $token->{type}: Unknown token type";          die "$0: $token->{type}: Unknown token type";
2108        }        }
2109          ## TODO: application cache selection algorithm
2110        my $root_element; !!!create-element ($root_element, 'html');        my $root_element; !!!create-element ($root_element, 'html');
2111        $self->{document}->append_child ($root_element);        $self->{document}->append_child ($root_element);
2112        push @{$self->{open_elements}}, [$root_element, 'html'];        push @{$self->{open_elements}}, [$root_element, 'html'];
# Line 3302  sub _tree_construction_main ($) { Line 3352  sub _tree_construction_main ($) {
3352        $insert = $insert_to_current;        $insert = $insert_to_current;
3353        #        #
3354      } elsif ($self->{insertion_mode} & TABLE_IMS) {      } elsif ($self->{insertion_mode} & TABLE_IMS) {
3355            if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
             ## NOTE: There are "character in table" code clones.  
3356              if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {              if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
3357                $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);                $self->{open_elements}->[-1]->[0]->manakai_append_text ($1);
3358                                
# Line 3360  sub _tree_construction_main ($) { Line 3409  sub _tree_construction_main ($) {
3409                            
3410              !!!next-token;              !!!next-token;
3411              redo B;              redo B;
3412            } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
3413              if ({              if ({
3414                   tr => ($self->{insertion_mode} != IN_ROW_IM),                   tr => ($self->{insertion_mode} != IN_ROW_IM),
3415                   th => 1, td => 1,                   th => 1, td => 1,
# Line 3546  sub _tree_construction_main ($) { Line 3595  sub _tree_construction_main ($) {
3595                  die "$0: in table: <>: $token->{tag_name}";                  die "$0: in table: <>: $token->{tag_name}";
3596                }                }
3597              } elsif ($token->{tag_name} eq 'table') {              } elsif ($token->{tag_name} eq 'table') {
               ## NOTE: There are code clones for this "table in table"  
3598                !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
3599    
3600                ## As if </table>                ## As if </table>
# Line 3594  sub _tree_construction_main ($) { Line 3642  sub _tree_construction_main ($) {
3642    
3643                ## reprocess                ## reprocess
3644                redo B;                redo B;
3645              } else {          } else {
3646                #            !!!parse-error (type => 'in table:'.$token->{tag_name});
3647              }  
3648            } elsif ($token->{type} == END_TAG_TOKEN) {            $insert = $insert_to_foster;
3649              #
3650            }
3651          } elsif ($token->{type} == END_TAG_TOKEN) {
3652              if ($token->{tag_name} eq 'tr' and              if ($token->{tag_name} eq 'tr' and
3653                  $self->{insertion_mode} == IN_ROW_IM) {                  $self->{insertion_mode} == IN_ROW_IM) {
3654                ## have an element in table scope                ## have an element in table scope
# Line 3854  sub _tree_construction_main ($) { Line 3905  sub _tree_construction_main ($) {
3905                ## Ignore the token                ## Ignore the token
3906                !!!next-token;                !!!next-token;
3907                redo B;                redo B;
3908              } else {          } else {
3909                #            !!!parse-error (type => 'in table:/'.$token->{tag_name});
             }  
           } else {  
             die "$0: $token->{type}: Unknown token type";  
           }  
   
       !!!parse-error (type => 'in table:'.$token->{tag_name});  
3910    
3911        $insert = $insert_to_foster;            $insert = $insert_to_foster;
3912        #            #
3913            }
3914          } else {
3915            die "$0: $token->{type}: Unknown token type";
3916          }
3917      } elsif ($self->{insertion_mode} == IN_COLUMN_GROUP_IM) {      } elsif ($self->{insertion_mode} == IN_COLUMN_GROUP_IM) {
3918            if ($token->{type} == CHARACTER_TOKEN) {            if ($token->{type} == CHARACTER_TOKEN) {
3919              if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {              if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
# Line 3923  sub _tree_construction_main ($) { Line 3972  sub _tree_construction_main ($) {
3972              redo B;              redo B;
3973            }            }
3974      } elsif ($self->{insertion_mode} == IN_SELECT_IM) {      } elsif ($self->{insertion_mode} == IN_SELECT_IM) {
3975            if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
3976              $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});          $self->{open_elements}->[-1]->[0]->manakai_append_text ($token->{data});
3977              !!!next-token;          !!!next-token;
3978              redo B;          redo B;
3979            } elsif ($token->{type} == START_TAG_TOKEN) {        } elsif ($token->{type} == START_TAG_TOKEN) {
3980              if ($token->{tag_name} eq 'option') {              if ($token->{tag_name} eq 'option') {
3981                if ($self->{open_elements}->[-1]->[1] eq 'option') {                if ($self->{open_elements}->[-1]->[1] eq 'option') {
3982                  ## As if </option>                  ## As if </option>
# Line 3980  sub _tree_construction_main ($) { Line 4029  sub _tree_construction_main ($) {
4029    
4030                !!!next-token;                !!!next-token;
4031                redo B;                redo B;
4032              } else {          } else {
4033                #            !!!parse-error (type => 'in select:'.$token->{tag_name});
4034              }            ## Ignore the token
4035            } elsif ($token->{type} == END_TAG_TOKEN) {            !!!next-token;
4036              redo B;
4037            }
4038          } elsif ($token->{type} == END_TAG_TOKEN) {
4039              if ($token->{tag_name} eq 'optgroup') {              if ($token->{tag_name} eq 'optgroup') {
4040                if ($self->{open_elements}->[-1]->[1] eq 'option' and                if ($self->{open_elements}->[-1]->[1] eq 'option' and
4041                    $self->{open_elements}->[-2]->[1] eq 'optgroup') {                    $self->{open_elements}->[-2]->[1] eq 'optgroup') {
# Line 4085  sub _tree_construction_main ($) { Line 4137  sub _tree_construction_main ($) {
4137    
4138                ## reprocess                ## reprocess
4139                redo B;                redo B;
4140              } else {          } else {
4141                #            !!!parse-error (type => 'in select:/'.$token->{tag_name});
             }  
           } else {  
             #  
           }  
   
           !!!parse-error (type => 'in select:'.$token->{tag_name});  
4142            ## Ignore the token            ## Ignore the token
4143            !!!next-token;            !!!next-token;
4144            redo B;            redo B;
4145            }
4146          } else {
4147            die "$0: $token->{type}: Unknown token type";
4148          }
4149      } elsif ($self->{insertion_mode} & BODY_AFTER_IMS) {      } elsif ($self->{insertion_mode} & BODY_AFTER_IMS) {
4150        if ($token->{type} == CHARACTER_TOKEN) {        if ($token->{type} == CHARACTER_TOKEN) {
4151          if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {          if ($token->{data} =~ s/^([\x09\x0A\x0B\x0C\x20]+)//) {
# Line 4626  sub _tree_construction_main ($) { Line 4676  sub _tree_construction_main ($) {
4676          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {          INSCOPE: for (reverse 0..$#{$self->{open_elements}}) {
4677            my $node = $self->{open_elements}->[$_];            my $node = $self->{open_elements}->[$_];
4678            if ($node->[1] eq 'nobr') {            if ($node->[1] eq 'nobr') {
4679              !!!parse-error (type => 'not closed:nobr');              !!!parse-error (type => 'in nobr:nobr');
4680              !!!back-token;              !!!back-token;
4681              $token = {type => END_TAG_TOKEN, tag_name => 'nobr'};              $token = {type => END_TAG_TOKEN, tag_name => 'nobr'};
4682              redo B;              redo B;
# Line 4831  sub _tree_construction_main ($) { Line 4881  sub _tree_construction_main ($) {
4881                  noframes => 1,                  noframes => 1,
4882                  noscript => 0, ## TODO: 1 if scripting is enabled                  noscript => 0, ## TODO: 1 if scripting is enabled
4883                 }->{$token->{tag_name}}) {                 }->{$token->{tag_name}}) {
4884          ## NOTE: There are two "as if in body" code clones.          ## NOTE: There is an "as if in body" code clone.
4885          $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);          $parse_rcdata->(CDATA_CONTENT_MODEL, $insert);
4886          redo B;          redo B;
4887        } elsif ($token->{tag_name} eq 'select') {        } elsif ($token->{tag_name} eq 'select') {
# Line 4987  sub _tree_construction_main ($) { Line 5037  sub _tree_construction_main ($) {
5037          if ($self->{open_elements}->[-1]->[1] eq $token->{tag_name}) {          if ($self->{open_elements}->[-1]->[1] eq $token->{tag_name}) {
5038            pop @{$self->{open_elements}};            pop @{$self->{open_elements}};
5039          } else {          } else {
5040            !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});
5041          }          }
5042    
5043          undef $self->{form_element};          undef $self->{form_element};
# Line 5025  sub _tree_construction_main ($) { Line 5075  sub _tree_construction_main ($) {
5075          } # INSCOPE          } # INSCOPE
5076                    
5077          if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {          if ($self->{open_elements}->[-1]->[1] ne $token->{tag_name}) {
5078            !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);            !!!parse-error (type => 'unmatched end tag:'.$token->{tag_name});
5079          }          }
5080                    
5081          splice @{$self->{open_elements}}, $i if defined $i;          splice @{$self->{open_elements}}, $i if defined $i;
# Line 5094  sub _tree_construction_main ($) { Line 5144  sub _tree_construction_main ($) {
5144                    
5145              ## Step 2              ## Step 2
5146              if ($token->{tag_name} ne $self->{open_elements}->[-1]->[1]) {              if ($token->{tag_name} ne $self->{open_elements}->[-1]->[1]) {
5147                  ## NOTE: <x><y></x>
5148                !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);                !!!parse-error (type => 'not closed:'.$self->{open_elements}->[-1]->[1]);
5149              }              }
5150                            

Legend:
Removed from v.1.56  
changed lines
  Added in v.1.60

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24