1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848(* 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. *)openCommonopenToken_tagopenKstream(* Namespaces for pattern matching. *)typens=[`HTML|`MathML|`SVG|`Otherofstring]typeqname=ns*stringmoduleNs:sigvalto_string:ns->stringend=structletto_string=function|`HTML->html_ns|`MathML->mathml_ns|`SVG->svg_ns|`Others->send(* Specialization of List.mem at qname list, to avoid polymorphic
comparison. *)letlist_mem_qname((ns,tag):qname)l=letrecloop=function|[]->false|(ns',tag')::_whenns'=ns&&tag'=tag->true|_::rest->looprestinloopl(* Elements. *)typeelement={element_name:qname;location:location;is_html_integration_point:bool;suppress:bool;mutablebuffering:bool;mutableis_open:bool;mutableattributes:(name*string)list;mutableend_location:location;mutablechildren:annotated_nodelist;mutableparent:element}andnode=|Elementofelement|Textofstringlist|PIofstring*string|Commentofstringandannotated_node=location*node(* Element helpers. *)moduleElement:sigvalcreate:?is_html_integration_point:bool->?suppress:bool->qname->location->elementvaldummy:elementvalis_special:qname->boolvalis_not_hidden:Token_tag.t->boolend=structletrecdummy={element_name=`HTML,"dummy";location=1,1;is_html_integration_point=false;suppress=true;buffering=false;is_open=false;attributes=[];end_location=1,1;children=[];parent=dummy}letcreate?(is_html_integration_point=false)?(suppress=false)namelocation={element_name=name;location;is_html_integration_point;suppress;buffering=false;is_open=true;attributes=[];end_location=1,1;children=[];parent=dummy}letis_specialname=list_mem_qnamename[`HTML,"address";`HTML,"applet";`HTML,"area";`HTML,"article";`HTML,"aside";`HTML,"base";`HTML,"basefont";`HTML,"bgsound";`HTML,"blockquote";`HTML,"body";`HTML,"br";`HTML,"button";`HTML,"caption";`HTML,"center";`HTML,"col";`HTML,"colgroup";`HTML,"dd";`HTML,"details";`HTML,"dir";`HTML,"div";`HTML,"dl";`HTML,"dt";`HTML,"embed";`HTML,"fieldset";`HTML,"figcaption";`HTML,"figure";`HTML,"footer";`HTML,"form";`HTML,"frame";`HTML,"frameset";`HTML,"h1";`HTML,"h2";`HTML,"h3";`HTML,"h4";`HTML,"h5";`HTML,"h6";`HTML,"head";`HTML,"header";`HTML,"hgroup";`HTML,"hr";`HTML,"html";`HTML,"iframe";`HTML,"img";`HTML,"input";`HTML,"isindex";`HTML,"li";`HTML,"link";`HTML,"listing";`HTML,"main";`HTML,"marquee";`HTML,"meta";`HTML,"nav";`HTML,"noembed";`HTML,"noframes";`HTML,"noscript";`HTML,"object";`HTML,"ol";`HTML,"p";`HTML,"param";`HTML,"plaintext";`HTML,"pre";`HTML,"script";`HTML,"section";`HTML,"select";`HTML,"source";`HTML,"style";`HTML,"summary";`HTML,"table";`HTML,"tbody";`HTML,"td";`HTML,"template";`HTML,"textarea";`HTML,"tfoot";`HTML,"th";`HTML,"thead";`HTML,"title";`HTML,"tr";`HTML,"track";`HTML,"ul";`HTML,"wbr";`HTML,"xmp";`MathML,"mi";`MathML,"mo";`MathML,"mn";`MathML,"ms";`MathML,"mtext";`MathML,"annotation-xml";`SVG,"foreignObject";`SVG,"desc";`SVG,"title"]letis_not_hiddentag=tag.Token_tag.attributes|>List.exists(fun(name,value)->name="type"&&value<>"hidden")end(* Context detection. *)typesimple_context=[`Document|`Fragmentofstring]typecontext=[`Document|`Fragmentofqname]moduleContext:sigtypetvaluninitialized:unit->tvalinitialize:(location*Html_tokenizer.token)Kstream.t->[<simple_context]option->t->unitcpsvalthe_context:t->contextvalelement:t->elementoptionvaltoken:t->stringoptionend=structletdetecttokensthrowk=lettokens,restore=checkpointtokensinletlast_name=refNoneinletnext_tokenk=next_expectedtokensthrow(funtoken->beginmatchtokenwith|_,`Start{name}->last_name:=Somename|_->()end;ktoken)inletkcontext=restore();k(context,!last_name)inletrecscan()=next_tokenbeginfunction|_,`Doctype_->k`Document|_,`Charcwhennot@@is_whitespacec->k(`Fragment"body")|_,`Char_->scan()|_,`EOF->k(`Fragment"body")|_,`Start{name="html"}->k`Document|_,`Start{name="head"|"body"|"frameset"}->k(`Fragment"html")|_,`Start{name="base"|"basefont"|"bgsound"|"link"|"meta"|"noframes"|"style"|"template"|"title"}->k(`Fragment"head")|_,`Start{name="frame"}->k(`Fragment"frameset")|_,`Start{name="li"}->k(`Fragment"ul")|_,`Start{name="caption"|"col"|"colgroup"|"tbody"|"tfoot"|"thead"}->k(`Fragment"table")|_,`Start{name="tr"}->k(`Fragment"tbody")|_,`Start{name="td"|"th"}->k(`Fragment"tr")|_,`Start{name="optgroup"|"option"}->k(`Fragment"select")|_,`Start{name="altglyph"|"altglyphdef"|"altglyphitem"|"animate"|"animatecolor"|"animatemotion"|"animatetransform"|"circle"|"clippath"|"color-profile"|"cursor"|"defs"|"desc"|"ellipse"|"feblend"|"fecolormatrix"|"fecomponenttransfer"|"fecomposite"|"fediffuselighting"|"fedisplacementmap"|"fedistantlight"|"feflood"|"fefunca"|"fefuncb"|"fefuncg"|"fefuncr"|"fegaussianblur"|"feimage"|"femerge"|"femergenode"|"femorphology"|"feoffset"|"fepointlight"|"fespecularlighting"|"fespotlight"|"fetile"|"feturbulence"|"filter"|"font-face"|"font-face-format"|"font-face-name"|"font-face-src"|"font-face-uri"|"foreignobject"|"g"|"glyph"|"glyphref"|"hkern"|"image"|"line"|"lineargradient"|"marker"|"mask"|"metadata"|"missing-glyph"|"mpath"|"path"|"pattern"|"polygon"|"polyline"|"radialgradient"|"rect"|"set"|"stop"|"switch"|"symbol"|"text"|"textpath"|"tref"|"tspan"|"use"}->k(`Fragment"svg")|_,`Start{name="maction"|"maligngroup"|"malignmark"|"menclose"|"merror"|"mfenced"|"mfrac"|"mglyph"|"mi"|"mlabeledtr"|"mlongdiv"|"mmultiscripts"|"mn"|"mo"|"mover"|"mpadded"|"mphantom"|"mroot"|"mrow"|"ms"|"mscarries"|"mscarry"|"msgroup"|"msline"|"mspace"|"msqrt"|"msrow"|"mstack"|"mstyle"|"msub"|"msup"|"msubsup"|"mtable"|"mtd"|"mtext"|"mtr"|"munder"|"munderover"|"semantics"|"annotation"|"annotation-xml"}->k(`Fragment"math")|_,`Start_->k(`Fragment"body")|_,(`End_|`Comment_)->scan()endinscan()typet=(context*elementoption*stringoption)refletuninitialized()=ref(`Document,None,None)letinitializetokensrequested_contextstatethrowk=(funk->matchrequested_contextwith|Some(`Fragmentelement)->(* HTML element names are case-insensitive, even in foreign content.
Lowercase the element name given by the user before analysis by the
parser, to match this convention. [String.lowercase] is acceptable
here because the API assumes the string [element] is in UTF-8. *)k(`Fragment(String.lowercase_asciielement),None)|Some(`Documentasc)->k(c,None)|None->detecttokensthrowk)(fun(detected_context,deciding_token)->letcontext=matchdetected_contextwith|`Document->`Document|`Fragment"math"->`Fragment(`MathML,"math")|`Fragment"svg"->`Fragment(`SVG,"svg")|`Fragmentname->`Fragment(`HTML,name)inletcontext_element=matchcontextwith|`Document->None|`Fragmentname->letis_html_integration_point=matchnamewith|`SVG,("foreignObject"|"desc"|"title")->true|_->falseinSome(Element.create~is_html_integration_point~suppress:truename(1,1))instate:=context,context_element,deciding_token;k())letthe_context{contents=(c,_,_)}=cletelement{contents=(_,e,_)}=elettoken{contents=(_,_,t)}=tend(* Heplers for foreign content. *)moduleForeign:sigvalis_mathml_text_integration_point:qname->boolvalis_html_integration_point:ns->string->(string*string)list->boolvaladjust_mathml_attributes:((string*string)*string)list->((string*string)*string)listvaladjust_svg_attributes:((string*string)*string)list->((string*string)*string)listvaladjust_svg_tag_name:string->stringend=structletis_mathml_text_integration_pointqname=list_mem_qnameqname[`MathML,"mi";`MathML,"mo";`MathML,"mn";`MathML,"ms";`MathML,"mtext"]letis_html_integration_pointnamespacetag_nameattributes=matchnamespacewith|`HTML|`Other_->false|`MathML->tag_name="annotation-xml"&&attributes|>List.exists(function|"encoding","text/html"->true|"encoding","application/xhtml+xml"->true|_->false)|`SVG->list_mem_stringtag_name["foreignObject";"desc";"title"]letadjust_mathml_attributesattributes=attributes|>List.map(fun((ns,name),value)->letname=ifns=mathml_ns&&name="definitionurl"then"definitionURL"elsenamein(ns,name),value)letadjust_svg_attributesattributes=attributes|>List.map(fun((ns,name),value)->ifns<>svg_nsthen(ns,name),valueelseletname=matchnamewith|"attributename"->"attributeName"|"attributetype"->"attributeType"|"basefrequency"->"baseFrequency"|"baseprofile"->"baseProfile"|"calcmode"->"calcMode"|"clippathunits"->"clipPathUnits"|"contentscripttype"->"contentScriptType"|"contentstyletype"->"contentStyleType"|"diffuseconstant"->"diffuseConstant"|"edgemode"->"edgeMode"|"externalresourcesrequired"->"externalResourcesRequired"|"filterres"->"filterRes"|"filterunits"->"filterUnits"|"glyphref"->"glyphRef"|"gradienttransform"->"gradientTransform"|"gradientunits"->"gradientUnits"|"kernelmatrix"->"kernelMatrix"|"kernelunitlength"->"kernelUnitLength"|"keypoints"->"keyPoints"|"keysplines"->"keySplines"|"keytimes"->"keyTimes"|"lengthadjust"->"lengthAdjust"|"limitingconeangle"->"limitingConeAngle"|"markerheight"->"markerHeight"|"markerunits"->"markerUnits"|"markerwidth"->"markerWidth"|"maskcontentunits"->"maskContentUnits"|"maskunits"->"maskUnits"|"numoctaves"->"numOctaves"|"pathlength"->"pathLength"|"patterncontentunits"->"patternContentUnits"|"patterntransform"->"patternTransform"|"patternunits"->"patternUnits"|"pointsatx"->"pointsAtX"|"pointsaty"->"pointsAtY"|"pointsatz"->"pointsAtZ"|"preservealpha"->"preserveAlpha"|"preserveaspectratio"->"preserveAspectRatio"|"primitiveunits"->"primitiveUnits"|"refx"->"refX"|"refy"->"refY"|"repeatcount"->"repeatCount"|"repeatdur"->"repeatDur"|"requiredextensions"->"requiredExtensions"|"requiredfeatures"->"requiredFeatures"|"specularconstant"->"specularConstant"|"specularexponent"->"specularExponent"|"spreadmethod"->"spreadMethod"|"startoffset"->"startOffset"|"stddeviation"->"stdDeviation"|"stitchtiles"->"stitchTiles"|"surfacescale"->"surfaceScale"|"systemlanguage"->"systemLanguage"|"tablevalues"->"tableValues"|"targetx"->"targetX"|"targety"->"targetY"|"textlength"->"textLength"|"viewbox"->"viewBox"|"viewtarget"->"viewTarget"|"xchannelselector"->"xChannelSelector"|"ychannelselector"->"yChannelSelector"|"zoomandpan"->"zoomAndPan"|_->namein(ns,name),value)letadjust_svg_tag_name=function|"altglyph"->"altGlyph"|"altglyphdef"->"altGlyphDef"|"altglyphitem"->"altGlyphItem"|"animatecolor"->"animateColor"|"animatemotion"->"animateMotion"|"animatetransform"->"animateTransform"|"clippath"->"clipPath"|"feblend"->"feBlend"|"fecolormatrix"->"feColorMatrix"|"fecomponenttransfer"->"feComponentTransfer"|"fecomposite"->"feComposite"|"feconvolvematrix"->"feConvolveMatrix"|"fediffuselighting"->"feDiffuseLighting"|"fedisplacementmap"->"feDisplacementMap"|"fedistantlight"->"feDistantLight"|"fedropshadow"->"feDropShadow"|"feflood"->"feFlood"|"fefunca"->"feFuncA"|"fefuncb"->"feFuncB"|"fefuncg"->"feFuncG"|"fefuncr"->"feFuncR"|"fegaussianblur"->"feGaussianBlur"|"feimage"->"feImage"|"femerge"->"feMerge"|"femergenode"->"feMergeNode"|"femorphology"->"feMorphology"|"feoffset"->"feOffset"|"fepointlight"->"fePointLight"|"fespecularlighting"->"feSpecularLighting"|"fespotlight"->"feSpotLight"|"fetile"->"feTile"|"feturbulence"->"feTurbulence"|"foreignobject"->"foreignObject"|"glyphref"->"glyphRef"|"lineargradient"->"linearGradient"|"radialgradient"->"radialGradient"|"textpath"->"textPath"|s->send(* Stack of open elements. *)moduleStack:sigtypet=elementlistrefvalcreate:unit->tvalcurrent_element:t->elementoptionvalrequire_current_element:t->elementvaladjusted_current_element:Context.t->t->elementoptionvalcurrent_element_is:t->stringlist->boolvalcurrent_element_is_foreign:Context.t->t->boolvalhas:t->string->boolvalin_scope:t->string->boolvalin_button_scope:t->string->boolvalin_list_item_scope:t->string->boolvalin_table_scope:t->string->boolvalin_select_scope:t->string->boolvalone_in_scope:t->stringlist->boolvalone_in_table_scope:t->stringlist->boolvaltarget_in_scope:t->element->boolvalremove:t->element->unitvalreplace:t->old:element->new_:element->unitvalinsert_below:t->anchor:element->new_:element->unitend=structtypet=elementlistrefletcreate()=ref[]letcurrent_elementopen_elements=match!open_elementswith|[]->None|element::_->Someelementletrequire_current_elementopen_elements=matchcurrent_elementopen_elementswith|None->failwith"require_current_element: None"|Someelement->elementletadjusted_current_elementcontextopen_elements=match!open_elements,Context.elementcontextwith|[_],Someelement->Someelement|[],_->None|element::_,_->Someelementletcurrent_element_isopen_elementsnames=match!open_elementswith|{element_name=`HTML,name}::_->list_mem_stringnamenames|_->falseletcurrent_element_is_foreigncontextopen_elements=matchadjusted_current_elementcontextopen_elementswith|Some{element_name=ns,_}whenns<>`HTML->true|_->falselethasopen_elementsname=List.exists(fun{element_name=ns,name'}->ns=`HTML&&name'=name)!open_elementsletin_scope_generalscope_delimitersopen_elementsname'=letrecscan=function|[]->false|{element_name=ns,name''asname}::more->ifns=`HTML&&name''=name'thentrueelseiflist_mem_qnamenamescope_delimitersthenfalseelsescanmoreinscan!open_elementsletscope_delimiters=[`HTML,"applet";`HTML,"caption";`HTML,"html";`HTML,"table";`HTML,"td";`HTML,"th";`HTML,"marquee";`HTML,"object";`HTML,"template";`MathML,"mi";`MathML,"mo";`MathML,"mn";`MathML,"ms";`MathML,"mtext";`MathML,"annotation-xml";`SVG,"foreignObject";`SVG,"desc";`SVG,"title"]letin_scope=in_scope_generalscope_delimitersletin_button_scope=in_scope_general((`HTML,"button")::scope_delimiters)letin_list_item_scope=in_scope_general((`HTML,"ol")::(`HTML,"ul")::scope_delimiters)letin_table_scope=in_scope_general[`HTML,"html";`HTML,"table";`HTML,"template"]letin_select_scopeopen_elementsname=letrecscan=function|[]->false|{element_name=ns,name'}::more->ifns<>`HTMLthenfalseelseifname'=namethentrueelseifname'="optgroup"||name'="option"thenscanmoreelsefalseinscan!open_elementsletone_in_scopeopen_elementsnames=letrecscan=function|[]->false|{element_name=ns,name'asname}::more->ifns=`HTML&&list_mem_stringname'namesthentrueelseiflist_mem_qnamenamescope_delimitersthenfalseelsescanmoreinscan!open_elementsletone_in_table_scopeopen_elementsnames=letrecscan=function|[]->false|{element_name=ns,name'asname}::more->ifns=`HTML&&list_mem_stringname'namesthentrueelseiflist_mem_qnamename[`HTML,"html";`HTML,"table";`HTML,"template"]thenfalseelsescanmoreinscan!open_elementslettarget_in_scopeopen_elementsnode=letrecscan=function|[]->false|e::more->ife==nodethentrueelseiflist_mem_qnamenode.element_namescope_delimitersthenfalseelsescanmoreinscan!open_elementsletremoveopen_elementselement=open_elements:=List.filter((!=)element)!open_elements;element.is_open<-falseletreplaceopen_elements~old~new_=open_elements:=List.map(fune->ife==oldthen(e.is_open<-false;new_)elsee)!open_elementsletinsert_belowopen_elements~anchor~new_=letrecinsertprefix=function|[]->List.revprefix|e::morewhene==anchor->(List.revprefix)@(new_::e::more)|e::more->insert(e::prefix)moreinopen_elements:=insert[]!open_elementsend(* List of active formatting elements. *)moduleActive:sigtypeentry=|Marker|Element_ofelement*location*Token_tag.ttypet=entrylistrefvalcreate:unit->tvaladd_marker:t->unitvalclear_until_marker:t->unitvalhas:t->element->boolvalremove:t->element->unitvalreplace:t->old:element->new_:element->unitvalinsert_after:t->anchor:element->new_:element->unitvalhas_before_marker:t->string->elementoptionend=structtypeentry=|Marker|Element_ofelement*location*Token_tag.ttypet=entrylistrefletcreate()=ref[]letadd_markeractive_formatting_elements=active_formatting_elements:=Marker::!active_formatting_elementsletclear_until_markeractive_formatting_elements=letreciterate=function|Marker::rest->rest|(Element__)::rest->iteraterest|[]->[]inactive_formatting_elements:=iterate!active_formatting_elementslethasactive_formatting_elementselement=!active_formatting_elements|>List.exists(function|Element_(e,_,_)whene==element->true|_->false)letremoveactive_formatting_elementselement=active_formatting_elements:=!active_formatting_elements|>List.filter(function|Element_(e,_,_)whene==element->false|_->true)letreplaceactive_formatting_elements~old~new_=active_formatting_elements:=!active_formatting_elements|>List.map(function|Element_(e,l,t)whene==old->Element_(new_,l,t)|e->e)letinsert_afteractive_formatting_elements~anchor~new_=letrecinsertprefix=function|[]->List.revprefix|(Element_(e,l,t)asv)::morewhene==anchor->letnew_entry=Element_(new_,l,t)in(List.revprefix)@(v::new_entry::more)|v::more->insert(v::prefix)moreinactive_formatting_elements:=insert[]!active_formatting_elementslethas_before_markeractive_formatting_elementsname=letrecscan=function|[]|Marker::_->None|Element_(n,_,_)::_whenn.element_name=(`HTML,name)->Somen|_::more->scanmoreinscan!active_formatting_elementsendtypemode=unit->unit(* Stack of template insertion modes. *)moduleTemplate:sigtypet=modelistrefvalcreate:unit->tvalpush:t->mode->unitvalpop:t->unitend=structtypet=(unit->unit)listrefletcreate()=ref[]letpushtemplate_insertion_modesmode=template_insertion_modes:=mode::!template_insertion_modesletpoptemplate_insertion_modes=match!template_insertion_modeswith|[]->()|_::rest->template_insertion_modes:=restend(* Subtree buffers. HTML specifies the "adoption agency algorithm" for
recovering from certain kinds of errors. This algorithm is (apparently)
incompatible with streaming parsers that do not maintain a DOM - such as
Markup.ml. So, when the Markup.ml parser encounters a situation in which it
may be necessary to later run the adoption agency algorithm, it buffers its
signal output. Instead of being emitted, the signals are used to construct a
DOM subtree. If the algorithm is run, it is run on this subtree. Whenever the
parser can "prove" that the subtree can no longer be involved in the adoption
agency algorithm, it serializes the subtree into the signal stream. In
practice, this means that buffering begins when a formatting element is
encountered, and ends when the parent of the formatting element is popped off
the open element stack. *)moduleSubtree:sigtypetvalcreate:Stack.t->tvalaccumulate:t->location->signal->boolvalenable:t->unitvaldisable:t->(location*signal)listvaladoption_agency_algorithm:t->Active.t->location->string->bool*(location*Error.t)listend=structtypet={open_elements:Stack.t;mutableenabled:bool;mutableposition:element}letcreateopen_elements={open_elements;enabled=false;position=Element.dummy}letaccumulatesubtree_bufferls=ifnotsubtree_buffer.enabledthentrueelsebeginbeginmatchswith|`Start_element(_,attributes)->letparent=subtree_buffer.positioninletchild=Stack.require_current_elementsubtree_buffer.open_elementsinchild.attributes<-attributes;child.parent<-parent;parent.children<-(l,Elementchild)::parent.children;subtree_buffer.position<-child|`End_element->subtree_buffer.position.end_location<-l;subtree_buffer.position<-Stack.require_current_elementsubtree_buffer.open_elements|`Textss->subtree_buffer.position.children<-(l,Textss)::subtree_buffer.position.children|`PI(t,s)->subtree_buffer.position.children<-(l,PI(t,s))::subtree_buffer.position.children|`Comments->subtree_buffer.position.children<-(l,Comments)::subtree_buffer.position.children|`Xml_|`Doctype_->()end;falseendletenablesubtree_buffer=ifsubtree_buffer.enabledthen()elsematchStack.current_elementsubtree_buffer.open_elementswith|None->()|Someelement->element.buffering<-true;subtree_buffer.position<-element;subtree_buffer.enabled<-trueletdisablesubtree_buffer=letrectraverseacc=function|l,Element{element_name;attributes;end_location;children}->letname=Ns.to_string(fstelement_name),sndelement_nameinletstart_signal=l,`Start_element(name,attributes)inletend_signal=end_location,`End_elementinstart_signal::(List.fold_lefttraverse(end_signal::acc)children)|l,Textss->beginmatchaccwith|(_,`Textss')::rest->(l,`Text(ss@ss'))::rest|_->(l,`Textss)::accend|l,PI(t,s)->(l,`PI(t,s))::acc|l,Comments->(l,`Comments)::accinletresult=List.fold_lefttraverse[](Stack.require_current_elementsubtree_buffer.open_elements).childreninsubtree_buffer.enabled<-false;result(* Part of 8.2.5.4.7. *)letadoption_agency_algorithmsubtree_bufferactive_formatting_elementslsubject=letopen_elements=subtree_buffer.open_elementsinletabove_removed_nodes=ref[]inletrecabove_in_stacknode=function|e::e'::_whene==node->e'|_::more->above_in_stacknodemore|[]->failwith"above_in_stack: not found"inletabove_nodenode=ifnode.is_openthenabove_in_stacknode!open_elementselsetryList.find(fun(e,_)->e==node)!above_removed_nodes|>sndwithNot_found->failwith"above_node: not found"inletremove_nodenode=above_removed_nodes:=(node,above_in_stacknode!open_elements)::!above_removed_nodes;Stack.removeopen_elementsnodeinletreparentnodenew_parent=letold_parent=node.parentinletentry,filtered_children=letrecremoveprefix=function|(_,Elementeasentry)::restwhene==node->entry,(List.revprefix)@rest|e::rest->remove(e::prefix)rest|[]->(node.location,Elementnode),old_parent.childreninremove[]old_parent.childreninold_parent.children<-filtered_children;new_parent.children<-entry::new_parent.children;node.parent<-new_parentinletinner_loopformatting_elementfurthest_block=letrecrepeatinner_loop_counternodelast_nodebookmark=letnode=above_nodenodeinifnode==formatting_elementthenlast_node,bookmarkelsebeginifinner_loop_counter>3thenActive.removeactive_formatting_elementsnode;ifnot@@Active.hasactive_formatting_elementsnodethenbeginremove_nodenode;repeat(inner_loop_counter+1)nodelast_nodebookmarkendelsebeginletnew_node={nodewithis_open=true;children=[];parent=Element.dummy}innode.end_location<-l;Stack.replaceopen_elements~old:node~new_:new_node;Active.replaceactive_formatting_elements~old:node~new_:new_node;reparentlast_nodenew_node;repeat(inner_loop_counter+1)new_nodenew_node(iflast_node==furthest_blockthenSomenew_nodeelsebookmark)endendinrepeat1furthest_blockfurthest_blockNoneinletfind_formatting_element()=letrecscan=function|[]->None|Active.Marker::_->None|(Active.Element_({element_name=`HTML,n}ase,_,_))::_whenn=subject->Somee|_::rest->scanrestinscan!active_formatting_elementsinletfind_furthest_blockformatting_element=letrecscanfurthest=function|[]->furthest|e::_whene==formatting_element->furthest|e::morewhenElement.is_speciale.element_name->scan(Somee)more|_::more->scanfurthestmoreinscanNone!open_elementsinletpop_to_formatting_elementformatting_element=letrecpop()=match!open_elementswith|[]->()|e::more->open_elements:=more;e.is_open<-false;e.end_location<-l;ife!=formatting_elementthenpop()inpop();subtree_buffer.position<-Stack.require_current_elementopen_elementsinletrecouter_loopouter_loop_countererrors=letouter_loop_counter=outer_loop_counter+1inifouter_loop_counter>=8thentrue,List.reverrorselsebeginmatchfind_formatting_element()with|None->false,List.reverrors|Someformatting_element->ifnotformatting_element.is_openthenbeginActive.removeactive_formatting_elementsformatting_element;true,List.rev((l,`Unmatched_end_tagsubject)::errors)endelsebeginifnot@@Stack.target_in_scopeopen_elementsformatting_elementthenbegintrue,List.rev((l,`Unmatched_end_tagsubject)::errors)endelsebeginleterrors=ifStack.require_current_elementopen_elements==formatting_elementthenerrorselse(l,`Unmatched_end_tagsubject)::errorsinmatchfind_furthest_blockformatting_elementwith|None->pop_to_formatting_elementformatting_element;Active.removeactive_formatting_elementsformatting_element;true,List.reverrors|Somefurthest_block->formatting_element.end_location<-l;letcommon_ancestor=above_in_stackformatting_element!open_elementsinletlast_node,bookmark=inner_loopformatting_elementfurthest_blockinreparentlast_nodecommon_ancestor;letnew_node={formatting_elementwithis_open=true;children=[];parent=Element.dummy}innew_node.children<-furthest_block.children;furthest_block.children<-[];new_node.children|>List.iter(function|_,Elementchild->child.parent<-new_node|_->());reparentnew_nodefurthest_block;beginmatchbookmarkwith|None->Active.replaceactive_formatting_elements~old:formatting_element~new_:new_node|Somenode->Active.removeactive_formatting_elementsformatting_element;Active.insert_afteractive_formatting_elements~anchor:node~new_:new_nodeend;Stack.removeopen_elementsformatting_element;Stack.insert_belowopen_elements~anchor:furthest_block~new_:new_node;outer_loopouter_loop_countererrorsendendendinletcurrent_node=Stack.require_current_elementopen_elementsinifcurrent_node.element_name=(`HTML,subject)thenbeginopen_elements:=List.tl!open_elements;current_node.is_open<-false;current_node.end_location<-l;subtree_buffer.position<-Stack.require_current_elementopen_elements;Active.removeactive_formatting_elementscurrent_node;true,[]endelseouter_loop0[]endletparserequested_contextreport(tokens,set_tokenizer_state,set_foreign)=letcontext=Context.uninitialized()inletthrow=ref(fun_->())inletended=ref(fun_->())inletoutput=ref(fun_->())inletreport_if=Error.report_ifreportinletunmatched_end_taglnamek=reportl(`Unmatched_end_tagname)!throwkinletmisnested_tagltcontext_namek=reportl(`Misnested_tag(t.name,context_name,t.Token_tag.attributes))!throwkinletopen_elements=Stack.create()inletactive_formatting_elements=Active.create()inletsubtree_buffer=Subtree.createopen_elementsinlettext=Text.prepare()inlettemplate_insertion_modes=Template.create()inletframeset_ok=reftrueinlethead_seen=reffalseinletform_element_pointer=refNoneinletadd_character=Text.addtextinset_foreign(fun()->Stack.current_element_is_foreigncontextopen_elements);letreport_if_stack_has_other_thannamesk=letreciterate=function|[]->k()|{element_name=ns,name;location}::more->report_if(not(ns=`HTML&&list_mem_stringnamenames))location(fun()->`Unmatched_start_tagname)!throw(fun()->iteratemore)initerate!open_elementsinletreccurrent_mode=refinitial_modeandconstructorthrow_k=Context.initializetokensrequested_contextcontextthrow_(fun()->letinitial_tokenizer_state=matchContext.the_contextcontextwith|`Fragment(`HTML,("title"|"textarea"))->`RCDATA|`Fragment(`HTML,("style"|"xmp"|"iframe"|"noembed"|"noframes"))->`RAWTEXT|`Fragment(`HTML,"script")->`Script_data|`Fragment(`HTML,"plaintext")->`PLAINTEXT|_->`Datainset_tokenizer_stateinitial_tokenizer_state;beginmatchContext.the_contextcontextwith|`Document->()|`Fragment_->letnotional_root=Element.create~suppress:true(`HTML,"html")(1,1)inopen_elements:=[notional_root]end;beginmatchContext.the_contextcontextwith|`Fragment(`HTML,"template")->Template.pushtemplate_insertion_modesin_template_mode|_->()end;(* The following is a deviation from conformance. The goal is to avoid
insertion of a <head> element into a fragment beginning with a <body> or
<frameset> element. *)beginmatchContext.tokencontextwith|Some("body"|"frameset")->head_seen:=true|_->()end;current_mode:=beginmatchContext.the_contextcontextwith|`Fragment_->reset_mode()|`Document->initial_modeend;(funthrow_ek->throw:=throw_;ended:=e;output:=k;!current_mode())|>make|>k)(* 8.2.3.1. *)andreset_mode()=letreciteratelast=function|[e]whennotlast&&Context.the_contextcontext<>`Document->beginmatchContext.the_contextcontextwith|`Document->assertfalse|`Fragmentname->iteratetrue[{ewithelement_name=name}]end|{element_name=_,"select"}::ancestors->letreciterate'=function|[]->in_select_mode|{element_name=_,"template"}::_->in_select_mode|{element_name=_,"table"}::_->in_select_in_table_mode|_::ancestors->iterate'ancestorsiniterate'ancestors|{element_name=_,("tr"|"th")}::_::_->in_cell_mode|{element_name=_,"tr"}::_->in_row_mode|{element_name=_,("tbody"|"thead"|"tfoot")}::_->in_table_body_mode|{element_name=_,"caption"}::_->in_caption_mode|{element_name=_,"colgroup"}::_->in_column_group_mode|{element_name=_,"table"}::_->in_table_mode|{element_name=_,"template"}::_->beginmatch!template_insertion_modeswith|[]->initial_mode(* This is an internal error, actually. *)|mode::_->modeend(* The next case corresponds to item 12 of "Resetting the insertion mode
appropriately." It is commented out as deliberate deviation from the
specification, because that makes parsing of fragments intended for
<head> elements more intuitive. For conformance, the pattern in the
following case would have to end with ::_::_, not ::_. *)(* | [{element_name = _, "head"}] -> in_body_mode *)|{element_name=_,"head"}::_->in_head_mode|{element_name=_,"body"}::_->in_body_mode|{element_name=_,"frameset"}::_->in_frameset_mode|{element_name=_,"html"}::_->if!head_seenthenafter_head_modeelsebefore_head_mode|_::rest->iteratelastrest|[]->in_body_modeiniteratefalse!open_elementsandemit'lsm=ifSubtree.accumulatesubtree_bufferlsthenbegincurrent_mode:=m;!output(l,s)endelsem()andemit_listssm=matchsswith|[]->m()|(l,s)::more->emit'ls(fun()->emit_listmorem)andemit_textm=matchText.emittextwith|None->m()|Some(l',strings)->emit'l'(`Textstrings)mandemitlsm=emit_text(fun()->emit'lsm)andpush_and_emit?(formatting=false)?(acknowledge=false)?(namespace=`HTML)?(set_form_element_pointer=false)location({Token_tag.name;attributes;self_closing}astag)mode=report_if(self_closing&¬acknowledge)location(fun()->`Bad_token("/>","tag","should not be self-closing"))!throw(fun()->letnamespace_string=Ns.to_stringnamespaceinlettag_name=matchnamespacewith|`SVG->Foreign.adjust_svg_tag_namename|_->nameinletis_html_integration_point=Foreign.is_html_integration_pointnamespacetag_nameattributesinletattributes=List.map(fun(n,v)->Namespace.Parsing.parsen,v)attributesinletattributes=matchnamespacewith|`HTML|`Other_->attributes|`MathML->Foreign.adjust_mathml_attributesattributes|`SVG->Foreign.adjust_svg_attributesattributesinletelement_entry=Element.create~is_html_integration_point(namespace,name)locationinopen_elements:=element_entry::!open_elements;ifset_form_element_pointerthenform_element_pointer:=Someelement_entry;ifformattingthenactive_formatting_elements:=Active.Element_(element_entry,location,tag)::!active_formatting_elements;emitlocation(`Start_element((namespace_string,tag_name),attributes))mode)andpush_implicitlocationnamemode=push_and_emitlocation{Token_tag.name=name;attributes=[];self_closing=false}modeandpoplocationmode=match!open_elementswith|[]->mode()|element::more->emit_text(fun()->(funk->ifnotelement.bufferingthenk()elseemit_list(Subtree.disablesubtree_buffer)k)(fun()->open_elements:=more;element.is_open<-false;ifelement.suppressthenmode()elseemit'location`End_elementmode))andpop_untilconditionlocationmode=letreciterate()=match!open_elementswith|[]->mode()|element::_->ifconditionelementthenmode()elsepoplocationiterateiniterate()andclose_element?(ns=`HTML)lnamemode=pop_until(fun{element_name=ns',name'}->ns'=ns&&name'=name)l(fun()->poplmode)andpop_until_and_raise_errorsnameslocationmode=letreciterate()=match!open_elementswith|[]->mode()|{element_name=ns,name}::_->ifns=`HTML&&list_mem_stringnamenamesthenpoplocationmodeelsereportlocation(`Unmatched_start_tagname)!throw(fun()->poplocationiterate)initerate()andpop_implied?(except="")locationmode=pop_until(fun{element_name=_,name}->name=except||not@@list_mem_stringname["dd";"dt";"li";"option";"optgroup";"p";"rb";"rp";"rt";"rtc"])locationmodeandpop_to_table_contextlocationmode=pop_until(function|{element_name=`HTML,("table"|"template"|"html")}->true|_->false)locationmodeandpop_to_table_body_contextlocationmode=pop_until(function|{element_name=`HTML,("tbody"|"thead"|"tfoot"|"template"|"html")}->true|_->false)locationmodeandpop_to_table_row_contextlocationmode=pop_until(function|{element_name=`HTML,("tr"|"template"|"html")}->true|_->false)locationmodeandclose_element_with_impliednamelocationmode=pop_implied~except:namelocation(fun()->letcheck_elementk=matchStack.current_elementopen_elementswith|Some{element_name=`HTML,name'}whenname'=name->k()|Some{element_name=_,name;location}->reportlocation(`Unmatched_start_tagname)!throwk|None->unmatched_end_taglocationnamekincheck_element(fun()->close_elementlocationnamemode))andclose_celllocationmode=pop_impliedlocation(fun()->(funmode->matchStack.current_elementopen_elementswith|Some{element_name=`HTML,("td"|"th")}->mode()|Some{element_name=_,name}->unmatched_end_taglocationnamemode|None->unmatched_end_taglocation""mode)@@(fun()->pop_until(function|{element_name=`HTML,("td"|"th")}->true|_->false)location(fun()->poplocationmode)))andclose_current_p_elementlmode=ifStack.in_button_scopeopen_elements"p"thenclose_element_with_implied"p"lmodeelsemode()andclose_preceding_tagnameslmode=letrecscan=function|[]->mode()|{element_name=(ns,name)asname'}::more->ifns=`HTML&&list_mem_stringnamenamesthenclose_element_with_impliednamelmodeelseifElement.is_specialname'&¬@@list_mem_qnamename'[`HTML,"address";`HTML,"div";`HTML,"p"]thenmode()elsescanmoreinscan!open_elementsandemit_endl=pop_until(fun_->false)l(fun()->emit_text(fun()->!ended()))andreconstruct_active_formatting_elementsmode=letrecget_prefixprefix=function|[]->prefix,[]|Active.Marker::_asl->prefix,l|Active.Element_({is_open=true},_,_)::_asl->prefix,l|Active.Element_({is_open=false},l,tag)::more->get_prefix((l,tag)::prefix)moreinletto_reopen,remainder=get_prefix[]!active_formatting_elementsinactive_formatting_elements:=remainder;beginmatchto_reopenwith|[]->()|_::_->Subtree.enablesubtree_bufferend;letrecreopen=function|[]->mode()|(l,tag)::more->push_and_emit~formatting:trueltag(fun()->reopenmore)inreopento_reopen(* 8.2.5. *)anddispatchtokensrules=nexttokens!throw(fun()->!ended())beginfun((_,t)asv)->letforeign=matchStack.adjusted_current_elementcontextopen_elements,twith|None,_->false|Some{element_name=`HTML,_},_->false|Some{element_name},`Start{name}whenForeign.is_mathml_text_integration_pointelement_name&&name<>"mglyph"&&name<>"malignmark"->false|Some{element_name=`MathML,"annotation-xml"},`Start{name="svg"}->false|Some{is_html_integration_point=true},`Start_->false|Some{is_html_integration_point=true},`Char_->false|_,`EOF->false|_->trueinifnotforeignthenrulesvelseforeign_content!current_mode(fun()->rulesv)vend(* 8.2.5.4.1. *)andinitial_mode()=dispatchtokensbeginfunction|_,`Char(0x0009|0x000A|0x000C|0x000D|0x0020)->initial_mode()|l,`Comments->emitl(`Comments)initial_mode|l,`Doctyped->emitl(`Doctyped)before_html_mode|v->pushtokensv;before_html_mode()end(* 8.2.5.4.2. *)andbefore_html_mode()=dispatchtokensbeginfunction|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwbefore_html_mode|l,`Comments->emitl(`Comments)before_html_mode|_,`Char(0x0009|0x000A|0x000C|0x000D|0x0020)->before_html_mode()|l,`Start({name="html"}ast)->push_and_emitltbefore_head_mode|l,`End{name}whennot@@list_mem_stringname["head";"body";"html";"br"]->unmatched_end_taglnamebefore_html_mode|l,_asv->pushtokensv;push_implicitl"html"before_head_modeend(* 8.2.5.4.3. *)andbefore_head_mode()=dispatchtokensbeginfunction|_,`Char(0x0009|0x000A|0x000C|0x000D|0x0020)->before_head_mode()|l,`Comments->emitl(`Comments)before_head_mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwbefore_head_mode|_,`Start{name="html"}asv->in_body_mode_rules"html"before_head_modev|l,`Start({name="head"}ast)->head_seen:=true;push_and_emitltin_head_mode|l,`End{name}whennot@@list_mem_stringname["head";"body";"html";"br"]->reportl(`Unmatched_end_tagname)!throwbefore_head_mode|l,_asv->head_seen:=true;pushtokensv;push_implicitl"head"in_head_modeend(* 8.2.5.4.4. *)andin_head_mode()=dispatchtokens(funv->in_head_mode_rulesin_head_modev)(* 8.2.5.4.4. *)andin_head_mode_rulesmode=function|l,`Char(0x0009|0x000A|0x000C|0x000D|0x0020asc)->add_characterlc;mode()|l,`Comments->emitl(`Comments)mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwmode|_,`Start{name="html"}asv->in_body_mode_rules"head"in_head_modev|l,`Start({name="base"|"basefont"|"bgsound"|"link"|"meta"}ast)->push_and_emit~acknowledge:truelt(fun()->poplmode)|l,`Start({name="title"}ast)->push_and_emitlt(fun()->parse_rcdatamode)|l,`Start({name="noframes"|"style"}ast)->push_and_emitlt(fun()->parse_rawtextmode)|l,`Start({name="noscript"}ast)->push_and_emitltin_head_noscript_mode|l,`Start({name="script"}ast)->push_and_emitlt(fun()->set_tokenizer_state`Script_data;text_modemode)|l,`End{name="head"}->poplafter_head_mode|l,`Start({name="template"}ast)->Active.add_markeractive_formatting_elements;frameset_ok:=false;Template.pushtemplate_insertion_modesin_template_mode;push_and_emitltin_template_mode|l,`End{name="template"}->ifnot@@Stack.hasopen_elements"template"thenreportl(`Unmatched_end_tag"template")!throwmodeelsebeginActive.clear_until_markeractive_formatting_elements;Template.poptemplate_insertion_modes;close_element_with_implied"template"l(fun()->reset_mode()())end|l,`Start({name="head"}ast)->misnested_taglt"head"mode|l,`End{name}whennot@@list_mem_stringname["body";"html";"br"]->reportl(`Unmatched_end_tagname)!throwmode|l,_asv->pushtokensv;poplafter_head_mode(* 8.2.5.4.5. *)andin_head_noscript_mode()=dispatchtokensbeginfunction|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwin_head_noscript_mode|_,`Start{name="html"}asv->in_body_mode_rules"noscript"in_head_noscript_modev|l,`End{name="noscript"}->poplin_head_mode|_,`Char(0x0009|0x000A|0x000C|0x000D|0x0020)|_,`Comment_|_,`Start{name="basefont"|"bgsound"|"link"|"meta"|"noframes"|"style"}asv->in_head_mode_rulesin_head_noscript_modev|l,`Start({name="head"|"noscript"}ast)->misnested_taglt"noscript"in_head_noscript_mode|l,`End{name}whenname<>"br"->reportl(`Unmatched_end_tagname)!throwin_head_noscript_mode|l,_asv->reportl(`Bad_content"noscript")!throw(fun()->pushtokensv;poplin_head_mode)end(* 8.2.5.4.6. *)andafter_head_mode()=dispatchtokensbeginfunction|l,`Char(0x0009|0x000A|0x000C|0x000D|0x0020asc)->add_characterlc;after_head_mode()|l,`Comments->emitl(`Comments)after_head_mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwafter_head_mode|_,`Start{name="html"}asv->in_body_mode_rules"html"after_head_modev|l,`Start({name="body"}ast)->frameset_ok:=false;push_and_emitltin_body_mode|l,`Start({name="frameset"}ast)->push_and_emitltin_frameset_mode|l,`Start({name="base"|"basefont"|"bgsound"|"link"|"meta"|"noframes"|"script"|"style"|"template"|"title"}ast)asv->misnested_taglt"html"(fun()->in_head_mode_rulesafter_head_modev)|_,`End{name="template"}asv->in_head_mode_rulesafter_head_modev|l,`Start{name="head"}->reportl(`Bad_document"duplicate head element")!throwafter_head_mode|l,`End{name}whennot@@list_mem_stringname["body";"html";"br"]->reportl(`Unmatched_end_tagname)!throwafter_head_mode(* This case is not found in the specification. It is a deliberate
deviation from conformance, so that fragments "<head>...</head>" don't
get an implicit <body> element generated after the <head> element. *)|l,`EOFwhen(Context.the_contextcontext=`Fragment(`HTML,"html")||Context.the_contextcontext=`Fragment(`HTML,"head"))->emit_endl|l,_ast->pushtokenst;push_implicitl"body"in_body_modeend(* 8.2.5.4.7. *)andin_body_mode()=dispatchtokens(funv->in_body_mode_rules"body"in_body_modev)(* 8.2.5.4.7. *)andin_body_mode_rulescontext_namemode=function|l,`Char0->reportl(`Bad_token("U+0000","body","null"))!throwmode|l,`Char(0x0009|0x000A|0x000C|0x000D|0x0020asc)->reconstruct_active_formatting_elements(fun()->add_characterlc;mode())|l,`Charc->frameset_ok:=false;reconstruct_active_formatting_elements(fun()->add_characterlc;mode())|l,`Comments->emitl(`Comments)mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwmode|l,`Start({name="html"}ast)->misnested_tagltcontext_namemode|_,`Start{name="base"|"basefont"|"bgsound"|"link"|"meta"|"noframes"|"script"|"style"|"template"|"title"}|_,`End{name="template"}asv->in_head_mode_rulesmodev|l,`Start({name="body"}ast)->misnested_tagltcontext_namemode|l,`Start({name="frameset"}ast)->misnested_tagltcontext_name(fun()->match!open_elementswith|[_]->mode()|_->letrecsecond_is_body=function|[{element_name=`HTML,"body"};_]->true|[]->false|_::more->second_is_bodymoreinifnot@@second_is_body!open_elementsthenmode()elseifnot!frameset_okthenmode()else(* There is a deviation here due to the nature of the parser: if a
body element has been emitted, it can't be suppressed. *)pop_until(fun_->match!open_elementswith[_]->true|_->false)l(fun()->push_and_emitltin_frameset_mode))|l,`EOFasv->report_if_stack_has_other_than["dd";"dt";"li";"p";"tbody";"td";"tfoot";"th";"thead";"tr";"body";"html"](fun()->match!template_insertion_modeswith|[]->emit_endl|_->in_template_mode_rulesmodev)|l,`End{name="body"}->ifnot@@Stack.in_scopeopen_elements"body"thenreportl(`Unmatched_end_tag"body")!throwmodeelsereport_if_stack_has_other_than["dd";"dt";"li";"optgroup";"option";"p";"rb";"rp";"rt";"rtc";"tbody";"td";"tfoot";"th";"thead";"tr";"body";"html"](fun()->after_body_mode())|l,`End{name="html"}asv->ifnot@@Stack.in_scopeopen_elements"body"thenreportl(`Unmatched_end_tag"html")!throwmodeelsereport_if_stack_has_other_than["dd";"dt";"li";"optgroup";"option";"p";"rb";"rp";"rt";"rtc";"tbody";"td";"tfoot";"th";"thead";"tr";"body";"html"](fun()->pushtokensv;after_body_mode())|l,`Start({name="address"|"article"|"aside"|"blockquote"|"center"|"details"|"dialog"|"dir"|"div"|"dl"|"fieldset"|"figcaption"|"figure"|"footer"|"header"|"hgroup"|"main"|"nav"|"ol"|"p"|"section"|"summary"|"ul"}ast)->close_current_p_elementl(fun()->push_and_emitltmode)|l,`Start({name="h1"|"h2"|"h3"|"h4"|"h5"|"h6"}ast)->close_current_p_elementl(fun()->(funmode'->matchStack.current_elementopen_elementswith|Some{element_name=`HTML,("h1"|"h2"|"h3"|"h4"|"h5"|"h6"asname')}->misnested_tagltname'(fun()->poplmode')|_->mode'())(fun()->push_and_emitltmode))|l,`Start({name="pre"|"listing"}ast)->frameset_ok:=false;close_current_p_elementl(fun()->push_and_emitlt(fun()->next_expectedtokens!throw(function|_,`Char0x000A->mode()|v->pushtokensv;mode())))|l,`Start({name="form"}ast)->if!form_element_pointer<>None&¬@@Stack.hasopen_elements"template"thenmisnested_taglt"form"modeelsebeginclose_current_p_elementl(fun()->letin_template=Stack.hasopen_elements"template"inpush_and_emit~set_form_element_pointer:(notin_template)ltmode)end|l,`Start({name="li"}ast)->frameset_ok:=false;close_preceding_tag["li"]l(fun()->close_current_p_elementl(fun()->push_and_emitltmode))|l,`Start({name="dd"|"dt"}ast)->frameset_ok:=false;close_preceding_tag["dd";"dt"]l(fun()->close_current_p_elementl(fun()->push_and_emitltmode))|l,`Start({name="plaintext"}ast)->close_current_p_elementl(fun()->set_tokenizer_state`PLAINTEXT;push_and_emitltmode)|l,`Start({name="button"}ast)->(funmode'->ifStack.in_scopeopen_elements"button"thenmisnested_taglt"button"(fun()->close_element_with_implied"button"lmode')elsemode'())(fun()->frameset_ok:=false;reconstruct_active_formatting_elements(fun()->push_and_emitltmode))|l,`End{name="address"|"article"|"aside"|"blockquote"|"button"|"center"|"details"|"dialog"|"dir"|"div"|"dl"|"fieldset"|"figcaption"|"figure"|"footer"|"header"|"hgroup"|"listing"|"main"|"nav"|"ol"|"pre"|"section"|"summary"|"ul"asname}->ifnot@@Stack.in_scopeopen_elementsnamethenreportl(`Unmatched_end_tagname)!throwmodeelseclose_element_with_impliednamelmode|l,`End{name="form"}->ifnot@@Stack.hasopen_elements"template"thenbeginletform_element=!form_element_pointerinform_element_pointer:=None;matchform_elementwith|SomeelementwhenStack.target_in_scopeopen_elementselement->pop_impliedl(fun()->matchStack.current_elementopen_elementswith|Someelement'whenelement'==element->poplmode|_->reportelement.location(`Unmatched_start_tag"form")!throw(fun()->pop_until(funelement'->element'==element)l(fun()->poplmode)))|_->reportl(`Unmatched_end_tag"form")!throwmodeendelseifnot@@Stack.in_scopeopen_elements"form"thenreportl(`Unmatched_end_tag"form")!throwmodeelseclose_element_with_implied"form"lmode|l,`End{name="p"}->(funmode'->ifnot@@Stack.in_button_scopeopen_elements"p"thenreportl(`Unmatched_end_tag"p")!throw(fun()->push_implicitl"p"mode')elsemode'())(fun()->close_element_with_implied"p"lmode)|l,`End{name="li"}->ifnot@@Stack.in_list_item_scopeopen_elements"li"thenreportl(`Unmatched_end_tag"li")!throwmodeelseclose_element_with_implied"li"lmode|l,`End{name="dd"|"dt"asname}->ifnot@@Stack.in_scopeopen_elementsnamethenreportl(`Unmatched_end_tagname)!throwmodeelseclose_element_with_impliednamelmode|l,`End{name="h1"|"h2"|"h3"|"h4"|"h5"|"h6"asname}->ifnot@@Stack.one_in_scopeopen_elements["h1";"h2";"h3";"h4";"h5";"h6"]thenreportl(`Unmatched_end_tagname)!throwmodeelsepop_impliedl(fun()->(funnext->matchStack.current_elementopen_elementswith|Some{element_name=`HTML,name'}whenlist_mem_stringname'["h1";"h2";"h3";"h4";"h5";"h6"]->next()|_->reportl(`Unmatched_end_tagname)!thrownext)@@(fun()->pop_until_and_raise_errors["h1";"h2";"h3";"h4";"h5";"h6"]lmode))|l,`Start({name="a"}ast)->(funk->matchActive.has_before_markeractive_formatting_elements"a"with|None->k()|Someexisting->misnested_taglt"a"(fun()->adoption_agency_algorithml"a"(fun()->Stack.removeopen_elementsexisting;Active.removeactive_formatting_elementsexisting;k())))(fun()->Subtree.enablesubtree_buffer;reconstruct_active_formatting_elements(fun()->push_and_emit~formatting:trueltmode))|l,`Start({name="b"|"big"|"code"|"em"|"font"|"i"|"s"|"small"|"strike"|"strong"|"tt"|"u"}ast)->Subtree.enablesubtree_buffer;reconstruct_active_formatting_elements(fun()->push_and_emit~formatting:trueltmode)|l,`Start({name="nobr"}ast)->Subtree.enablesubtree_buffer;reconstruct_active_formatting_elements(fun()->(funk->ifnot@@Stack.in_scopeopen_elements"nobr"thenk()elsemisnested_taglt"nobr"(fun()->adoption_agency_algorithml"nobr"(fun()->reconstruct_active_formatting_elementsk)))(fun()->push_and_emit~formatting:trueltmode))|l,`End{name="a"|"b"|"big"|"code"|"em"|"font"|"i"|"nobr"|"s"|"small"|"strike"|"strong"|"tt"|"u"asname}->adoption_agency_algorithmlnamemode|l,`Start({name="applet"|"marquee"|"object"}ast)->frameset_ok:=false;reconstruct_active_formatting_elements(fun()->Active.add_markeractive_formatting_elements;push_and_emitltmode)|l,`End{name="applet"|"marquee"|"object"asname}->ifnot@@Stack.in_scopeopen_elementsnamethenreportl(`Unmatched_end_tagname)!throwmodeelsebeginActive.clear_until_markeractive_formatting_elements;close_element_with_impliednamelmodeend|l,`Start({name="table"}ast)->frameset_ok:=false;close_current_p_elementl(fun()->push_and_emitltin_table_mode)|l,`End{name="br"}->reportl(`Unmatched_end_tag"br")!throw(fun()->in_body_mode_rulescontext_namemode(l,`Start{Token_tag.name="br";attributes=[];self_closing=false}))|l,`Start({name="area"|"br"|"embed"|"img"|"keygen"|"wbr"}ast)->frameset_ok:=false;reconstruct_active_formatting_elements(fun()->push_and_emit~acknowledge:truelt(fun()->poplmode))|l,`Start({name="input"}ast)->ifElement.is_not_hiddentthenframeset_ok:=false;reconstruct_active_formatting_elements(fun()->push_and_emit~acknowledge:truelt(fun()->poplmode))|l,`Start({name="param"|"source"|"track"}ast)->push_and_emit~acknowledge:truelt(fun()->poplmode)|l,`Start({name="hr"}ast)->frameset_ok:=false;close_current_p_elementl(fun()->push_and_emit~acknowledge:truelt(fun()->poplmode))|l,`Start({name="image"}ast)->reportl(`Bad_token("image","tag","should be 'img'"))!throw(fun()->pushtokens(l,`Start{twithname="img"});mode())|l,`Start({name="textarea"}ast)->frameset_ok:=false;push_and_emitlt(fun()->set_tokenizer_state`RCDATA;next_expectedtokens!throw(function|_,`Char0x000A->text_modemode|v->pushtokensv;text_modemode))|l,`Start{name="xmp"}->frameset_ok:=false;close_current_p_elementl(fun()->reconstruct_active_formatting_elements(fun()->parse_rawtextmode))|l,`Start({name="iframe"}ast)->frameset_ok:=false;push_and_emitlt(fun()->parse_rawtextmode)|l,`Start({name="noembed"}ast)->push_and_emitlt(fun()->parse_rawtextmode)|l,`Start({name="select"}ast)->frameset_ok:=false;select_in_bodyltin_select_mode|l,`Start({name="optgroup"|"option"}ast)->(funmode'->ifStack.current_element_isopen_elements["option"]thenpoplmode'elsemode'())(fun()->reconstruct_active_formatting_elements(fun()->push_and_emitltmode))|l,`Start({name="rb"|"rtc"}ast)->(funmode'->letfinish()=ifStack.current_element_isopen_elements["ruby"]thenmode'()elsemisnested_tagltcontext_namemode'inifStack.in_scopeopen_elements"ruby"thenpop_impliedlfinishelsefinish())(fun()->push_and_emitltmode)|l,`Start({name="rp"|"rt"}ast)->(funmode'->letfinish()=ifStack.current_element_isopen_elements["ruby";"rtc"]thenmode'()elsemisnested_tagltcontext_namemode'inifStack.in_scopeopen_elements"ruby"thenpop_implied~except:"rtc"lfinishelsefinish())(fun()->push_and_emitltmode)|l,`Start({name="math"}ast)->reconstruct_active_formatting_elements(fun()->push_and_emit~acknowledge:true~namespace:`MathMLlt(fun()->ift.self_closingthenpoplmodeelsemode()))|l,`Start({name="svg"}ast)->reconstruct_active_formatting_elements(fun()->push_and_emit~acknowledge:true~namespace:`SVGlt(fun()->ift.self_closingthenpoplmodeelsemode()))|l,`Start({name="caption"|"col"|"colgroup"|"frame"|"head"|"tbody"|"td"|"tfoot"|"th"|"thead"|"tr"}ast)->misnested_tagltcontext_namemode|l,`Startt->reconstruct_active_formatting_elements(fun()->push_and_emitltmode)|l,`End{name}->any_other_end_tag_in_bodylnamemode(* Part of 8.2.5.4.7. *)andany_other_end_tag_in_bodylnamemode=letrecclose=function|[]->mode()|{element_name=(ns,name')asname''}::rest->ifns=`HTML&&name'=namethenpop_implied~except:namel(fun()->poplmode)elseifElement.is_specialname''thenreportl(`Unmatched_end_tagname)!throwmodeelsecloserestinclose!open_elements(* Part of 8.2.5.4.7. *)andadoption_agency_algorithmlnamemode=Subtree.enablesubtree_buffer;emit_text(fun()->lethandled,errors=Subtree.adoption_agency_algorithmsubtree_bufferactive_formatting_elementslnameinletrecreport_allerrorsk=matcherrorswith|[]->k()|(l,error)::more->reportlerror!throw(fun()->report_allmorek)inreport_allerrors(fun()->ifnothandledthenany_other_end_tag_in_bodylnamemodeelsemode()))(* Part of 8.2.5.4.7. *)andselect_in_bodyltnext_mode=frameset_ok:=false;reconstruct_active_formatting_elements(fun()->push_and_emitltnext_mode)(* 8.2.5.4.8. *)andtext_modeoriginal_mode=dispatchtokensbeginfunction|l,`Charc->add_characterlc;text_modeoriginal_mode|l,`EOFasv->reportl(`Unexpected_eoi"content")!throw(fun()->pushtokensv;poploriginal_mode)|l,`End_->poploriginal_mode|_->text_modeoriginal_modeend(* 8.2.5.2. *)andparse_rcdataoriginal_mode=set_tokenizer_state`RCDATA;text_modeoriginal_mode(* 8.2.5.2. *)andparse_rawtextoriginal_mode=set_tokenizer_state`RAWTEXT;text_modeoriginal_modeandanything_else_in_tablemode(l,_asv)=reportl(`Bad_content"table")!throw(fun()->in_body_mode_rules"table"modev)(* 8.2.5.4.9. *)andin_table_mode()=dispatchtokens(funv->in_table_mode_rulesin_table_modev)andin_table_mode_rulesmode=function|_,`Char_asvwhenStack.current_element_isopen_elements["table";"tbody";"tfoot";"thead";"tr"]->pushtokensv;in_table_text_modetrue[]mode|l,`Comments->emitl(`Comments)mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwmode|l,`Start({name="caption"}ast)->pop_to_table_contextl(fun()->Active.add_markeractive_formatting_elements;push_and_emitltin_caption_mode)|l,`Start({name="colgroup"}ast)->pop_to_table_contextl(fun()->push_and_emitltin_column_group_mode)|l,`Start{name="col"}asv->pop_to_table_contextl(fun()->pushtokensv;push_implicitl"colgroup"in_column_group_mode)|l,`Start({name="tbody"|"tfoot"|"thead"}ast)->pop_to_table_contextl(fun()->push_and_emitltin_table_body_mode)|l,`Start{name="td"|"th"|"tr"}asv->pop_to_table_contextl(fun()->pushtokensv;push_implicitl"tbody"in_table_body_mode)|l,`Start({name="table"}ast)asv->misnested_taglt"table"(fun()->ifnot@@Stack.hasopen_elements"table"thenmode()elsebeginpushtokensv;close_elementl"table"(fun()->reset_mode()())end)|l,`End{name="table"}->ifnot@@Stack.in_table_scopeopen_elements"table"thenreportl(`Unmatched_end_tag"table")!throwmodeelseclose_elementl"table"(fun()->reset_mode()())|l,`End{name="body"|"caption"|"col"|"colgroup"|"html"|"tbody"|"td"|"tfoot"|"th"|"thead"|"tr"asname}->reportl(`Unmatched_end_tagname)!throwmode|_,`Start{name="style"|"script"|"template"}|_,`End{name="template"}asv->in_head_mode_rulesmodev|l,`Start({name="input"}ast)whenElement.is_not_hiddent->misnested_taglt"table"(fun()->push_and_emit~acknowledge:truelt(fun()->poplmode))|l,`Start({name="form"}ast)->misnested_taglt"table"(fun()->push_and_emitlt(fun()->poplmode))|_,`EOFasv->in_body_mode_rules"table"modev|v->anything_else_in_tablemodev(* 8.2.5.4.10. *)andin_table_text_modeonly_spacecsmode=dispatchtokensbeginfunction|l,`Char0->reportl(`Bad_token("U+0000","table","null"))!throw(fun()->in_table_text_modeonly_spacecsmode)|_,`Char(0x0009|0x000A|0x000C|0x000D|0x0020)asv->in_table_text_modeonly_space(v::cs)mode|_,`Char_asv->in_table_text_modefalse(v::cs)mode|v->pushtokensv;ifnotonly_spacethenletrecreprocess=function|[]->mode()|v::more->anything_else_in_table(fun()->reprocessmore)vinreprocess(List.revcs)elsebeginList.revcs|>List.iter(function|l,`Charc->add_characterlc|_->());mode()endend(* 8.2.5.4.11. *)andin_caption_mode()=dispatchtokensbeginfunction|l,`End{name="caption"}->ifnot@@Stack.in_table_scopeopen_elements"caption"thenreportl(`Unmatched_end_tag"caption")!throwin_caption_modeelsebeginActive.clear_until_markeractive_formatting_elements;close_element_with_implied"caption"lin_table_modeend|l,`Start({name="caption"|"col"|"colgroup"|"tbody"|"td"|"tfoot"|"th"|"thead"|"tr"}ast)asv->misnested_taglt"caption"(fun()->ifnot@@Stack.in_table_scopeopen_elements"caption"thenin_caption_mode()elsebeginActive.clear_until_markeractive_formatting_elements;pushtokensv;close_elementl"caption"in_table_modeend)|l,`End{name="table"}asv->reportl(`Unmatched_end_tag"table")!throw(fun()->ifnot@@Stack.in_table_scopeopen_elements"caption"thenin_caption_mode()elsebeginActive.clear_until_markeractive_formatting_elements;pushtokensv;close_elementl"caption"in_table_modeend)|l,`End{name=("body"|"col"|"colgroup"|"html"|"tbody"|"td"|"tfoot"|"th"|"thead"|"tr")asname}->reportl(`Unmatched_end_tagname)!throwin_caption_mode|l,`Start({name="select"}ast)->select_in_bodyltin_select_in_table_mode|v->in_body_mode_rules"caption"in_caption_modevend(* 8.2.5.4.12. *)andin_column_group_mode()=dispatchtokensbeginfunction|l,`Char(0x0009|0x000A|0x000C|0x000D|0x0020asc)->add_characterlc;in_column_group_mode()|l,`Comments->emitl(`Comments)in_column_group_mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwin_column_group_mode|_,`Start{name="html"}asv->in_body_mode_rules"colgroup"in_column_group_modev|l,`Start({name="col"}ast)->push_and_emit~acknowledge:truelt(fun()->poplin_column_group_mode)|l,`End{name="colgroup"}->ifnot@@Stack.current_element_isopen_elements["colgroup"]thenreportl(`Unmatched_end_tag"colgroup")!throwin_column_group_modeelsepoplin_table_mode|l,`End{name="col"}->reportl(`Unmatched_end_tag"col")!throwin_column_group_mode|_,`Start{name="template"}|_,`End{name="template"}asv->in_head_mode_rulesin_column_group_modev|_,`EOFasv->in_body_mode_rules"colgroup"in_column_group_modev|l,_asv->ifnot@@Stack.current_element_isopen_elements["colgroup"]thenreportl(`Bad_content"colgroup")!throwin_table_modeelsebeginpushtokensv;poplin_table_modeendend(* 8.2.5.4.13. *)andin_table_body_mode()=dispatchtokensbeginfunction|l,`Start({name="tr"}ast)->pop_to_table_body_contextl(fun()->push_and_emitltin_row_mode)|l,`Start({name="th"|"td"}ast)asv->misnested_taglt"table"(fun()->pop_to_table_body_contextl(fun()->pushtokensv;push_implicitl"tr"in_row_mode))|l,`End{name="tbody"|"tfoot"|"thead"asname}->ifnot@@Stack.in_table_scopeopen_elementsnamethenreportl(`Unmatched_end_tagname)!throwin_table_body_modeelsepop_to_table_body_contextl(fun()->poplin_table_mode)|l,`Start({name="caption"|"col"|"colgroup"|"tbody"|"tfoot"|"thead"}ast)asv->ifnot@@Stack.one_in_table_scopeopen_elements["tbody";"thead";"tfoot"]thenmisnested_taglt"table"in_table_body_modeelsebeginpushtokensv;pop_to_table_body_contextl(fun()->poplin_table_mode)end|l,`End{name="table"asname}asv->ifnot@@Stack.one_in_table_scopeopen_elements["tbody";"thead";"tfoot"]thenreportl(`Unmatched_end_tagname)!throwin_table_body_modeelsebeginpushtokensv;pop_to_table_body_contextl(fun()->poplin_table_mode)end|l,`End{name="body"|"caption"|"col"|"colgroup"|"html"|"td"|"th"|"tr"asname}->reportl(`Unmatched_end_tagname)!throwin_table_body_mode|v->in_table_mode_rulesin_table_body_modevend(* 8.2.5.4.14. *)andin_row_mode()=dispatchtokensbeginfunction|l,`Start({name="th"|"td"}ast)->Active.add_markeractive_formatting_elements;pop_to_table_row_contextl(fun()->push_and_emitltin_cell_mode)|l,`End{name="tr"}->ifnot@@Stack.in_table_scopeopen_elements"tr"thenreportl(`Unmatched_end_tag"tr")!throwin_row_modeelsepop_to_table_row_contextl(fun()->poplin_table_body_mode)|l,`Start{name=("caption"|"col"|"colgroup"|"tbody"|"tfoot"|"thead"|"tr")}|l,`End{name="table"}asv->ifnot@@Stack.in_table_scopeopen_elements"tr"thenmatchsndvwith|`Startt->misnested_taglt"tr"in_row_mode|`End{name}->reportl(`Unmatched_end_tagname)!throwin_row_modeelsepop_to_table_row_contextl(fun()->pushtokensv;poplin_table_body_mode)|l,`End{name="tbody"|"tfoot"|"thead"asname}asv->ifnot@@Stack.in_table_scopeopen_elementsnamethenreportl(`Unmatched_end_tagname)!throwin_row_modeelseifnot@@Stack.in_table_scopeopen_elements"tr"thenin_row_mode()elsepop_to_table_row_contextl(fun()->pushtokensv;poplin_table_body_mode)|l,`End{name="body"|"caption"|"col"|"colgroup"|"html"|"td"|"th"asname}->reportl(`Unmatched_end_tagname)!throwin_row_mode|v->in_table_mode_rulesin_row_modevend(* 8.2.5.4.15. *)andin_cell_mode()=dispatchtokensbeginfunction|l,`End{name="td"|"th"asname}->ifnot@@Stack.in_table_scopeopen_elementsnamethenreportl(`Unmatched_end_tagname)!throwin_cell_modeelseclose_element_with_impliednamel(fun()->Active.clear_until_markeractive_formatting_elements;in_row_mode())|l,`Start({name="caption"|"col"|"colgroup"|"tbody"|"td"|"tfoot"|"th"|"thead"|"tr"}ast)asv->ifnot@@Stack.one_in_table_scopeopen_elements["td";"th"]thenmisnested_taglt"td/th"in_cell_modeelseclose_celll(fun()->Active.clear_until_markeractive_formatting_elements;pushtokensv;in_row_mode())|l,`End{name="body"|"caption"|"col"|"colgroup"|"html"asname}->reportl(`Unmatched_end_tagname)!throwin_cell_mode|l,`End{name="table"|"tbody"|"tfoot"|"thead"|"tr"asname}asv->ifnot@@Stack.in_table_scopeopen_elementsnamethenreportl(`Unmatched_end_tagname)!throwin_cell_modeelseclose_celll(fun()->Active.clear_until_markeractive_formatting_elements;pushtokensv;in_row_mode())|l,`Start({name="select"}ast)->select_in_bodyltin_select_in_table_mode|v->in_body_mode_rules"td"in_cell_modevend(* 8.2.5.4.16. *)andin_select_mode()=dispatchtokens(funv->in_select_mode_rulesin_select_modev)andin_select_mode_rulesmode=function|l,`Char0->reportl(`Bad_token("U+0000","select","null"))!throwmode|l,`Charc->add_characterlc;mode()|l,`Comments->emitl(`Comments)mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwmode|_,`Start{name="html"}asv->in_body_mode_rules"select"modev|l,`Start({name="option"}ast)->(funmode'->ifStack.current_element_isopen_elements["option"]thenpoplmode'elsemode'())(fun()->push_and_emitltmode)|l,`Start({name="optgroup"}ast)->(funmode'->ifStack.current_element_isopen_elements["option"]thenpoplmode'elsemode'())@@(funmode'()->ifStack.current_element_isopen_elements["optgroup"]thenpoplmode'elsemode'())@@(fun()->push_and_emitltmode)|l,`End{name="optgroup"}->(funmode'->match!open_elementswith|{element_name=`HTML,"option"}::{element_name=`HTML,"optgroup"}::_->poplmode'|_->mode'())(fun()->ifStack.current_element_isopen_elements["optgroup"]thenpoplmodeelsereportl(`Unmatched_end_tag"optgroup")!throwmode)|l,`End{name="option"}->ifStack.current_element_isopen_elements["option"]thenpoplmodeelsereportl(`Unmatched_end_tag"option")!throwmode|l,`End{name="select"}->ifnot@@Stack.in_select_scopeopen_elements"select"thenreportl(`Unmatched_end_tag"select")!throwmodeelseclose_elementl"select"(fun()->reset_mode()())|l,`Start({name="select"}ast)->misnested_taglt"select"(fun()->close_elementl"select"(fun()->reset_mode()()))|l,`Start({name="input"|"keygen"|"textarea"}ast)asv->misnested_taglt"select"(fun()->ifnot@@Stack.in_select_scopeopen_elements"select"thenmode()elsebeginpushtokensv;close_elementl"select"(fun()->reset_mode()())end)|_,(`Start{name="script"|"template"}|`End{name="template"})asv->in_head_mode_rulesmodev|_,`EOFasv->in_body_mode_rules"select"modev|l,_->reportl(`Bad_content"select")!throwmode(* 8.2.5.4.17. *)andin_select_in_table_mode()=dispatchtokensbeginfunction|l,`Start({name="caption"|"table"|"tbody"|"tfoot"|"thead"|"tr"|"td"|"th"}ast)asv->misnested_taglt"table"(fun()->pushtokensv;close_elementl"select"(fun()->reset_mode()()))|l,`End{name="caption"|"table"|"tbody"|"tfoot"|"thead"|"tr"|"td"|"th"asname}asv->reportl(`Unmatched_end_tag"name")!throw(fun()->ifnot@@Stack.in_table_scopeopen_elementsnamethenin_select_in_table_mode()elsebeginpushtokensv;close_elementl"select"(fun()->reset_mode()())end)|v->in_select_mode_rulesin_select_in_table_modevend(* 8.2.5.4.18. *)andin_template_mode()=dispatchtokens(funv->in_table_mode_rulesin_template_modev)(* 8.2.5.4.18. *)andin_template_mode_rulesmode=function|_,(`Char_|`Comment_|`Doctype_)asv->in_body_mode_rules"template"modev|_,`Start{name="base"|"basefont"|"bgsound"|"link"|"meta"|"noframes"|"script"|"style"|"template"|"title"}|_,`End{name="template"}asv->in_head_mode_rulesmodev|_,`Start{name="caption"|"colgroup"|"tbody"|"tfoot"|"thead"}asv->Template.poptemplate_insertion_modes;Template.pushtemplate_insertion_modesin_table_mode;pushtokensv;in_table_mode()|_,`Start{name="col"}asv->Template.poptemplate_insertion_modes;Template.pushtemplate_insertion_modesin_column_group_mode;pushtokensv;in_column_group_mode()|_,`Start{name="tr"}asv->Template.poptemplate_insertion_modes;Template.pushtemplate_insertion_modesin_table_body_mode;pushtokensv;in_table_body_mode()|_,`Start{name="td"|"th"}asv->Template.poptemplate_insertion_modes;Template.pushtemplate_insertion_modesin_row_mode;pushtokensv;in_row_mode()|_,`Start_asv->Template.poptemplate_insertion_modes;Template.pushtemplate_insertion_modesin_body_mode;pushtokensv;in_body_mode()|l,`End{name}->reportl(`Unmatched_end_tagname)!throwmode|l,`EOFasv->ifnot@@Stack.hasopen_elements"template"thenemit_endlelsebeginreportl(`Unmatched_end_tag"template")!throw(fun()->Active.clear_until_markeractive_formatting_elements;Template.poptemplate_insertion_modes;pushtokensv;close_elementl"template"(fun()->reset_mode()()))end(* 8.2.5.4.19. *)andafter_body_mode()=dispatchtokensbeginfunction|_,`Char(0x0009|0x000A|0x000C|0x000D|0x0020)asv->in_body_mode_rules"html"after_body_modev|l,`Comments->emitl(`Comments)after_body_mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwafter_body_mode|_,`Start{name="html"}asv->in_body_mode_rules"html"after_body_modev|_,`End{name="html"}->after_after_body_mode()|l,`EOF->emit_endl|l,_asv->reportl(`Bad_document"content after body")!throw(fun()->pushtokensv;in_body_mode())end(* 8.2.5.4.20. *)andin_frameset_mode()=dispatchtokensbeginfunction|l,`Char(0x0009|0x000A|0x000C|0x000D|0x0020asc)->add_characterlc;in_frameset_mode()|l,`Comments->emitl(`Comments)in_frameset_mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwin_frameset_mode|_,`Start{name="html"}asv->in_body_mode_rules"frameset"in_frameset_modev|l,`Start({name="frameset"}ast)->push_and_emitltin_frameset_mode|l,`End{name="frameset"}->(funmode'->ifStack.current_element_isopen_elements["html"]thenreportl(`Unmatched_end_tag"frameset")!throwmode'elsepoplmode')(fun()->ifStack.current_element_isopen_elements["frameset"]thenin_frameset_mode()elseafter_frameset_mode())|l,`Start({name="frame"}ast)->push_and_emit~acknowledge:truelt(fun()->poplin_frameset_mode)|_,`Start{name="noframes"}asv->in_head_mode_rulesin_frameset_modev|l,`EOF->(funmode'->ifnot@@Stack.current_element_isopen_elements["html"]thenreportl(`Unexpected_eoi"frameset")!throwmode'elsemode'())(fun()->emit_endl)|l,_->reportl(`Bad_content"frameset")!throwin_frameset_modeend(* 8.2.5.4.21. *)andafter_frameset_mode()=dispatchtokensbeginfunction|l,`Char(0x0009|0x000A|0x000C|0x000D|0x0020asc)->add_characterlc;after_frameset_mode()|l,`Comments->emitl(`Comments)after_frameset_mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwafter_frameset_mode|_,`Start{name="html"}asv->in_body_mode_rules"html"after_frameset_modev|l,`End{name="html"}->close_elementl"html"after_after_frameset_mode|_,`Start{name="noframes"}asv->in_head_mode_rulesafter_frameset_modev|l,`EOF->emit_endl|l,_->reportl(`Bad_content"html")!throwafter_frameset_modeend(* 8.2.5.4.22. *)andafter_after_body_mode()=dispatchtokensbeginfunction|l,`Comments->emitl(`Comments)after_after_body_mode|_,`Doctype_|_,`Char(0x0009|0x000A|0x000C|0x000D|0x0020)|_,`Start{name="html"}asv->in_body_mode_rules"html"after_after_body_modev|l,`EOF->emit_endl|l,_asv->pushtokensv;reportl(`Bad_content"html")!throwin_body_modeend(* 8.2.5.4.23. *)andafter_after_frameset_mode()=dispatchtokensbeginfunction|l,`Comments->emitl(`Comments)after_after_frameset_mode|_,`Doctype_|_,`Char(0x0009|0x000A|0x000C|0x000D|0x0020)|_,`Start{name="html"}asv->in_body_mode_rules"html"after_after_frameset_modev|l,`EOF->emit_endl|_,`Start{name="noframes"}asv->in_head_mode_rulesafter_after_frameset_modev|l,_->reportl(`Bad_content"html")!throwafter_after_frameset_modeend(* 8.2.5.5. *)andforeign_start_tagmodeltag=letnamespace=matchStack.adjusted_current_elementcontextopen_elementswith|None->`HTML|Some{element_name=ns,_}->nsinpush_and_emit~acknowledge:true~namespaceltag(fun()->iftag.self_closingthenpoplmodeelsemode())andis_html_font_tagtag=tag.Token_tag.attributes|>List.exists(function|("color"|"face"|"size"),_->true|_->false)andforeign_contentmodeforce_htmlv=matchvwith|l,`Char0->reportl(`Bad_token("U+0000","foreign content","null"))!throw(fun()->add_characterlu_rep;mode())|l,`Char(0x0009|0x000A|0x000C|0x000D|0x0020asc)->add_characterlc;mode()|l,`Charc->frameset_ok:=false;add_characterlc;mode()|l,`Comments->emitl(`Comments)mode|l,`Doctype_->reportl(`Bad_document"doctype should be first")!throwmode|l,`Start({name="b"|"big"|"blockquote"|"body"|"br"|"center"|"code"|"dd"|"div"|"dl"|"dt"|"em"|"embed"|"font"|"h1"|"h2"|"h3"|"h4"|"h5"|"h6"|"head"|"hr"|"i"|"img"|"li"|"listing"|"main"|"meta"|"nobr"|"ol"|"p"|"pre"|"ruby"|"s"|"small"|"span"|"strong"|"strike"|"sub"|"sup"|"table"|"tt"|"u"|"ul"|"var"asname}ast)asv->ifname="font"&¬@@is_html_font_tagtthenforeign_start_tagmodeltelsemisnested_taglt"xml tag"(fun()->pushtokensv;popl(fun()->pop_until(function|{element_name=`HTML,_}->true|{is_html_integration_point=true}->true|{element_name}->Foreign.is_mathml_text_integration_pointelement_name)lmode))|l,`Startt->foreign_start_tagmodelt|l,`End{name="script"}whenmatchStack.current_elementopen_elementswith|Some{element_name=`SVG,"script"}->true|_->false->poplmode|l,`End{name}->(funmode'->matchStack.current_elementopen_elementswith|Some{element_name=_,name'}whenString.lowercase_asciiname'=name->mode'()|_->reportl(`Unmatched_end_tagname)!throw(fun()->mode'()))(fun()->letrecscan=function|[]->mode()|{element_name=ns,name'}::_whenString.lowercase_asciiname'=name->close_element~nslnamemode|{element_name=`HTML,_}::_->force_html()|_::rest->scanrestinscan!open_elements)|_,`EOF->force_html()inconstructconstructor