123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053(* This file is part of Markup.ml, released under the MIT license. See
LICENSE.md for details, or visit https://github.com/aantron/markup.ml. *)openCommontypetoken=[`Xmlofxml_declaration|`Doctypeofdoctype|`StartofToken_tag.t|`EndofToken_tag.t|`Charsofstringlist|`PIofstring*string|`Commentofstring|`EOF]letis_name_start_charc=is_in_range0x00410x005Ac||is_in_range0x00610x007Ac||c=0x003A||c=0x005F||is_in_range0x00C00x00D6c||is_in_range0x00D80x00F6c||is_in_range0x00F80x02FFc||is_in_range0x03700x037Dc||is_in_range0x037F0x1FFFc||is_in_range0x200C0x200Dc||is_in_range0x20700x218Fc||is_in_range0x2C000x2FEFc||is_in_range0x30010xD7EFc||is_in_range0xF9000xFDCFc||is_in_range0xFDF00xFFFDc||is_in_range0x100000xEFFFFcletis_name_charc=is_name_start_charc||is_in_range0x00300x0039c||c=0x002D||c=0x002E||c=0x00B7||is_in_range0x03000x036Fc||is_in_range0x203F0x2040cletresolve_builtin_reference=function|"quot"->Some"\""|"amp"->Some"&"|"apos"->Some"'"|"lt"->Some"<"|"gt"->Some">"|_->NoneopenKstreamopenCommon.Token_taglettokenizereportresolve_reference(input,get_location)=letresolve_references=matchresolve_builtin_referenceswith|Some_asv->v|None->resolve_referencesinletreport_if=Error.report_ifreportinletthrow=ref(fun_->())inletended=ref(fun_->())inletoutput=ref(fun_->())inletparse_referencel'k=letinput,restore=checkpointinputinletunresolved()=restore();kNoneinletks=k(Somes)inletunexpected_eoi()=report(get_location())(`Unexpected_eoi"reference")!throw(fun()->unresolved())inletcharacter_referencefilternotation_prefixreference_prefix=letbuffer=Buffer.create32inletrecread()=nextinput!throwunexpected_eoibeginfunction|_,0x003B->ifBuffer.lengthbuffer=0thenreportl'(`Bad_token(Printf.sprintf"&#%s;"reference_prefix,"reference","empty character reference"))!throwunresolvedelselets=Buffer.contentsbufferinletmaybe_n=trySome(int_of_string(notation_prefix^s))withFailure_->Noneinbeginmatchmaybe_nwith|None->reportl'(`Bad_token(Printf.sprintf"&#%s%s;"reference_prefixs,"reference","number out of range"))!throwunresolved|Somen->letutf_8_encoded=Buffer.create8inadd_utf_8utf_8_encodedn;k(Buffer.contentsutf_8_encoded)end|_,cwhenfilterc->add_utf_8bufferc;read()|l,c->reportl(`Bad_token(charc,"reference","expected digit"))!throwunresolvedendinread()innextinput!throwunexpected_eoibeginfunction|_,0x003B->reportl'(`Bad_token("&;","reference","empty reference"))!throwunresolved|_,0x0023->nextinput!throwunexpected_eoibeginfunction|_,0x0078->character_referenceis_hex_digit"0x""x"|_,casvwhenis_digitc||c=0x003B->pushinputv;character_referenceis_digit""""|l,c->reportl(`Bad_token(charc,"reference","expected digit"))!throwunresolvedend|_,cwhenis_name_start_charc->letbuffer=Buffer.create32inadd_utf_8bufferc;letrecread()=nextinput!throwunexpected_eoibeginfunction|_,0x003B->lets=Buffer.contentsbufferinbeginmatchresolve_referenceswith|Somes->ks|None->reportl'(`Bad_token(s,"reference","unknown entity"))!throwunresolvedend|_,cwhenis_name_charc->add_utf_8bufferc;read()|l,c->reportl(`Bad_token(charc,"reference","invalid name character"))!throwunresolvedendinread()|l,c->reportl(`Bad_token(charc,"reference","invalid start character"))!throwunresolvedendinletextra_whitespacewherelck=reportl(`Bad_token(charc,where,"whitespace not allowed here"))!throwkinletrecconsume_whitespacek=nextinput!throwk(function|_,cwhenis_whitespacec->consume_whitespacek|v->pushinputv;k())inletparse_attributewith_referencesterminatorslk'=letname_buffer=Buffer.create32inletvalue_buffer=Buffer.create256inletquote_opened=reffalseinletquote_closed=reffalseinletfinish()=ifBuffer.lengthname_buffer=0thenk'Noneelseletemit()=k'(Some(Buffer.contentsname_buffer,Buffer.contentsvalue_buffer))inif!quote_openedthenifnot!quote_closedthenreport(get_location())(`Unexpected_eoi"attribute value")!throwemitelseemit()elseifBuffer.lengthvalue_buffer=0thenreportl(`Bad_token(Buffer.contentsname_buffer,"attribute","has no value"))!throwemitelseemit()inletnext'f=nextinput!throwfinishbeginfunction|_,casvwhenList.memcterminators->pushinputv;finish();|v->fvendinletrecname_start_state()=next'beginfunction|l,c->report_if(not@@is_name_start_charc)l(fun()->`Bad_token(charc,"attribute","invalid start character"))!throw(fun()->add_utf_8name_bufferc;name_state())endandname_state()=next'beginfunction|_,0x003D->value_state()|l,cwhenis_whitespacec->extra_whitespace"attribute"lc(fun()->consume_whitespaceequals_state)|l,c->report_if(not@@is_name_charc)l(fun()->`Bad_token(charc,"attribute","invalid name character"))!throw(fun()->add_utf_8name_bufferc;name_state())endandequals_state()=next'beginfunction|_,0x003D->value_state()|v->pushinputv;finish()endandvalue_state()=next'beginfunction|l,cwhenis_whitespacec->extra_whitespace"attribute"lc(fun()->consume_whitespacevalue_state)|_,(0x0022|0x0027asc)->quote_opened:=true;quoted_value_statec|l,casv->pushinputv;reportl(`Bad_token(charc,"attribute","unquoted value"))!throwunquoted_value_stateendandhandle_ampersandlstate=parse_referencelbeginfunction|Somes->Buffer.add_stringvalue_buffers;state()|None->reportl(`Bad_token("&","attribute","replace with '&'"))!throw(fun()->add_utf_8value_buffer0x0026;state())endandhandle_ltlstate=reportl(`Bad_token("<","attribute","replace with '<'"))!throw(fun()->add_utf_8value_buffer0x003C;state())andquoted_value_statequote=nextinput!throwfinishbeginfunction|_,cwhenc=quote->quote_closed:=true;finish()|l,0x0026whenwith_references->handle_ampersandl(fun()->quoted_value_statequote)|l,0x003C->handle_ltl(fun()->quoted_value_statequote)|_,c->add_utf_8value_bufferc;quoted_value_statequoteendandunquoted_value_state()=next'beginfunction|_,casvwhenis_whitespacec->pushinputv;finish()|l,0x0026whenwith_references->handle_ampersandlunquoted_value_state|l,0x003C->handle_ltlunquoted_value_state|_,c->add_utf_8value_bufferc;unquoted_value_state()endinname_start_state()inletparse_declaration_or_processing_instructionlk=letpi="processing instruction"inletxml="xml declaration"inlettarget_buffer=Buffer.create32inlettext_buffer=Buffer.create512inletattributes=ref[]inletnext'contextfinishf=letrecinitial_state()=nextinput!throw(fun()->report(get_location())(`Unexpected_eoicontext)!throwfinish)beginfunction|l,0x003F->question_mark_statel|v->fvendandquestion_mark_statel=nextinput!throw(fun()->report(get_location())(`Unexpected_eoicontext)!throwfinish)beginfunction|_,0x003E->finish()|v->pushinputv;f(l,0x003F)endininitial_state()inletrectarget_start_state()=next'pifinish_pibeginfunction|l,cwhenis_whitespacec->extra_whitespacepilc(fun()->consume_whitespacetarget_start_state)|l,c->report_if(not@@is_name_start_charc)l(fun()->`Bad_token(charc,pi,"invalid start character"))!throw(fun()->add_utf_8target_bufferc;target_state())endandtarget_state()=next'pifinish_pibeginfunction|_,cwhenis_whitespacec->ifString.lowercase_ascii(Buffer.contentstarget_buffer)="xml"thenxml_declaration_state()elsetext_state()|l,c->report_if(not@@is_name_charc)l(fun()->`Bad_token(charc,pi,"invalid name character"))!throw(fun()->add_utf_8target_bufferc;target_state())endandtext_state()=next'pifinish_pi(fun(_,c)->add_utf_8text_bufferc;text_state())andxml_declaration_state()=next'xmlfinish_xmlbeginfunction|_,cwhenis_whitespacec->xml_declaration_state()|_,0x003F->xml_declaration_state()|l,_asv->pushinputv;parse_attributefalse[0x003F]l(function|None->xml_declaration_state()|Some(name,value)->attributes:=(l,name,value)::!attributes;xml_declaration_state())endandfinish_pi()=ifBuffer.lengthtarget_buffer=0thenreportl(`Bad_token("<?...",pi,"empty"))!throw(fun()->kNone)elseifString.lowercase_ascii(Buffer.contentstarget_buffer)="xml"thenfinish_xml()elsek(Some(`PI(Buffer.contentstarget_buffer,Buffer.contentstext_buffer)))andfinish_xml()=letsplitfl=letrecscanprefix=function|x::suffixwhenfx->Some(List.revprefix,x,suffix)|x::suffix->scan(x::prefix)suffix|[]->Noneinscan[]linletmatchess(_,name,_)=String.lowercase_asciiname=sinletversion_valids=String.lengths=3&&s.[0]='1'&&s.[1]='.'&&is_digit(Char.codes.[2])inletreccheck_nameattributes=lettarget=Buffer.contentstarget_bufferinreport_if(target<>"xml")l(fun()->`Bad_token(target,xml,"must be 'xml'"))!throw(fun()->version_stateattributes)andversion_stateattributes=matchsplit(matches"version")attributeswith|None->reportl(`Bad_token("<?xml...",xml,"missing version"))!throw(fun()->encoding_state"1.0"attributes)|Some(prefix,(l,name,value),suffix)->report_if(name<>"version")l(fun()->`Bad_token(name,xml,"must be 'version'"))!throw(fun()->report_if(List.lengthprefix<>0)l(fun()->`Bad_token(name,xml,"must be first"))!throw(fun()->report_if(not@@version_validvalue)l(fun()->`Bad_token(value,xml,"must match 1.x"))!throw(fun()->encoding_statevalue(prefix@suffix))))andencoding_stateversionattributes=matchsplit(matches"encoding")attributeswith|None->standalone_stateversionNone0attributes|Some(prefix,(l,name,value),suffix)->report_if(name<>"encoding")l(fun()->`Bad_token(name,xml,"must be 'encoding'"))!throw(fun()->standalone_stateversion(Somevalue)(List.lengthprefix)(prefix@suffix))andstandalone_stateversionencodingencoding_indexattributes=matchsplit(matches"standalone")attributeswith|None->final_stateversionencodingNoneattributes|Some(prefix,(l,name,value),suffix)->report_if(name<>"standalone")l(fun()->`Bad_token(name,xml,"must be 'standalone'"))!throw(fun()->report_if(List.lengthprefix<encoding_index)l(fun()->`Bad_token(name,xml,"must come after 'encoding'"))!throw(fun()->(funk->matchvaluewith|"yes"->k(Sometrue)|"no"->k(Somefalse)|_->reportl(`Bad_token(value,xml,"must be 'yes' or 'no'"))!throw(fun()->matchString.lowercase_asciivaluewith|"yes"->k(Sometrue)|"no"->k(Somefalse)|_->kNone))(funv->final_stateversionencodingv(prefix@suffix))))andfinal_stateversionencodingstandaloneattributes=(funk->matchattributeswith|(l,name,_)::_->reportl(`Bad_token(name,xml,"not allowed here"))!throwk|[]->k())(fun()->k(Some(`Xml{version;encoding;standalone})))incheck_name(List.rev!attributes)intarget_start_state()inlettext=Text.prepare()inletnote_character_location=Text.note_locationtextinletadd_character=Text.addtextinletadd_string=Text.add_stringtextinletreccurrent_state=refinitial_stateandemit'lts=current_state:=s;!output(l,t)andemit_charsstate=matchText.emittextwith|None->state()|Some(l,strings)->emit'l(`Charsstrings)stateandemitltstate=emit_chars(fun()->emit'ltstate)andemit_eoi?during()=letl=get_location()inemit_chars(fun()->(funk'->matchduringwith|None->k'()|Someproduction->reportl(`Unexpected_eoiproduction)!throwk')(fun()->emit'l`EOF(fun()->!ended())))andemit_startlnameself_closingattributesstate=lettag={name=name;self_closing;attributes=List.revattributes}inemitl(`Starttag)stateandemit_endlnamestate=lettag={name=name;self_closing=false;attributes=[]}inemitl(`Endtag)stateandemit_doctypelbuffers=letdoctype={doctype_name=None;public_identifier=None;system_identifier=None;raw_text=Some(Buffer.contentsbuffer);force_quirks=false}inemitl(`Doctypedoctype)sandlt_in_textlk=reportl(`Bad_token("<","text","replace with '<'"))!throwkandinitial_state()=nextinput!throw(fun()->emit_eoi())beginfunction|l,(0x005Dasc)->add_characterlc;one_bracket_statel|l,0x003C->begin_markup_statel|l,(0x0026asc)->parse_referencel(function|None->reportl(`Bad_token(charc,"text","replace with '&'"))!throw(fun()->add_characterlc;initial_state())|Somes->add_stringls;initial_state())|l,c->add_characterlc;initial_state()endandone_bracket_statel'=next_optioninput!throwbeginfunction|Some(l,(0x005Dasc))->add_characterlc;two_brackets_statel'l|v->push_optioninputv;initial_state()endandtwo_brackets_statel'l''=next_optioninput!throwbeginfunction|Some(l,(0x003Easc))->reportl'(`Bad_token("]]>","text","must end a CDATA section"))!throw(fun()->add_characterlc;initial_state())|Some(l,(0x005Dasc))->add_characterlc;two_brackets_statel''l|v->push_optioninputv;initial_state()endandbegin_markup_statel'=letrecoverv=lt_in_textl'(fun()->add_characterl'0x003C;push_optioninputv;initial_state())innextinput!throw(fun()->report(get_location())(`Unexpected_eoi"tag")!throw(fun()->recoverNone))beginfunction|_,0x0021->comment_cdata_or_doctype_statel'|_,0x003F->parse_declaration_or_processing_instructionl'(function|None->initial_state()|Sometoken->emitl'tokeninitial_state)|_,0x002F->end_tag_statel'|_,cwhenis_name_start_charc->lettag_name_buffer=Buffer.create32inadd_utf_8tag_name_bufferc;start_tag_statel'tag_name_buffer|l,casv->reportl(`Bad_token(charc,"tag","invalid start character"))!throw(fun()->recover(Somev))endandstart_tag_statel'buffer=letrecoverv=lt_in_textl'(fun()->add_characterl'0x003C;add_stringl'(Buffer.contentsbuffer);push_optioninputv;initial_state())innextinput!throw(fun()->report(get_location())(`Unexpected_eoi"tag")!throw(fun()->recoverNone))beginfunction|_,0x003E->emit_startl'(Buffer.contentsbuffer)false[]initial_state|l,0x002F->close_empty_element_statel'l(Buffer.contentsbuffer)[]|_,cwhenis_whitespacec->attributes_statel'(Buffer.contentsbuffer)[]|_,cwhenis_name_charc->add_utf_8bufferc;start_tag_statel'buffer|l,casv->reportl(`Bad_token(charc,"tag","invalid name character"))!throw(fun()->recover(Somev))endandattributes_statel'tag_nameattributes=nextinput!throwbeginfun()->emit_startl'tag_namefalseattributes(fun()->emit_eoi~during:"tag"())endbeginfunction|_,cwhenis_whitespacec->attributes_statel'tag_nameattributes|_,0x003E->emit_startl'tag_namefalseattributesinitial_state|l,0x002F->close_empty_element_statel'ltag_nameattributes|l,_asv->pushinputv;parse_attributetrue[0x003E;0x002F]l(function|None->attributes_statel'tag_nameattributes|Some(name,value)->attributes_statel'tag_name((name,value)::attributes))endandclose_empty_element_statel'l''nameattributes=nextinput!throwbeginfun()->emit_startl'nametrueattributes(fun()->emit_eoi~during:"tag"())endbeginfunction|_,0x003E->emit_startl'nametrueattributesinitial_state|v->reportl''(`Bad_token(char0x002F,"tag","should be part of '/>'"))!throw(fun()->pushinputv;attributes_statel'nameattributes)endandend_tag_statel'=letrecoverv=lt_in_textl'(fun()->add_characterl'0x003C;add_characterl'0x002F;push_optioninputv;initial_state())innextinput!throw(fun()->report(get_location())(`Unexpected_eoi"tag")!throw(fun()->recoverNone))beginfunction|_,cwhenis_name_start_charc->letname_buffer=Buffer.create32inadd_utf_8name_bufferc;end_tag_name_statel'name_buffer|l,casv->reportl(`Bad_token(charc,"tag","invalid start character"))!throw(fun()->recover(Somev))endandend_tag_name_statel'buffer=letrecoverv=lt_in_textl'(fun()->add_characterl'0x003C;add_characterl'0x002F;add_stringl'(Buffer.contentsbuffer);push_optioninputv;initial_state())innextinput!throw(fun()->report(get_location())(`Unexpected_eoi"tag")!throw(fun()->recoverNone))beginfunction|_,0x003E->emit_endl'(Buffer.contentsbuffer)initial_state|_,cwhenis_whitespacec->end_tag_whitespace_statefalsel'(Buffer.contentsbuffer)|_,cwhenis_name_charc->add_utf_8bufferc;end_tag_name_statel'buffer|l,casv->reportl(`Bad_token(charc,"tag","invalid name character"))!throw(fun()->recover(Somev))endandend_tag_whitespace_statereportedl'name=nextinput!throwbeginfun()->emit_endl'name(fun()->emit_eoi~during:"tag"())endbeginfunction|_,0x003E->emit_endl'nameinitial_state|_,cwhenis_whitespacec->end_tag_whitespace_statereportedl'name|l,c->ifnotreportedthenreportl(`Bad_token(charc,"tag","attribute in end tag"))!throw(fun()->end_tag_whitespace_statetruel'name)elseend_tag_whitespace_statereportedl'nameendandbad_comment_startslk'=reportl(`Bad_token(s,"comment","should start with '<!--'"))!throw(fun()->lt_in_textlk')andcomment_cdata_or_doctype_statel'=next_optioninput!throwbeginfunction|Some(_,0x002D)->comment_start_statel'|Some(_,0x005B)->cdata_start_statel'|Some(_,0x0044)->doctype_start_statel'|v->bad_comment_start"<!"l'(fun()->add_characterl'0x003C;add_characterl'0x0021;push_optioninputv;initial_state())endandcomment_start_statel'=next_optioninput!throwbeginfunction|Some(_,0x002D)->comment_statel'(Buffer.create256)|v->bad_comment_start"<!-"l'(fun()->add_characterl'0x003C;add_characterl'0x0021;add_characterl'0x002D;push_optioninputv;initial_state())endandunterminated_commentlbuffer=emitl(`Comment(Buffer.contentsbuffer))(fun()->emit_eoi~during:"comment"())andcomment_statel'buffer=nextinput!throw(fun()->unterminated_commentl'buffer)beginfunction|l,0x002D->comment_one_dash_statel'lbuffer|_,c->add_utf_8bufferc;comment_statel'bufferendandcomment_one_dash_statel'l''buffer=nextinput!throw(fun()->unterminated_commentl'buffer)beginfunction|_,0x002D->comment_two_dashes_statefalsel'l''buffer|_,c->add_utf_8buffer0x002D;add_utf_8bufferc;comment_statel'bufferendandcomment_two_dashes_statereportedl'l''buffer=letrecoverk'=ifreportedthenk'()elsereportl''(`Bad_token("--","comment","should be followed by '>'"))!throwk'innextinput!throw(fun()->unterminated_commentl'buffer)beginfunction|_,0x003E->emitl'(`Comment(Buffer.contentsbuffer))initial_state|_,0x002D->recover(fun()->add_utf_8buffer0x002D;comment_two_dashes_statetruel'l''buffer)|_,c->recover(fun()->add_utf_8buffer0x002D;add_utf_8buffer0x002D;add_utf_8bufferc;comment_statel'buffer)endandcdata_start_statel'=next_n6input!throwbeginfunction|[_,0x43;_,0x44;_,0x41;_,0x54;_,0x41;_,0x005B]->note_character_locationl';cdata_statel'|cs->reportl'(`Bad_token("<![","cdata","should start with '<![CDATA['"))!throw(fun()->lt_in_textl'(fun()->push_listinputcs;add_characterl'0x003C;add_characterl'0x0021;add_characterl'0x005B;initial_state()))endandcdata_statel'=nextinput!throw(fun()->emit_eoi~during:"cdata"())beginfunction|l,0x005D->cdata_one_bracket_statel'l|l,c->add_characterlc;cdata_statel'endandcdata_one_bracket_statel'l''=nextinput!throw(fun()->emit_eoi~during:"cdata"())beginfunction|l,0x005D->cdata_two_brackets_statel'l''l|l,c->add_characterl''0x005D;add_characterlc;cdata_statel'endandcdata_two_brackets_statel'l''l'''=nextinput!throw(fun()->emit_eoi~during:"cdata"())beginfunction|_,0x003E->initial_state()|l,0x005D->add_characterl''0x005D;cdata_two_brackets_statel'l'''l|l,c->add_characterl''0x005D;add_characterl'''0x005D;add_characterlc;cdata_statel'endanddoctype_start_statel'=next_n7input!throwbeginfunction|[_,0x4F;_,0x43;_,0x54;_,0x59;_,0x50;_,0x45;_,c]whenis_whitespacec->doctype_statel'(Buffer.create512)|cs->reportl'(`Bad_token("<!D","doctype","should start with '<!DOCTYPE '"))!throw(fun()->lt_in_textl'(fun()->push_listinputcs;add_characterl'0x003C;add_characterl'0x0021;add_characterl'0x0044;initial_state()))endandunterminated_doctypelbuffer=emit_doctypelbuffer(fun()->emit_eoi~during:"doctype"())anddoctype_statel'buffer=nextinput!throw(fun()->unterminated_doctypel'buffer)beginfunction|_,0x003E->emit_doctypel'bufferinitial_state|_,(0x0022|0x0027asc)->add_utf_8bufferc;doctype_quoted_state(fun()->doctype_statel'buffer)cl'buffer|_,(0x003Casc)->add_utf_8bufferc;doctype_item_state(fun()->doctype_statel'buffer)l'buffer|_,c->add_utf_8bufferc;doctype_statel'bufferendanddoctype_quoted_statestatequotel'buffer=nextinput!throw(fun()->unterminated_doctypel'buffer)beginfunction|_,cwhenc=quote->add_utf_8bufferc;state()|_,c->add_utf_8bufferc;doctype_quoted_statestatequotel'bufferendanddoctype_item_statestatel'buffer=nextinput!throw(fun()->unterminated_doctypel'buffer)beginfunction|_,(0x0021asc)->add_utf_8bufferc;doctype_declaration_statestatel'buffer|l,(0x003Fasc)->add_utf_8bufferc;letundo=tap(fun(_,c)->add_utf_8bufferc)inputinparse_declaration_or_processing_instructionl(fun_->undo();state())|_,c->add_utf_8bufferc;state()endanddoctype_declaration_statestatel'buffer=nextinput!throw(fun()->unterminated_doctypel'buffer)beginfunction|_,(0x003Easc)->add_utf_8bufferc;state()|_,(0x0022|0x0027asc)->add_utf_8bufferc;doctype_quoted_state(fun()->doctype_declaration_statestatel'buffer)cl'buffer|_,c->add_utf_8bufferc;doctype_declaration_statestatel'bufferendin(funthrow_ek->throw:=throw_;ended:=e;output:=k;!current_state())|>make