| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922 |
- // Copyright (C) 2024 T. Zachary Laine
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_PARSER_PARSER_HPP
- #define BOOST_PARSER_PARSER_HPP
- #include <boost/parser/parser_fwd.hpp>
- #include <boost/parser/concepts.hpp>
- #include <boost/parser/error_handling.hpp>
- #include <boost/parser/tuple.hpp>
- #include <boost/parser/detail/hl.hpp>
- #include <boost/parser/detail/numeric.hpp>
- #include <boost/parser/detail/case_fold.hpp>
- #include <boost/parser/detail/unicode_char_sets.hpp>
- #include <boost/parser/detail/pp_for_each.hpp>
- #include <boost/parser/detail/printing.hpp>
- #include <boost/parser/detail/text/algorithm.hpp>
- #include <boost/parser/detail/text/trie_map.hpp>
- #include <boost/parser/detail/text/unpack.hpp>
- #include <type_traits>
- #include <variant>
- #include <vector>
- namespace boost { namespace parser {
- /** A placeholder type used to represent the absence of information,
- value, etc., inside semantic actions. For instance, calling
- `_locals(ctx)` in a semantic action associated with a parser that has
- no locals will yield a `none`. */
- struct none;
- #if defined(BOOST_PARSER_NO_RUNTIME_ASSERTIONS)
- struct none
- {};
- #else
- struct none
- {
- none() = default;
- // Constructible from, assignable from, and implicitly convertible to,
- // anything.
- template<typename T>
- none(T const &)
- {
- fail();
- }
- template<typename T>
- none & operator=(T const &)
- {
- fail();
- return *this;
- }
- template<typename T>
- operator T() const
- {
- fail();
- return T{};
- }
- // unary operators
- none operator+() const
- {
- fail();
- return none{};
- }
- none operator-() const
- {
- fail();
- return none{};
- }
- none operator*() const
- {
- fail();
- return none{};
- }
- none operator~() const
- {
- fail();
- return none{};
- }
- none operator&() const
- {
- fail();
- return none{};
- }
- none operator!() const
- {
- fail();
- return none{};
- }
- none operator++()
- {
- fail();
- return none{};
- }
- none & operator++(int)
- {
- fail();
- return *this;
- }
- none operator--()
- {
- fail();
- return none{};
- }
- none operator--(int)
- {
- fail();
- return *this;
- }
- // binary operators
- template<typename T>
- none operator<<(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator>>(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator*(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator/(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator%(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator+(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator-(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator<(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator>(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator<=(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator>=(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator==(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator!=(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator||(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator&&(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator&(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator|(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator^(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator,(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator->*(T const &) const
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator<<=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator>>=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator*=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator/=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator%=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator+=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator-=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator&=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator|=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator^=(T const &)
- {
- fail();
- return none{};
- }
- template<typename T>
- none operator[](T const &) const
- {
- fail();
- return none{};
- }
- // n-ary operators
- template<typename... Args>
- none operator()(Args const &...) const
- {
- fail();
- return none{};
- }
- void fail() const
- {
- // If you're seeing this, you've probably gotten a `none` out of
- // the parse context, and are trying to use it because you think
- // it's something else. For instance, if your parser produces an
- // int attribute, the semantic ation `[](auto & ctx) { _attr(ctx)
- // = 0; }` may be fine. If you attach that same semantic action
- // to `eps`, you end up here, because `eps` has no attribute, and
- // so `_attr(ctx)` produces a `none`.
- BOOST_PARSER_DEBUG_ASSERT(false);
- }
- };
- #endif
- namespace detail {
- // Follows boost/mpl/print.hpp.
- #if defined(_MSC_VER)
- #pragma warning(push, 3)
- #pragma warning(disable : 4307)
- #endif
- #if defined(__EDG_VERSION__)
- namespace print_aux {
- template<typename T>
- struct dependent_unsigned
- {
- static const unsigned int value = 1;
- };
- }
- #endif
- template<typename T>
- struct identity_t
- {
- using type = T;
- };
- template<typename T>
- struct print_t : identity_t<T>
- {
- #if defined(__clang__)
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wc++11-extensions"
- const int x_ = 1 / (sizeof(T) - sizeof(T));
- #pragma clang diagnostic pop
- #elif defined(_MSC_VER)
- enum { n = sizeof(T) + -1 };
- #elif defined(__MWERKS__)
- void f(int);
- #else
- enum {
- n =
- #if defined(__EDG_VERSION__)
- print_aux::dependent_unsigned<T>::value > -1
- #else
- sizeof(T) > -1
- #endif
- };
- #endif
- };
- #if defined(_MSC_VER)
- #pragma warning(pop)
- #endif
- template<typename T>
- using print_type = typename print_t<T>::type;
- struct null_parser
- {};
- template<typename R, typename Parser, typename SkipParser = null_parser>
- struct attribute_impl;
- // Utility types.
- struct nope
- {
- template<typename T>
- constexpr nope & operator=(T const &)
- {
- return *this;
- }
- operator std::nullopt_t() const noexcept { return std::nullopt; }
- template<typename Context>
- constexpr bool operator()(Context const &) const noexcept
- {
- return true;
- }
- constexpr nope operator*() const noexcept { return nope{}; }
- friend constexpr bool operator==(nope, nope) { return true; }
- friend constexpr bool operator!=(nope, nope) { return false; }
- template<typename T>
- friend constexpr bool operator==(T, nope)
- {
- return false;
- }
- template<typename T>
- friend constexpr bool operator!=(T, nope)
- {
- return false;
- }
- };
- inline nope const global_nope;
- template<typename T>
- using parser_interface_tag_expr =
- typename T::parser_interface_derivation_tag;
- template<typename T>
- constexpr bool derived_from_parser_interface_v =
- is_detected_v<parser_interface_tag_expr, T>;
- template<typename T, bool AlwaysConst = false>
- using nope_or_pointer_t = std::conditional_t<
- std::is_same_v<std::remove_const_t<T>, nope>,
- nope,
- std::conditional_t<AlwaysConst, T const *, T *>>;
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename I,
- typename S,
- typename ErrorHandler,
- typename GlobalState = nope const,
- typename Callbacks = nope,
- typename Attr = nope,
- typename Val = nope,
- typename RuleTag = void,
- typename RuleLocals = nope,
- typename RuleParams = nope,
- typename Where = nope>
- struct parse_context
- {
- parse_context() = default;
- parse_context(parse_context const &) = default;
- parse_context & operator=(parse_context const &) = default;
- using rule_tag = RuleTag;
- static constexpr bool do_trace = DoTrace;
- static constexpr bool use_callbacks = UseCallbacks;
- I first_;
- S last_;
- bool * pass_ = nullptr;
- int * trace_indent_ = nullptr;
- symbol_table_tries_t * symbol_table_tries_ = nullptr;
- pending_symbol_table_operations_t *
- pending_symbol_table_operations_ = nullptr;
- ErrorHandler const * error_handler_ = nullptr;
- nope_or_pointer_t<GlobalState> globals_{};
- nope_or_pointer_t<Callbacks, true> callbacks_{};
- nope_or_pointer_t<Attr> attr_{};
- nope_or_pointer_t<Val> val_{};
- nope_or_pointer_t<RuleLocals> locals_{};
- nope_or_pointer_t<RuleParams, true> params_{};
- nope_or_pointer_t<Where, true> where_{};
- int no_case_depth_ = 0;
- // These exist in order to provide an address, if requested, for
- // either kind of symbol table struct. The nonstatic member
- // pointers for these will be null if this context was created
- // inside of detail::skip(), but nothing prevents the user from
- // trying to use a symbol_parser anyway. So, we have these.
- static std::optional<symbol_table_tries_t>
- empty_symbol_table_tries_;
- static std::optional<pending_symbol_table_operations_t>
- empty_pending_symbol_table_operations_;
- symbol_table_tries_t & get_symbol_table_tries() const
- {
- if (symbol_table_tries_)
- return *symbol_table_tries_;
- if (!empty_symbol_table_tries_)
- empty_symbol_table_tries_ = symbol_table_tries_t();
- return *empty_symbol_table_tries_;
- }
- pending_symbol_table_operations_t &
- get_pending_symbol_table_operations() const
- {
- if (pending_symbol_table_operations_)
- return *pending_symbol_table_operations_;
- if (!empty_pending_symbol_table_operations_) {
- empty_pending_symbol_table_operations_ =
- pending_symbol_table_operations_t();
- }
- return *empty_pending_symbol_table_operations_;
- }
- template<typename T>
- static auto nope_or_address(T & x)
- {
- if constexpr (std::is_same_v<std::remove_const_t<T>, nope>)
- return nope{};
- else
- return std::addressof(x);
- }
- template<typename T, typename U>
- static auto other_or_address(T other, U & x)
- {
- if constexpr (std::is_same_v<std::remove_const_t<U>, nope>)
- return other;
- else
- return std::addressof(x);
- }
- parse_context(
- std::bool_constant<DoTrace>,
- std::bool_constant<UseCallbacks>,
- I & first,
- S last,
- bool & success,
- int & indent,
- ErrorHandler const & error_handler,
- GlobalState & globals,
- symbol_table_tries_t & symbol_table_tries,
- pending_symbol_table_operations_t &
- pending_symbol_table_operations) :
- first_(first),
- last_(last),
- pass_(std::addressof(success)),
- trace_indent_(std::addressof(indent)),
- symbol_table_tries_(std::addressof(symbol_table_tries)),
- pending_symbol_table_operations_(
- std::addressof(pending_symbol_table_operations)),
- error_handler_(std::addressof(error_handler)),
- globals_(nope_or_address(globals))
- {}
- parse_context(
- std::bool_constant<DoTrace>,
- std::bool_constant<UseCallbacks>,
- I & first,
- S last,
- bool & success,
- int & indent,
- ErrorHandler const & error_handler,
- GlobalState & globals) :
- first_(first),
- last_(last),
- pass_(std::addressof(success)),
- trace_indent_(std::addressof(indent)),
- error_handler_(std::addressof(error_handler)),
- globals_(nope_or_address(globals))
- {}
- // With callbacks.
- parse_context(
- std::bool_constant<DoTrace>,
- std::bool_constant<UseCallbacks>,
- I & first,
- S last,
- bool & success,
- int & indent,
- ErrorHandler const & error_handler,
- Callbacks const & callbacks,
- GlobalState & globals,
- symbol_table_tries_t & symbol_table_tries,
- pending_symbol_table_operations_t &
- pending_symbol_table_operations) :
- first_(first),
- last_(last),
- pass_(std::addressof(success)),
- trace_indent_(std::addressof(indent)),
- symbol_table_tries_(std::addressof(symbol_table_tries)),
- pending_symbol_table_operations_(
- std::addressof(pending_symbol_table_operations)),
- error_handler_(std::addressof(error_handler)),
- globals_(nope_or_address(globals)),
- callbacks_(std::addressof(callbacks))
- {}
- // For making rule contexts.
- template<
- typename OldVal,
- typename OldRuleTag,
- typename OldRuleLocals,
- typename OldRuleParams,
- typename NewVal,
- typename NewRuleTag,
- typename NewRuleLocals,
- typename NewRuleParams>
- parse_context(
- parse_context<
- DoTrace,
- UseCallbacks,
- I,
- S,
- ErrorHandler,
- GlobalState,
- Callbacks,
- Attr,
- OldVal,
- OldRuleTag,
- OldRuleLocals,
- OldRuleParams> const & other,
- NewRuleTag * tag_ptr,
- NewVal & value,
- NewRuleLocals & locals,
- NewRuleParams const & params) :
- first_(other.first_),
- last_(other.last_),
- pass_(other.pass_),
- trace_indent_(other.trace_indent_),
- symbol_table_tries_(other.symbol_table_tries_),
- pending_symbol_table_operations_(
- other.pending_symbol_table_operations_),
- error_handler_(other.error_handler_),
- globals_(other.globals_),
- callbacks_(other.callbacks_),
- attr_(other.attr_),
- no_case_depth_(other.no_case_depth_)
- {
- if constexpr (
- std::is_same_v<OldRuleTag, NewRuleTag> &&
- !std::is_same_v<OldRuleTag, void>) {
- val_ = other.val_;
- locals_ = other.locals_;
- params_ = other.params_;
- } else {
- val_ = other_or_address(other.val_, value);
- locals_ = other_or_address(other.locals_, locals);
- params_ = other_or_address(other.params_, params);
- }
- }
- // For making action contexts.
- template<typename OldAttr, typename OldWhere>
- parse_context(
- parse_context<
- DoTrace,
- UseCallbacks,
- I,
- S,
- ErrorHandler,
- GlobalState,
- Callbacks,
- OldAttr,
- Val,
- RuleTag,
- RuleLocals,
- RuleParams,
- OldWhere> const & other,
- Attr & attr,
- Where const & where) :
- first_(other.first_),
- last_(other.last_),
- pass_(other.pass_),
- trace_indent_(other.trace_indent_),
- symbol_table_tries_(other.symbol_table_tries_),
- pending_symbol_table_operations_(
- other.pending_symbol_table_operations_),
- error_handler_(other.error_handler_),
- globals_(other.globals_),
- callbacks_(other.callbacks_),
- attr_(nope_or_address(attr)),
- val_(other.val_),
- locals_(other.locals_),
- params_(other.params_),
- where_(nope_or_address(where)),
- no_case_depth_(other.no_case_depth_)
- {}
- };
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename I,
- typename S,
- typename ErrorHandler,
- typename GlobalState,
- typename Callbacks,
- typename Attr,
- typename Val,
- typename RuleTag,
- typename RuleLocals,
- typename RuleParams,
- typename Where>
- std::optional<symbol_table_tries_t> parse_context<
- DoTrace,
- UseCallbacks,
- I,
- S,
- ErrorHandler,
- GlobalState,
- Callbacks,
- Attr,
- Val,
- RuleTag,
- RuleLocals,
- RuleParams,
- Where>::empty_symbol_table_tries_;
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename I,
- typename S,
- typename ErrorHandler,
- typename GlobalState,
- typename Callbacks,
- typename Attr,
- typename Val,
- typename RuleTag,
- typename RuleLocals,
- typename RuleParams,
- typename Where>
- std::optional<pending_symbol_table_operations_t> parse_context<
- DoTrace,
- UseCallbacks,
- I,
- S,
- ErrorHandler,
- GlobalState,
- Callbacks,
- Attr,
- Val,
- RuleTag,
- RuleLocals,
- RuleParams,
- Where>::empty_pending_symbol_table_operations_;
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename I,
- typename S,
- typename ErrorHandler,
- typename GlobalState,
- typename Callbacks,
- typename Val,
- typename RuleTag,
- typename RuleLocals,
- typename RuleParams,
- typename Attr,
- typename Where,
- typename OldAttr>
- auto make_action_context(
- parse_context<
- DoTrace,
- UseCallbacks,
- I,
- S,
- ErrorHandler,
- GlobalState,
- Callbacks,
- OldAttr,
- Val,
- RuleTag,
- RuleLocals,
- RuleParams> const & context,
- Attr & attr,
- Where const & where)
- {
- using result_type = parse_context<
- DoTrace,
- UseCallbacks,
- I,
- S,
- ErrorHandler,
- GlobalState,
- Callbacks,
- Attr,
- Val,
- RuleTag,
- RuleLocals,
- RuleParams,
- Where>;
- return result_type(context, attr, where);
- }
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename I,
- typename S,
- typename ErrorHandler,
- typename GlobalState,
- typename Callbacks,
- typename Attr,
- typename Val,
- typename RuleTag,
- typename RuleLocals,
- typename RuleParams,
- typename NewVal,
- typename NewRuleTag,
- typename NewRuleLocals,
- typename NewRuleParams>
- auto make_rule_context(
- parse_context<
- DoTrace,
- UseCallbacks,
- I,
- S,
- ErrorHandler,
- GlobalState,
- Callbacks,
- Attr,
- Val,
- RuleTag,
- RuleLocals,
- RuleParams> const & context,
- NewRuleTag * tag_ptr,
- NewVal & value,
- NewRuleLocals & locals,
- NewRuleParams const & params)
- {
- using result_type = parse_context<
- DoTrace,
- UseCallbacks,
- I,
- S,
- ErrorHandler,
- GlobalState,
- Callbacks,
- Attr,
- std::conditional_t<std::is_same_v<NewVal, nope>, Val, NewVal>,
- NewRuleTag,
- std::conditional_t<
- std::is_same_v<NewRuleLocals, nope>,
- RuleLocals,
- NewRuleLocals>,
- std::conditional_t<
- std::is_same_v<NewRuleParams, nope>,
- RuleParams,
- NewRuleParams>>;
- return result_type(context, tag_ptr, value, locals, params);
- }
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename Iter,
- typename Sentinel,
- typename ErrorHandler>
- auto make_context(
- Iter first,
- Sentinel last,
- bool & success,
- int & indent,
- ErrorHandler const & error_handler,
- nope const & n,
- symbol_table_tries_t & symbol_table_tries,
- pending_symbol_table_operations_t &
- pending_symbol_table_operations) noexcept
- {
- return parse_context(
- std::bool_constant<DoTrace>{},
- std::bool_constant<UseCallbacks>{},
- first,
- last,
- success,
- indent,
- error_handler,
- n,
- symbol_table_tries,
- pending_symbol_table_operations);
- }
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename Iter,
- typename Sentinel,
- typename ErrorHandler>
- auto make_context(
- Iter first,
- Sentinel last,
- bool & success,
- int & indent,
- ErrorHandler const & error_handler,
- nope const & n,
- nope const &,
- nope const &) noexcept
- {
- return parse_context(
- std::bool_constant<DoTrace>{},
- std::bool_constant<UseCallbacks>{},
- first,
- last,
- success,
- indent,
- error_handler,
- n);
- }
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename Iter,
- typename Sentinel,
- typename ErrorHandler,
- typename GlobalState>
- auto make_context(
- Iter first,
- Sentinel last,
- bool & success,
- int & indent,
- ErrorHandler const & error_handler,
- GlobalState & globals,
- symbol_table_tries_t & symbol_table_tries,
- pending_symbol_table_operations_t &
- pending_symbol_table_operations) noexcept
- {
- return parse_context(
- std::bool_constant<DoTrace>{},
- std::bool_constant<UseCallbacks>{},
- first,
- last,
- success,
- indent,
- error_handler,
- globals,
- symbol_table_tries,
- pending_symbol_table_operations);
- }
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename Iter,
- typename Sentinel,
- typename ErrorHandler,
- typename Callbacks>
- auto make_context(
- Iter first,
- Sentinel last,
- bool & success,
- int & indent,
- ErrorHandler const & error_handler,
- Callbacks const & callbacks,
- nope & n,
- symbol_table_tries_t & symbol_table_tries,
- pending_symbol_table_operations_t &
- pending_symbol_table_operations) noexcept
- {
- return parse_context(
- std::bool_constant<DoTrace>{},
- std::bool_constant<UseCallbacks>{},
- first,
- last,
- success,
- indent,
- error_handler,
- callbacks,
- n,
- symbol_table_tries,
- pending_symbol_table_operations);
- }
- template<
- bool DoTrace,
- bool UseCallbacks,
- typename Iter,
- typename Sentinel,
- typename ErrorHandler,
- typename Callbacks,
- typename GlobalState>
- auto make_context(
- Iter first,
- Sentinel last,
- bool & success,
- int & indent,
- ErrorHandler const & error_handler,
- Callbacks const & callbacks,
- GlobalState & globals,
- symbol_table_tries_t & symbol_table_tries,
- pending_symbol_table_operations_t &
- pending_symbol_table_operations) noexcept
- {
- return parse_context(
- std::bool_constant<DoTrace>{},
- std::bool_constant<UseCallbacks>{},
- first,
- last,
- success,
- indent,
- error_handler,
- callbacks,
- globals,
- symbol_table_tries,
- pending_symbol_table_operations);
- }
- template<unsigned int I>
- struct param_t
- {
- template<typename Context>
- decltype(auto) operator()(Context const & context) const
- {
- return parser::get(parser::_params(context), llong<I>{});
- }
- };
- template<typename T, typename... Args>
- using callable = decltype(std::declval<T>()(std::declval<Args>()...));
- template<
- typename Context,
- typename T,
- bool Callable = is_detected_v<callable, T const &, Context const &>>
- struct resolve_impl
- {
- static auto call(Context const &, T const & x) { return x; }
- };
- template<typename Context, typename T>
- struct resolve_impl<Context, T, true>
- {
- static auto call(Context const & context, T const & x)
- {
- return x(context);
- }
- };
- template<typename Context, typename T>
- auto resolve(Context const & context, T const & x)
- {
- return resolve_impl<Context, T>::call(context, x);
- }
- template<typename Context>
- auto resolve(Context const &, nope n)
- {
- return n;
- }
- template<typename Context, typename ParamsTuple>
- auto
- resolve_rule_params(Context const & context, ParamsTuple const & params)
- {
- return detail::hl::transform(params, [&](auto const & x) {
- return detail::resolve(context, x);
- });
- }
- template<typename Context>
- nope resolve_rule_params(Context const & context, nope)
- {
- return {};
- }
- template<typename LocalsType, typename Context>
- LocalsType make_locals_impl(Context const & context, std::true_type)
- {
- return LocalsType(context);
- }
- template<typename LocalsType, typename Context>
- LocalsType make_locals_impl(Context const & context, std::false_type)
- {
- return LocalsType();
- }
- template<typename LocalsType, typename Context>
- LocalsType make_locals(Context const & context)
- {
- return detail::make_locals_impl<LocalsType>(
- context,
- typename std::is_convertible<Context const &, LocalsType>::
- type{});
- }
- template<typename Context>
- decltype(auto) _indent(Context const & context)
- {
- return *context.trace_indent_;
- }
- template<typename Context>
- decltype(auto) _callbacks(Context const & context)
- {
- return *context.callbacks_;
- }
- // Type traits.
- template<typename T>
- using remove_cv_ref_t = typename std::remove_cv<
- typename std::remove_reference<T>::type>::type;
- template<typename T, typename U>
- using comparison = decltype(std::declval<T>() == std::declval<U>());
- template<typename T, typename U>
- constexpr bool is_equality_comparable_with_v =
- is_detected_v<comparison, T, U>;
- template<typename T>
- struct is_nope : std::false_type
- {};
- template<>
- struct is_nope<nope> : std::true_type
- {};
- template<typename T>
- constexpr bool is_nope_v = is_nope<remove_cv_ref_t<T>>::value;
- template<typename T>
- struct is_eps_p : std::false_type
- {};
- template<typename T>
- struct is_eps_p<eps_parser<T>> : std::true_type
- {};
- template<typename T>
- struct is_unconditional_eps : std::false_type
- {};
- template<>
- struct is_unconditional_eps<eps_parser<nope>> : std::true_type
- {};
- template<typename T>
- constexpr bool is_unconditional_eps_v =
- is_unconditional_eps<remove_cv_ref_t<T>>::value;
- template<typename T>
- struct is_zero_plus_p : std::false_type
- {};
- template<typename T>
- struct is_zero_plus_p<zero_plus_parser<T>> : std::true_type
- {};
- template<typename T>
- struct is_or_p : std::false_type
- {};
- template<typename T>
- struct is_or_p<or_parser<T>> : std::true_type
- {};
- template<typename T>
- struct is_perm_p : std::false_type
- {};
- template<typename T, typename DelimiterParser>
- struct is_perm_p<perm_parser<T, DelimiterParser>> : std::true_type
- {};
- template<typename T>
- struct is_seq_p : std::false_type
- {};
- template<typename T, typename U, typename V>
- struct is_seq_p<seq_parser<T, U, V>> : std::true_type
- {};
- template<typename T>
- struct is_one_plus_p : std::false_type
- {};
- template<typename T>
- struct is_one_plus_p<one_plus_parser<T>> : std::true_type
- {};
- template<typename T>
- struct is_utf8_view : std::false_type
- {};
- template<typename V>
- struct is_utf8_view<text::utf8_view<V>> : std::true_type
- {};
- template<typename T>
- using optional_type = remove_cv_ref_t<decltype(*std::declval<T &>())>;
- template<typename F, typename... Args>
- constexpr bool is_invocable_v = is_detected_v<callable, F, Args...>;
- template<typename T>
- using has_begin =
- decltype(*detail::text::detail::begin(std::declval<T &>()));
- template<typename T>
- using has_end =
- decltype(detail::text::detail::end(std::declval<T &>()));
- template<typename T>
- constexpr bool is_range =
- is_detected_v<has_begin, T> && is_detected_v<has_end, T>;
- template<typename T>
- using has_push_back =
- decltype(std::declval<T &>().push_back(*std::declval<T>().begin()));
- #if BOOST_PARSER_USE_CONCEPTS
- template<typename T>
- using iterator_t = std::ranges::iterator_t<T>;
- template<typename T>
- using sentinel_t = std::ranges::sentinel_t<T>;
- template<typename T>
- using iter_value_t = std::iter_value_t<T>;
- template<typename T>
- using iter_reference_t = std::iter_reference_t<T>;
- template<typename T>
- using range_value_t = std::ranges::range_value_t<T>;
- template<typename T>
- using range_reference_t = std::ranges::range_reference_t<T>;
- template<typename T>
- using range_rvalue_reference_t =
- std::ranges::range_rvalue_reference_t<T>;
- template<typename T>
- constexpr bool is_parsable_code_unit_v = code_unit<T>;
- #else
- template<typename T>
- using iterator_t =
- decltype(detail::text::detail::begin(std::declval<T &>()));
- template<typename Range>
- using sentinel_t =
- decltype(detail::text::detail::end(std::declval<Range &>()));
- template<typename T>
- using iter_value_t = typename std::iterator_traits<T>::value_type;
- template<typename T>
- using iter_reference_t = decltype(*std::declval<T &>());
- template<typename T>
- using iter_rvalue_reference_t =
- decltype(std::move(*std::declval<T &>()));
- template<typename T>
- using range_value_t = iter_value_t<iterator_t<T>>;
- template<typename T>
- using range_reference_t = iter_reference_t<iterator_t<T>>;
- template<typename T>
- using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<T>>;
- template<typename T>
- using has_insert = decltype(std::declval<T &>().insert(
- std::declval<T>().begin(), *std::declval<T>().begin()));
- template<typename T>
- using has_range_insert = decltype(std::declval<T &>().insert(
- std::declval<T>().begin(),
- std::declval<T>().begin(),
- std::declval<T>().end()));
- template<typename T>
- constexpr bool is_container_v = is_detected_v<has_insert, T>;
- template<typename T, typename U>
- constexpr bool container_and_value_type =
- is_container_v<T> &&
- (std::is_same_v<detected_t<range_value_t, T>, U> ||
- (std::is_same_v<T, std::string> && std::is_same_v<U, char32_t>));
- template<typename T>
- constexpr bool is_parsable_code_unit_impl =
- std::is_same_v<T, char> || std::is_same_v<T, wchar_t> ||
- #if defined(__cpp_char8_t)
- std::is_same_v<T, char8_t> ||
- #endif
- std::is_same_v<T, char16_t> || std::is_same_v<T, char32_t>;
- template<typename T>
- constexpr bool is_parsable_code_unit_v =
- is_parsable_code_unit_impl<std::remove_cv_t<T>>;
- template<typename T>
- constexpr bool is_parsable_iter_v = is_parsable_code_unit_v<
- remove_cv_ref_t<detected_t<iter_value_t, T>>>;
- template<typename T>
- constexpr bool is_parsable_range_v = is_parsable_code_unit_v<
- remove_cv_ref_t<detected_t<has_begin, T>>> &&
- is_detected_v<has_end, T>;
- template<typename T>
- constexpr bool is_parsable_pointer_v =
- std::is_pointer_v<remove_cv_ref_t<T>> && is_parsable_code_unit_v<
- std::remove_pointer_t<remove_cv_ref_t<T>>>;
- template<typename T>
- constexpr bool is_parsable_range_like_v =
- is_parsable_range_v<T> || is_parsable_pointer_v<T>;
- }
- template<typename T>
- constexpr bool container = detail::is_container_v<T>;
- namespace detail {
- #endif
- template<typename T, bool = std::is_pointer_v<T>>
- constexpr bool is_code_unit_pointer_v = false;
- template<typename T>
- constexpr bool is_code_unit_pointer_v<T, true> =
- is_parsable_code_unit_v<std::remove_pointer_t<T>>;
- template<typename T>
- constexpr bool is_range_like = is_range<T> || is_code_unit_pointer_v<T>;
- template<typename I>
- constexpr bool is_char8_iter_v =
- #if defined(__cpp_char8_t)
- std::is_same_v<iter_value_t<I>, char8_t>
- #else
- false
- #endif
- ;
- // Metafunctions.
- template<bool WrapInOptional, typename Tuple>
- struct to_hana_tuple_or_type_impl;
- template<typename... T>
- struct to_hana_tuple_or_type_impl<true, tuple<T...>>
- {
- using type = std::optional<std::variant<T...>>;
- };
- template<typename... T>
- struct to_hana_tuple_or_type_impl<false, tuple<T...>>
- {
- using type = std::variant<T...>;
- };
- template<typename T>
- struct to_hana_tuple_or_type_impl<true, tuple<T>>
- {
- // The reason this is not two separate specializations, one
- // for tuple<t> and on for tuple<optional<T>>, is because
- // MSVC.
- using type =
- std::conditional_t<is_optional_v<T>, T, std::optional<T>>;
- };
- template<typename T>
- struct to_hana_tuple_or_type_impl<false, tuple<T>>
- {
- using type = T;
- };
- template<>
- struct to_hana_tuple_or_type_impl<true, tuple<>>
- {
- using type = nope;
- };
- template<>
- struct to_hana_tuple_or_type_impl<false, tuple<>>
- {
- using type = nope;
- };
- template<typename Pair>
- struct to_hana_tuple_or_type;
- template<typename Tuple, typename TrueFalse>
- struct to_hana_tuple_or_type<tuple<Tuple, TrueFalse>>
- {
- // This has to be done in two steps like this because MSVC.
- using type =
- typename to_hana_tuple_or_type_impl<TrueFalse::value, Tuple>::
- type;
- };
- template<typename T>
- using to_hana_tuple_or_type_t = typename to_hana_tuple_or_type<T>::type;
- template<typename T>
- auto make_sequence_of()
- {
- if constexpr (
- std::is_same_v<T, char> || std::is_same_v<T, char32_t>) {
- return std::string{};
- } else if constexpr (std::is_same_v<T, nope>) {
- return nope{};
- } else {
- return std::vector<T>{};
- }
- }
- template<typename T>
- constexpr bool is_char_type_v =
- std::is_same_v<T, char> || std::is_same_v<T, char32_t>;
- template<typename T>
- struct optional_of_impl
- {
- using type = std::optional<T>;
- };
- template<typename T>
- struct optional_of_impl<std::optional<T>>
- {
- using type = std::optional<T>;
- };
- template<>
- struct optional_of_impl<nope>
- {
- using type = nope;
- };
- template<typename T>
- using optional_of = typename optional_of_impl<T>::type;
- template<typename T>
- struct unwrapped_optional
- {
- using type = T;
- };
- template<typename T>
- struct unwrapped_optional<std::optional<T>>
- {
- using type = T;
- };
- template<typename T>
- using unwrapped_optional_t = typename unwrapped_optional<T>::type;
- // Etc.
- template<typename T>
- struct wrapper
- {
- using type = T;
- constexpr bool operator==(wrapper) const { return true; }
- };
- struct wrap
- {
- template<typename T>
- constexpr auto operator()(T type) const
- {
- return wrapper<T>{};
- }
- };
- struct unwrap
- {
- template<typename T>
- constexpr auto operator()(T wrapped_type) const
- {
- return typename T::type{};
- }
- };
- template<typename Container, typename T>
- void insert(Container & c, T && x)
- {
- if constexpr (is_detected_v<has_push_back, Container>) {
- c.push_back((T &&) x);
- } else {
- c.insert((T &&) x);
- }
- }
- template<typename Container, typename I>
- void insert(Container & c, I first, I last)
- {
- std::for_each(first, last, [&](auto && x) {
- using type = decltype(x);
- insert(c, (type &&) x);
- });
- }
- template<typename Container, typename T>
- constexpr bool needs_transcoding_to_utf8 =
- (std::is_same_v<range_value_t<remove_cv_ref_t<Container>>, char>
- #if defined(__cpp_char8_t)
- || std::is_same_v<range_value_t<remove_cv_ref_t<Container>>, char8_t>
- #endif
- ) && (std::is_same_v<remove_cv_ref_t<T>, char32_t>
- #if !defined(_MSC_VER)
- || std::is_same_v<remove_cv_ref_t<T>, wchar_t>
- #endif
- );
- template<typename Container, typename T>
- void append(Container & c, T && x, bool gen_attrs)
- {
- if (!gen_attrs)
- return;
- if constexpr (needs_transcoding_to_utf8<Container, T>) {
- char32_t cps[1] = {(char32_t)x};
- auto const r = cps | text::as_utf8;
- c.insert(c.end(), r.begin(), r.end());
- } else {
- detail::insert(c, (T &&)x);
- }
- }
- template<typename Container, typename T>
- void append(std::optional<Container> & c, T && x, bool gen_attrs)
- {
- if (!gen_attrs)
- return;
- if (!c)
- c = Container();
- return detail::append(*c, (T &&) x, gen_attrs);
- }
- template<typename Container>
- void append(Container & c, nope &&, bool)
- {}
- template<typename T>
- void append(nope &, T &&, bool)
- {}
- inline void append(nope &, nope &&, bool) {}
- template<typename Container, typename Iter, typename Sentinel>
- void append(Container & c, Iter first, Sentinel last, bool gen_attrs)
- {
- if (!gen_attrs)
- return;
- if constexpr (needs_transcoding_to_utf8<
- Container,
- iter_value_t<Iter>>) {
- auto const r =
- BOOST_PARSER_SUBRANGE(first, last) | text::as_utf8;
- c.insert(c.end(), r.begin(), r.end());
- } else {
- detail::insert(c, first, last);
- }
- }
- template<typename Container, typename Iter, typename Sentinel>
- void append(
- std::optional<Container> & c,
- Iter first,
- Sentinel last,
- bool gen_attrs)
- {
- if (!gen_attrs)
- return;
- if (!c)
- c = Container();
- return detail::append(*c, first, last, gen_attrs);
- }
- template<typename Iter, typename Sentinel>
- void append(nope &, Iter first, Sentinel last, bool gen_attrs)
- {}
- constexpr inline flags default_flags()
- {
- return flags(
- uint32_t(flags::gen_attrs) | uint32_t(flags::use_skip));
- }
- constexpr inline flags enable_skip(flags f)
- {
- return flags(uint32_t(f) | uint32_t(flags::use_skip));
- }
- constexpr inline flags disable_skip(flags f)
- {
- return flags(uint32_t(f) & ~uint32_t(flags::use_skip));
- }
- constexpr inline flags enable_attrs(flags f)
- {
- return flags(uint32_t(f) | uint32_t(flags::gen_attrs));
- }
- constexpr inline flags disable_attrs(flags f)
- {
- return flags(uint32_t(f) & ~uint32_t(flags::gen_attrs));
- }
- constexpr inline flags enable_trace(flags f)
- {
- return flags(uint32_t(f) | uint32_t(flags::trace));
- }
- constexpr inline flags disable_trace(flags f)
- {
- return flags(uint32_t(f) & ~uint32_t(flags::trace));
- }
- constexpr inline flags set_in_apply_parser(flags f)
- {
- return flags(uint32_t(f) | uint32_t(flags::in_apply_parser));
- }
- constexpr inline bool gen_attrs(flags f)
- {
- return (uint32_t(f) & uint32_t(flags::gen_attrs)) ==
- uint32_t(flags::gen_attrs);
- }
- constexpr inline bool use_skip(flags f)
- {
- return (uint32_t(f) & uint32_t(flags::use_skip)) ==
- uint32_t(flags::use_skip);
- }
- constexpr inline bool in_apply_parser(flags f)
- {
- return (uint32_t(f) & uint32_t(flags::in_apply_parser)) ==
- uint32_t(flags::in_apply_parser);
- }
- struct skip_skipper
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- nope operator()(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- flags flags,
- bool & success) const noexcept
- {
- return {};
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void operator()(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- flags flags,
- bool & success,
- Attribute & retval) const
- {}
- };
- template<typename Iter, typename Sentinel>
- void
- skip(Iter & first, Sentinel last, null_parser const & skip_, flags f)
- {}
- template<typename Iter, typename Sentinel, typename SkipParser>
- void
- skip(Iter & first, Sentinel last, SkipParser const & skip_, flags f)
- {
- if (!detail::use_skip(f))
- return;
- bool success = true;
- int indent = 0;
- rethrow_error_handler eh;
- nope const n;
- auto const context = detail::make_context<false, false>(
- first, last, success, indent, eh, n, n, n);
- while (success) {
- skip_(
- first,
- last,
- context,
- skip_skipper{},
- detail::disable_trace(detail::disable_skip(f)),
- success);
- }
- }
- enum : int64_t { unbounded = -1 };
- template<typename T>
- std::optional<T> make_parse_result(T & x, bool success)
- {
- std::optional<T> retval;
- if (success)
- retval = std::move(x);
- return retval;
- }
- inline bool make_parse_result(nope &, bool success) { return success; }
- inline bool make_parse_result(none &, bool success) { return success; }
- template<typename LoType, typename HiType>
- struct char_pair
- {
- LoType lo_;
- HiType hi_;
- };
- using case_fold_array_t = std::array<char32_t, detail::longest_mapping>;
- template<typename I, typename S>
- struct no_case_iter : stl_interfaces::proxy_iterator_interface<
- no_case_iter<I, S>,
- std::forward_iterator_tag,
- char32_t>
- {
- no_case_iter() : it_(), last_(), idx_(0), last_idx_() {}
- no_case_iter(I it, S last) :
- it_(it), last_(last), idx_(0), last_idx_(0)
- {
- fold();
- }
- char32_t operator*() const { return folded_[idx_]; }
- no_case_iter & operator++()
- {
- ++idx_;
- if (last_idx_ <= idx_) {
- ++it_;
- fold();
- }
- return *this;
- }
- I base() const { return it_; }
- friend bool operator==(no_case_iter lhs, S rhs) noexcept
- {
- return lhs.it_ == rhs;
- }
- friend bool operator==(no_case_iter lhs, no_case_iter rhs) noexcept
- {
- return lhs.it_ == rhs.it_ && lhs.idx_ == rhs.idx_;
- }
- using base_type = stl_interfaces::proxy_iterator_interface<
- no_case_iter<I, S>,
- std::forward_iterator_tag,
- char32_t>;
- using base_type::operator++;
- private:
- void fold()
- {
- idx_ = 0;
- if (it_ == last_) {
- folded_[0] = 0;
- last_idx_ = 1;
- return;
- }
- auto const folded_last =
- detail::case_fold(*it_, folded_.begin());
- last_idx_ = int(folded_last - folded_.begin());
- }
- case_fold_array_t folded_;
- I it_;
- [[no_unique_address]] S last_;
- int idx_;
- int last_idx_;
- };
- template<typename V>
- struct case_fold_view
- {
- using iterator =
- no_case_iter<detail::iterator_t<V>, detail::sentinel_t<V>>;
- case_fold_view(V base) : base_(std::move(base)) {}
- iterator begin() const
- {
- return iterator(
- text::detail::begin(base_), text::detail::end(base_));
- }
- auto end() const { return text::detail::end(base_); }
- private:
- V base_;
- };
- enum class symbol_table_op { insert, erase, clear };
- template<typename T>
- struct symbol_table_operation
- {
- std::string key_;
- std::optional<T> value_;
- symbol_table_op kind_;
- };
- template<typename T>
- void apply_symbol_table_operations(
- std::vector<std::pair<std::string, T>> & initial_elements,
- std::vector<symbol_table_operation<T>> & pending_operations)
- {
- auto lower_bound = [&initial_elements](std::string const & str) {
- return std::lower_bound(
- initial_elements.begin(),
- initial_elements.end(),
- str,
- [](auto const & a, auto b) {
- return a.first < b;
- });
- };
- for (auto & op : pending_operations) {
- if (op.kind_ == symbol_table_op::insert) {
- auto it = lower_bound(op.key_);
- if (it == initial_elements.end() ||
- it->first != op.key_) {
- initial_elements.insert(
- it,
- std::pair<std::string, T>(
- std::move(op.key_), std::move(*op.value_)));
- } else {
- it->second = std::move(*op.value_);
- }
- } else if (op.kind_ == symbol_table_op::erase) {
- auto it = lower_bound(op.key_);
- if (it != initial_elements.end() && it->first == op.key_)
- initial_elements.erase(it);
- } else {
- initial_elements.clear();
- }
- }
- pending_operations.clear();
- }
- template<typename Context, typename T>
- auto get_trie(
- Context const & context, symbol_parser<T> const & sym_parser)
- {
- using trie_t = text::trie_map<std::vector<char32_t>, T>;
- using result_type = std::pair<trie_t &, bool>;
- symbol_table_tries_t & symbol_table_tries =
- context.get_symbol_table_tries();
- auto & [any, has_case_folded] =
- symbol_table_tries[(void *)&sym_parser.ref()];
- bool const needs_case_folded = context.no_case_depth_;
- if (!any.has_value()) {
- any = trie_t{};
- has_case_folded = false;
- trie_t & trie = *std::any_cast<trie_t>(&any);
- for (auto const & e : sym_parser.initial_elements()) {
- trie.insert(e.first | text::as_utf32, e.second);
- if (needs_case_folded) {
- trie.insert(
- case_fold_view(e.first | text::as_utf32), e.second);
- has_case_folded = true;
- }
- }
- return result_type(trie, has_case_folded);
- } else {
- trie_t & trie = *std::any_cast<trie_t>(&any);
- if (needs_case_folded && !has_case_folded) {
- trie_t new_trie = trie;
- for (auto && [key, value] : trie) {
- new_trie.insert(
- case_fold_view(key | text::as_utf32), value);
- }
- std::swap(new_trie, trie);
- }
- return result_type(trie, has_case_folded);
- }
- }
- template<typename Context, typename T>
- decltype(auto) get_pending_symtab_ops(
- Context const & context, symbol_parser<T> const & sym_parser)
- {
- void const * ptr = static_cast<void const *>(&sym_parser);
- auto & entry = (context.get_pending_symbol_table_operations())[ptr];
- std::vector<detail::symbol_table_operation<T>> * retval = nullptr;
- if (entry.visit_) {
- retval = std::any_cast<
- std::vector<detail::symbol_table_operation<T>>>(
- &entry.ops_);
- } else {
- entry.ops_ = std::vector<detail::symbol_table_operation<T>>{};
- retval = std::any_cast<
- std::vector<detail::symbol_table_operation<T>>>(
- &entry.ops_);
- entry.visit_ = [&sym_parser, ops_ptr = retval] {
- detail::apply_symbol_table_operations(
- sym_parser.initial_elements_, *ops_ptr);
- };
- }
- return *retval;
- }
- template<>
- struct char_subranges<hex_digit_subranges>
- {
- static constexpr char_subrange ranges[] = {
- {U'0', U'9'},
- {U'A', U'F'},
- {U'a', U'f'},
- {U'\uff10', U'\uff19'},
- {U'\uff21', U'\uff26'},
- {U'\uff41', U'\uff46'}};
- };
- template<>
- struct char_subranges<control_subranges>
- {
- static constexpr char_subrange ranges[] = {
- {U'\u0000', U'\u001f'}, {U'\u007f', U'\u009f'}};
- };
- template<typename Iter, typename Sentinel, bool SortedUTF32>
- struct char_range
- {
- template<typename T, typename Context>
- bool contains(T c_, Context const & context) const
- {
- if constexpr (SortedUTF32) {
- return std::binary_search(chars_.begin(), chars_.end(), c_);
- }
- if (context.no_case_depth_) {
- case_fold_array_t folded;
- auto folded_last = detail::case_fold(c_, folded.begin());
- if constexpr (std::is_same_v<T, char32_t>) {
- auto const cps = chars_ | text::as_utf32;
- auto chars_first = no_case_iter(cps.begin(), cps.end());
- auto chars_last = cps.end();
- auto result = text::search(
- chars_first,
- chars_last,
- folded.begin(),
- folded_last);
- return !result.empty();
- } else {
- auto chars_first =
- no_case_iter(chars_.begin(), chars_.end());
- auto chars_last = chars_.end();
- auto result = text::search(
- chars_first,
- chars_last,
- folded.begin(),
- folded_last);
- return !result.empty();
- }
- } else {
- if constexpr (std::is_same_v<T, char32_t>) {
- auto const cps = chars_ | text::as_utf32;
- return text::find(cps.begin(), cps.end(), c_) !=
- cps.end();
- } else {
- using element_type =
- remove_cv_ref_t<decltype(*chars_.begin())>;
- element_type const c = c_;
- return text::find(chars_.begin(), chars_.end(), c) !=
- chars_.end();
- }
- }
- }
- BOOST_PARSER_SUBRANGE<Iter, Sentinel> chars_;
- };
- template<bool SortedUTF32, typename Iter, typename Sentinel>
- constexpr auto make_char_range(Iter first, Sentinel last)
- {
- return char_range<Iter, Sentinel, SortedUTF32>{
- BOOST_PARSER_SUBRANGE<Iter, Sentinel>{first, last}};
- }
- template<bool SortedUTF32, typename R>
- constexpr auto make_char_range(R && r) noexcept
- {
- if constexpr (std::is_pointer_v<remove_cv_ref_t<R>>) {
- return detail::make_char_range<SortedUTF32>(
- r, text::null_sentinel);
- } else {
- return detail::make_char_range<SortedUTF32>(
- text::detail::begin(r), text::detail::end(r));
- }
- }
- template<bool Equal, typename Context>
- auto no_case_aware_compare(Context const & context)
- {
- return [no_case = context.no_case_depth_](char32_t a, char32_t b) {
- if (no_case) {
- case_fold_array_t folded_a = {0, 0, 0};
- detail::case_fold(a, folded_a.begin());
- case_fold_array_t folded_b = {0, 0, 0};
- detail::case_fold(b, folded_b.begin());
- return Equal ? folded_a == folded_b : folded_a < folded_b;
- } else {
- return Equal ? a == b : a < b;
- }
- };
- }
- template<typename T, typename U>
- constexpr bool both_character_types =
- is_parsable_code_unit_v<T> && is_parsable_code_unit_v<U>;
- template<typename T, typename U>
- using eq_comparable =
- decltype(std::declval<T &>() == std::declval<U &>());
- template<
- typename Context,
- typename CharType,
- typename Expected,
- bool BothCharacters = both_character_types<CharType, Expected>>
- struct unequal_impl
- {
- static bool
- call(Context const & context, CharType c, Expected const & expected)
- {
- auto resolved = detail::resolve(context, expected);
- if constexpr (is_detected_v<
- eq_comparable,
- CharType,
- decltype(resolved)>) {
- auto const compare =
- detail::no_case_aware_compare<true>(context);
- return !compare(c, resolved);
- } else {
- return !resolved.contains(c, context);
- }
- }
- };
- template<typename Context, typename CharType, typename Expected>
- struct unequal_impl<Context, CharType, Expected, true>
- {
- static bool
- call(Context const & context, CharType c, Expected expected)
- {
- return !detail::no_case_aware_compare<true>(context)(
- c, expected);
- }
- };
- template<typename Context, typename CharType, typename Expected>
- bool unequal(Context const & context, CharType c, Expected expected)
- {
- return unequal_impl<Context, CharType, Expected>::call(
- context, c, expected);
- }
- template<
- typename Context,
- typename CharType,
- typename LoType,
- typename HiType>
- bool unequal(
- Context const & context,
- CharType c,
- char_pair<LoType, HiType> const & expected)
- {
- auto const less = detail::no_case_aware_compare<false>(context);
- {
- auto lo = detail::resolve(context, expected.lo_);
- if (less(c, lo))
- return true;
- }
- {
- auto hi = detail::resolve(context, expected.hi_);
- if (less(hi, c))
- return true;
- }
- return false;
- }
- template<typename Context, typename CharType>
- bool unequal(Context const &, CharType, nope)
- {
- return false;
- }
- template<typename Container, typename T>
- using insertable = decltype(std::declval<Container &>().insert(
- std::declval<Container &>().end(), std::declval<T>()));
- template<typename T, typename Tuple, int... Is>
- auto
- make_from_tuple_impl(Tuple && tup, std::integer_sequence<int, Is...>)
- -> decltype(T(parser::get((Tuple &&)tup, llong<Is>{})...))
- {
- return T(parser::get((Tuple &&)tup, llong<Is>{})...);
- }
- template<typename T, typename... Args>
- auto make_from_tuple(tuple<Args...> && tup)
- -> decltype(detail::make_from_tuple_impl<T>(
- std::move(tup),
- std::make_integer_sequence<int, tuple_size_<tuple<Args...>>>()))
- {
- return detail::make_from_tuple_impl<T>(
- std::move(tup),
- std::make_integer_sequence<int, tuple_size_<tuple<Args...>>>());
- }
- template<typename T, typename Tuple>
- using constructible_from_tuple_expr =
- decltype(detail::make_from_tuple<T>(std::declval<Tuple>()));
- template<typename T, typename Tuple, bool = is_tuple<Tuple>{}>
- constexpr bool is_constructible_from_tuple_v = false;
- template<typename T, typename Tuple>
- constexpr bool is_constructible_from_tuple_v<T, Tuple, true> =
- is_detected_v<constructible_from_tuple_expr, T, Tuple>;
- template<typename Container, typename U>
- constexpr void move_back_impl(Container & c, U && x)
- {
- using just_t = range_value_t<Container>;
- using just_u = remove_cv_ref_t<U>;
- if constexpr (needs_transcoding_to_utf8<Container, U>) {
- char32_t cps[1] = {(char32_t)x};
- auto const r = cps | text::as_utf8;
- c.insert(c.end(), r.begin(), r.end());
- } else if constexpr (std::is_convertible_v<just_u &&, just_t>) {
- detail::insert(c, (U &&)x);
- } else if constexpr (
- !is_tuple<just_t>::value && is_tuple<just_u>::value &&
- std::is_aggregate_v<just_t> &&
- !is_detected_v<insertable, Container, just_u &&> &&
- is_struct_assignable_v<just_t, just_u>) {
- auto int_seq =
- std::make_integer_sequence<int, tuple_size_<just_u>>();
- detail::insert(
- c, detail::tuple_to_aggregate<just_t>((U &&)x, int_seq));
- } else if constexpr (
- is_tuple<just_t>::value && !is_tuple<just_u>::value &&
- std::is_aggregate_v<just_u> &&
- !is_detected_v<insertable, Container, just_u &&> &&
- is_tuple_assignable_v<just_t, just_u>) {
- just_t t;
- auto tie = detail::tie_aggregate(x);
- detail::aggregate_to_tuple(
- t,
- tie,
- std::make_integer_sequence<int, tuple_size_<just_t>>());
- detail::insert(c, std::move(t));
- } else if constexpr (is_constructible_from_tuple_v<
- just_t,
- just_u>) {
- detail::insert(c, detail::make_from_tuple<just_t>((U &&)x));
- } else {
- static_assert(
- sizeof(U) && false,
- "Could not insert value into container, by: just inserting "
- "it; doing tuple -> aggregate or aggregate -> tuple "
- "conversions; or tuple -> class type construction.");
- }
- }
- template<typename Container, typename T>
- constexpr void move_back(Container & c, T && x, bool gen_attrs)
- {
- if (!gen_attrs)
- return;
- detail::move_back_impl(c, (T &&)x);
- }
- template<typename Container>
- constexpr void move_back(Container & c, Container & x, bool gen_attrs)
- {
- if (!gen_attrs)
- return;
- c.insert(c.end(), x.begin(), x.end());
- }
- template<typename Container>
- constexpr void
- move_back(Container & c, std::optional<Container> && x, bool gen_attrs)
- {
- if (!gen_attrs || !x)
- return;
- c.insert(c.end(), x->begin(), x->end());
- }
- template<typename Container, typename T>
- constexpr void
- move_back(Container & c, std::optional<T> & x, bool gen_attrs)
- {
- if (!gen_attrs || !x)
- return;
- detail::move_back_impl(c, std::move(*x));
- }
- template<
- typename Container,
- typename T,
- typename Enable = std::enable_if_t<!std::is_same_v<Container, T>>>
- constexpr void
- move_back(Container & c, std::optional<T> && x, bool gen_attrs)
- {
- if (!gen_attrs || !x)
- return;
- detail::move_back_impl(c, std::move(*x));
- }
- constexpr void move_back(nope, nope, bool gen_attrs) {}
- template<typename Container>
- constexpr void move_back(Container & c, nope, bool gen_attrs)
- {}
- template<typename From, typename To>
- using move_assignable_expr =
- decltype(std::declval<To &>() = std::declval<From &&>());
- template<typename From, typename To>
- constexpr bool is_move_assignable_v =
- is_detected_v<move_assignable_expr, From, To>;
- template<typename T, typename U>
- constexpr void assign(T & t, U && u)
- {
- using just_t = remove_cv_ref_t<T>;
- using just_u = remove_cv_ref_t<U>;
- if constexpr (is_move_assignable_v<just_u, just_t>) {
- static_assert(
- (!std::is_same_v<just_t, std::string> ||
- !std::is_arithmetic_v<just_u>),
- "std::string is assignable from a char. Due to implicit "
- "conversions among arithmetic types, any arithmetic type "
- "(like int or double) is assignable to std::string. This "
- "is almost certainly not what you meant to write, so "
- "Boost.Parser disallows it. If you want to do this, write "
- "a semantic action and do it explicitly.");
- t = (U &&)u;
- } else if constexpr (
- !is_tuple<just_t>::value && is_tuple<just_u>::value &&
- std::is_aggregate_v<just_t> &&
- !std::is_convertible_v<just_u &&, just_t> &&
- is_struct_assignable_v<just_t, just_u>) {
- auto int_seq =
- std::make_integer_sequence<int, tuple_size_<just_u>>();
- t = detail::tuple_to_aggregate<just_t>((U &&)u, int_seq);
- } else if constexpr (
- is_tuple<just_t>::value && !is_tuple<just_u>::value &&
- std::is_aggregate_v<just_u> &&
- !std::is_convertible_v<just_u &&, just_t> &&
- is_tuple_assignable_v<just_t, just_u>) {
- auto tie = detail::tie_aggregate(u);
- detail::aggregate_to_tuple(
- t,
- tie,
- std::make_integer_sequence<int, tuple_size_<just_t>>());
- } else if constexpr (is_constructible_from_tuple_v<
- just_t,
- just_u>) {
- t = detail::make_from_tuple<just_t>((U &&)u);
- } else {
- static_assert(
- sizeof(T) && false,
- "Could not assign value, by: just assigning it; doing tuple "
- "-> aggregate or aggregate -> tuple conversions; or tuple "
- "-> class type construction.");
- }
- }
- template<typename T>
- constexpr void assign(T &, nope)
- {}
- template<typename T, typename U>
- constexpr void assign_copy(T & t, U const & u)
- {
- t = u;
- }
- template<typename T>
- constexpr void assign_copy(T &, nope)
- {}
- template<
- typename Parser,
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename... T>
- void apply_parser(
- Parser const & parser,
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- flags flags,
- bool & success,
- std::optional<std::variant<T...>> & retval)
- {
- using attr_t = decltype(parser.call(
- first, last, context, skip, flags, success));
- if constexpr (std::is_same<
- attr_t,
- std::optional<std::variant<T...>>>{}) {
- parser.call(first, last, context, skip, flags, success, retval);
- } else if constexpr (is_nope_v<attr_t>) {
- parser.call(first, last, context, skip, flags, success);
- } else {
- auto attr =
- parser.call(first, last, context, skip, flags, success);
- if (success)
- detail::assign(retval, std::variant<T...>(std::move(attr)));
- }
- }
- template<
- typename Parser,
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename... T>
- void apply_parser(
- Parser const & parser,
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- flags flags,
- bool & success,
- std::variant<T...> & retval)
- {
- auto attr = parser.call(first, last, context, skip, flags, success);
- if (success)
- detail::assign(retval, std::move(attr));
- }
- template<
- typename Parser,
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename T>
- void apply_parser(
- Parser const & parser,
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- flags flags,
- bool & success,
- std::optional<T> & retval)
- {
- auto attr = parser.call(first, last, context, skip, flags, success);
- if (success)
- detail::assign(retval, std::move(attr));
- }
- template<
- typename Parser,
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void apply_parser(
- Parser const & parser,
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- flags flags,
- bool & success,
- Attribute & retval)
- {
- parser.call(first, last, context, skip, flags, success, retval);
- }
- // API implementations
- template<typename Iter, typename Sentinel, typename Parser>
- auto has_attribute(Iter first, Sentinel last, Parser parser);
- template<typename BaseIter, typename Iter>
- struct scoped_base_assign
- {
- scoped_base_assign(BaseIter & base, Iter & it) :
- base_(base), it_(it)
- {}
- ~scoped_base_assign() { base_ = it_.base(); }
- BaseIter & base_;
- Iter & it_;
- };
- template<typename Parser>
- using has_parser_data_member_expr =
- decltype(std::declval<Parser>().parser_);
- template<typename Parser>
- constexpr bool has_parser_data_member_v =
- is_detected_v<has_parser_data_member_expr, Parser>;
- template<typename Parser>
- using has_parsers_data_member_expr =
- decltype(std::declval<Parser>().parsers_);
- template<typename Parser>
- constexpr bool has_parsers_data_member_v =
- is_detected_v<has_parsers_data_member_expr, Parser>;
- struct scoped_apply_pending_symbol_table_operations
- {
- scoped_apply_pending_symbol_table_operations(
- pending_symbol_table_operations_t & pending_ops) :
- pending_ops_(pending_ops)
- {}
- ~scoped_apply_pending_symbol_table_operations()
- {
- for (auto & [_, entry] : pending_ops_) {
- entry.visit_();
- }
- }
- pending_symbol_table_operations_t & pending_ops_;
- };
- template<
- bool Debug,
- typename Iter,
- typename Sentinel,
- typename Parser,
- typename Attr,
- typename ErrorHandler>
- bool parse_impl(
- Iter & first,
- Sentinel last,
- Parser const & parser,
- ErrorHandler const & error_handler,
- Attr & attr)
- {
- auto const initial_first = first;
- bool success = true;
- int trace_indent = 0;
- detail::symbol_table_tries_t symbol_table_tries;
- pending_symbol_table_operations_t pending_symbol_table_operations;
- scoped_apply_pending_symbol_table_operations apply_pending(
- pending_symbol_table_operations);
- auto context = detail::make_context<Debug, false>(
- first,
- last,
- success,
- trace_indent,
- error_handler,
- parser.globals_,
- symbol_table_tries,
- pending_symbol_table_operations);
- auto const flags =
- Debug ? detail::enable_trace(detail::flags::gen_attrs)
- : detail::flags::gen_attrs;
- try {
- parser(
- first,
- last,
- context,
- detail::null_parser{},
- flags,
- success,
- attr);
- if (Debug)
- detail::final_trace(context, flags, attr);
- return success;
- } catch (parse_error<Iter> const & e) {
- if (error_handler(initial_first, last, e) ==
- error_handler_result::rethrow) {
- throw;
- }
- return false;
- }
- }
- template<
- bool Debug,
- typename Iter,
- typename Sentinel,
- typename Parser,
- typename ErrorHandler>
- auto parse_impl(
- Iter & first,
- Sentinel last,
- Parser const & parser,
- ErrorHandler const & error_handler)
- {
- auto const initial_first = first;
- bool success = true;
- int trace_indent = 0;
- detail::symbol_table_tries_t symbol_table_tries;
- pending_symbol_table_operations_t pending_symbol_table_operations;
- scoped_apply_pending_symbol_table_operations apply_pending(
- pending_symbol_table_operations);
- auto context = detail::make_context<Debug, false>(
- first,
- last,
- success,
- trace_indent,
- error_handler,
- parser.globals_,
- symbol_table_tries,
- pending_symbol_table_operations);
- auto const flags =
- Debug ? detail::enable_trace(detail::flags::gen_attrs)
- : detail::flags::gen_attrs;
- using attr_t = typename detail::attribute_impl<
- BOOST_PARSER_SUBRANGE<std::remove_const_t<Iter>, Sentinel>,
- Parser>::type;
- try {
- attr_t attr_ = parser(
- first,
- last,
- context,
- detail::null_parser{},
- flags,
- success);
- if (Debug)
- detail::final_trace(context, flags, nope{});
- return detail::make_parse_result(attr_, success);
- } catch (parse_error<Iter> const & e) {
- if (error_handler(initial_first, last, e) ==
- error_handler_result::rethrow) {
- throw;
- }
- attr_t attr_{};
- return detail::make_parse_result(attr_, false);
- }
- }
- template<
- bool Debug,
- typename Iter,
- typename Sentinel,
- typename Parser,
- typename ErrorHandler,
- typename Callbacks>
- bool callback_parse_impl(
- Iter & first,
- Sentinel last,
- Parser const & parser,
- ErrorHandler const & error_handler,
- Callbacks const & callbacks)
- {
- auto const initial_first = first;
- bool success = true;
- int trace_indent = 0;
- detail::symbol_table_tries_t symbol_table_tries;
- pending_symbol_table_operations_t pending_symbol_table_operations;
- scoped_apply_pending_symbol_table_operations apply_pending(
- pending_symbol_table_operations);
- auto context = detail::make_context<Debug, true>(
- first,
- last,
- success,
- trace_indent,
- error_handler,
- callbacks,
- parser.globals_,
- symbol_table_tries,
- pending_symbol_table_operations);
- auto const flags =
- Debug ? detail::enable_trace(detail::flags::gen_attrs)
- : detail::flags::gen_attrs;
- try {
- parser(
- first,
- last,
- context,
- detail::null_parser{},
- flags,
- success);
- if (Debug)
- detail::final_trace(context, flags, nope{});
- return success;
- } catch (parse_error<Iter> const & e) {
- if (error_handler(initial_first, last, e) ==
- error_handler_result::rethrow) {
- throw;
- }
- return false;
- }
- }
- template<
- bool Debug,
- typename Iter,
- typename Sentinel,
- typename Parser,
- typename SkipParser,
- typename Attr,
- typename ErrorHandler>
- bool skip_parse_impl(
- Iter & first,
- Sentinel last,
- Parser const & parser,
- SkipParser const & skip,
- ErrorHandler const & error_handler,
- Attr & attr)
- {
- auto const initial_first = first;
- bool success = true;
- int trace_indent = 0;
- detail::symbol_table_tries_t symbol_table_tries;
- pending_symbol_table_operations_t pending_symbol_table_operations;
- scoped_apply_pending_symbol_table_operations apply_pending(
- pending_symbol_table_operations);
- auto context = detail::make_context<Debug, false>(
- first,
- last,
- success,
- trace_indent,
- error_handler,
- parser.globals_,
- symbol_table_tries,
- pending_symbol_table_operations);
- auto const flags =
- Debug ? detail::enable_trace(detail::default_flags())
- : detail::default_flags();
- detail::skip(first, last, skip, flags);
- try {
- parser(first, last, context, skip, flags, success, attr);
- detail::skip(first, last, skip, flags);
- if (Debug)
- detail::final_trace(context, flags, attr);
- return success;
- } catch (parse_error<Iter> const & e) {
- if (error_handler(initial_first, last, e) ==
- error_handler_result::rethrow) {
- throw;
- }
- return false;
- }
- }
- template<
- bool Debug,
- typename Iter,
- typename Sentinel,
- typename Parser,
- typename SkipParser,
- typename ErrorHandler>
- auto skip_parse_impl(
- Iter & first,
- Sentinel last,
- Parser const & parser,
- SkipParser const & skip,
- ErrorHandler const & error_handler)
- {
- auto const initial_first = first;
- bool success = true;
- int trace_indent = 0;
- detail::symbol_table_tries_t symbol_table_tries;
- pending_symbol_table_operations_t pending_symbol_table_operations;
- scoped_apply_pending_symbol_table_operations apply_pending(
- pending_symbol_table_operations);
- auto context = detail::make_context<Debug, false>(
- first,
- last,
- success,
- trace_indent,
- error_handler,
- parser.globals_,
- symbol_table_tries,
- pending_symbol_table_operations);
- auto const flags =
- Debug ? detail::enable_trace(detail::default_flags())
- : detail::default_flags();
- detail::skip(first, last, skip, flags);
- using attr_t = typename detail::attribute_impl<
- BOOST_PARSER_SUBRANGE<std::remove_const_t<Iter>, Sentinel>,
- Parser, SkipParser>::type;
- try {
- attr_t attr_ =
- parser(first, last, context, skip, flags, success);
- detail::skip(first, last, skip, flags);
- if (Debug)
- detail::final_trace(context, flags, nope{});
- return detail::make_parse_result(attr_, success);
- } catch (parse_error<Iter> const & e) {
- if (error_handler(initial_first, last, e) ==
- error_handler_result::rethrow) {
- throw;
- }
- attr_t attr_{};
- return detail::make_parse_result(attr_, false);
- }
- }
- template<
- bool Debug,
- typename Iter,
- typename Sentinel,
- typename Parser,
- typename SkipParser,
- typename ErrorHandler,
- typename Callbacks>
- bool callback_skip_parse_impl(
- Iter & first,
- Sentinel last,
- Parser const & parser,
- SkipParser const & skip,
- ErrorHandler const & error_handler,
- Callbacks const & callbacks)
- {
- auto const initial_first = first;
- bool success = true;
- int trace_indent = 0;
- detail::symbol_table_tries_t symbol_table_tries;
- pending_symbol_table_operations_t pending_symbol_table_operations;
- scoped_apply_pending_symbol_table_operations apply_pending(
- pending_symbol_table_operations);
- auto context = detail::make_context<Debug, true>(
- first,
- last,
- success,
- trace_indent,
- error_handler,
- callbacks,
- parser.globals_,
- symbol_table_tries,
- pending_symbol_table_operations);
- auto const flags =
- Debug ? detail::enable_trace(detail::default_flags())
- : detail::default_flags();
- detail::skip(first, last, skip, flags);
- try {
- parser(first, last, context, skip, flags, success);
- detail::skip(first, last, skip, flags);
- if (Debug)
- detail::final_trace(context, flags, nope{});
- return success;
- } catch (parse_error<Iter> const & e) {
- if (error_handler(initial_first, last, e) ==
- error_handler_result::rethrow) {
- throw;
- }
- return false;
- }
- }
- template<typename R>
- constexpr auto make_input_subrange(R && r) noexcept
- {
- using r_t = remove_cv_ref_t<R>;
- if constexpr (std::is_pointer_v<r_t>) {
- using value_type = iter_value_t<r_t>;
- if constexpr (std::is_same_v<value_type, char>) {
- return BOOST_PARSER_SUBRANGE(r, text::null_sentinel);
- } else {
- return r | text::as_utf32;
- }
- } else {
- using value_type = range_value_t<r_t>;
- if constexpr (text::detail::is_bounded_array_v<r_t>) {
- if constexpr (std::is_same_v<value_type, char>) {
- auto first = detail::text::detail::begin(r);
- auto last = detail::text::detail::end(r);
- if (first != last && !*std::prev(last))
- --last;
- return BOOST_PARSER_SUBRANGE(first, last);
- } else {
- return r | text::as_utf32;
- }
- } else {
- if constexpr (
- std::is_same_v<value_type, char> &&
- !is_utf8_view<r_t>::value) {
- return BOOST_PARSER_SUBRANGE(
- detail::text::detail::begin(r),
- detail::text::detail::end(r));
- } else {
- return r | text::as_utf32;
- }
- }
- }
- }
- template<typename R>
- constexpr auto make_view_begin(R & r) noexcept
- {
- if constexpr (std::is_pointer_v<std::decay_t<R>>) {
- return r;
- } else {
- return detail::text::detail::begin(r);
- }
- }
- template<typename R>
- constexpr auto make_view_end(R & r) noexcept
- {
- if constexpr (std::is_pointer_v<std::decay_t<R>>) {
- return text::null_sentinel;
- } else {
- return detail::text::detail::end(r);
- }
- }
- template<
- typename Iter1,
- typename Sentinel1,
- typename Iter2,
- typename Sentinel2,
- typename Pred>
- std::pair<Iter1, Iter2> mismatch(
- Iter1 first1,
- Sentinel1 last1,
- Iter2 first2,
- Sentinel2 last2,
- Pred pred)
- {
- std::pair<Iter1, Iter2> retval{first1, first2};
- while (retval.first != last1 && retval.second != last2 &&
- pred(*retval.first, *retval.second)) {
- ++retval.first;
- ++retval.second;
- }
- return retval;
- }
- template<
- typename Iter1,
- typename Sentinel1,
- typename Iter2,
- typename Sentinel2>
- std::pair<Iter1, Iter2> no_case_aware_string_mismatch(
- Iter1 first1,
- Sentinel1 last1,
- Iter2 first2,
- Sentinel2 last2,
- bool no_case)
- {
- if (no_case) {
- auto it1 = no_case_iter(first1, last1);
- auto it2 = no_case_iter(first2, last2);
- auto const mismatch = detail::mismatch(
- it1, last1, it2, last2, std::equal_to<char32_t>{});
- return std::pair<Iter1, Iter2>{
- mismatch.first.base(), mismatch.second.base()};
- } else {
- return detail::mismatch(
- first1, last1, first2, last2, std::equal_to<char32_t>{});
- }
- }
- template<typename I, typename S, typename ErrorHandler, typename T>
- T if_full_parse(
- I initial_first,
- I & first,
- S last,
- ErrorHandler const & error_handler,
- T retval)
- {
- if (first != last) {
- if (retval && error_handler(
- initial_first,
- last,
- parse_error<I>(first, "end of input")) ==
- error_handler_result::rethrow) {
- throw;
- }
- if constexpr (std::is_same_v<T, bool>)
- retval = false;
- else
- retval = std::nullopt;
- }
- return std::move(retval);
- }
- // The notion of comaptibility is that, given a parser with the
- // Attribute Tuple, we can parse into Struct instead.
- template<typename Struct, typename Tuple>
- constexpr auto is_struct_compatible();
- struct element_compatibility
- {
- template<typename T, typename U>
- constexpr auto operator()(T result, U x) const
- {
- using struct_elem =
- remove_cv_ref_t<decltype(parser::get(x, llong<0>{}))>;
- using tuple_elem =
- remove_cv_ref_t<decltype(parser::get(x, llong<1>{}))>;
- if constexpr (!T::value) {
- return std::false_type{};
- } else if constexpr (
- is_optional_v<struct_elem> && is_optional_v<tuple_elem>) {
- using struct_opt_type = optional_type<struct_elem>;
- using tuple_opt_type = optional_type<tuple_elem>;
- using retval_t = decltype((*this)(
- result,
- detail::hl::make_tuple(
- std::declval<struct_opt_type &>(),
- std::declval<tuple_opt_type &>())));
- return retval_t{};
- } else if constexpr (std::is_convertible_v<
- tuple_elem &&,
- struct_elem>) {
- return std::true_type{};
- } else if constexpr (
- container<struct_elem> && container<tuple_elem>) {
- return detail::is_struct_compatible<
- range_value_t<struct_elem>,
- range_value_t<tuple_elem>>();
- } else {
- return std::bool_constant<detail::is_struct_compatible<
- struct_elem,
- tuple_elem>()>{};
- }
- }
- };
- template<typename T, typename U>
- constexpr auto is_struct_compatible()
- {
- if constexpr (
- !std::is_aggregate_v<T> ||
- struct_arity_v<T> != tuple_size_<U>) {
- return std::false_type{};
- } else {
- using result_t = decltype(detail::hl::fold_left(
- detail::hl::zip(
- detail::tie_aggregate(std::declval<T &>()),
- std::declval<U &>()),
- std::true_type{},
- element_compatibility{}));
- return result_t{};
- }
- }
- template<typename Struct, typename Tuple>
- constexpr bool is_struct_compatible_v =
- detail::is_struct_compatible<Struct, Tuple>();
- template<typename ParserAttr, typename GivenContainerAttr>
- constexpr auto parser_attr_or_container_value_type()
- {
- if constexpr (is_nope_v<ParserAttr>) {
- return nope{};
- } else if constexpr (is_optional_v<ParserAttr>) {
- return ParserAttr{};
- } else {
- using value_type = range_value_t<GivenContainerAttr>;
- return std::conditional_t<
- std::is_convertible_v<ParserAttr, value_type>,
- ParserAttr,
- value_type>{};
- }
- }
- template<typename ParserAttr, typename GivenContainerAttr>
- using parser_attr_or_container_value_type_v =
- decltype(parser_attr_or_container_value_type<
- ParserAttr,
- GivenContainerAttr>());
- template<typename T>
- constexpr auto tuple_or_struct_size(T && x)
- {
- if constexpr (is_tuple<remove_cv_ref_t<T>>{}) {
- return hl::size(x);
- } else {
- return llong<struct_arity_v<remove_cv_ref_t<T>>>{};
- }
- }
- template<typename T>
- struct attr_reset
- {
- attr_reset(T & x) : x_(std::addressof(x)) {}
- attr_reset(attr_reset const &) = delete;
- attr_reset(attr_reset &&) = delete;
- attr_reset & operator=(attr_reset const &) = delete;
- attr_reset & operator=(attr_reset &&) = delete;
- ~attr_reset()
- {
- if (x_)
- *x_ = T();
- }
- bool operator=(bool b)
- {
- if (b)
- x_ = nullptr;
- return b;
- }
- private:
- T * x_;
- };
- }
- #ifndef BOOST_PARSER_DOXYGEN
- // This constraint is only here to allow the alternate-call semantic
- // action metaprogramming logic to function on MSVC.
- template<typename Context>
- auto _val(Context const & context) -> std::conditional_t<
- detail::is_nope_v<decltype(*context.val_)>,
- none,
- decltype(*context.val_)>
- {
- if constexpr (detail::is_nope_v<decltype(*context.val_)>)
- return none{};
- else
- return *context.val_;
- }
- template<typename Context>
- decltype(auto) _attr(Context const & context)
- {
- if constexpr (detail::is_nope_v<decltype(*context.attr_)>)
- return none{};
- else
- return *context.attr_;
- }
- template<typename Context>
- decltype(auto) _where(Context const & context)
- {
- return *context.where_;
- }
- template<typename Context>
- decltype(auto) _begin(Context const & context)
- {
- return context.first_;
- }
- template<typename Context>
- decltype(auto) _end(Context const & context)
- {
- return context.last_;
- }
- template<typename Context>
- decltype(auto) _pass(Context const & context)
- {
- return *context.pass_;
- }
- template<typename Context>
- decltype(auto) _locals(Context const & context)
- {
- if constexpr (detail::is_nope_v<decltype(*context.locals_)>)
- return none{};
- else
- return *context.locals_;
- }
- template<typename Context>
- decltype(auto) _params(Context const & context)
- {
- if constexpr (detail::is_nope_v<decltype(*context.params_)>)
- return none{};
- else
- return *context.params_;
- }
- template<typename Context>
- decltype(auto) _globals(Context const & context)
- {
- if constexpr (detail::is_nope_v<decltype(*context.globals_)>)
- return none{};
- else
- return *context.globals_;
- }
- template<typename Context>
- decltype(auto) _no_case(Context const & context)
- {
- return context.no_case_depth_;
- }
- template<typename Context>
- decltype(auto) _error_handler(Context const & context)
- {
- return *context.error_handler_;
- }
- #if BOOST_PARSER_USE_CONCEPTS
- template<std::forward_iterator I, typename Context>
- #else
- template<typename I, typename Context>
- #endif
- void
- _report_error(Context const & context, std::string_view message, I location)
- {
- return context.error_handler_->diagnose(
- diagnostic_kind::error, message, context, location);
- }
- template<typename Context>
- void _report_error(Context const & context, std::string_view message)
- {
- return context.error_handler_->diagnose(
- diagnostic_kind::error, message, context);
- }
- #if BOOST_PARSER_USE_CONCEPTS
- template<std::forward_iterator I, typename Context>
- #else
- template<typename I, typename Context>
- #endif
- void _report_warning(
- Context const & context, std::string_view message, I location)
- {
- return context.error_handler_->diagnose(
- diagnostic_kind::warning, message, context, location);
- }
- template<typename Context>
- void _report_warning(Context const & context, std::string_view message)
- {
- return context.error_handler_->diagnose(
- diagnostic_kind::warning, message, context);
- }
- #endif
- /** An invocable that returns the `I`th parameter to the bottommost rule.
- This is useful for forwarding parameters to sub-rules. */
- template<unsigned int I>
- inline constexpr detail::param_t<I> _p = {};
- // Second order parsers.
- /** A very large sentinel value used to represent pseudo-infinity. */
- int64_t const Inf = detail::unbounded;
- #ifndef BOOST_PARSER_DOXYGEN
- template<
- typename Parser,
- typename DelimiterParser,
- typename MinType,
- typename MaxType>
- struct repeat_parser
- {
- constexpr repeat_parser(
- Parser parser,
- MinType _min,
- MaxType _max,
- DelimiterParser delimiter_parser = DelimiterParser{}) :
- parser_(parser),
- delimiter_parser_(delimiter_parser),
- min_(_min),
- max_(_max)
- {}
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- using attr_t = decltype(parser_.call(
- first, last, context, skip, flags, success));
- auto retval = detail::make_sequence_of<attr_t>();
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this,
- first,
- last,
- context,
- detail::in_apply_parser(flags) ? detail::disable_trace(flags)
- : flags,
- retval);
- if constexpr (detail::is_optional_v<Attribute>) {
- detail::optional_type<Attribute> attr;
- detail::apply_parser(
- *this,
- first,
- last,
- context,
- skip,
- detail::set_in_apply_parser(flags),
- success,
- attr);
- if (success)
- retval = std::move(attr);
- } else { // Otherwise, Attribute must be a container or a nope.
- using attr_t = detail::parser_attr_or_container_value_type_v<
- decltype(parser_.call(
- first, last, context, skip, flags, success)),
- Attribute>;
- int64_t count = 0;
- for (int64_t end = detail::resolve(context, min_); count != end;
- ++count) {
- detail::skip(first, last, skip, flags);
- attr_t attr{};
- parser_.call(
- first, last, context, skip, flags, success, attr);
- if (!success) {
- detail::assign(retval, Attribute());
- return;
- }
- detail::move_back(
- retval, std::move(attr), detail::gen_attrs(flags));
- }
- int64_t const end = detail::resolve(context, max_);
- // It looks like you've created a repeated epsilon parser, by
- // writing "*eps", "+eps", "repeat(2, Inf)[eps]", or similar.
- BOOST_PARSER_DEBUG_ASSERT(
- !detail::is_unconditional_eps<Parser>{} || end < Inf);
- for (; count != end; ++count) {
- auto const prev_first = first;
- // This is only ever used in delimited_parser, which
- // always has a min=1; we therefore know we're after a
- // previous element when this executes.
- if constexpr (!detail::is_nope_v<DelimiterParser>) {
- detail::skip(first, last, skip, flags);
- delimiter_parser_.call(
- first,
- last,
- context,
- skip,
- detail::disable_attrs(flags),
- success);
- if (!success) {
- success = true;
- first = prev_first;
- break;
- }
- }
- detail::skip(first, last, skip, flags);
- attr_t attr{};
- parser_.call(
- first, last, context, skip, flags, success, attr);
- if (!success) {
- success = true;
- first = prev_first;
- break;
- }
- detail::move_back(
- retval, std::move(attr), detail::gen_attrs(flags));
- }
- }
- }
- Parser parser_;
- DelimiterParser delimiter_parser_;
- MinType min_;
- MaxType max_;
- };
- #endif
- template<typename Parser>
- struct zero_plus_parser : repeat_parser<Parser>
- {
- constexpr zero_plus_parser(Parser parser) :
- repeat_parser<Parser>(parser, 0, Inf)
- {}
- };
- template<typename Parser>
- struct one_plus_parser : repeat_parser<Parser>
- {
- constexpr one_plus_parser(Parser parser) :
- repeat_parser<Parser>(parser, 1, Inf)
- {}
- };
- template<typename Parser, typename DelimiterParser>
- struct delimited_seq_parser : repeat_parser<Parser, DelimiterParser>
- {
- constexpr delimited_seq_parser(
- Parser parser, DelimiterParser delimiter_parser) :
- repeat_parser<Parser, DelimiterParser>(
- parser, 1, Inf, delimiter_parser)
- {}
- };
- //[ opt_parser_beginning
- template<typename Parser>
- struct opt_parser
- {
- //]
- //[ opt_parser_attr_call
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- using attr_t = decltype(parser_.call(
- first, last, context, skip, flags, success));
- detail::optional_of<attr_t> retval;
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- //]
- //[ opt_parser_out_param_call
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- //[ opt_parser_trace
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- //]
- //[ opt_parser_skip
- detail::skip(first, last, skip, flags);
- //]
- //[ opt_parser_no_gen_attr_path
- if (!detail::gen_attrs(flags)) {
- parser_.call(first, last, context, skip, flags, success);
- success = true;
- return;
- }
- //]
- //[ opt_parser_gen_attr_path
- parser_.call(first, last, context, skip, flags, success, retval);
- if (!success)
- retval = Attribute();
- success = true;
- //]
- }
- //]
- //[ opt_parser_end
- Parser parser_;
- };
- //]
- template<typename ParserTuple>
- struct or_parser
- {
- constexpr or_parser(ParserTuple parsers) : parsers_(parsers) {}
- #ifndef BOOST_PARSER_DOXYGEN
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- struct use_parser_t
- {
- template<typename Parser>
- auto operator()(Parser const & parser) const
- {
- detail::skip(first_, last_, skip_, flags_);
- success_ = true; // In case someone earlier already failed...
- return parser.call(
- first_,
- last_,
- context_,
- skip_,
- flags_,
- success_);
- }
- template<typename Parser, typename Attribute>
- void operator()(Parser const & parser, Attribute & retval) const
- {
- detail::skip(first_, last_, skip_, flags_);
- success_ = true; // In case someone earlier already failed...
- detail::apply_parser(
- parser,
- first_,
- last_,
- context_,
- skip_,
- flags_,
- success_,
- retval);
- }
- Iter & first_;
- Sentinel last_;
- Context const & context_;
- SkipParser const & skip_;
- detail::flags flags_;
- bool & success_;
- };
- #endif
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
- first, last, context, skip, flags, success};
- // A result type for each of the parsers in parsers_.
- using all_types =
- decltype(detail::hl::transform(parsers_, use_parser));
- // Same as above, wrapped in detail::wrapper.
- using all_types_wrapped =
- decltype(detail::hl::transform(all_types{}, detail::wrap{}));
- // Returns a tuple<> containing two things: 1) A tuple of only the
- // unique wrapped types from above, without nopes; this may be
- // empty. 2) std::true_type or std::false_type indicating whether
- // nopes were found; if so, the final result is an optional.
- auto append_unique = [](auto result, auto x) {
- using x_type = typename decltype(x)::type;
- if constexpr (detail::is_nope_v<x_type>) {
- return detail::hl::make_pair(
- detail::hl::first(result), std::true_type{});
- } else if constexpr (detail::hl::contains(
- detail::hl::first(result), x)) {
- return result;
- } else {
- return detail::hl::make_pair(
- detail::hl::append(detail::hl::first(result), x),
- detail::hl::second(result));
- }
- };
- using wrapped_unique_types = decltype(detail::hl::fold_left(
- all_types_wrapped{},
- detail::hl::make_pair(tuple<>{}, std::false_type{}),
- append_unique));
- // Same as above, with the tuple types unwrapped.
- using unwrapped_types = decltype(detail::hl::make_pair(
- detail::hl::transform(
- detail::hl::first(wrapped_unique_types{}),
- detail::unwrap{}),
- detail::hl::second(wrapped_unique_types{})));
- // Types above converted to a "variant", which may actually be a
- // non-variant type T if that is the only unique non-nope type, or a
- // nope if unwrapped_types is empty.
- using result_t = detail::to_hana_tuple_or_type_t<unwrapped_types>;
- result_t retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
- first, last, context, skip, flags, success};
- bool done = false;
- auto try_parser = [prev_first = first,
- &use_parser,
- &success,
- flags,
- &retval,
- &done](auto const & parser) {
- if (done)
- return;
- if (detail::gen_attrs(flags))
- use_parser(parser, retval);
- else
- use_parser(parser);
- if (success)
- done = true;
- else
- use_parser.first_ = prev_first;
- };
- detail::hl::for_each(parsers_, try_parser); // TODO: -> fold-expr
- if (!done)
- success = false;
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser>
- constexpr auto prepend(parser_interface<Parser> parser) const noexcept;
- template<typename Parser>
- constexpr auto append(parser_interface<Parser> parser) const noexcept;
- #endif
- ParserTuple parsers_;
- };
- template<typename ParserTuple, typename DelimiterParser>
- struct perm_parser
- {
- constexpr perm_parser(ParserTuple parsers) : parsers_(parsers) {}
- constexpr perm_parser(
- ParserTuple parsers, DelimiterParser delimiter_parser) :
- parsers_(parsers), delimiter_parser_(delimiter_parser)
- {}
- #ifndef BOOST_PARSER_DOXYGEN
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- struct use_parser_t
- {
- template<typename Parser>
- auto operator()(Parser const & parser) const
- {
- detail::skip(first_, last_, skip_, flags_);
- success_ = true; // In case someone earlier already failed...
- return parser.call(
- first_,
- last_,
- context_,
- skip_,
- flags_,
- success_);
- }
- template<typename Parser, typename Attribute>
- void operator()(Parser const & parser, Attribute & retval) const
- {
- detail::skip(first_, last_, skip_, flags_);
- success_ = true; // In case someone earlier already failed...
- detail::apply_parser(
- parser,
- first_,
- last_,
- context_,
- skip_,
- flags_,
- success_,
- retval);
- }
- Iter & first_;
- Sentinel last_;
- Context const & context_;
- SkipParser const & skip_;
- detail::flags flags_;
- bool & success_;
- };
- #endif
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first_,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- Iter first = first_;
- use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
- first, last, context, skip, flags, success};
- using result_t =
- decltype(detail::hl::transform(parsers_, use_parser));
- result_t retval{};
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first_, last, context, flags, retval);
- call_impl(
- first,
- last,
- context,
- skip,
- flags,
- success,
- retval,
- std::make_integer_sequence<
- int,
- detail::tuple_size_<ParserTuple>>{});
- if (success)
- first_ = first;
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first_,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first_, last, context, flags, retval);
- Iter first = first_;
- use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
- first, last, context, skip, flags, success};
- using result_t =
- decltype(detail::hl::transform(parsers_, use_parser));
- constexpr auto indices = std::
- make_integer_sequence<int, detail::tuple_size_<ParserTuple>>{};
- if constexpr (detail::is_optional_v<Attribute>) {
- typename Attribute::value_type attr;
- call(first, last, context, skip, flags, success, attr);
- if (success)
- detail::assign(retval, std::move(attr));
- } else if constexpr (detail::is_tuple<Attribute>{}) {
- call_impl(
- first,
- last,
- context,
- skip,
- flags,
- success,
- retval,
- indices);
- if (!success)
- detail::assign(retval, Attribute());
- } else if constexpr (
- detail::is_struct_compatible_v<Attribute, result_t> ||
- detail::is_constructible_from_tuple_v<Attribute, result_t>) {
- result_t temp_retval{};
- call_impl(
- first,
- last,
- context,
- skip,
- flags,
- success,
- temp_retval,
- indices);
- if (success && detail::gen_attrs(flags)) {
- if constexpr (detail::is_struct_compatible_v<
- Attribute,
- result_t>) {
- detail::assign(retval, temp_retval);
- } else {
- detail::assign(
- retval,
- detail::make_from_tuple<Attribute>(
- std::move(temp_retval)));
- }
- }
- } else {
- #if 0 // TODO Seems incompatible with this parser.
- // call_impl requires a tuple, so we must wrap this scalar.
- tuple<Attribute> temp_retval{};
- call_impl(
- first,
- last,
- context,
- skip,
- flags,
- success,
- temp_retval,
- indices);
- if (success && detail::gen_attrs(flags)) {
- detail::assign(
- retval, std::move(detail::hl::front(temp_retval)));
- }
- #else
- static_assert(
- std::is_same_v<Attribute, void> && false,
- "It looks like you passed an attribute to this permutation "
- "parser that is not capable of taking the number, or the "
- "types of values compatible with the ones it produces.");
- #endif
- }
- if (success)
- first_ = first;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename... Ts,
- int... Is>
- void call_impl(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- tuple<Ts...> & retval,
- std::integer_sequence<int, Is...>) const
- {
- std::array<bool, sizeof...(Ts)> used_parsers = {{}};
- // Use "parser" to fill in attribute "x", unless "parser" has
- // previously been used.
- auto parse_into = [&](int i, auto const & parser, auto & x) {
- if (used_parsers[i])
- return false;
- detail::skip(first, last, skip, flags);
- parser.call(first, last, context, skip, flags, success, x);
- if (success) {
- used_parsers[i] = true;
- return true;
- }
- success = true;
- return false;
- };
- // Use one of the previously-unused parsers to parse one
- // alternative.
- bool first_iteration = true;
- auto parsed_one = [&](auto) {
- if constexpr (!detail::is_nope_v<DelimiterParser>) {
- if (!first_iteration) {
- detail::skip(first, last, skip, flags);
- bool local_success = true;
- delimiter_parser_.call(
- first, last, context, skip, flags, local_success);
- if (!local_success)
- return false;
- }
- first_iteration = false;
- }
- return (
- parse_into(
- Is,
- parser::get(parsers_, llong<Is>{}),
- parser::get(retval, llong<Is>{})) ||
- ...);
- };
- success = (parsed_one(Is) && ...);
- if (!success)
- retval = tuple<Ts...>{};
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser>
- constexpr auto prepend(parser_interface<Parser> parser) const noexcept;
- template<typename Parser>
- constexpr auto append(parser_interface<Parser> parser) const noexcept;
- #endif
- ParserTuple parsers_;
- DelimiterParser delimiter_parser_;
- };
- namespace detail {
- template<int N, int... I>
- constexpr auto
- make_default_combining_impl(std::integer_sequence<int, I...>)
- {
- return hl::make_tuple(((void)I, llong<N>{})...);
- }
- template<template<class...> class Tuple, typename... Args>
- constexpr auto make_default_combining(Tuple<Args...>)
- {
- return detail::make_default_combining_impl<0>(
- std::make_integer_sequence<int, sizeof...(Args)>());
- }
- template<typename ParserTuple>
- using default_combining_t = decltype(detail::make_default_combining(
- std::declval<ParserTuple>()));
- struct merge_t
- {};
- struct separate_t
- {};
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- struct dummy_use_parser_t
- {
- dummy_use_parser_t(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) :
- first_(first),
- last_(last),
- context_(context),
- skip_(skip),
- flags_(flags),
- success_(success)
- {}
- template<typename Parser>
- auto operator()(Parser const & parser) const
- {
- return parser.call(
- first_,
- last_,
- context_,
- skip_,
- flags_,
- success_);
- }
- Iter & first_;
- Sentinel last_;
- Context const & context_;
- SkipParser const & skip_;
- detail::flags flags_;
- bool & success_;
- };
- template<typename... Args>
- constexpr void static_assert_merge_attributes(tuple<Args...> parsers);
- // Combining groups are: 0, which is default merge behavior, as in
- // seq_parser::combine; -1, which is don't merge with anything, ever;
- // and N>0, which is merge with other members of group N.
- template<typename CombiningGroups, typename... Args>
- constexpr auto make_combining(tuple<Args...> parsers)
- {
- if constexpr (std::is_same_v<CombiningGroups, merge_t>) {
- detail::static_assert_merge_attributes(parsers);
- return detail::make_default_combining_impl<1>(
- std::make_integer_sequence<int, sizeof...(Args)>());
- } else if constexpr (std::is_same_v<CombiningGroups, separate_t>) {
- return detail::make_default_combining_impl<-1>(
- std::make_integer_sequence<int, sizeof...(Args)>());
- } else {
- return CombiningGroups{};
- }
- }
- template<typename ParserTuple, typename CombiningGroups>
- using combining_t = decltype(detail::make_combining<CombiningGroups>(
- std::declval<ParserTuple>()));
- struct max_
- {
- template<typename T, typename U>
- constexpr auto operator()(T x, U y) const
- {
- if constexpr (T::value < U::value)
- return y;
- else
- return x;
- }
- };
- template<int MaxGroupIdx>
- struct adjust_combining_groups
- {
- template<typename T, typename U>
- constexpr auto operator()(T result, U x) const
- {
- if constexpr (U::value <= 0)
- return hl::append(result, x);
- else
- return hl::append(result, llong<MaxGroupIdx + U::value>{});
- }
- };
- template<typename Tuple1, typename Tuple2>
- constexpr auto make_combined_combining(Tuple1 lhs, Tuple2 rhs)
- {
- auto max_group_idx = detail::hl::fold_left(lhs, llong<0>{}, max_{});
- auto rhs_adjusted = detail::hl::fold_left(
- rhs,
- tuple<>{},
- adjust_combining_groups<decltype(max_group_idx)::value>{});
- return hl::concat(lhs, rhs_adjusted);
- }
- template<typename CombiningGroups1, typename CombiningGroups2>
- using combined_combining_t = decltype(detail::make_combined_combining(
- std::declval<CombiningGroups1>(),
- std::declval<CombiningGroups2>()));
- enum class merge_kind { second_pass_detect, singleton, merged, group };
- template<merge_kind Kind>
- struct merge_kind_t
- {
- static constexpr merge_kind kind = Kind;
- };
- template<merge_kind Kind>
- static constexpr auto merge_wrap = merge_kind_t<Kind>{};
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<
- typename ParserTuple,
- typename BacktrackingTuple,
- typename CombiningGroups>
- struct seq_parser
- {
- using backtracking = BacktrackingTuple;
- using combining_groups = CombiningGroups;
- constexpr seq_parser(ParserTuple parsers) : parsers_(parsers) {}
- static constexpr auto true_ = std::true_type{};
- static constexpr auto false_ = std::false_type{};
- struct combine
- {
- template<typename T, typename U>
- auto operator()(
- T result_merging_indices_and_prev_group, U x_and_group) const
- {
- using namespace literals;
- using detail::merge_wrap;
- using detail::merge_kind;
- auto x = parser::get(x_and_group, 0_c);
- auto group = parser::get(x_and_group, 1_c);
- auto result =
- parser::get(result_merging_indices_and_prev_group, 0_c);
- using result_back_type =
- typename std::decay_t<decltype(detail::hl::back(
- result))>::type;
- using unwrapped_optional_result_back_type =
- detail::unwrapped_optional_t<result_back_type>;
- auto merging =
- parser::get(result_merging_indices_and_prev_group, 1_c);
- auto indices =
- parser::get(result_merging_indices_and_prev_group, 2_c);
- auto prev_group =
- parser::get(result_merging_indices_and_prev_group, 3_c);
- using x_type = typename decltype(x)::type;
- using unwrapped_optional_x_type =
- detail::unwrapped_optional_t<x_type>;
- if constexpr (detail::is_nope_v<x_type>) {
- if constexpr (
- !detail::is_nope_v<result_back_type> &&
- 0 < decltype(group)::value &&
- decltype(group)::value != decltype(prev_group)::value) {
- // T >> merge[nope >> ...] -> nope
- // This is a very special case. If we see a nope at
- // the begining of a group, and there's a non-nope
- // before it, we put the nope in place in the result
- // tuple temporarily, knowing that a non-nope will
- // come along later in the group to replace it.
- return detail::hl::make_tuple(
- detail::hl::append(result, x),
- detail::hl::append(
- merging,
- merge_wrap<merge_kind::second_pass_detect>),
- detail::hl::append(
- indices, detail::hl::size(result)),
- group);
- } else {
- // T >> nope -> T
- return detail::hl::make_tuple(
- result,
- detail::hl::append(
- merging,
- merge_wrap<merge_kind::second_pass_detect>),
- detail::hl::append(
- indices, detail::hl::size_minus_one(result)),
- prev_group);
- }
- } else if constexpr (detail::is_nope_v<result_back_type>) {
- // tuple<nope> >> T -> tuple<T>
- constexpr auto merge =
- 0 < decltype(group)::value
- ? merge_kind::group
- : (decltype(group)::value == -1
- ? merge_kind::singleton
- : merge_kind::second_pass_detect);
- return detail::hl::make_tuple(
- detail::hl::append(detail::hl::drop_back(result), x),
- detail::hl::append(merging, merge_wrap<merge>),
- detail::hl::append(
- indices, detail::hl::size_minus_one(result)),
- group);
- } else if constexpr (0 < decltype(group)::value) {
- if constexpr (
- decltype(prev_group)::value == decltype(group)::value) {
- return detail::hl::make_tuple(
- result,
- detail::hl::append(
- merging, merge_wrap<merge_kind::group>),
- detail::hl::append(
- indices, detail::hl::size_minus_one(result)),
- group);
- } else {
- return detail::hl::make_tuple(
- detail::hl::append(result, x),
- detail::hl::append(
- merging, merge_wrap<merge_kind::group>),
- detail::hl::append(
- indices, detail::hl::size(result)),
- group);
- }
- } else if constexpr (
- decltype(group)::value == -1 ||
- decltype(group)::value != decltype(prev_group)::value) {
- constexpr auto merge = decltype(group)::value == -1
- ? merge_kind::singleton
- : merge_kind::second_pass_detect;
- return detail::hl::make_tuple(
- detail::hl::append(result, x),
- detail::hl::append(merging, merge_wrap<merge>),
- detail::hl::append(indices, detail::hl::size(result)),
- group);
- } else if constexpr (
- detail::is_char_type_v<result_back_type> &&
- (detail::is_char_type_v<x_type> ||
- detail::is_char_type_v<unwrapped_optional_x_type>)) {
- // CHAR >> CHAR -> string
- return detail::hl::make_tuple(
- detail::hl::append(
- detail::hl::drop_back(result),
- detail::wrapper<std::string>{}),
- detail::hl::append(
- detail::hl::append(
- detail::hl::drop_front(merging),
- merge_wrap<merge_kind::second_pass_detect>),
- merge_wrap<merge_kind::second_pass_detect>),
- detail::hl::append(
- indices, detail::hl::size_minus_one(result)),
- group);
- } else if constexpr (
- detail::
- container_and_value_type<result_back_type, x_type> ||
- detail::container_and_value_type<
- result_back_type,
- unwrapped_optional_x_type>) {
- // C<T> >> T -> C<T>
- // C<T> >> optional<T> -> C<T>
- return detail::hl::make_tuple(
- result,
- detail::hl::append(
- merging,
- merge_wrap<merge_kind::second_pass_detect>),
- detail::hl::append(
- indices, detail::hl::size_minus_one(result)),
- group);
- } else if constexpr (
- detail::
- container_and_value_type<x_type, result_back_type> ||
- detail::container_and_value_type<
- x_type,
- unwrapped_optional_result_back_type>) {
- // T >> C<T> -> C<T>
- // optional<T> >> C<T> -> C<T>
- return detail::hl::make_tuple(
- detail::hl::append(detail::hl::drop_back(result), x),
- detail::hl::append(
- detail::hl::append(
- detail::hl::drop_front(merging),
- merge_wrap<merge_kind::second_pass_detect>),
- merge_wrap<merge_kind::second_pass_detect>),
- detail::hl::append(
- indices, detail::hl::size_minus_one(result)),
- group);
- } else {
- // tuple<Ts...> >> T -> tuple<Ts..., T>
- return detail::hl::make_tuple(
- detail::hl::append(result, x),
- detail::hl::append(
- merging, merge_wrap<merge_kind::second_pass_detect>),
- detail::hl::append(indices, detail::hl::size(result)),
- group);
- }
- }
- };
- struct find_merged
- {
- template<typename T, typename U>
- auto operator()(
- T final_types_and_result, U x_index_and_prev_merged) const
- {
- using namespace literals;
- using detail::merge_wrap;
- using detail::merge_kind;
- auto final_types = parser::get(final_types_and_result, 0_c);
- auto result = parser::get(final_types_and_result, 1_c);
- auto x_type_wrapper = parser::get(x_index_and_prev_merged, 0_c);
- auto index = parser::get(x_index_and_prev_merged, 1_c);
- auto prev_merged = parser::get(x_index_and_prev_merged, 2_c);
- auto type_at_index_wrapper = parser::get(final_types, index);
- using x_type = typename decltype(x_type_wrapper)::type;
- using type_at_index =
- typename decltype(type_at_index_wrapper)::type;
- if constexpr (
- decltype(prev_merged)::kind ==
- merge_kind::second_pass_detect) {
- if constexpr (
- !std::is_same_v<x_type, type_at_index> &&
- container<type_at_index>) {
- return detail::hl::make_tuple(
- final_types,
- detail::hl::append(
- result, merge_wrap<merge_kind::merged>));
- } else {
- return detail::hl::make_tuple(
- final_types,
- detail::hl::append(
- result, merge_wrap<merge_kind::singleton>));
- }
- } else {
- return detail::hl::make_tuple(
- final_types, detail::hl::append(result, prev_merged));
- }
- }
- };
- template<long long I>
- static constexpr auto
- merging_from_group(integral_constant<long long, I>)
- {
- using detail::merge_wrap;
- using detail::merge_kind;
- if constexpr (0 < I)
- return merge_wrap<merge_kind::group>;
- else if constexpr (I == -1)
- return merge_wrap<merge_kind::singleton>;
- else
- return merge_wrap<merge_kind::second_pass_detect>;
- }
- // Returns the tuple of values produced by this parser, and the
- // indices into that tuple that each parser should use in turn. The
- // case where the tuple only has one element is handled elsewhere.
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto make_temp_result(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- using namespace literals;
- detail::
- dummy_use_parser_t<Iter, Sentinel, Context, SkipParser> const
- dummy_use_parser(
- first, last, context, skip, flags, success);
- // A result type for each of the parsers in parsers_.
- using all_types =
- decltype(detail::hl::transform(parsers_, dummy_use_parser));
- // Same as above, wrapped in detail::wrapper.
- using all_types_wrapped =
- decltype(detail::hl::transform(all_types{}, detail::wrap{}));
- using combining_groups =
- detail::combining_t<ParserTuple, CombiningGroups>;
- constexpr auto first_group = detail::hl::front(combining_groups{});
- // Generate a tuple of outputs; the index that each parser should
- // use to write into its output; and whether the attribute for
- // each parser was merged into an adjacent container-attribute.
- constexpr auto combine_start = detail::hl::make_tuple(
- detail::hl::make_tuple(detail::hl::front(all_types_wrapped{})),
- detail::hl::make_tuple(merging_from_group(first_group)),
- tuple<llong<0>>{},
- first_group);
- using combined_types = decltype(detail::hl::fold_left(
- detail::hl::zip(
- detail::hl::drop_front(all_types_wrapped{}),
- detail::hl::drop_front(combining_groups{})),
- combine_start,
- combine{}));
- // Unwrap the result tuple's types.
- constexpr auto result_type_wrapped =
- parser::get(combined_types{}, 0_c);
- using result_type = decltype(detail::hl::transform(
- result_type_wrapped, detail::unwrap{}));
- using indices = decltype(parser::get(combined_types{}, 2_c));
- using first_pass_merged =
- decltype(parser::get(combined_types{}, 1_c));
- constexpr auto find_merged_start =
- detail::hl::make_tuple(result_type_wrapped, tuple<>{});
- using merged = decltype(detail::hl::fold_left(
- detail::hl::zip(
- all_types_wrapped{}, indices{}, first_pass_merged{}),
- find_merged_start,
- find_merged{}));
- return detail::hl::make_tuple(
- result_type{}, indices{}, parser::get(merged{}, 1_c));
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first_,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- Iter first = first_;
- auto temp_result =
- make_temp_result(first, last, context, skip, flags, success);
- std::decay_t<decltype(parser::get(temp_result, llong<0>{}))>
- retval{};
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this,
- first_,
- last,
- context,
- detail::in_apply_parser(flags) ? detail::disable_trace(flags)
- : flags,
- retval);
- std::decay_t<decltype(parser::get(temp_result, llong<1>{}))>
- indices;
- std::decay_t<decltype(parser::get(temp_result, llong<2>{}))>
- merged;
- call_impl(
- first,
- last,
- context,
- skip,
- flags,
- success,
- retval,
- indices,
- merged);
- if (success)
- first_ = first;
- // A 1-tuple is converted to a scalar.
- if constexpr (detail::hl::size(retval) == llong<1>{}) {
- using namespace literals;
- return parser::get(retval, 0_c);
- } else {
- return retval;
- }
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first_,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this,
- first_,
- last,
- context,
- detail::in_apply_parser(flags) ? detail::disable_trace(flags)
- : flags,
- retval);
- Iter first = first_;
- auto temp_result =
- make_temp_result(first, last, context, skip, flags, success);
- using temp_result_attr_t =
- std::decay_t<decltype(parser::get(temp_result, llong<0>{}))>;
- std::decay_t<decltype(parser::get(temp_result, llong<1>{}))>
- indices;
- std::decay_t<decltype(parser::get(temp_result, llong<2>{}))> merged;
- auto max_ = [](auto result, auto x) {
- if constexpr (decltype(result)::value < decltype(x)::value) {
- return x;
- } else {
- return result;
- }
- };
- using max_index_t =
- decltype(detail::hl::fold_left(indices, llong<0>{}, max_));
- if constexpr (detail::is_optional_v<Attribute>) {
- typename Attribute::value_type attr;
- call(first, last, context, skip, flags, success, attr);
- if (success)
- detail::assign(retval, std::move(attr));
- } else if constexpr (
- detail::is_tuple<Attribute>{} ||
- detail::is_struct_compatible_v<Attribute, temp_result_attr_t>) {
- call_impl(
- first,
- last,
- context,
- skip,
- flags,
- success,
- retval,
- indices,
- merged);
- if (!success)
- detail::assign(retval, Attribute());
- } else if constexpr (
- 0 < max_index_t::value && detail::is_constructible_from_tuple_v<
- Attribute,
- temp_result_attr_t>) {
- temp_result_attr_t temp_retval{};
- call_impl(
- first,
- last,
- context,
- skip,
- flags,
- success,
- temp_retval,
- indices,
- merged);
- if (success && detail::gen_attrs(flags)) {
- detail::assign(
- retval,
- detail::make_from_tuple<Attribute>(
- std::move(temp_retval)));
- }
- } else {
- // call_impl requires a tuple, so we must wrap this scalar.
- tuple<Attribute> temp_retval{};
- call_impl(
- first,
- last,
- context,
- skip,
- flags,
- success,
- temp_retval,
- indices,
- merged);
- if (success && detail::gen_attrs(flags)) {
- detail::assign(
- retval, std::move(detail::hl::front(temp_retval)));
- }
- }
- if (success)
- first_ = first;
- }
- // Invokes each parser, placing the resulting values (if any) into
- // retval, using the index mapping in indices. The case of a tuple
- // containing only a single value is handled elsewhere.
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute,
- typename Indices,
- typename Merged>
- void call_impl(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval,
- Indices const & indices,
- Merged const & merged) const
- {
- using detail::merge_wrap;
- using detail::merge_kind;
- static_assert(
- detail::is_tuple<Attribute>{} || std::is_aggregate_v<Attribute>,
- "");
- auto use_parser = [&first,
- last,
- &context,
- &skip,
- flags_ = flags,
- &success,
- &retval](auto const &
- parser_index_merged_and_backtrack) {
- if (!success) // Someone earlier already failed...
- return;
- auto flags = flags_;
- using namespace literals;
- detail::skip(first, last, skip, flags);
- auto const & parser =
- parser::get(parser_index_merged_and_backtrack, 0_c);
- auto merge_kind_t_ =
- parser::get(parser_index_merged_and_backtrack, 2_c);
- constexpr bool was_merged_into_adjacent_container =
- decltype(merge_kind_t_)::kind == merge_kind::merged;
- constexpr bool is_in_a_group =
- decltype(merge_kind_t_)::kind == merge_kind::group;
- bool const can_backtrack =
- parser::get(parser_index_merged_and_backtrack, 3_c);
- if (!detail::gen_attrs(flags)) {
- parser.call(first, last, context, skip, flags, success);
- if (!success && !can_backtrack) {
- std::stringstream oss;
- detail::print_parser(context, parser, oss);
- throw parse_error<Iter>(first, oss.str());
- }
- return;
- }
- auto const tuple_idx =
- parser::get(parser_index_merged_and_backtrack, 1_c);
- auto const tuple_size = detail::tuple_or_struct_size(retval);
- static_assert(
- decltype(tuple_idx)::value < decltype(tuple_size)::value,
- "Looks like you're trying to write some attribute into an "
- "out-of-bounds position in a tuple/struct. In other "
- "words, the attribute you're parsing into does not match "
- "the default attribute used by this parser. This may be "
- "because you passed an out-param to parse() at the top "
- "level that is not compatible with the attribute type "
- "generated by the parser you passed to parse().");
- if constexpr (!(decltype(tuple_idx)::value <
- decltype(tuple_size)::value)) {
- [[maybe_unused]] detail::print_type<Attribute> _;
- }
- auto & out = parser::get(retval, tuple_idx);
- using attr_t = decltype(parser.call(
- first, last, context, skip, flags, success));
- constexpr bool out_container =
- container<std::decay_t<decltype(out)>>;
- constexpr bool attr_container = container<attr_t>;
- if constexpr (
- (out_container == attr_container &&
- !was_merged_into_adjacent_container &&
- !detail::is_nope_v<attr_t>) ||
- is_in_a_group) {
- parser.call(
- first, last, context, skip, flags, success, out);
- if (!success) {
- if (!can_backtrack) {
- std::stringstream oss;
- detail::print_parser(context, parser, oss);
- throw parse_error<Iter>(first, oss.str());
- }
- out = std::decay_t<decltype(out)>();
- return;
- }
- } else {
- attr_t x =
- parser.call(first, last, context, skip, flags, success);
- if (!success) {
- if (!can_backtrack) {
- std::stringstream oss;
- detail::print_parser(context, parser, oss);
- throw parse_error<Iter>(first, oss.str());
- }
- return;
- }
- using just_x = attr_t;
- using just_out = detail::remove_cv_ref_t<decltype(out)>;
- if constexpr (detail::is_nope_v<attr_t>) {
- // nothing to do
- } if constexpr (
- (!out_container ||
- !std::is_same_v<just_x, just_out>) &&
- std::is_assignable_v<just_out &, just_x &&> &&
- (!std::is_same_v<just_out, std::string> ||
- !std::is_integral_v<just_x>)) {
- detail::assign(out, std::move(x));
- } else {
- detail::move_back(
- out, std::move(x), detail::gen_attrs(flags));
- }
- }
- };
- auto const parsers_and_indices =
- detail::hl::zip(parsers_, indices, merged, backtracking{});
- detail::hl::for_each(parsers_and_indices, use_parser);
- }
- template<bool AllowBacktracking, typename Parser>
- constexpr auto prepend(parser_interface<Parser> parser) const noexcept;
- template<bool AllowBacktracking, typename Parser>
- constexpr auto append(parser_interface<Parser> parser) const noexcept;
- ParserTuple parsers_;
- };
- #endif
- namespace detail {
- template<typename Action, typename Attribute>
- using action_direct_call_expr =
- decltype(std::declval<Action>()(std::declval<Attribute>()));
- template<typename Action, typename Attribute>
- using action_apply_call_expr = decltype(hl::apply(
- std::declval<Action>(), std::declval<Attribute>()));
- template<typename Action, typename Attribute, typename Context>
- using action_assignable_to_val_direct_expr =
- decltype(_val(std::declval<Context>()) = std::declval<Action>()(std::declval<Attribute>()));
- template<typename Action, typename Attribute, typename Context>
- using action_assignable_to_val_apply_expr =
- decltype(_val(std::declval<Context>()) = hl::apply(std::declval<Action>(), std::declval<Attribute>()));
- template<typename Action, typename Attribute, typename Context>
- constexpr auto action_assignable_to_val_direct()
- {
- if constexpr (is_nope_v<decltype(*std::declval<Context>().val_)>) {
- return false;
- } else if constexpr (!is_detected_v<
- action_direct_call_expr,
- Action,
- Attribute>) {
- return false;
- } else if constexpr (std::is_same_v<
- action_direct_call_expr<Action, Attribute>,
- void>) {
- return false;
- } else {
- return is_detected_v<
- action_assignable_to_val_direct_expr,
- Action,
- Attribute,
- Context>;
- }
- }
- template<typename Action, typename Attribute, typename Context>
- constexpr auto action_assignable_to_val_apply()
- {
- if constexpr (is_nope_v<decltype(*std::declval<Context>().val_)>) {
- return false;
- } else if constexpr (!is_tuple<remove_cv_ref_t<Attribute>>{}) {
- return false;
- } else if constexpr (tuple_size_<remove_cv_ref_t<Attribute>> < 2) {
- return false;
- } else if constexpr (!is_detected_v<
- action_apply_call_expr,
- Action,
- Attribute>) {
- return false;
- } else if constexpr (std::is_same_v<
- action_apply_call_expr<Action, Attribute>,
- void>) {
- return false;
- } else {
- return is_detected_v<
- action_assignable_to_val_apply_expr,
- Action,
- Attribute,
- Context>;
- }
- }
- template<typename Context, typename TagType>
- constexpr bool in_recursion =
- std::is_same_v<typename Context::rule_tag, TagType> &&
- !std::is_same_v<typename Context::rule_tag, void>;
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser, typename Action>
- struct action_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- detail::nope call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- detail::nope retval;
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- auto const initial_first = first;
- auto attr = parser_.call(
- first,
- last,
- context,
- skip,
- detail::enable_attrs(flags),
- success);
- if (!success)
- return;
- if constexpr (detail::action_assignable_to_val_apply<
- decltype(action_) &,
- decltype(attr),
- decltype(context)>()) {
- _val(context) = detail::hl::apply(action_, std::move(attr));
- } else {
- BOOST_PARSER_SUBRANGE const where(initial_first, first);
- auto const action_context =
- detail::make_action_context(context, attr, where);
- if constexpr (detail::action_assignable_to_val_direct<
- decltype(action_) &,
- decltype(action_context) &,
- decltype(action_context) &>()) {
- _val(action_context) = action_(action_context);
- } else if constexpr (std::is_same_v<
- decltype(action_(action_context)),
- void>) {
- action_(action_context);
- } else {
- // If you see an error here, it's because you are using an
- // invocable for a semantic action that returns a non-void
- // type Ret, but values of type Ret is not assignable to
- // _val(ctx). To fix this, only use this invocable within
- // a rule whose attribute type is assignable from Ret, or
- // remove the non-void return statement(s) from your
- // invocable.
- [[maybe_unused]] none n = action_(action_context);
- }
- }
- }
- Parser parser_;
- Action action_;
- };
- template<typename Parser, typename F>
- struct transform_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, detail::global_nope);
- auto attr =
- parser_.call(first, last, context, skip, flags, success);
- if (success && detail::gen_attrs(flags))
- return f_(std::move(attr));
- else
- return decltype(f_(std::move(attr))){};
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- auto attr =
- parser_.call(first, last, context, skip, flags, success);
- if (success && detail::gen_attrs(flags))
- detail::assign(retval, f_(std::move(attr)));
- }
- Parser parser_;
- F f_;
- };
- template<typename Parser>
- struct omit_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- detail::nope call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, detail::global_nope);
- parser_.call(
- first,
- last,
- context,
- skip,
- detail::disable_attrs(flags),
- success);
- return {};
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- parser_.call(
- first,
- last,
- context,
- skip,
- detail::disable_attrs(flags),
- success);
- }
- Parser parser_;
- };
- template<typename Parser>
- struct raw_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- BOOST_PARSER_SUBRANGE<Iter> call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- BOOST_PARSER_SUBRANGE<Iter> retval;
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- auto const initial_first = first;
- parser_.call(
- first,
- last,
- context,
- skip,
- detail::disable_attrs(flags),
- success);
- if (success && detail::gen_attrs(flags))
- detail::assign(
- retval, BOOST_PARSER_SUBRANGE<Iter>(initial_first, first));
- }
- Parser parser_;
- };
- #if BOOST_PARSER_USE_CONCEPTS
- template<typename Parser>
- struct string_view_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- auto r =
- parser::detail::text::unpack_iterator_and_sentinel(first, last);
- static_assert(
- std::contiguous_iterator<decltype(r.first)>,
- "string_view_parser and the string_view[] directive that uses "
- "it requires that the underlying char sequence being parsed be "
- "a contiguous range. If you're seeing this static_assert, you "
- "have not met this contract.");
- using char_type = detail::remove_cv_ref_t<decltype(*r.first)>;
- std::basic_string_view<char_type> retval;
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- auto const initial_first = first;
- parser_.call(
- first,
- last,
- context,
- skip,
- detail::disable_attrs(flags),
- success);
- if (!success || !detail::gen_attrs(flags))
- return;
- auto r = parser::detail::text::unpack_iterator_and_sentinel(
- initial_first, first);
- static_assert(
- std::contiguous_iterator<decltype(r.first)>,
- "string_view_parser and the string_view[] directive that uses "
- "it requires that the underlying char sequence being parsed be "
- "a contiguous range. If you're seeing this static_assert, you "
- "have not met this contract.");
- using char_type = detail::remove_cv_ref_t<decltype(*r.first)>;
- if (initial_first == first) {
- detail::assign(retval, std::basic_string_view<char_type>{});
- } else {
- detail::assign(
- retval,
- std::basic_string_view<char_type>{
- &*r.first, std::size_t(r.last - r.first)});
- }
- }
- Parser parser_;
- };
- #endif
- template<typename Parser>
- struct lexeme_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- using attr_t = decltype(parser_.call(
- first, last, context, skip, flags, success));
- attr_t retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- parser_.call(
- first,
- last,
- context,
- skip,
- detail::disable_skip(flags),
- success,
- retval);
- }
- Parser parser_;
- };
- template<typename Parser>
- struct no_case_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context_,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- auto context = context_;
- ++context.no_case_depth_;
- using attr_t = decltype(parser_.call(
- first, last, context, skip, flags, success));
- attr_t retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context_,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- auto context = context_;
- ++context.no_case_depth_;
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- parser_.call(first, last, context, skip, flags, success, retval);
- }
- Parser parser_;
- };
- template<typename Parser, typename SkipParser>
- struct skip_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser_>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser_ const & skip,
- detail::flags flags,
- bool & success) const
- {
- using attr_t = decltype(parser_.call(
- first, last, context, skip, flags, success));
- attr_t retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser_,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser_ const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if constexpr (detail::is_nope_v<SkipParser>) {
- parser_.call(
- first,
- last,
- context,
- skip,
- detail::enable_skip(flags),
- success,
- retval);
- } else {
- parser_.call(
- first,
- last,
- context,
- skip_parser_,
- detail::enable_skip(flags),
- success,
- retval);
- }
- }
- Parser parser_;
- SkipParser skip_parser_;
- };
- template<typename Parser, bool FailOnMatch>
- struct expect_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- detail::nope call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- detail::nope retval;
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- auto first_copy = first;
- parser_.call(
- first_copy,
- last,
- context,
- skip,
- detail::disable_attrs(flags),
- success);
- if (FailOnMatch)
- success = !success;
- }
- Parser parser_;
- };
- template<typename T>
- struct symbol_parser
- {
- symbol_parser() : copied_from_(nullptr) {}
- explicit symbol_parser(std::string_view diagnostic_text) :
- copied_from_(nullptr), diagnostic_text_(diagnostic_text)
- {}
- symbol_parser(symbol_parser const & other) :
- initial_elements_(other.initial_elements_),
- copied_from_(other.copied_from_ ? other.copied_from_ : &other),
- diagnostic_text_(other.diagnostic_text_)
- {}
- symbol_parser(symbol_parser && other) :
- initial_elements_(std::move(other.initial_elements_)),
- copied_from_(other.copied_from_),
- diagnostic_text_(other.diagnostic_text_)
- {}
- /** Inserts an entry consisting of a UTF-8 string `str` to match, and
- an associated attribute `x`, to `*this`. The entry is added for
- use in all subsequent top-level parses. Subsequent lookups during
- the current top-level parse will not necessarily match `str`. */
- template<typename Context>
- void insert_for_next_parse(
- Context const & context, std::string_view str, T x)
- {
- auto & pending_ops =
- detail::get_pending_symtab_ops(context, ref());
- pending_ops.push_back(detail::symbol_table_operation<T>{
- std::string(str),
- std::move(x),
- detail::symbol_table_op::insert});
- }
- /** Erases the entry whose UTF-8 match string is `str`, from `*this`.
- The entry will no longer be available for use in all subsequent
- top-level parses. `str` will not be removed from the symbols
- matched in the current top-level parse. */
- template<typename Context>
- void erase_for_next_parse(Context const & context, std::string_view str)
- {
- auto & pending_ops =
- detail::get_pending_symtab_ops(context, ref());
- pending_ops.push_back(detail::symbol_table_operation<T>{
- std::string(str),
- std::nullopt,
- detail::symbol_table_op::erase});
- }
- /** Erases all the entries from the copy of the symbol table inside
- the parse context `context`. */
- template<typename Context>
- void clear_for_next_parse(Context const & context)
- {
- auto & pending_ops =
- detail::get_pending_symtab_ops(context, ref());
- pending_ops.push_back(detail::symbol_table_operation<T>{
- {}, std::nullopt, detail::symbol_table_op::clear});
- }
- /** Uses UTF-8 string `str` to look up an attribute in the table
- during parsing, returning it as an optional reference. The lookup
- is done on the copy of the symbol table inside the parse context
- `context`. */
- template<typename Context>
- parser::detail::text::optional_ref<T>
- find(Context const & context, std::string_view str) const
- {
- auto [trie, has_case_folded] = detail::get_trie(context, ref());
- if (context.no_case_depth_) {
- return trie[detail::case_fold_view(
- str | detail::text::as_utf32)];
- } else {
- return trie[str | detail::text::as_utf32];
- }
- }
- /** Inserts an entry consisting of a UTF-8 string `str` to match, and
- an associtated attribute `x`, to the copy of the symbol table
- inside the parse context `context`. */
- template<typename Context>
- void insert(Context const & context, std::string_view str, T && x) const
- {
- auto [trie, has_case_folded] = detail::get_trie(context, ref());
- if (context.no_case_depth_) {
- trie.insert(
- detail::case_fold_view(str | detail::text::as_utf32),
- std::move(x));
- } else {
- trie.insert(str | detail::text::as_utf32, std::move(x));
- }
- }
- /** Erases the entry whose UTF-8 match string is `str` from the copy
- of the symbol table inside the parse context `context`. */
- template<typename Context>
- void erase(Context const & context, std::string_view str) const
- {
- auto [trie, has_case_folded] = detail::get_trie(context, ref());
- if (context.no_case_depth_) {
- trie.erase(
- detail::case_fold_view(str | detail::text::as_utf32));
- } else {
- trie.erase(str | detail::text::as_utf32);
- }
- }
- /** Erases the entry whose UTF-8 match string is `str` from the copy
- of the symbol table inside the parse context `context`. */
- template<typename Context>
- void clear(Context const & context) const
- {
- auto [trie, _] = detail::get_trie(context, ref());
- trie.clear();
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- T call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- T retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- auto [trie, _0] = detail::get_trie(context, ref());
- auto const lookup = context.no_case_depth_
- ? trie.longest_match(detail::case_fold_view(
- BOOST_PARSER_SUBRANGE(first, last)))
- : trie.longest_match(first, last);
- if (lookup.match) {
- std::advance(first, lookup.size);
- detail::assign(retval, T{*trie[lookup]});
- } else {
- success = false;
- }
- }
- mutable std::vector<std::pair<std::string, T>> initial_elements_;
- symbol_parser const * copied_from_;
- symbol_parser const & ref() const noexcept
- {
- if (copied_from_)
- return *copied_from_;
- return *this;
- }
- std::vector<std::pair<std::string, T>> &
- initial_elements() const noexcept
- {
- return ref().initial_elements_;
- }
- std::string_view diagnostic_text_;
- };
- template<
- bool CanUseCallbacks,
- typename TagType,
- typename Attribute,
- typename LocalState,
- typename ParamsTuple>
- struct rule_parser
- {
- using tag_type = TagType;
- using attr_type = Attribute;
- using locals_type = LocalState;
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- std::conditional_t<
- detail::in_recursion<Context, tag_type>,
- detail::nope,
- attr_type>
- call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- constexpr bool in_recursion =
- detail::in_recursion<Context, tag_type>;
- if constexpr (in_recursion)
- flags = detail::disable_attrs(flags);
- attr_type retval{};
- locals_type locals = detail::make_locals<locals_type>(context);
- auto params = detail::resolve_rule_params(context, params_);
- tag_type * const tag_ptr = nullptr;
- auto const rule_context = detail::make_rule_context(
- context, tag_ptr, retval, locals, params);
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, rule_context, flags, retval);
- bool dont_assign = false;
- if constexpr (in_recursion) {
- // We have to use this out-arg overload for iterations >= 1 in
- // recursive rules, since every iteration past the first is
- // defined to return nope.
- parse_rule(
- tag_ptr,
- first,
- last,
- rule_context,
- skip,
- flags,
- success,
- dont_assign,
- retval);
- } else {
- auto attr = parse_rule(
- tag_ptr,
- first,
- last,
- rule_context,
- skip,
- flags,
- success,
- dont_assign);
- if (success && !dont_assign) {
- if constexpr (!detail::is_nope_v<decltype(attr)>)
- detail::assign(retval, attr);
- }
- }
- if constexpr (
- CanUseCallbacks && Context::use_callbacks && !in_recursion) {
- if (!success)
- return attr_type{};
- auto const & callbacks = _callbacks(context);
- if constexpr (detail::is_nope_v<attr_type>) {
- static_assert(
- detail::is_invocable_v<decltype(callbacks), tag_type>,
- "For rules without attributes, Callbacks must be a "
- "struct with overloads of the form void(tag_type). If "
- "you're seeing an error here, you probably have not "
- "met this contract.");
- callbacks(tag_type{});
- } else {
- static_assert(
- detail::is_invocable_v<
- decltype(callbacks),
- tag_type,
- decltype(std::move(retval))>,
- "For rules with attributes, Callbacks must be a struct "
- "with overloads of the form void(tag_type, attr_type). "
- "If you're seeing an error here, you probably have not "
- "met this contract.");
- callbacks(tag_type{}, std::move(retval));
- }
- return attr_type{};
- } else {
- if (!success && !in_recursion)
- detail::assign(retval, attr_type());
- if constexpr (in_recursion)
- return detail::nope{};
- else
- return retval;
- }
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute_>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute_ & retval) const
- {
- if constexpr (CanUseCallbacks && Context::use_callbacks) {
- call(first, last, context, skip, flags, success);
- } else {
- locals_type locals = detail::make_locals<locals_type>(context);
- auto params = detail::resolve_rule_params(context, params_);
- tag_type * const tag_ptr = nullptr;
- auto const rule_context = detail::make_rule_context(
- context, tag_ptr, retval, locals, params);
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, rule_context, flags, retval);
- bool dont_assign = false;
- parse_rule(
- tag_ptr,
- first,
- last,
- rule_context,
- skip,
- flags,
- success,
- dont_assign,
- retval);
- if (!success || dont_assign)
- retval = Attribute_();
- }
- }
- std::string_view diagnostic_text_;
- ParamsTuple params_;
- };
- #endif
- namespace detail {
- template<typename T>
- using base_member_function_template_expr =
- decltype(std::declval<T>().template base<2>());
- template<typename T>
- constexpr bool has_base_member_function_template_v =
- is_detected_v<base_member_function_template_expr, T>;
- template<typename T>
- using has_digits1_member_function_template_expr =
- decltype(std::declval<T>().template digits<1>());
- template<typename T>
- constexpr bool has_digits1_member_function_template_v =
- is_detected_v<has_digits1_member_function_template_expr, T>;
- template<typename T>
- using has_digits2_member_function_template_expr =
- decltype(std::declval<T>().template digits<1, 2>());
- template<typename T>
- constexpr bool has_digits2_member_function_template_v =
- is_detected_v<has_digits2_member_function_template_expr, T>;
- }
- // Parser interface.
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- struct parser_interface
- {
- using parser_type = Parser;
- using global_state_type = GlobalState;
- using error_handler_type = ErrorHandler;
- constexpr parser_interface() : parser_() {}
- constexpr parser_interface(parser_type p) : parser_(std::move(p)) {}
- constexpr parser_interface(
- parser_type p, global_state_type gs, error_handler_type eh) :
- parser_(p), globals_(gs), error_handler_(eh)
- {}
- /** Returns a `parser_interface` containing a parser equivalent to an
- `expect_parser` containing `parser_`, with `FailOnMatch ==
- true`. */
- constexpr auto operator!() const noexcept
- {
- return parser::parser_interface{
- expect_parser<parser_type, true>{parser_}};
- }
- /** Returns a `parser_interface` containing a parser equivalent to an
- `expect_parser` containing `parser_`, with `FailOnMatch ==
- false`. */
- constexpr auto operator&() const noexcept
- {
- return parser::parser_interface{
- expect_parser<parser_type, false>{parser_}};
- }
- /** Returns a `parser_interface` containing a parser equivalent to a
- `zero_plus_parser` containing `parser_`. */
- constexpr auto operator*() const noexcept
- {
- if constexpr (detail::is_zero_plus_p<parser_type>{}) {
- return *this;
- } else if constexpr (detail::is_one_plus_p<parser_type>{}) {
- using inner_parser = decltype(parser_type::parser_);
- return parser::parser_interface{
- zero_plus_parser<inner_parser>(parser_.parser_)};
- } else {
- return parser::parser_interface{
- zero_plus_parser<parser_type>(parser_)};
- }
- }
- /** Returns a `parser_interface` containing a parser equivalent to a
- `one_plus_parser` containing `parser_`. */
- constexpr auto operator+() const noexcept
- {
- if constexpr (detail::is_zero_plus_p<parser_type>{}) {
- using inner_parser = decltype(parser_type::parser_);
- return parser::parser_interface{
- zero_plus_parser<inner_parser>(parser_.parser_)};
- } else if constexpr (detail::is_one_plus_p<parser_type>{}) {
- return *this;
- } else {
- return parser::parser_interface{
- one_plus_parser<parser_type>(parser_)};
- }
- }
- /** Returns a `parser_interface` containing a parser equivalent to a
- `opt_parser` containing `parser_`. */
- constexpr auto operator-() const noexcept
- {
- return parser::parser_interface{opt_parser<parser_type>{parser_}};
- }
- /** Returns a `parser_interface` containing a parser equivalent to a
- `seq_parser` containing `parser_` followed by `rhs.parser_`. */
- template<typename ParserType2>
- constexpr auto
- operator>>(parser_interface<ParserType2> rhs) const noexcept
- {
- if constexpr (detail::is_seq_p<parser_type>{}) {
- return parser_.template append<true>(rhs);
- } else if constexpr (detail::is_seq_p<ParserType2>{}) {
- return rhs.parser_.template prepend<true>(*this);
- } else {
- using parser_t = seq_parser<
- tuple<parser_type, ParserType2>,
- tuple<std::true_type, std::true_type>,
- tuple<llong<0>, llong<0>>>;
- return parser::parser_interface{parser_t{
- tuple<parser_type, ParserType2>{parser_, rhs.parser_}}};
- }
- }
- /** Returns a `parser_interface` containing a parser equivalent to a
- `seq_parser` containing `parser_` followed by `lit(rhs)`. */
- constexpr auto operator>>(char rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to a
- `seq_parser` containing `parser_` followed by `lit(rhs)`. */
- constexpr auto operator>>(char32_t rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to a
- `seq_parser` containing `parser_` followed by `lit(rhs)`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator>>(R && r) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to a
- `seq_parser` containing `parser_` followed by `rhs.parser_`. No
- back-tracking is allowed after `parser_` succeeds; if
- `rhs.parser_` fails after `parser_` succeeds, the top-level parse
- fails. */
- template<typename ParserType2>
- constexpr auto
- operator>(parser_interface<ParserType2> rhs) const noexcept
- {
- if constexpr (detail::is_seq_p<parser_type>{}) {
- return parser_.template append<false>(rhs);
- } else if constexpr (detail::is_seq_p<ParserType2>{}) {
- return rhs.parser_.template prepend<false>(*this);
- } else {
- using parser_t = seq_parser<
- tuple<parser_type, ParserType2>,
- tuple<std::true_type, std::false_type>,
- tuple<llong<0>, llong<0>>>;
- return parser::parser_interface{parser_t{
- tuple<parser_type, ParserType2>{parser_, rhs.parser_}}};
- }
- }
- /** Returns a `parser_interface` containing a parser equivalent to a
- `seq_parser` containing `parser_` followed by `lit(rhs)`. No
- back-tracking is allowed after `parser_` succeeds; if `lit(rhs)`
- fails after `parser_` succeeds, the top-level parse fails. */
- constexpr auto operator>(char rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to a
- `seq_parser` containing `parser_` followed by `lit(rhs)`. No
- back-tracking is allowed after `parser_` succeeds; if `lit(rhs)`
- fails after `parser_` succeeds, the top-level parse fails. */
- constexpr auto operator>(char32_t rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to a
- `seq_parser` containing `parser_` followed by `lit(rhs)`. No
- back-tracking is allowed after `parser_` succeeds; if `lit(rhs)`
- fails after `parser_` succeeds, the top-level parse fails. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator>(R && r) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to an
- `or_parser` containing `parser_` followed by `rhs.parser_`. */
- template<typename ParserType2>
- constexpr auto
- operator|(parser_interface<ParserType2> rhs) const noexcept
- {
- if constexpr (detail::is_or_p<parser_type>{}) {
- return parser_.append(rhs);
- } else if constexpr (detail::is_or_p<ParserType2>{}) {
- return rhs.parser_.prepend(*this);
- } else {
- // If you're seeing this as a compile- or run-time failure,
- // you've tried to put an eps parser at the beginning of an
- // alternative-parser, such as "eps | int_". This is not what
- // you meant. Since eps always matches any input, "eps |
- // int_" is just an awkward spelling for "eps". To fix this
- // this, put the eps as the last alternative, so the other
- // alternatives get a chance. Possibly, you may have meant to
- // add a condition to the eps, like "eps(condition) | int_",
- // which also is meaningful, and so is allowed.
- BOOST_PARSER_ASSERT(
- !detail::is_unconditional_eps<parser_type>{});
- return parser::parser_interface{
- or_parser<tuple<parser_type, ParserType2>>{
- tuple<parser_type, ParserType2>{parser_, rhs.parser_}}};
- }
- }
- /** Returns a `parser_interface` containing a parser equivalent to a
- `perm_parser` containing `parser_` followed by `rhs.parser_`. It
- is an error to use `eps` (conditional or not) with this
- operator. */
- template<typename ParserType2>
- constexpr auto
- operator||(parser_interface<ParserType2> rhs) const noexcept
- {
- // If you're seeing this as a compile- or run-time failure, you've
- // tried to put an eps parser in a permutation-parser, such as
- // "eps || int_".
- BOOST_PARSER_ASSERT(!detail::is_eps_p<parser_type>{});
- BOOST_PARSER_ASSERT(!detail::is_eps_p<ParserType2>{});
- if constexpr (detail::is_perm_p<parser_type>{}) {
- return parser_.append(rhs);
- } else if constexpr (detail::is_perm_p<ParserType2>{}) {
- return rhs.parser_.prepend(*this);
- } else {
- return parser::parser_interface{
- perm_parser<tuple<parser_type, ParserType2>, detail::nope>{
- tuple<parser_type, ParserType2>{parser_, rhs.parser_}}};
- }
- }
- /** Returns a `parser_interface` containing a parser equivalent to an
- `or_parser` containing `parser_` followed by `lit(rhs)`. */
- constexpr auto operator|(char rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to an
- `or_parser` containing `parser_` followed by `lit(rhs)`. */
- constexpr auto operator|(char32_t rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to an
- `or_parser` containing `parser_` followed by `lit(rhs)`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator|(R && r) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to
- `!rhs >> *this`. */
- template<typename ParserType2>
- constexpr auto
- operator-(parser_interface<ParserType2> rhs) const noexcept
- {
- return !rhs >> *this;
- }
- /** Returns a `parser_interface` containing a parser equivalent to
- `!lit(rhs) >> *this`. */
- constexpr auto operator-(char rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to
- `!lit(rhs) >> *this`. */
- constexpr auto operator-(char32_t rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to
- `!lit(rhs) >> *this`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator-(R && r) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to an
- `delimited_seq_parser` containing `parser_` and `rhs.parser_`. */
- template<typename ParserType2>
- constexpr auto
- operator%(parser_interface<ParserType2> rhs) const noexcept
- {
- return parser::parser_interface{
- delimited_seq_parser<parser_type, ParserType2>(
- parser_, rhs.parser_)};
- }
- /** Returns a `parser_interface` containing a parser equivalent to an
- `delimited_seq_parser` containing `parser_` and `lit(rhs)`. */
- constexpr auto operator%(char rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to an
- `delimited_seq_parser` containing `parser_` and `lit(rhs)`. */
- constexpr auto operator%(char32_t rhs) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to an
- `delimited_seq_parser` containing `parser_` and `lit(rhs)`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator%(R && r) const noexcept;
- /** Returns a `parser_interface` containing a parser equivalent to an
- `action_parser` containing `parser_`, with semantic action
- `action`. */
- template<typename Action>
- constexpr auto operator[](Action action) const
- {
- using action_parser_t = action_parser<parser_type, Action>;
- return parser::parser_interface{action_parser_t{parser_, action}};
- }
- /** Returns `parser_((Arg &&)arg, (Args &&)args...)`. This is useful
- for those parsers that have `operator()` overloads,
- e.g. `char_('x')`. By convention, parsers' `operator()`s return
- `parser_interface`s.
- This function does not participate in overload resolution unless
- `parser_((Arg &&)arg, (Args &&)args...)` is well-formed. */
- template<typename Arg, typename... Args>
- constexpr auto operator()(Arg && arg, Args &&... args) const noexcept
- -> decltype(std::declval<parser_type const &>()(
- (Arg &&) arg, (Args &&) args...))
- {
- return parser_((Arg &&) arg, (Args &&) args...);
- }
- #ifndef BOOST_PARSER_DOXYGEN
- /** Applies `parser_`, returning the parsed attribute, if any, unless
- the attribute is reported via callback. */
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParserType>
- auto operator()(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParserType const & skip,
- detail::flags flags,
- bool & success) const
- {
- return parser_.call(first, last, context, skip, flags, success);
- }
- /** Applies `parser_`, assinging the parsed attribute, if any, to
- `attr`, unless the attribute is reported via callback. */
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParserType,
- typename Attribute>
- void operator()(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParserType const & skip,
- detail::flags flags,
- bool & success,
- Attribute & attr) const
- {
- parser_.call(first, last, context, skip, flags, success, attr);
- }
- /** Returns a new `parser_interface` constructed from
- `parser_.base<Radix2>()`. Note that this only works for integral
- numeric parsers like `int_` and `uint_`. */
- template<int Radix2>
- constexpr auto base() const noexcept
- {
- if constexpr (detail::has_base_member_function_template_v<
- parser_type>) {
- return parser::parser_interface{
- parser_.template base<Radix2>()};
- } else {
- static_assert(
- detail::has_base_member_function_template_v<parser_type>,
- "Only certain parsers have a .base<>() member function. "
- "This is not one of them.");
- }
- }
- /** Returns a new `parser_interface` constructed from
- `parser_.digits<Digits>()`. Note that this only works for
- integral numeric parsers like `int_` and `uint_`. */
- template<int Digits>
- constexpr auto digits() const noexcept
- {
- if constexpr (detail::has_digits1_member_function_template_v<
- parser_type>) {
- return parser::parser_interface{
- parser_.template digits<Digits>()};
- } else {
- static_assert(
- detail::has_digits1_member_function_template_v<parser_type>,
- "Only certain parsers have a .base<>() member function. "
- "This is not one of them.");
- }
- }
- /** Returns a new `parser_interface` constructed from
- `parser_.digits<MinDigits2, MaxDigits2>()`. Note that this only
- works for integral numeric parsers like `int_` and `uint_`. */
- template<int MinDigits2, int MaxDigits2>
- constexpr auto digits() const noexcept
- {
- if constexpr (detail::has_digits2_member_function_template_v<
- parser_type>) {
- return parser::parser_interface{
- parser_.template digits<MinDigits2, MaxDigits2>()};
- } else {
- static_assert(
- detail::has_digits2_member_function_template_v<parser_type>,
- "Only certain parsers have a .base<>() member function. "
- "This is not one of them.");
- }
- }
- parser_type parser_;
- global_state_type globals_;
- error_handler_type error_handler_;
- #endif
- using parser_interface_derivation_tag = int;
- };
- /** Returns a `parser_interface` with the same parser and error handler,
- with `globals` added. The result of passing any non-top-level parser
- for the `parser` argument is undefined. */
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- auto with_globals(
- parser_interface<Parser, detail::nope, ErrorHandler> const & parser,
- GlobalState & globals)
- {
- return parser_interface<Parser, GlobalState &, ErrorHandler>{
- parser.parser_, globals, parser.error_handler_};
- }
- /** Returns a `parser_interface` with the same parser and globals, with
- `error_handler` added. The result of passing any non-top-level parser
- for the `parser` argument is undefined. */
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- auto with_error_handler(
- parser_interface<Parser, GlobalState, default_error_handler> const &
- parser,
- ErrorHandler & error_handler)
- {
- return parser_interface<Parser, GlobalState, ErrorHandler &>{
- parser.parser_, parser.globals_, error_handler};
- }
- /** A `symbols<T>` represents the initial state of a symbol table parser
- that produces attributes of type `T`. The entries in the symbol table
- can be changed during parsing, but those mutations do not affect the
- `symbols<T>` object itself; all mutations happen to a copy of the
- symbol table in the parse context. For table entries that should be
- used during every parse, add entries via `add()` or `operator()`. For
- mid-parse mutations, use `insert()` and `erase()`. */
- template<typename T>
- struct symbols : parser_interface<symbol_parser<T>>
- {
- symbols() {}
- symbols(char const * diagnostic_text) :
- parser_interface<symbol_parser<T>>(
- symbol_parser<T>(diagnostic_text))
- {}
- symbols(std::initializer_list<std::pair<std::string_view, T>> il)
- {
- this->parser_.initial_elements_.resize(il.size());
- std::copy(il.begin(), il.end(),
- this->parser_.initial_elements_.begin());
- }
- symbols(
- char const * diagnostic_text,
- std::initializer_list<std::pair<std::string_view, T>> il) :
- parser_interface<symbol_parser<T>>(
- symbol_parser<T>(diagnostic_text))
- {
- this->parser_.initial_elements_.resize(il.size());
- std::copy(il.begin(), il.end(),
- this->parser_.initial_elements_.begin());
- }
- /** Inserts an entry consisting of a UTF-8 string `str` to match, and
- an associated attribute `x`, to `*this`. The entry is added for
- use in all subsequent top-level parses. Subsequent lookups during
- the current top-level parse will not necessarily match `str`. */
- void insert_for_next_parse(std::string_view str, T x)
- {
- this->parser_.initial_elements_.push_back(
- std::pair(std::string(str), std::move(x)));
- }
- /** Erases the entry whose UTF-8 match string is `str`, from `*this`.
- The entry will no longer be available for use in all subsequent
- top-level parses. `str` will not be removed from the symbols
- matched in the current top-level parse. */
- void erase_for_next_parse(std::string_view str)
- {
- auto it = std::find_if(
- this->parser_.initial_elements_.begin(),
- this->parser_.initial_elements_.end(),
- [str](auto const & x) { return x.first == str; });
- this->parser_.initial_elements_.erase(it);
- }
- /** Erases all the entries from the copy of the symbol table inside
- the parse context `context`. */
- void clear_for_next_parse() { this->parser_.initial_elements_.clear(); }
- /** Inserts an entry consisting of a UTF-8 string `str` to match, and
- an associated attribute `x`, to `*this`. The entry is added for
- use in all subsequent top-level parses. Subsequent lookups during
- the current top-level parse will not necessarily match `str`. */
- template<typename Context>
- void insert_for_next_parse(
- Context const & context, std::string_view str, T x)
- {
- this->parser_.insert_for_next_parse(context, str, std::move(x));
- }
- /** Erases the entry whose UTF-8 match string is `str`, from `*this`.
- The entry will no longer be available for use in all subsequent
- top-level parses. `str` will not be removed from the symbols
- matched in the current top-level parse. */
- template<typename Context>
- void erase_for_next_parse(Context const & context, std::string_view str)
- {
- this->parser_.erase_for_next_parse(context, str);
- }
- /** Erases all the entries from the copy of the symbol table inside
- the parse context `context`. */
- template<typename Context>
- void clear_for_next_parse(Context const & context)
- {
- this->parser_.clear_for_next_parse(context);
- }
- /** Uses UTF-8 string `str` to look up an attribute in the table
- during parsing, returning it as an optional reference. The lookup
- is done on the copy of the symbol table inside the parse context
- `context`, not `*this`. */
- template<typename Context>
- parser::detail::text::optional_ref<T>
- find(Context const & context, std::string_view str) const
- {
- return this->parser_.find(context, str);
- }
- /** Inserts an entry consisting of a UTF-8 string to match `str`, and
- an associated attribute `x`, to the copy of the symbol table
- inside the parse context `context`. */
- template<typename Context>
- void insert(Context const & context, std::string_view str, T x) const
- {
- this->parser_.insert(context, str, std::move(x));
- }
- /** Erases the entry whose UTF-8 match string is `str` from the copy
- of the symbol table inside the parse context `context`. */
- template<typename Context>
- void erase(Context const & context, std::string_view str) const
- {
- this->parser_.erase(context, str);
- }
- /** Erases all the entries from the copy of the symbol table inside
- the parse context `context`. */
- template<typename Context>
- void clear(Context const & context) const
- {
- this->parser_.clear(context);
- }
- };
- #ifndef BOOST_PARSER_DOXYGEN
- template<
- typename TagType,
- typename Attribute,
- typename LocalState,
- typename ParamsTuple>
- struct rule
- : parser_interface<
- rule_parser<false, TagType, Attribute, LocalState, ParamsTuple>>
- {
- static_assert(
- !std::is_same_v<TagType, void>,
- "void is not a valid tag type for a rule.");
- constexpr rule(char const * diagnostic_text)
- {
- this->parser_.diagnostic_text_ = diagnostic_text;
- }
- template<typename T, typename... Ts>
- constexpr auto with(T && x, Ts &&... xs) const
- {
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<ParamsTuple> &&
- "If you're seeing this, you tried to chain calls on a rule, "
- "like 'rule.with(foo).with(bar)'. Quit it!'"));
- using params_tuple_type = decltype(detail::hl::make_tuple(
- static_cast<T &&>(x), static_cast<Ts &&>(xs)...));
- using rule_parser_type = rule_parser<
- false,
- TagType,
- Attribute,
- LocalState,
- params_tuple_type>;
- using result_type = parser_interface<rule_parser_type>;
- return result_type{rule_parser_type{
- this->parser_.diagnostic_text_,
- detail::hl::make_tuple(
- static_cast<T &&>(x), static_cast<Ts &&>(xs)...)}};
- }
- };
- template<
- typename TagType,
- typename Attribute,
- typename LocalState,
- typename ParamsTuple>
- struct callback_rule
- : parser_interface<
- rule_parser<true, TagType, Attribute, LocalState, ParamsTuple>>
- {
- constexpr callback_rule(char const * diagnostic_text)
- {
- this->parser_.diagnostic_text_ = diagnostic_text;
- }
- template<typename T, typename... Ts>
- constexpr auto with(T && x, Ts &&... xs) const
- {
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<ParamsTuple> &&
- "If you're seeing this, you tried to chain calls on a "
- "callback_rule, like 'rule.with(foo).with(bar)'. Quit it!'"));
- using params_tuple_type = decltype(detail::hl::make_tuple(
- static_cast<T &&>(x), static_cast<Ts &&>(xs)...));
- using rule_parser_type = rule_parser<
- true,
- TagType,
- Attribute,
- LocalState,
- params_tuple_type>;
- using result_type = parser_interface<rule_parser_type>;
- return result_type{rule_parser_type{
- this->parser_.diagnostic_text_,
- detail::hl::make_tuple(
- static_cast<T &&>(x), static_cast<Ts &&>(xs)...)}};
- }
- };
- //[ define_rule_definition
- #define BOOST_PARSER_DEFINE_IMPL(_, rule_name_) \
- template< \
- typename Iter, \
- typename Sentinel, \
- typename Context, \
- typename SkipParser> \
- decltype(rule_name_)::parser_type::attr_type parse_rule( \
- decltype(rule_name_)::parser_type::tag_type *, \
- Iter & first, \
- Sentinel last, \
- Context const & context, \
- SkipParser const & skip, \
- boost::parser::detail::flags flags, \
- bool & success, \
- bool & dont_assign) \
- { \
- auto const & parser = BOOST_PARSER_PP_CAT(rule_name_, _def); \
- using attr_t = \
- decltype(parser(first, last, context, skip, flags, success)); \
- using attr_type = decltype(rule_name_)::parser_type::attr_type; \
- if constexpr (boost::parser::detail::is_nope_v<attr_t>) { \
- dont_assign = true; \
- parser(first, last, context, skip, flags, success); \
- return {}; \
- } else if constexpr (std::is_same_v<attr_type, attr_t>) { \
- return parser(first, last, context, skip, flags, success); \
- } else if constexpr (std::is_constructible_v<attr_type, attr_t>) { \
- return attr_type( \
- parser(first, last, context, skip, flags, success)); \
- } else { \
- attr_type attr{}; \
- parser(first, last, context, skip, flags, success, attr); \
- return attr; \
- } \
- } \
- \
- template< \
- typename Iter, \
- typename Sentinel, \
- typename Context, \
- typename SkipParser, \
- typename Attribute> \
- void parse_rule( \
- decltype(rule_name_)::parser_type::tag_type *, \
- Iter & first, \
- Sentinel last, \
- Context const & context, \
- SkipParser const & skip, \
- boost::parser::detail::flags flags, \
- bool & success, \
- bool & /*dont_assign*/, \
- Attribute & retval) \
- { \
- auto const & parser = BOOST_PARSER_PP_CAT(rule_name_, _def); \
- using attr_t = \
- decltype(parser(first, last, context, skip, flags, success)); \
- if constexpr (boost::parser::detail::is_nope_v<attr_t>) { \
- parser(first, last, context, skip, flags, success); \
- } else { \
- parser(first, last, context, skip, flags, success, retval); \
- } \
- }
- //]
- #endif
- /** For each given token `t`, defines a pair of `parse_rule()`
- overloads, used internally within Boost.Parser. Each such pair
- implements the parsing behavior rule `t`, using the parser `t_def`.
- This implementation is in the form of a pair of function templates.
- You should therefore write this macro only at namespace scope. */
- #define BOOST_PARSER_DEFINE_RULES(...) \
- BOOST_PARSER_PP_FOR_EACH(BOOST_PARSER_DEFINE_IMPL, _, __VA_ARGS__)
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename ParserTuple>
- template<typename Parser>
- constexpr auto or_parser<ParserTuple>::prepend(
- parser_interface<Parser> parser) const noexcept
- {
- // If you're seeing this as a compile- or run-time failure, you've
- // tried to put an eps parser at the beginning of an
- // alternative-parser, such as "eps | (int_ | double_)". This is not
- // what you meant. Since eps always matches any input, "eps | (int_ |
- // double_)" is just an awkward spelling for "eps". To fix this this,
- // put the eps as the last alternative, so the other alternatives get
- // a chance. Possibly, you may have meant to add a condition to the
- // eps, like "eps(condition) | (int_ | double_)", which also is
- // meaningful, and so is allowed.
- BOOST_PARSER_ASSERT(!detail::is_unconditional_eps<Parser>{});
- return parser_interface{
- or_parser<decltype(detail::hl::prepend(parsers_, parser.parser_))>{
- detail::hl::prepend(parsers_, parser.parser_)}};
- }
- template<typename ParserTuple>
- template<typename Parser>
- constexpr auto or_parser<ParserTuple>::append(
- parser_interface<Parser> parser) const noexcept
- {
- // If you're seeing this as a compile- or run-time failure, you've
- // tried to put an eps parser in the middle of an alternative-parser,
- // such as "int_ | eps | double_". This is not what you meant. Since
- // eps always matches any input, "int_ | eps | double_" is just an
- // awkward spelling for "int_ | eps". To fix this this, put the eps
- // as the last alternative, so the other alternatives get a chance.
- // Possibly, you may have meant to add a condition to the eps, like
- // "int_ | eps(condition) | double_", which also is meaningful, and so
- // is allowed.
- BOOST_PARSER_ASSERT(!detail::is_unconditional_eps_v<decltype(
- detail::hl::back(parsers_))>);
- if constexpr (detail::is_or_p<Parser>{}) {
- return parser_interface{or_parser<decltype(
- detail::hl::concat(parsers_, parser.parser_.parsers_))>{
- detail::hl::concat(parsers_, parser.parser_.parsers_)}};
- } else {
- return parser_interface{or_parser<decltype(
- detail::hl::append(parsers_, parser.parser_))>{
- detail::hl::append(parsers_, parser.parser_)}};
- }
- }
- template<typename ParserTuple, typename DelimiterParser>
- template<typename Parser>
- constexpr auto perm_parser<ParserTuple, DelimiterParser>::prepend(
- parser_interface<Parser> parser) const noexcept
- {
- // If you're seeing this as a compile- or run-time failure, you've
- // tried to put an eps parser in a permutation-parser, such as "eps ||
- // int_".
- BOOST_PARSER_ASSERT(!detail::is_eps_p<Parser>{});
- return parser_interface{perm_parser<
- decltype(detail::hl::prepend(parsers_, parser.parser_)),
- detail::nope>{detail::hl::prepend(parsers_, parser.parser_)}};
- }
- template<typename ParserTuple, typename DelimiterParser>
- template<typename Parser>
- constexpr auto perm_parser<ParserTuple, DelimiterParser>::append(
- parser_interface<Parser> parser) const noexcept
- {
- // If you're seeing this as a compile- or run-time failure, you've
- // tried to put an eps parser in a permutation-parser, such as "int_
- // || eps".
- BOOST_PARSER_ASSERT(!detail::is_eps_p<Parser>{});
- if constexpr (detail::is_perm_p<Parser>{}) {
- return parser_interface{perm_parser<
- decltype(detail::hl::concat(parsers_, parser.parser_.parsers_)),
- detail::nope>{
- detail::hl::concat(parsers_, parser.parser_.parsers_)}};
- } else {
- return parser_interface{perm_parser<
- decltype(detail::hl::append(parsers_, parser.parser_)),
- detail::nope>{detail::hl::append(parsers_, parser.parser_)}};
- }
- }
- template<
- typename ParserTuple,
- typename BacktrackingTuple,
- typename CombiningGroups>
- template<bool AllowBacktracking, typename Parser>
- constexpr auto
- seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>::prepend(
- parser_interface<Parser> parser) const noexcept
- {
- using combining_groups =
- detail::combining_t<ParserTuple, CombiningGroups>;
- using final_combining_groups =
- decltype(detail::hl::prepend(combining_groups{}, llong<0>{}));
- using backtracking = decltype(detail::hl::prepend(
- detail::hl::prepend(
- detail::hl::drop_front(BacktrackingTuple{}),
- std::bool_constant<AllowBacktracking>{}),
- std::true_type{}));
- using parser_t = seq_parser<
- decltype(detail::hl::prepend(parsers_, parser.parser_)),
- backtracking,
- final_combining_groups>;
- return parser_interface{
- parser_t{detail::hl::prepend(parsers_, parser.parser_)}};
- }
- template<
- typename ParserTuple,
- typename BacktrackingTuple,
- typename CombiningGroups>
- template<bool AllowBacktracking, typename Parser>
- constexpr auto
- seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>::append(
- parser_interface<Parser> parser) const noexcept
- {
- using combining_groups =
- detail::combining_t<ParserTuple, CombiningGroups>;
- if constexpr (detail::is_seq_p<Parser>{}) {
- using parser_combining_groups = detail::combining_t<
- decltype(parser.parser_.parsers_),
- typename Parser::combining_groups>;
- using final_combining_groups = detail::
- combined_combining_t<combining_groups, parser_combining_groups>;
- using rhs_backtracking = decltype(detail::hl::prepend(
- detail::hl::drop_front(typename Parser::backtracking{}),
- std::bool_constant<AllowBacktracking>{}));
- using backtracking = decltype(detail::hl::concat(
- BacktrackingTuple{}, rhs_backtracking{}));
- using parser_t = seq_parser<
- decltype(detail::hl::concat(parsers_, parser.parser_.parsers_)),
- backtracking,
- final_combining_groups>;
- return parser_interface{parser_t{
- detail::hl::concat(parsers_, parser.parser_.parsers_)}};
- } else {
- using final_combining_groups =
- decltype(detail::hl::append(combining_groups{}, llong<0>{}));
- using backtracking = decltype(detail::hl::append(
- BacktrackingTuple{}, std::bool_constant<AllowBacktracking>{}));
- using parser_t = seq_parser<
- decltype(detail::hl::append(parsers_, parser.parser_)),
- backtracking,
- final_combining_groups>;
- return parser_interface{
- parser_t{detail::hl::append(parsers_, parser.parser_)}};
- }
- }
- #endif
- // Directives.
- /** Represents an unparameterized higher-order parser (e.g. `omit_parser`)
- as a directive (e.g. `omit[other_parser]`). */
- template<template<class> class Parser>
- struct directive
- {
- template<typename Parser2>
- constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
- {
- return parser_interface{Parser<Parser2>{rhs.parser_}};
- }
- };
- /** The `omit` directive, whose `operator[]` returns a
- `parser_interface<omit_parser<P>>` from a given parser of type
- `parser_interface<P>`. */
- inline constexpr directive<omit_parser> omit;
- /** The `raw` directive, whose `operator[]` returns a
- `parser_interface<raw_parser<P>>` from a given parser of type
- `parser_interface<P>`. */
- inline constexpr directive<raw_parser> raw;
- #if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
- /** The `string_view` directive, whose `operator[]` returns a
- `parser_interface<string_view_parser<P>>` from a given parser of type
- `parser_interface<P>`. This is only available in C++20 and later. */
- inline constexpr directive<string_view_parser> string_view;
- #endif
- /** The `lexeme` directive, whose `operator[]` returns a
- `parser_interface<lexeme_parser<P>>` from a given parser of type
- `parser_interface<P>`. */
- inline constexpr directive<lexeme_parser> lexeme;
- /** The `no_case` directive, whose `operator[]` returns a
- `parser_interface<no_case_parser<P>>` from a given parser of type
- `parser_interface<P>`. */
- inline constexpr directive<no_case_parser> no_case;
- /** Represents a `repeat_parser` as a directive
- (e.g. `repeat[other_parser]`). */
- template<typename MinType, typename MaxType>
- struct repeat_directive
- {
- template<typename Parser2>
- constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
- {
- using repeat_parser_type =
- repeat_parser<Parser2, detail::nope, MinType, MaxType>;
- return parser_interface{
- repeat_parser_type{rhs.parser_, min_, max_}};
- }
- MinType min_;
- MaxType max_;
- };
- /** Returns a `repeat_directive` that repeats exactly `n` times, and whose
- `operator[]` returns a `parser_interface<repeat_parser<P>>` from a
- given parser of type `parser_interface<P>`. */
- template<typename T>
- constexpr repeat_directive<T, T> repeat(T n) noexcept
- {
- return repeat_directive<T, T>{n, n};
- }
- /** Returns a `repeat_directive` that repeats between `min_` and `max_`
- times, inclusive, and whose `operator[]` returns a
- `parser_interface<repeat_parser<P>>` from a given parser of type
- `parser_interface<P>`. */
- template<typename MinType, typename MaxType>
- constexpr repeat_directive<MinType, MaxType>
- repeat(MinType min_, MaxType max_) noexcept
- {
- return repeat_directive<MinType, MaxType>{min_, max_};
- }
- /** A directive that represents a `perm_parser`, where the items parsed
- are delimited by `DelimiterParser`
- (e.g. `delimiter(delimter_parser)[some_perm_parser]`). This directive
- only applies to `perm_parser`s. */
- template<typename DelimiterParser>
- struct delimiter_directive
- {
- template<typename ParserTuple, typename DelimiterParser2>
- constexpr auto operator[](
- parser_interface<perm_parser<ParserTuple, DelimiterParser2>> rhs)
- const noexcept
- {
- using parser_type = perm_parser<ParserTuple, DelimiterParser>;
- return parser_interface{
- parser_type{rhs.parser_.parsers_, delimiter_parser_}};
- }
- DelimiterParser delimiter_parser_;
- };
- /** Returns a `delimiter_directive` whose `operator[]` returns a
- `perm_parser`, where the items parsed are delimited by
- `delimiter_parser`. */
- template<typename DelimiterParser>
- constexpr delimiter_directive<DelimiterParser>
- delimiter(parser_interface<DelimiterParser> delimiter_parser) noexcept
- {
- return delimiter_directive<DelimiterParser>{delimiter_parser.parser_};
- }
- /** Represents a skip parser as a directive. When used without a skip
- parser, e.g. `skip[parser_in_which_to_do_skipping]`, the skipper for
- the entire parse is used. When given another parser, e.g.
- `skip(skip_parser)[parser_in_which_to_do_skipping]`, that other parser
- is used as the skipper within the directive. */
- template<typename SkipParser = detail::nope>
- struct skip_directive
- {
- template<typename Parser>
- constexpr auto operator[](parser_interface<Parser> rhs) const noexcept
- {
- return parser_interface{
- skip_parser<Parser, SkipParser>{rhs.parser_, skip_parser_}};
- }
- /** Returns a `skip_directive` with `skip_parser` as its skipper. */
- template<typename SkipParser2>
- constexpr auto
- operator()(parser_interface<SkipParser2> skip_parser) const noexcept
- {
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<SkipParser> &&
- "If you're seeing this, you tried to chain calls on skip, "
- "like 'skip(foo)(bar)'. Quit it!'"));
- return skip_directive<parser_interface<SkipParser2>>{skip_parser};
- }
- SkipParser skip_parser_;
- };
- /** The `skip_directive`, whose `operator[]` returns a
- `parser_interface<skip_parser<P>>` from a given parser of type
- `parser_interface<P>`. */
- inline constexpr skip_directive<> skip;
- /** A directive type that can only be used on sequence parsers, that
- forces the merge of all the sequence_parser's subparser's attributes
- into a single attribute. */
- struct merge_directive
- {
- template<
- typename ParserTuple,
- typename BacktrackingTuple,
- typename CombiningGroups>
- constexpr auto
- operator[](parser_interface<
- seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>>
- rhs) const noexcept
- {
- return parser_interface{
- seq_parser<ParserTuple, BacktrackingTuple, detail::merge_t>{
- rhs.parser_.parsers_}};
- }
- };
- /** The `merge_directive`, whose `operator[]` returns a
- `parser_interface<P2>`, from a given parser of type
- `parser_interface<P>`, where `P` is a `seq_parser`. `P2` is the same
- as `P`, except that its `CombiningGroups` template parameter is
- replaced with a tag type that causes the subparser's attributes to be
- merged into a single attribute. */
- inline constexpr merge_directive merge;
- /** A directive type that can only be used on sequence parsers, that
- prevents each of the sequence_parser's subparser's attributes from
- merging with any other subparser's attribute. */
- struct separate_directive
- {
- template<
- typename ParserTuple,
- typename BacktrackingTuple,
- typename CombiningGroups>
- constexpr auto
- operator[](parser_interface<
- seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>>
- rhs) const noexcept
- {
- return parser_interface{
- seq_parser<ParserTuple, BacktrackingTuple, detail::separate_t>{
- rhs.parser_.parsers_}};
- }
- };
- /** The `separate_directive`, whose `operator[]` returns a
- `parser_interface<P2>`, from a given parser of type
- `parser_interface<P>`, where `P` is a `seq_parser`. `P2` is the same
- as `P`, except that its `CombiningGroups` template parameter is
- replaced with a tag type that prevents each subparser's attribute from
- merging with any other subparser's attribute. */
- inline constexpr separate_directive separate;
- /** A directive that transforms the attribute generated by a parser.
- `operator[]` returns a `parser_interface<transform_parser<Parser,
- F>>`. */
- template<typename F>
- struct transform_directive
- {
- template<typename Parser>
- constexpr auto operator[](parser_interface<Parser> rhs) const noexcept
- {
- return parser_interface{
- transform_parser<Parser, F>{rhs.parser_, f_}};
- }
- F f_;
- };
- /** Returns a `transform_directive` that uses invocable `F` to do its
- work. */
- template<typename F>
- constexpr auto transform(F f)
- {
- return transform_directive<F>{std::move(f)};
- }
- // First order parsers.
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Predicate>
- struct eps_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- detail::nope call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const noexcept
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, detail::global_nope);
- BOOST_PARSER_SUBRANGE const where(first, first);
- auto const predicate_context = detail::make_action_context(
- context, detail::global_nope, where);
- // Predicate must be a parse predicate. If you see an error here,
- // you have not met this contract. See the terminology section of
- // the online docs if you don't know what that a parse predicate
- // is.
- success = pred_(predicate_context);
- return {};
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- BOOST_PARSER_SUBRANGE const where(first, first);
- auto const predicate_context = detail::make_action_context(
- context, detail::global_nope, where);
- // Predicate must be a parse predicate. If you see an error here,
- // you have not met this contract. See the terminology section of
- // the online docs if you don't know what that a parse predicate
- // is.
- success = pred_(predicate_context);
- }
- /** Returns a `parser_interface` containing an `eps_parser` that will
- fail if `pred` evaluates to false. */
- template<typename Predicate2>
- constexpr auto operator()(Predicate2 pred) const noexcept
- {
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<Predicate> &&
- "If you're seeing this, you tried to chain calls on eps, "
- "like 'eps(foo)(bar)'. Quit it!'"));
- return parser_interface{eps_parser<Predicate2>{std::move(pred)}};
- }
- Predicate pred_;
- };
- #endif
- /** The epsilon parser. This matches anything, and consumes no input. If
- used with an optional predicate, like `eps(pred)`, it matches iff
- `pred(ctx)` evaluates to true, where `ctx` is the parser context. */
- inline constexpr parser_interface<eps_parser<detail::nope>> eps;
- #ifndef BOOST_PARSER_DOXYGEN
- struct eoi_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- detail::nope call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, detail::global_nope);
- if (first != last)
- success = false;
- return {};
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (first != last)
- success = false;
- }
- };
- #endif
- /** The end-of-input parser. It matches only the end of input. */
- inline constexpr parser_interface<eoi_parser> eoi;
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Attribute>
- struct attr_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const &,
- detail::flags flags,
- bool &) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, detail::global_nope);
- return detail::resolve(context, attr_);
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute_>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute_ & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (detail::gen_attrs(flags))
- detail::assign_copy(retval, detail::resolve(context, attr_));
- }
- Attribute attr_;
- };
- #endif
- /** Returns an `attr_parser` which matches anything, and consumes no
- input, and which produces `a` as its attribute. */
- template<typename Attribute>
- constexpr auto attr(Attribute a) noexcept
- {
- return parser_interface{attr_parser<Attribute>{std::move(a)}};
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Expected, typename AttributeType>
- struct char_parser
- {
- constexpr char_parser() {}
- constexpr char_parser(Expected expected) : expected_(expected) {}
- template<typename T>
- using attribute_type = std::conditional_t<
- std::is_same_v<AttributeType, void>,
- std::decay_t<T>,
- AttributeType>;
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const -> attribute_type<decltype(*first)>
- {
- attribute_type<decltype(*first)> retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (first == last) {
- success = false;
- return;
- }
- attribute_type<decltype(*first)> const x = *first;
- if (detail::unequal(context, x, expected_)) {
- success = false;
- return;
- }
- detail::assign(retval, x);
- ++first;
- }
- /** Returns a `parser_interface` containing a `char_parser` that
- matches `x`.
- \tparam T Constrained by `!parsable_range_like<T>`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<typename T>
- requires(!parsable_range_like<T>)
- #else
- template<
- typename T,
- typename Enable =
- std::enable_if_t<!detail::is_parsable_range_like_v<T>>>
- #endif
- constexpr auto operator()(T x) const noexcept
- {
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<Expected> &&
- "If you're seeing this, you tried to chain calls on char_, "
- "like 'char_('a')('b')'. Quit it!'"));
- return parser_interface{
- char_parser<T, AttributeType>{std::move(x)}};
- }
- /** Returns a `parser_interface` containing a `char_parser` that
- matches any value in `[lo, hi]`. */
- template<typename LoType, typename HiType>
- constexpr auto operator()(LoType lo, HiType hi) const noexcept
- {
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<Expected> &&
- "If you're seeing this, you tried to chain calls on char_, "
- "like 'char_('a', 'b')('c', 'd')'. Quit it!'"));
- using char_pair_t = detail::char_pair<LoType, HiType>;
- using char_parser_t = char_parser<char_pair_t, AttributeType>;
- return parser_interface(
- char_parser_t(char_pair_t{std::move(lo), std::move(hi)}));
- }
- /** Returns a `parser_interface` containing a `char_parser` that
- matches one of the values in `r`. If the character being matched
- during the parse is a `char32_t` value, the elements of `r` are
- transcoded from their presumed encoding to UTF-32 during the
- comparison. Otherwise, the character begin matched is directly
- compared to the elements of `r`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator()(R && r) const noexcept
- {
- BOOST_PARSER_ASSERT(
- ((!std::is_rvalue_reference_v<R &&> ||
- !detail::is_range<detail::remove_cv_ref_t<R>>) &&
- "It looks like you tried to pass an rvalue range to "
- "char_(). Don't do that, or you'll end up with dangling "
- "references."));
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<Expected> &&
- "If you're seeing this, you tried to chain calls on char_, "
- "like 'char_(char-set)(char-set)'. Quit it!'"));
- auto chars = detail::make_char_range<false>(r);
- using char_range_t = decltype(chars);
- using char_parser_t = char_parser<char_range_t, AttributeType>;
- return parser_interface(char_parser_t(chars));
- }
- /** Returns a `parser_interface` containing a `char_parser` that
- matches one of the values in `r`. `r` must be a sorted,
- random-access sequence of `char32_t`. The character begin matched
- is directly compared to the elements of `r`. The match is found
- via binary search. No case folding is performed.
- \tparam R Additionally constrained by
- `std::same_as<std::ranges::range_value_t<R>, char32_t>`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- requires std::same_as<std::ranges::range_value_t<R>, char32_t>
- #else
- template<
- typename R,
- typename Enable = std::enable_if_t<
- detail::is_parsable_range_like_v<R> &&
- std::is_same_v<detail::range_value_t<R>, char32_t>>>
- #endif
- constexpr auto operator()(sorted_t, R && r) const noexcept
- {
- BOOST_PARSER_ASSERT(
- ((!std::is_rvalue_reference_v<R &&> ||
- !detail::is_range<detail::remove_cv_ref_t<R>>) &&
- "It looks like you tried to pass an rvalue range to "
- "char_(). Don't do that, or you'll end up with dangling "
- "references."));
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<Expected> &&
- "If you're seeing this, you tried to chain calls on char_, "
- "like 'char_(char-set)(char-set)'. Quit it!'"));
- auto chars = detail::make_char_range<true>(r);
- using char_range_t = decltype(chars);
- using char_parser_t = char_parser<char_range_t, AttributeType>;
- return parser_interface(char_parser_t(chars));
- }
- Expected expected_;
- };
- struct digit_parser
- {
- constexpr digit_parser() {}
- template<typename T>
- using attribute_type = std::decay_t<T>;
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const -> attribute_type<decltype(*first)>
- {
- attribute_type<decltype(*first)> retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (first == last) {
- success = false;
- return;
- }
- attribute_type<decltype(*first)> const x = *first;
- char32_t const x_cmp = x;
- if (x_cmp < U'\x0100' && (x_cmp < U'0' || U'9' < x_cmp)) {
- success = false;
- return;
- }
- char32_t const * it = std::upper_bound(
- std::begin(zero_cps) + 1, std::end(zero_cps), x_cmp);
- if (it == std::begin(zero_cps) || x_cmp < *(it - 1) ||
- *(it - 1) + 9 < x_cmp) {
- success = false;
- return;
- }
- detail::assign(retval, x);
- ++first;
- }
- // Produced from
- // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp, using
- // "[:nt=De:]" for the Input field.
- static constexpr char32_t zero_cps[] = {
- U'\u0030', // U+0030 DIGIT ZERO
- U'\u0660', // U+0660 ARABIC-INDIC DIGIT ZERO
- U'\u06F0', // U+06F0 EXTENDED ARABIC-INDIC DIGIT ZERO
- U'\u07C0', // U+07C0 NKO DIGIT ZERO
- U'\u0966', // U+0966 DEVANAGARI DIGIT ZERO
- U'\u09E6', // U+09E6 BENGALI DIGIT ZERO
- U'\u0A66', // U+0A66 GURMUKHI DIGIT ZERO
- U'\u0AE6', // U+0AE6 GUJARATI DIGIT ZERO
- U'\u0B66', // U+0B66 ORIYA DIGIT ZERO
- U'\u0BE6', // U+0BE6 TAMIL DIGIT ZERO
- U'\u0C66', // U+0C66 TELUGU DIGIT ZERO
- U'\u0CE6', // U+0CE6 KANNADA DIGIT ZERO
- U'\u0D66', // U+0D66 MALAYALAM DIGIT ZERO
- U'\u0DE6', // U+0DE6 SINHALA LITH DIGIT ZERO
- U'\u0E50', // U+0E50 THAI DIGIT ZERO
- U'\u0ED0', // U+0ED0 LAO DIGIT ZERO
- U'\u0F20', // U+0F20 TIBETAN DIGIT ZERO
- U'\u1040', // U+1040 MYANMAR DIGIT ZERO
- U'\u1090', // U+1090 MYANMAR SHAN DIGIT ZERO
- U'\u17E0', // U+17E0 KHMER DIGIT ZERO
- U'\u1810', // U+1810 MONGOLIAN DIGIT ZERO
- U'\u1946', // U+1946 LIMBU DIGIT ZERO
- U'\u19D0', // U+19D0 NEW TAI LUE DIGIT ZERO
- U'\u1A80', // U+1A80 TAI THAM HORA DIGIT ZERO
- U'\u1A90', // U+1A90 TAI THAM THAM DIGIT ZERO
- U'\u1B50', // U+1B50 BALINESE DIGIT ZERO
- U'\u1BB0', // U+1BB0 SUNDANESE DIGIT ZERO
- U'\u1C40', // U+1C40 LEPCHA DIGIT ZERO
- U'\u1C50', // U+1C50 OL CHIKI DIGIT ZERO
- U'\uA620', // U+A620 VAI DIGIT ZERO
- U'\uA8D0', // U+A8D0 SAURASHTRA DIGIT ZERO
- U'\uA900', // U+A900 KAYAH LI DIGIT ZERO
- U'\uA9D0', // U+A9D0 JAVANESE DIGIT ZERO
- U'\uA9F0', // U+A9F0 MYANMAR TAI LAING DIGIT ZERO
- U'\uAA50', // U+AA50 CHAM DIGIT ZERO
- U'\uABF0', // U+ABF0 MEETEI MAYEK DIGIT ZERO
- U'\uFF10', // U+FF10 FULLWIDTH DIGIT ZERO
- U'\U000104A0', // U+104A0 OSMANYA DIGIT ZERO
- U'\U00010D30', // U+10D30 HANIFI ROHINGYA DIGIT ZERO
- U'\U00011066', // U+11066 BRAHMI DIGIT ZERO
- U'\U000110F0', // U+110F0 SORA SOMPENG DIGIT ZERO
- U'\U00011136', // U+11136 CHAKMA DIGIT ZERO
- U'\U000111D0', // U+111D0 SHARADA DIGIT ZERO
- U'\U000112F0', // U+112F0 KHUDAWADI DIGIT ZERO
- U'\U00011450', // U+11450 NEWA DIGIT ZERO
- U'\U000114D0', // U+114D0 TIRHUTA DIGIT ZERO
- U'\U00011650', // U+11650 MODI DIGIT ZERO
- U'\U000116C0', // U+116C0 TAKRI DIGIT ZERO
- U'\U00011730', // U+11730 AHOM DIGIT ZERO
- U'\U000118E0', // U+118E0 WARANG CITI DIGIT ZERO
- U'\U00011950', // U+11950 DIVES AKURU DIGIT ZERO
- U'\U00011C50', // U+11C50 BHAIKSUKI DIGIT ZERO
- U'\U00011D50', // U+11D50 MASARAM GONDI DIGIT ZERO
- U'\U00011DA0', // U+11DA0 GUNJALA GONDI DIGIT ZERO
- U'\U00011F50', // U+11F50 KAWI DIGIT ZERO
- U'\U00016A60', // U+16A60 MRO DIGIT ZERO
- U'\U00016AC0', // U+16AC0 TANGSA DIGIT ZERO
- U'\U00016B50', // U+16B50 PAHAWH HMONG DIGIT ZERO
- U'\U0001D7CE', // U+1D7CE MATHEMATICAL BOLD DIGIT ZERO
- U'\U0001D7D8', // U+1D7D8 MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO
- U'\U0001D7E2', // U+1D7E2 MATHEMATICAL SANS-SERIF DIGIT ZERO
- U'\U0001D7EC', // U+1D7EC MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO
- U'\U0001D7F6', // U+1D7F6 MATHEMATICAL MONOSPACE DIGIT ZERO
- U'\U0001E140', // U+1E140 NYIAKENG PUACHUE HMONG DIGIT ZERO
- U'\U0001E2F0', // U+1E2F0 WANCHO DIGIT ZERO
- U'\U0001E4F0', // U+1E4F0 NAG MUNDARI DIGIT ZERO
- U'\U0001E950', // U+1E950 ADLAM DIGIT ZERO
- U'\U0001FBF0' // U+1FBF0 SEGMENTED DIGIT ZERO
- };
- };
- template<typename Tag>
- struct char_set_parser
- {
- BOOST_PARSER_ALGO_CONSTEXPR char_set_parser()
- {
- auto const & chars = detail::char_set<Tag>::chars;
- auto const first = std::begin(chars);
- auto const last = std::end(chars);
- auto it = std::upper_bound(first, last, 0x100, [](auto x, auto y){
- using common_t = std::common_type_t<decltype(x), decltype(x)>;
- return (common_t)x < (common_t)y;
- });
- if (it != last)
- one_byte_offset_ = int(it - first);
- }
- template<typename T>
- using attribute_type = std::decay_t<T>;
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const -> attribute_type<decltype(*first)>
- {
- attribute_type<decltype(*first)> retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (first == last) {
- success = false;
- return;
- }
- auto const & chars = detail::char_set<Tag>::chars;
- attribute_type<decltype(*first)> const x = *first;
- uint32_t const x_cmp = x;
- if (x_cmp < U'\x0100') {
- uint32_t const * it = std::lower_bound(
- std::begin(chars),
- std::begin(chars) + one_byte_offset_,
- x_cmp);
- if (it != std::end(chars) && *it == x_cmp) {
- detail::assign(retval, x_cmp);
- ++first;
- } else {
- success = false;
- }
- return;
- }
- uint32_t const * it = std::lower_bound(
- std::begin(chars) + one_byte_offset_, std::end(chars), x_cmp);
- if (it != std::end(chars) && *it == x_cmp) {
- detail::assign(retval, x_cmp);
- ++first;
- return;
- }
- success = false;
- }
- int one_byte_offset_ = 0;
- };
- template<typename Tag>
- struct char_subrange_parser
- {
- constexpr char_subrange_parser() {}
- template<typename T>
- using attribute_type = std::decay_t<T>;
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const -> attribute_type<decltype(*first)>
- {
- attribute_type<decltype(*first)> retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (first == last) {
- success = false;
- return;
- }
- attribute_type<decltype(*first)> const x = *first;
- char32_t const x_cmp = x;
- success = false;
- for (auto subrange : detail::char_subranges<Tag>::ranges) {
- if (subrange.lo_ <= x_cmp && x_cmp <= subrange.hi_) {
- success = true;
- detail::assign(retval, x);
- ++first;
- return;
- }
- }
- }
- };
- #endif
- /** The single-character parser. The produced attribute is the type of
- the matched code point (`char` or `char32_t`). Used as-is, `char_`
- matches any code point. `char_` can also be used to create code
- point parsers that match one or more specific code point values, by
- calling it with: a single value comparable to a code point; a closed
- range of code point values `[lo, hi]`, or a set of code point values
- passed as a range. When calling with a range, only the iterators that
- bound the range are stored. Make sure the range you pass outlives the
- use of the resulting parser. Note that a string literal is a range,
- and that it outlives any parser it is used to construct. */
- inline constexpr parser_interface<char_parser<detail::nope>> char_;
- /** The code point parser. It produces a `char32_t` attribute. Used
- as-is, `cp` matches any code point. `cp` can also be used to
- create code point parsers that match one or more specific code point
- values, by calling it with: a single value comparable to a code point;
- a closed range of code point values `[lo, hi]`, or a set of code point
- values passed as a range. When calling with a range, only the
- iterators that bound the range are stored. Make sure the range you
- pass outlives the use of the resulting parser. Note that a string
- literal is a range, and that it outlives any parser it is used to
- construct. */
- inline constexpr parser_interface<char_parser<detail::nope, char32_t>> cp;
- /** The code unit parser. It produces a `char` attribute. Used as-is,
- `cu` matches any code point. `cu` can also can be used to create code
- point parsers that match one or more specific code point values, by
- calling it with: a single value comparable to a code point; a closed
- range of code point values `[lo, hi]`, or a set of code point values
- passed as a range. When calling with a range, only the iterators that
- bound the range are stored. Make sure the range you pass outlives the
- use of the resulting parser. Note that a string literal is a range,
- and that it outlives any parser it is used to construct. */
- inline constexpr parser_interface<char_parser<detail::nope, char>> cu;
- /** Returns a literal code point parser that produces no attribute. */
- inline constexpr auto lit(char c) noexcept { return omit[char_(c)]; }
- #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
- /** Returns a literal code point parser that produces no attribute. */
- inline constexpr auto lit(char8_t c) noexcept { return omit[char_(c)]; }
- #endif
- /** Returns a literal code point parser that produces no attribute. */
- inline constexpr auto lit(char32_t c) noexcept { return omit[char_(c)]; }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename StrIter, typename StrSentinel>
- struct string_parser
- {
- constexpr string_parser() : expected_first_(), expected_last_() {}
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr string_parser(R && r) :
- expected_first_(detail::make_view_begin(r)),
- expected_last_(detail::make_view_end(r))
- {}
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- std::string call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- std::string retval;
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (first == last) {
- success = false;
- return;
- }
- if constexpr (std::is_same_v<
- detail::remove_cv_ref_t<decltype(*first)>,
- char32_t>) {
- auto const cps =
- BOOST_PARSER_SUBRANGE(expected_first_, expected_last_) |
- detail::text::as_utf32;
- auto const mismatch = detail::no_case_aware_string_mismatch(
- first,
- last,
- cps.begin(),
- cps.end(),
- context.no_case_depth_);
- if (mismatch.second != cps.end()) {
- success = false;
- return;
- }
- detail::append(
- retval, first, mismatch.first, detail::gen_attrs(flags));
- first = mismatch.first;
- } else {
- auto const mismatch = detail::no_case_aware_string_mismatch(
- first,
- last,
- expected_first_,
- expected_last_,
- context.no_case_depth_);
- if (mismatch.second != expected_last_) {
- success = false;
- return;
- }
- detail::append(
- retval, first, mismatch.first, detail::gen_attrs(flags));
- first = mismatch.first;
- }
- }
- StrIter expected_first_;
- StrSentinel expected_last_;
- };
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<typename R>
- #endif
- string_parser(R r) -> string_parser<
- decltype(detail::make_view_begin(r)),
- decltype(detail::make_view_end(r))>;
- #endif
- /** Returns a parser that matches `str` that produces the matched string
- as its attribute. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<typename R>
- #endif
- constexpr auto string(R && str) noexcept
- {
- return parser_interface{string_parser(str)};
- }
- template<typename Quotes, typename Escapes, typename CharParser>
- struct quoted_string_parser
- {
- constexpr quoted_string_parser() : chs_(), ch_('"') {}
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr quoted_string_parser(
- R && r,
- parser_interface<CharParser> char_p =
- parser_interface{CharParser()}) :
- chs_((R &&)r), char_p_(char_p), ch_(0)
- {
- BOOST_PARSER_DEBUG_ASSERT(r.begin() != r.end());
- }
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<
- typename R,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr quoted_string_parser(
- R && r,
- Escapes escapes,
- parser_interface<CharParser> char_p =
- parser_interface{CharParser()}) :
- chs_((R &&)r), escapes_(escapes), char_p_(char_p), ch_(0)
- {
- BOOST_PARSER_DEBUG_ASSERT(r.begin() != r.end());
- }
- constexpr quoted_string_parser(
- char32_t cp,
- parser_interface<CharParser> char_p =
- parser_interface{CharParser()}) :
- chs_(), char_p_(char_p), ch_(cp)
- {}
- constexpr quoted_string_parser(
- char32_t cp,
- Escapes escapes,
- parser_interface<CharParser> char_p =
- parser_interface{CharParser()}) :
- chs_(), escapes_(escapes), char_p_(char_p), ch_(cp)
- {}
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- std::string call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- std::string retval;
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (first == last) {
- success = false;
- return;
- }
- auto const prev_first = first;
- auto append = [&retval,
- gen_attrs = detail::gen_attrs(flags)](auto & ctx) {
- detail::move_back(retval, _attr(ctx), gen_attrs);
- };
- auto quote_ch = [&]() {
- if constexpr (detail::is_nope_v<Quotes>) {
- detail::remove_cv_ref_t<decltype(*first)> curr = *first;
- if ((char32_t)curr == ch_)
- ++first;
- else
- success = false;
- return ch_;
- } else {
- detail::remove_cv_ref_t<decltype(*first)> const ch = *first;
- bool found = false;
- if constexpr (std::
- is_same_v<decltype(ch), char32_t const>) {
- auto r = chs_ | detail::text::as_utf32;
- found = detail::text::find(r.begin(), r.end(), ch) !=
- r.end();
- } else {
- found = detail::text::find(
- chs_.begin(), chs_.end(), ch) != chs_.end();
- }
- if (found)
- ++first;
- else
- success = false;
- return ch;
- }
- };
- auto const ch = quote_ch();
- if (!success)
- return;
- decltype(ch) const backslash_and_delim[] = {'\\', ch};
- auto const back_delim = char_(backslash_and_delim);
- auto make_parser = [&]() {
- if constexpr (detail::is_nope_v<Escapes>) {
- return *((lit('\\') >> back_delim) |
- (char_p_ - back_delim))[append] > ch;
- } else {
- return *((lit('\\') >> back_delim)[append] |
- (lit('\\') >> parser_interface(escapes_))[append] |
- (char_p_ - back_delim)[append]) > ch;
- }
- };
- auto const p = make_parser();
- p.parser_.call(
- first,
- last,
- context,
- skip,
- detail::disable_skip(flags),
- success);
- if (!success) {
- retval = Attribute();
- first = prev_first;
- }
- }
- /** Returns a `parser_interface` containing a `quoted_string_parser`
- that uses `x` as its quotation marks. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<typename T, typename Parser = char_parser<detail::nope>>
- requires(!parsable_range_like<T>)
- #else
- template<
- typename T,
- typename Parser = char_parser<detail::nope>,
- typename Enable =
- std::enable_if_t<!detail::is_parsable_range_like_v<T>>>
- #endif
- constexpr auto
- operator()(T x, parser_interface<Parser> char_p = char_) const noexcept
- {
- if constexpr (!detail::is_nope_v<Quotes>) {
- BOOST_PARSER_ASSERT(
- (chs_.empty() && ch_ == '"' &&
- "If you're seeing this, you tried to chain calls on "
- "quoted_string, like 'quoted_string('\"')('\\'')'. Quit "
- "it!'"));
- }
- return parser_interface(
- quoted_string_parser<detail::nope, detail::nope, Parser>(
- std::move(x), char_p));
- }
- /** Returns a `parser_interface` containing a `quoted_string_parser`
- that accepts any of the values in `r` as its quotation marks. If
- the input being matched during the parse is a a sequence of
- `char32_t`, the elements of `r` are transcoded from their presumed
- encoding to UTF-32 during the comparison. Otherwise, the
- character begin matched is directly compared to the elements of
- `r`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range_like R,
- typename Parser = char_parser<detail::nope>>
- #else
- template<
- typename R,
- typename Parser = char_parser<detail::nope>,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator()(
- R && r, parser_interface<Parser> char_p = char_) const noexcept
- {
- BOOST_PARSER_ASSERT(((
- !std::is_rvalue_reference_v<R &&> ||
- !detail::is_range<detail::remove_cv_ref_t<
- R>>)&&"It looks like you tried to pass an rvalue range to "
- "quoted_string(). Don't do that, or you'll end up "
- "with dangling references."));
- if constexpr (!detail::is_nope_v<Quotes>) {
- BOOST_PARSER_ASSERT(
- (chs_.empty() && ch_ == '"' &&
- "If you're seeing this, you tried to chain calls on "
- "quoted_string, like "
- "'quoted_string(char-range)(char-range)'. Quit it!'"));
- }
- return parser_interface(
- quoted_string_parser<
- decltype(BOOST_PARSER_SUBRANGE(
- detail::make_view_begin(r), detail::make_view_end(r))),
- detail::nope,
- Parser>(
- BOOST_PARSER_SUBRANGE(
- detail::make_view_begin(r), detail::make_view_end(r)),
- char_p));
- }
- /** Returns a `parser_interface` containing a `quoted_string_parser`
- that uses `x` as its quotation marks. `symbols` provides a list
- of strings that may appear after a backslash to form an escape
- sequence, and what character(s) each escape sequence represents.
- Note that `"\\"` and `"\ch"` are always valid escape sequences. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- typename T,
- typename U,
- typename Parser = char_parser<detail::nope>>
- requires(!parsable_range_like<T>)
- #else
- template<
- typename T,
- typename U,
- typename Parser = char_parser<detail::nope>,
- typename Enable =
- std::enable_if_t<!detail::is_parsable_range_like_v<T>>>
- #endif
- auto operator()(
- T x,
- symbols<U> const & escapes,
- parser_interface<Parser> char_p = char_) const noexcept
- {
- if constexpr (!detail::is_nope_v<Quotes>) {
- BOOST_PARSER_ASSERT(
- (chs_.empty() && ch_ == '"' &&
- "If you're seeing this, you tried to chain calls on "
- "quoted_string, like 'quoted_string('\"')('\\'')'. Quit "
- "it!'"));
- }
- auto symbols = symbol_parser(escapes.parser_);
- auto parser =
- quoted_string_parser<detail::nope, decltype(symbols), Parser>(
- char32_t(x), symbols, char_p);
- return parser_interface(parser);
- }
- /** Returns a `parser_interface` containing a `quoted_string_parser`
- that accepts any of the values in `r` as its quotation marks. If
- the input being matched during the parse is a a sequence of
- `char32_t`, the elements of `r` are transcoded from their presumed
- encoding to UTF-32 during the comparison. Otherwise, the
- character begin matched is directly compared to the elements of
- `r`. `symbols` provides a list of strings that may appear after a
- backslash to form an escape sequence, and what character(s) each
- escape sequence represents. Note that `"\\"` and `"\ch"` are
- always valid escape sequences. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range_like R,
- typename T,
- typename Parser = char_parser<detail::nope>>
- #else
- template<
- typename R,
- typename T,
- typename Parser = char_parser<detail::nope>,
- typename Enable =
- std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- auto operator()(
- R && r,
- symbols<T> const & escapes,
- parser_interface<Parser> char_p = char_) const noexcept
- {
- BOOST_PARSER_ASSERT(((
- !std::is_rvalue_reference_v<R &&> ||
- !detail::is_range<detail::remove_cv_ref_t<
- R>>)&&"It looks like you tried to pass an rvalue range to "
- "quoted_string(). Don't do that, or you'll end up "
- "with dangling references."));
- if constexpr (!detail::is_nope_v<Quotes>) {
- BOOST_PARSER_ASSERT(
- (chs_.empty() && ch_ == '"' &&
- "If you're seeing this, you tried to chain calls on "
- "quoted_string, like "
- "'quoted_string(char-range)(char-range)'. Quit it!'"));
- }
- auto symbols = symbol_parser(escapes.parser_);
- auto quotes = BOOST_PARSER_SUBRANGE(
- detail::make_view_begin(r), detail::make_view_end(r));
- auto parser = quoted_string_parser<
- decltype(quotes),
- decltype(symbols),
- Parser>(quotes, symbols, char_p);
- return parser_interface(parser);
- }
- Quotes chs_;
- Escapes escapes_;
- parser_interface<CharParser> char_p_;
- char32_t ch_;
- };
- /** Parses a string delimited by quotation marks. This parser can be used
- to create parsers that accept one or more specific quotation mark
- characters. By default, the quotation marks are `'"'`; an alternate
- quotation mark can be specified by calling this parser with a single
- character, or a range of characters. If a range is specified, the
- opening quote must be one of the characters specified, and the closing
- quote must match the opening quote. Quotation marks may appear within
- the string if escaped with a backslash, and a pair of backslashes is
- treated as a single escaped backslash; all other backslashes cause the
- parse to fail, unless a symbol table is in use. A symbol table can be
- provided as a second parameter after the single character or range
- described above. The symbol table is used to recognize escape
- sequences. Each escape sequence is a backslash followed by a value in
- the symbol table. When using a symbol table, any backslash that is
- not followed by another backslash, the opening quote character, or a
- symbol from the symbol table will cause the parse to fail. Skipping
- is disabled during parsing of the entire quoted string, including the
- quotation marks. There is an expectation point before the closing
- quotation mark. Produces a `std::string` attribute. */
- inline constexpr parser_interface<quoted_string_parser<>> quoted_string;
- /** Returns a parser that matches `str` that produces no attribute. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<typename R>
- #endif
- constexpr auto lit(R && str) noexcept
- {
- return omit[parser::string(str)];
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<bool NewlinesOnly, bool NoNewlines>
- struct ws_parser
- {
- constexpr ws_parser() {}
- static_assert(!NewlinesOnly || !NoNewlines);
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- detail::nope call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- detail::nope nope;
- call(first, last, context, skip, flags, success, nope);
- return {};
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- if (first == last) {
- success = false;
- return;
- }
- int const x = *first;
- if constexpr (NewlinesOnly) {
- if (x == 0x000a) { // lf
- ++first;
- return;
- }
- if (x == 0x000d) { // cr
- ++first;
- if (first != last && *first == 0x000a) // lf
- ++first;
- return;
- }
- if (0x000b == x || x == 0x000c || x == 0x0085 || x == 0x2028 ||
- x == 0x2029) {
- ++first;
- return;
- }
- success = false;
- } else if constexpr (NoNewlines) {
- if (x == 0x0020) { // space
- ++first;
- return;
- }
- if (x == 0x0009) { // tab
- ++first;
- return;
- }
- if (x == 0x00a0 || x == 0x1680 ||
- (0x2000 <= x && x <= 0x200a) || x == 0x202F ||
- x == 0x205F || x == 0x3000) {
- ++first;
- return;
- }
- success = false;
- } else {
- if (x == 0x0020 || x == 0x000a) { // space, lf
- ++first;
- return;
- }
- if (x == 0x000d) { // cr
- ++first;
- if (first != last && *first == 0x000a) // lf
- ++first;
- return;
- }
- if (0x0009 <= x && x <= 0x000c) { // tab through cr
- ++first;
- return;
- }
- if (x == 0x0085 || x == 0x00a0 || x == 0x1680 ||
- (0x2000 <= x && x <= 0x200a) || x == 0x2028 ||
- x == 0x2029 || x == 0x202F || x == 0x205F || x == 0x3000) {
- ++first;
- return;
- }
- success = false;
- }
- }
- };
- #endif
- /** The end-of-line parser. This matches "\r\n", or any one of the line
- break code points from the Unicode Line Break Algorithm, described in
- https://unicode.org/reports/tr14. Produces no attribute. */
- inline constexpr parser_interface<ws_parser<true, false>> eol;
- /** The whitespace parser. This matches "\r\n", or any one of the Unicode
- code points with the White_Space property, as defined in
- https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt. Produces
- no attribute. */
- inline constexpr parser_interface<ws_parser<false, false>> ws;
- /** The whitespace parser that does not match end-of-line. This matches
- any one of the Unicode code points with the White_Space property, as
- defined in https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt,
- except for the ones matched by `eol`. Produces no attribute. */
- inline constexpr parser_interface<ws_parser<false, true>> blank;
- /** The decimal digit parser. Matches the full set of Unicode decimal
- digits; in other words, all Unicode code points with the "Nd"
- character property. Note that this covers all Unicode scripts, only a
- few of which are Latin. */
- inline constexpr parser_interface<digit_parser> digit;
- /** The hexadecimal digit parser. Matches the full set of Unicode
- hexadecimal digits (upper or lower case); in other words, all Unicode
- code points with the "Hex_Digit" character property. */
- inline constexpr parser_interface<
- char_subrange_parser<detail::hex_digit_subranges>>
- hex_digit;
- /** The control character parser. Matches the all Unicode code points
- with the "Cc" ("control character") character property. */
- inline constexpr parser_interface<
- char_subrange_parser<detail::control_subranges>>
- control;
- /** The punctuation character parser. Matches the full set of Unicode
- punctuation classes (specifically, "Pc", "Pd", "Pe", "Pf", "Pi", "Ps",
- and "Po"). */
- inline BOOST_PARSER_ALGO_CONSTEXPR
- parser_interface<char_set_parser<detail::punct_chars>>
- punct;
- /** The symbol character parser. Matches the full set of Unicode
- symbol classes (specifically, "Sc", "Sk", "Sm", and "So"). */
- inline BOOST_PARSER_ALGO_CONSTEXPR
- parser_interface<char_set_parser<detail::symb_chars>>
- symb;
- /** The lower case character parser. Matches the full set of Unicode
- lower case code points (class "Ll"). */
- inline BOOST_PARSER_ALGO_CONSTEXPR
- parser_interface<char_set_parser<detail::lower_case_chars>>
- lower;
- /** The lower case character parser. Matches the full set of Unicode
- upper case code points (class "Lu"). */
- inline BOOST_PARSER_ALGO_CONSTEXPR
- parser_interface<char_set_parser<detail::upper_case_chars>>
- upper;
- #ifndef BOOST_PARSER_DOXYGEN
- struct bool_parser
- {
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- bool call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- bool retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- auto compare =
- [no_case = context.no_case_depth_](char32_t a, char32_t b) {
- if (no_case && 0x41 <= b && b < 0x5b)
- b += 0x20;
- return a == b;
- };
- // The lambda quiets a signed/unsigned mismatch warning when
- // comparing the chars here to code points.
- char const t[] = "true";
- if (detail::mismatch(t, t + 4, first, last, compare).first ==
- t + 4) {
- std::advance(first, 4);
- detail::assign(retval, true);
- return;
- }
- char const f[] = "false";
- if (detail::mismatch(f, f + 5, first, last, compare).first ==
- f + 5) {
- std::advance(first, 5);
- detail::assign(retval, false);
- return;
- }
- success = false;
- }
- };
- #endif
- /** The Boolean parser. Parses "true" and "false", producing attributes
- `true` and `false`, respectively, and fails on any other input. */
- inline constexpr parser_interface<bool_parser> bool_;
- #ifndef BOOST_PARSER_DOXYGEN
- template<
- typename T,
- int Radix,
- int MinDigits,
- int MaxDigits,
- typename Expected>
- struct uint_parser
- {
- static_assert(
- Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16,
- "Unsupported radix.");
- static_assert(1 <= MinDigits);
- static_assert(MaxDigits == -1 || MinDigits <= MaxDigits);
- constexpr uint_parser() {}
- explicit constexpr uint_parser(Expected expected) : expected_(expected)
- {}
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- T call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- T retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- T attr = 0;
- auto const initial = first;
- success =
- detail::numeric::parse_int<false, Radix, MinDigits, MaxDigits>(
- first, last, attr);
- if (first == initial || attr != detail::resolve(context, expected_))
- success = false;
- if (success)
- detail::assign(retval, attr);
- }
- /** Returns a `parser_interface` containing a `uint_parser` that
- matches the exact value `expected`. */
- template<typename Expected2>
- constexpr auto operator()(Expected2 expected) const noexcept
- {
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<Expected> &&
- "If you're seeing this, you tried to chain calls on this "
- "parser, like 'uint_(2)(3)'. Quit it!'"));
- using parser_t =
- uint_parser<T, Radix, MinDigits, MaxDigits, Expected2>;
- return parser_interface{parser_t{expected}};
- }
- /** Returns a `uint_parser` identical to `*this`, except that it
- parses digits as base-`Radix2` instead of base-`Radix`. */
- template<int Radix2>
- constexpr auto base() const noexcept
- {
- return uint_parser<T, Radix2, MinDigits, MaxDigits, Expected>{
- expected_};
- }
- /** Returns a `uint_parser` identical to `*this`, except that it only
- accepts numbers exactly `Digits` digits. */
- template<int Digits>
- constexpr auto digits() const noexcept
- {
- return uint_parser<T, Radix, Digits, Digits, Expected>{expected_};
- }
- /** Returns a `uint_parser` identical to `*this`, except that it
- only accepts numbers `D` digits long, where `D` is in
- [`MinDigits2`, MaxDigits2`]. */
- template<int MinDigits2, int MaxDigits2>
- constexpr auto digits() const noexcept
- {
- return uint_parser<T, Radix, MinDigits2, MaxDigits2, Expected>{
- expected_};
- }
- Expected expected_;
- };
- #endif
- /** The binary unsigned integer parser. Produces an `unsigned int`
- attribute. To parse a particular value `x`, use `bin(x)`. */
- inline constexpr parser_interface<uint_parser<unsigned int, 2>> bin;
- /** The octal unsigned integer parser. Produces an `unsigned int`
- attribute. To parse a particular value `x`, use `oct(x)`. */
- inline constexpr parser_interface<uint_parser<unsigned int, 8>> oct;
- /** The hexadecimal unsigned integer parser. Produces an `unsigned int`
- attribute. To parse a particular value `x`, use `hex(x)`. */
- inline constexpr parser_interface<uint_parser<unsigned int, 16>> hex;
- /** The `unsigned short` parser. Produces an `unsigned short` attribute.
- To parse a particular value `x`, use `ushort_(x)`. */
- inline constexpr parser_interface<uint_parser<unsigned short>> ushort_;
- /** The `unsigned int` parser. Produces an `unsigned int` attribute. To
- parse a particular value `x`, use `uint_(x)`. */
- inline constexpr parser_interface<uint_parser<unsigned int>> uint_;
- /** The `unsigned long` parser. Produces an `unsigned long` attribute.
- To parse a particular value `x`, use `ulong_(x)`. */
- inline constexpr parser_interface<uint_parser<unsigned long>> ulong_;
- /** The `unsigned long long` parser. Produces an `unsigned long long`
- attribute. To parse a particular value `x`, use `ulong_long(x)`. */
- inline constexpr parser_interface<uint_parser<unsigned long long>>
- ulong_long;
- #ifndef BOOST_PARSER_DOXYGEN
- template<
- typename T,
- int Radix,
- int MinDigits,
- int MaxDigits,
- typename Expected>
- struct int_parser
- {
- static_assert(
- Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16,
- "Unsupported radix.");
- static_assert(1 <= MinDigits);
- static_assert(MaxDigits == -1 || MinDigits <= MaxDigits);
- constexpr int_parser() {}
- explicit constexpr int_parser(Expected expected) : expected_(expected)
- {}
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- T call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- T retval{};
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- T attr = 0;
- auto const initial = first;
- success =
- detail::numeric::parse_int<true, Radix, MinDigits, MaxDigits>(
- first, last, attr);
- if (first == initial || attr != detail::resolve(context, expected_))
- success = false;
- if (success)
- detail::assign(retval, attr);
- }
- /** Returns a `parser_interface` containing an `int_parser` that
- matches the exact value `expected`. */
- template<typename Expected2>
- constexpr auto operator()(Expected2 expected) const noexcept
- {
- BOOST_PARSER_ASSERT(
- (detail::is_nope_v<Expected> &&
- "If you're seeing this, you tried to chain calls on this "
- "parser, like 'int_(2)(3)'. Quit it!'"));
- using parser_t =
- int_parser<T, Radix, MinDigits, MaxDigits, Expected2>;
- return parser_interface{parser_t{expected}};
- }
- /** Returns an `int_parser` identical to `*this`, except that it
- parses digits as base-`Radix2` instead of base-`Radix`. */
- template<int Radix2>
- constexpr auto base() const noexcept
- {
- return int_parser<T, Radix2, MinDigits, MaxDigits, Expected>{
- expected_};
- }
- /** Returns an `int_parser` identical to `*this`, except that it only
- accepts numbers exactly `Digits` digits. */
- template<int Digits>
- constexpr auto digits() const noexcept
- {
- return int_parser<T, Radix, Digits, Digits, Expected>{expected_};
- }
- /** Returns an `int_parser` identical to `*this`, except that it
- only accepts numbers `D` digits long, where `D` is in
- [`MinDigits2`, MaxDigits2`]. */
- template<int MinDigits2, int MaxDigits2>
- constexpr auto digits() const noexcept
- {
- return int_parser<T, Radix, MinDigits2, MaxDigits2, Expected>{
- expected_};
- }
- Expected expected_;
- };
- #endif
- /** The `short` parser. Produces a `short` attribute. To parse a
- particular value `x`, use `short_(x)`. */
- inline constexpr parser_interface<int_parser<short>> short_;
- /** The `int` parser. Produces an `int` attribute. To parse a particular
- value `x`, use `int_(x)`. */
- inline constexpr parser_interface<int_parser<int>> int_;
- /** The `long` parser. Produces a `long` attribute. To parse a particular
- value `x`, use `long_(x)`. */
- inline constexpr parser_interface<int_parser<long>> long_;
- /** The `long long` parser. Produces a `long long` attribute. To parse a
- particular value `x`, use `long_long(x)`. */
- inline constexpr parser_interface<int_parser<long long>> long_long;
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename T>
- struct float_parser
- {
- constexpr float_parser() {}
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- T call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- T retval = 0;
- call(first, last, context, skip, flags, success, retval);
- return retval;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- T attr = 0;
- auto const initial = first;
- success = detail::numeric::parse_real(first, last, attr);
- if (first == initial)
- success = false;
- if (success)
- detail::assign(retval, attr);
- }
- };
- #endif
- /** The `float` parser. Produces a `float` attribute. */
- inline constexpr parser_interface<float_parser<float>> float_;
- /** The `double` parser. Produces a `double` attribute. */
- inline constexpr parser_interface<float_parser<double>> double_;
- /** Represents a sequence parser, the first parser of which is an
- `epsilon_parser` with predicate, as a directive
- (e.g. `if_(pred)[p]`). */
- template<typename Predicate>
- struct if_directive
- {
- template<typename Parser2>
- constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
- {
- return eps(pred_) >> rhs;
- }
- Predicate pred_;
- };
- /** Returns an `if_directive` that fails if the given predicate `pred` is
- `false`, and otherwise, applies another parser. For instance, in
- `if_(pred)[p]`, `p` is only applied if `pred` is true. */
- template<typename Predicate>
- constexpr auto if_(Predicate pred) noexcept
- {
- return if_directive<Predicate>{pred};
- }
- namespace detail {
- template<typename SwitchValue, typename Value>
- struct switch_parser_equal
- {
- template<typename Context>
- bool operator()(Context & context) const
- {
- auto const switch_value =
- detail::resolve(context, switch_value_);
- auto const value = detail::resolve(context, value_);
- return value == switch_value;
- }
- SwitchValue switch_value_;
- Value value_;
- };
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename SwitchValue, typename OrParser>
- struct switch_parser
- {
- switch_parser() {}
- switch_parser(SwitchValue switch_value) : switch_value_(switch_value) {}
- switch_parser(SwitchValue switch_value, OrParser or_parser) :
- switch_value_(switch_value), or_parser_(or_parser)
- {}
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser>
- auto call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success) const
- {
- BOOST_PARSER_ASSERT(
- (!detail::is_nope_v<OrParser> &&
- "It looks like you tried to write switch_(val). You need at "
- "least one alternative, like: switch_(val)(value_1, "
- "parser_1)(value_2, parser_2)..."));
- using attr_t = decltype(or_parser_.call(
- first, last, context, skip, flags, success));
- attr_t attr{};
- [[maybe_unused]] auto _ =
- detail::scoped_trace(*this, first, last, context, flags, attr);
- attr = or_parser_.call(first, last, context, skip, flags, success);
- return attr;
- }
- template<
- typename Iter,
- typename Sentinel,
- typename Context,
- typename SkipParser,
- typename Attribute>
- void call(
- Iter & first,
- Sentinel last,
- Context const & context,
- SkipParser const & skip,
- detail::flags flags,
- bool & success,
- Attribute & retval) const
- {
- BOOST_PARSER_ASSERT(
- (!detail::is_nope_v<OrParser> &&
- "It looks like you tried to write switch_(val). You need at "
- "least one alternative, like: switch_(val)(value_1, "
- "parser_1)(value_2, parser_2)..."));
- [[maybe_unused]] auto _ = detail::scoped_trace(
- *this, first, last, context, flags, retval);
- or_parser_.call(first, last, context, skip, flags, success, retval);
- }
- /** Returns a `parser_interface` containing a `switch_parser`, with
- the case `value_`,`rhs` appended to its `or_parser_`. */
- template<typename Value, typename Parser2>
- constexpr auto
- operator()(Value value_, parser_interface<Parser2> rhs) const noexcept
- {
- auto const match = detail::switch_parser_equal<SwitchValue, Value>{
- switch_value_, value_};
- auto or_parser = make_or_parser(or_parser_, eps(match) >> rhs);
- using switch_parser_type =
- switch_parser<SwitchValue, decltype(or_parser)>;
- return parser_interface{
- switch_parser_type{switch_value_, or_parser}};
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser1, typename Parser2>
- static constexpr auto
- make_or_parser(Parser1 parser1, parser_interface<Parser2> parser2)
- {
- return (parser_interface{parser1} | parser2).parser_;
- }
- template<typename Parser>
- static constexpr auto
- make_or_parser(detail::nope, parser_interface<Parser> parser)
- {
- return parser.parser_;
- }
- #endif
- SwitchValue switch_value_;
- OrParser or_parser_;
- };
- #endif
- /** Returns a `switch`-like parser. The resulting parser uses the given
- value `x` to select one of the following value/parser pairs, and to
- apply the selected parser. `x` may be a value to be used directly, or
- a unary invocable that takes a reference to the parse context, and
- returns the value to use. You can add more value/parser cases to the
- returned parser, using its call operator, e.g. `switch_(x)(y1, p1)(y2,
- p2)`. As with the `x` passed to this function, each `yN` value can be
- a value or a unary invocable. */
- template<typename T>
- constexpr auto switch_(T x) noexcept
- {
- return switch_parser<T>{x};
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator>>(
- char rhs) const noexcept
- {
- return *this >> parser::lit(rhs);
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator>>(
- char32_t rhs) const noexcept
- {
- return *this >> parser::lit(rhs);
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<typename R, typename>
- #endif
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator>>(
- R && r) const noexcept
- {
- return *this >> parser::lit(r);
- }
- #endif
- /** Returns a parser equivalent to `lit(c) >> rhs`. */
- template<typename Parser>
- constexpr auto operator>>(char c, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_seq_p<Parser>{}) {
- return rhs.parser_.template prepend<true>(parser::lit(c));
- } else {
- return parser::lit(c) >> rhs;
- }
- }
- /** Returns a parser equivalent to `lit(c) >> rhs`. */
- template<typename Parser>
- constexpr auto operator>>(char32_t c, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_seq_p<Parser>{}) {
- return rhs.parser_.template prepend<true>(parser::lit(c));
- } else {
- return parser::lit(c) >> rhs;
- }
- }
- /** Returns a parser equivalent to `lit(str) >> rhs`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R, typename Parser>
- #else
- template<
- typename R,
- typename Parser,
- typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator>>(R && r, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_seq_p<Parser>{}) {
- return rhs.parser_.template prepend<true>(parser::lit(r));
- } else {
- return parser::lit(r) >> rhs;
- }
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator>(
- char rhs) const noexcept
- {
- return *this > parser::lit(rhs);
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator>(
- char32_t rhs) const noexcept
- {
- return *this > parser::lit(rhs);
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<typename R, typename>
- #endif
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator>(
- R && r) const noexcept
- {
- return *this > parser::lit(r);
- }
- #endif
- /** Returns a parser equivalent to `lit(c) > rhs`. */
- template<typename Parser>
- constexpr auto operator>(char c, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_seq_p<Parser>{}) {
- return rhs.parser_.template prepend<false>(parser::lit(c));
- } else {
- return parser::lit(c) > rhs;
- }
- }
- /** Returns a parser equivalent to `lit(c) > rhs`. */
- template<typename Parser>
- constexpr auto operator>(char32_t c, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_seq_p<Parser>{}) {
- return rhs.parser_.template prepend<false>(parser::lit(c));
- } else {
- return parser::lit(c) > rhs;
- }
- }
- /** Returns a parser equivalent to `lit(str) > rhs`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R, typename Parser>
- #else
- template<
- typename R,
- typename Parser,
- typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator>(R && r, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_seq_p<Parser>{}) {
- return rhs.parser_.template prepend<false>(parser::lit(r));
- } else {
- return parser::lit(r) > rhs;
- }
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator|(
- char rhs) const noexcept
- {
- return *this | parser::lit(rhs);
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator|(
- char32_t rhs) const noexcept
- {
- return *this | parser::lit(rhs);
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<typename R, typename>
- #endif
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator|(
- R && r) const noexcept
- {
- return *this | parser::lit(r);
- }
- #endif
- /** Returns a parser equivalent to `lit(c) | rhs`. */
- template<typename Parser>
- constexpr auto operator|(char c, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_or_p<Parser>{}) {
- return rhs.parser_.prepend(parser::lit(c));
- } else {
- return parser::lit(c) | rhs;
- }
- }
- /** Returns a parser equivalent to `lit(c) | rhs`. */
- template<typename Parser>
- constexpr auto operator|(char32_t c, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_or_p<Parser>{}) {
- return rhs.parser_.prepend(parser::lit(c));
- } else {
- return parser::lit(c) | rhs;
- }
- }
- /** Returns a parser equivalent to `lit(str) | rhs`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R, typename Parser>
- #else
- template<
- typename R,
- typename Parser,
- typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator|(R && r, parser_interface<Parser> rhs) noexcept
- {
- if constexpr (detail::is_or_p<Parser>{}) {
- return rhs.parser_.prepend(parser::lit(r));
- } else {
- return parser::lit(r) | rhs;
- }
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator-(
- char rhs) const noexcept
- {
- return !parser::lit(rhs) >> *this;
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator-(
- char32_t rhs) const noexcept
- {
- return !parser::lit(rhs) >> *this;
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<typename R, typename>
- #endif
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator-(
- R && r) const noexcept
- {
- return !parser::lit(r) >> *this;
- }
- #endif
- /** Returns a parser equivalent to `!rhs >> lit(c)`. */
- template<typename Parser>
- constexpr auto operator-(char c, parser_interface<Parser> rhs) noexcept
- {
- return !rhs >> parser::lit(c);
- }
- /** Returns a parser equivalent to `!rhs >> lit(c)`. */
- template<typename Parser>
- constexpr auto operator-(char32_t c, parser_interface<Parser> rhs) noexcept
- {
- return !rhs >> parser::lit(c);
- }
- /** Returns a parser equivalent to `!rhs >> lit(str)`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R, typename Parser>
- #else
- template<
- typename R,
- typename Parser,
- typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator-(R && r, parser_interface<Parser> rhs) noexcept
- {
- return !rhs >> parser::lit(r);
- }
- #ifndef BOOST_PARSER_DOXYGEN
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator%(
- char rhs) const noexcept
- {
- return *this % parser::lit(rhs);
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator%(
- char32_t rhs) const noexcept
- {
- return *this % parser::lit(rhs);
- }
- template<typename Parser, typename GlobalState, typename ErrorHandler>
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R>
- #else
- template<typename R, typename>
- #endif
- constexpr auto
- parser_interface<Parser, GlobalState, ErrorHandler>::operator%(
- R && r) const noexcept
- {
- return *this % parser::lit(r);
- }
- #endif
- /** Returns a parser equivalent to `lit(c) % rhs`. */
- template<typename Parser>
- constexpr auto operator%(char c, parser_interface<Parser> rhs) noexcept
- {
- return parser::lit(c) % rhs;
- }
- /** Returns a parser equivalent to `lit(c) % rhs`. */
- template<typename Parser>
- constexpr auto operator%(char32_t c, parser_interface<Parser> rhs) noexcept
- {
- return parser::lit(c) % rhs;
- }
- /** Returns a parser equivalent to `lit(str) % rhs`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<parsable_range_like R, typename Parser>
- #else
- template<
- typename R,
- typename Parser,
- typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
- #endif
- constexpr auto operator%(R && r, parser_interface<Parser> rhs) noexcept
- {
- return parser::lit(r) % rhs;
- }
- }}
- #include <boost/parser/detail/printing_impl.hpp>
- namespace boost { namespace parser {
- /** An enumeration used for parameters to enable and disable trace in the
- `*parse()` functions. */
- enum class trace { off, on };
- // Parse API.
- /** Parses `[first, last)` using `parser`, and returns whether the parse
- was successful. On success, `attr` will be assigned the value of the
- attribute produced by `parser`. If `trace_mode == trace::on`, a
- verbose trace of the parse will be streamed to `std::cout`.
- \tparam Attr Constrained by
- `!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_iter I,
- std::sentinel_for<I> S,
- typename Parser,
- typename GlobalState,
- error_handler<I, S, GlobalState> ErrorHandler,
- typename Attr>
- #else
- template<
- typename I,
- typename S,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename Attr,
- typename Enable = std::enable_if_t<
- detail::is_parsable_iter_v<I> &&
- detail::is_equality_comparable_with_v<I, S> &&
- !detail::derived_from_parser_interface_v<
- detail::remove_cv_ref_t<Attr>>>>
- #endif
- bool prefix_parse(
- I & first,
- S last,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- Attr & attr,
- trace trace_mode = trace::off)
- #if BOOST_PARSER_USE_CONCEPTS
- requires(
- !detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>>)
- #endif
- {
- detail::attr_reset reset(attr);
- if constexpr (!detail::is_char8_iter_v<I>) {
- static_assert(
- decltype(detail::has_attribute(first, last, parser)){},
- "If you're seeing this error, you're trying to get parse() to "
- "fill in attr above, using the attribute generated by parser. "
- "However, parser does not generate an attribute.");
- if (trace_mode == trace::on) {
- return reset = detail::parse_impl<true>(
- first, last, parser, parser.error_handler_, attr);
- } else {
- return reset = detail::parse_impl<false>(
- first, last, parser, parser.error_handler_, attr);
- }
- } else {
- auto r =
- BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
- auto f = r.begin();
- auto const l = r.end();
- auto _ = detail::scoped_base_assign(first, f);
- static_assert(
- decltype(detail::has_attribute(f, l, parser)){},
- "If you're seeing this error, you're trying to get parse() to "
- "fill in attr above, using the attribute generated by parser. "
- "However, parser does not generate an attribute.");
- if (trace_mode == trace::on) {
- return reset = detail::parse_impl<true>(
- f, l, parser, parser.error_handler_, attr);
- } else {
- return reset = detail::parse_impl<false>(
- f, l, parser, parser.error_handler_, attr);
- }
- }
- }
- /** Parses `r` using `parser`, and returns whether the parse was
- successful. The entire input range `r` must be consumed for the parse
- to be considered successful. On success, `attr` will be assigned the
- value of the attribute produced by `parser`. If `trace_mode ==
- trace::on`, a verbose trace of the parse will be streamed to
- `std::cout`.
- \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
- where `subrange_of` is an implementation detail that: creates
- subranges out of pointers; trims trailing zeros off of bounded
- arrays (such as string literals); and transcodes to UTF-32 if the
- input is non-`char`.
- \tparam Attr Constrained by
- `!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename Attr>
- #else
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename Attr,
- typename Enable = std::enable_if_t<
- detail::is_parsable_range_v<R> &&
- !detail::derived_from_parser_interface_v<
- detail::remove_cv_ref_t<Attr>>>>
- #endif
- bool parse(
- R const & r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- Attr & attr,
- trace trace_mode = trace::off)
- #if BOOST_PARSER_USE_CONCEPTS
- // clang-format off
- requires error_handler<
- ErrorHandler,
- std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
- std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
- GlobalState> &&
- (!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>>)
- // clang-format on
- #endif
- {
- detail::attr_reset reset(attr);
- auto r_ = detail::make_input_subrange(r);
- auto first = r_.begin();
- auto const last = r_.end();
- auto const initial_first = first;
- return reset = detail::if_full_parse(
- initial_first,
- first,
- last,
- parser.error_handler_,
- parser::prefix_parse(first, last, parser, attr, trace_mode));
- }
- /** Parses `[first, last)` using `parser`. Returns a `std::optional`
- containing the attribute produced by `parser` on parse success, and
- `std::nullopt` on parse failure. If `trace_mode == trace::on`, a
- verbose trace of the parse will be streamed to `std::cout`.
- \tparam Attr Constrained by
- `!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_iter I,
- std::sentinel_for<I> S,
- typename Parser,
- typename GlobalState,
- error_handler<I, S, GlobalState> ErrorHandler>
- #else
- template<
- typename I,
- typename S,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename Enable = std::enable_if_t<
- detail::is_parsable_iter_v<I> &&
- detail::is_equality_comparable_with_v<I, S>>>
- #endif
- auto prefix_parse(
- I & first,
- S last,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- trace trace_mode = trace::off)
- {
- if constexpr (!detail::is_char8_iter_v<I>) {
- if (trace_mode == trace::on) {
- return detail::parse_impl<true>(
- first, last, parser, parser.error_handler_);
- } else {
- return detail::parse_impl<false>(
- first, last, parser, parser.error_handler_);
- }
- } else {
- auto r =
- BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
- auto f = r.begin();
- auto const l = r.end();
- auto _ = detail::scoped_base_assign(first, f);
- if (trace_mode == trace::on) {
- return detail::parse_impl<true>(
- f, l, parser, parser.error_handler_);
- } else {
- return detail::parse_impl<false>(
- f, l, parser, parser.error_handler_);
- }
- }
- }
- /** Parses `r` using `parser`. Returns a `std::optional` containing the
- attribute produced by `parser` on parse success, and `std::nullopt` on
- parse failure. The entire input range `r` must be consumed for the
- parse to be considered successful. If `trace_mode == trace::on`, a
- verbose trace of the parse will be streamed to `std::cout`.
- \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
- where `subrange_of` is an implementation detail that: creates
- subranges out of pointers; trims trailing zeros off of bounded
- arrays (such as string literals); and transcodes to UTF-32 if the
- input is non-`char`.
- \tparam Attr Constrained by
- `!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler>
- #else
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
- #endif
- auto parse(
- R const & r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- trace trace_mode = trace::off)
- #if BOOST_PARSER_USE_CONCEPTS
- // clang-format off
- requires error_handler<
- ErrorHandler,
- std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
- std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
- GlobalState>
- // clang-format on
- #endif
- {
- auto r_ = detail::make_input_subrange(r);
- auto first = r_.begin();
- auto const last = r_.end();
- auto const initial_first = first;
- return detail::if_full_parse(
- initial_first,
- first,
- last,
- parser.error_handler_,
- parser::prefix_parse(first, last, parser, trace_mode));
- }
- /** Parses `[first, last)` using `parser`, skipping all input recognized
- by `skip` between the application of any two parsers, and returns
- whether the parse was successful. On success, `attr` will be assigned
- the value of the attribute produced by `parser`. If `trace_mode ==
- trace::on`, a verbose trace of the parse will be streamed to
- `std::cout`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_iter I,
- std::sentinel_for<I> S,
- typename Parser,
- typename GlobalState,
- error_handler<I, S, GlobalState> ErrorHandler,
- typename SkipParser,
- typename Attr>
- #else
- template<
- typename I,
- typename S,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser,
- typename Attr,
- typename Enable = std::enable_if_t<
- detail::is_parsable_iter_v<I> &&
- detail::is_equality_comparable_with_v<I, S>>>
- #endif
- bool prefix_parse(
- I & first,
- S last,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- Attr & attr,
- trace trace_mode = trace::off)
- {
- detail::attr_reset reset(attr);
- if constexpr (!detail::is_char8_iter_v<I>) {
- static_assert(
- decltype(detail::has_attribute(first, last, parser)){},
- "If you're seeing this error, you're trying to get parse() to "
- "fill in attr above, using the attribute generated by parser. "
- "However, parser does not generate an attribute.");
- if (trace_mode == trace::on) {
- return reset = detail::skip_parse_impl<true>(
- first,
- last,
- parser,
- skip,
- parser.error_handler_,
- attr);
- } else {
- return reset = detail::skip_parse_impl<false>(
- first,
- last,
- parser,
- skip,
- parser.error_handler_,
- attr);
- }
- } else {
- auto r =
- BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
- auto f = r.begin();
- auto const l = r.end();
- auto _ = detail::scoped_base_assign(first, f);
- static_assert(
- decltype(detail::has_attribute(f, l, parser)){},
- "If you're seeing this error, you're trying to get parse() to "
- "fill in attr above, using the attribute generated by parser. "
- "However, parser does not generate an attribute.");
- if (trace_mode == trace::on) {
- return reset = detail::skip_parse_impl<true>(
- f, l, parser, skip, parser.error_handler_, attr);
- } else {
- return reset = detail::skip_parse_impl<false>(
- f, l, parser, skip, parser.error_handler_, attr);
- }
- }
- }
- /** Parses `r` using `parser`, skipping all input recognized by `skip`
- between the application of any two parsers, and returns whether the
- parse was successful. The entire input range `r` must be consumed for
- the parse to be considered successful. On success, `attr` will be
- assigned the value of the attribute produced by `parser`. If
- `trace_mode == trace::on`, a verbose trace of the parse will be
- streamed to `std::cout`.
- \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
- where `subrange_of` is an implementation detail that: creates
- subranges out of pointers; trims trailing zeros off of bounded
- arrays (such as string literals); and transcodes to UTF-32 if the
- input is non-`char`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser,
- typename Attr>
- #else
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser,
- typename Attr,
- typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
- #endif
- bool parse(
- R const & r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- Attr & attr,
- trace trace_mode = trace::off)
- #if BOOST_PARSER_USE_CONCEPTS
- // clang-format off
- requires error_handler<
- ErrorHandler,
- std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
- std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
- GlobalState>
- // clang-format on
- #endif
- {
- detail::attr_reset reset(attr);
- auto r_ = detail::make_input_subrange(r);
- auto first = r_.begin();
- auto const last = r_.end();
- auto const initial_first = first;
- return reset = detail::if_full_parse(
- initial_first,
- first,
- last,
- parser.error_handler_,
- parser::prefix_parse(
- first, last, parser, skip, attr, trace_mode));
- }
- /** Parses `[first, last)` using `parser`, skipping all input recognized
- by `skip` between the application of any two parsers. Returns a
- `std::optional` containing the attribute produced by `parser` on parse
- success, and `std::nullopt` on parse failure. If `trace_mode ==
- trace::on`, a verbose trace of the parse will be streamed to
- `std::cout`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_iter I,
- std::sentinel_for<I> S,
- typename Parser,
- typename GlobalState,
- error_handler<I, S, GlobalState> ErrorHandler,
- typename SkipParser>
- #else
- template<
- typename I,
- typename S,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser,
- typename Enable = std::enable_if_t<
- detail::is_parsable_iter_v<I> &&
- detail::is_equality_comparable_with_v<I, S>>>
- #endif
- auto prefix_parse(
- I & first,
- S last,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode = trace::off)
- {
- if constexpr (!detail::is_char8_iter_v<I>) {
- if (trace_mode == trace::on) {
- return detail::skip_parse_impl<true>(
- first, last, parser, skip, parser.error_handler_);
- } else {
- return detail::skip_parse_impl<false>(
- first, last, parser, skip, parser.error_handler_);
- }
- } else {
- auto r =
- BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
- auto f = r.begin();
- auto const l = r.end();
- auto _ = detail::scoped_base_assign(first, f);
- if (trace_mode == trace::on) {
- return detail::skip_parse_impl<true>(
- f, l, parser, skip, parser.error_handler_);
- } else {
- return detail::skip_parse_impl<false>(
- f, l, parser, skip, parser.error_handler_);
- }
- }
- }
- /** Parses `r` using `parser`, skipping all input recognized by `skip`
- between the application of any two parsers. Returns a `std::optional`
- containing the attribute produced by `parser` on parse success, and
- `std::nullopt` on parse failure. The entire input range `r` must be
- consumed for the parse to be considered successful. If `trace_mode ==
- trace::on`, a verbose trace of the parse will be streamed to
- `std::cout`.
- \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
- where `subrange_of` is an implementation detail that: creates
- subranges out of pointers; trims trailing zeros off of bounded
- arrays (such as string literals); and transcodes to UTF-32 if the
- input is non-`char`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- #else
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser,
- typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
- #endif
- auto parse(
- R const & r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode = trace::off)
- #if BOOST_PARSER_USE_CONCEPTS
- // clang-format off
- requires error_handler<
- ErrorHandler,
- std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
- std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
- GlobalState>
- // clang-format on
- #endif
- {
- auto r_ = detail::make_input_subrange(r);
- auto first = r_.begin();
- auto const last = r_.end();
- auto const initial_first = first;
- return detail::if_full_parse(
- initial_first,
- first,
- last,
- parser.error_handler_,
- parser::prefix_parse(first, last, parser, skip, trace_mode));
- }
- /** Parses `[first, last)` using `parser`, and returns whether the parse
- was successful. When a callback rule `r` is successful during the
- parse, one of two things happens: 1) if `r` has an attribute,
- `callbacks(tag, x)` will be called (where `tag` is
- `decltype(r)::tag_type{}`, and `x` is the attribute produced by `r`);
- or 2) if `r` has no attribute, `callbacks(tag)` will be called.
- `Callbacks` is expected to be an invocable with the correct overloads
- required to support all successful rule parses that might occur. If
- `trace_mode == trace::on`, a verbose trace of the parse will be
- streamed to `std::cout`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_iter I,
- std::sentinel_for<I> S,
- typename Parser,
- typename GlobalState,
- error_handler<I, S, GlobalState> ErrorHandler,
- typename Callbacks>
- #else
- template<
- typename I,
- typename S,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename Callbacks,
- typename Enable = std::enable_if_t<
- detail::is_parsable_iter_v<I> &&
- detail::is_equality_comparable_with_v<I, S>>>
- #endif
- bool callback_prefix_parse(
- I & first,
- S last,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- Callbacks const & callbacks,
- trace trace_mode = trace::off)
- {
- if constexpr (!detail::is_char8_iter_v<I>) {
- if (trace_mode == trace::on) {
- return detail::callback_parse_impl<true>(
- first, last, parser, parser.error_handler_, callbacks);
- } else {
- return detail::callback_parse_impl<false>(
- first, last, parser, parser.error_handler_, callbacks);
- }
- } else {
- auto r =
- BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
- auto f = r.begin();
- auto const l = r.end();
- auto _ = detail::scoped_base_assign(first, f);
- if (trace_mode == trace::on) {
- return detail::callback_parse_impl<true>(
- f, l, parser, parser.error_handler_, callbacks);
- } else {
- return detail::callback_parse_impl<false>(
- f, l, parser, parser.error_handler_, callbacks);
- }
- }
- }
- /** Parses `r` using `parser`, and returns whether the parse was
- successful. The entire input range `r` must be consumed for the parse
- to be considered successful. When a callback rule `r` is successful
- during the parse, one of two things happens: 1) if `r` has an
- attribute, `callbacks(tag, x)` will be called (where `tag` is
- `decltype(r)::tag_type{}`, and `x` is the attribute produced by `r`);
- or 2) if `r` has no attribute, `callbacks(tag)` will be called.
- `Callbacks` is expected to be an invocable with the correct overloads
- required to support all successful rule parses that might occur. If
- `trace_mode == trace::on`, a verbose trace of the parse will be
- streamed to `std::cout`.
- \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
- where `subrange_of` is an implementation detail that: creates
- subranges out of pointers; trims trailing zeros off of bounded
- arrays (such as string literals); and transcodes to UTF-32 if the
- input is non-`char`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename Callbacks>
- #else
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename Callbacks,
- typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
- #endif
- bool callback_parse(
- R const & r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- Callbacks const & callbacks,
- trace trace_mode = trace::off)
- #if BOOST_PARSER_USE_CONCEPTS
- // clang-format off
- requires error_handler<
- ErrorHandler,
- std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
- std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
- GlobalState>
- // clang-format on
- #endif
- {
- auto r_ = detail::make_input_subrange(r);
- auto first = r_.begin();
- auto const last = r_.end();
- auto const initial_first = first;
- return detail::if_full_parse(
- initial_first,
- first,
- last,
- parser.error_handler_,
- parser::callback_prefix_parse(first, last, parser, callbacks));
- }
- /** Parses `[first, last)` using `parser`, skipping all input recognized
- by `skip` between the application of any two parsers, and returns
- whether the parse was successful. When a callback rule `r` is
- successful during the parse, one of two things happens: 1) if `r` has
- an attribute, `callbacks(tag, x)` will be called (where `tag` is
- `decltype(r)::tag_type{}`, and `x` is the attribute produced by `r`);
- or 2) if `r` has no attribute, `callbacks(tag)` will be called.
- `Callbacks` is expected to be an invocable with the correct overloads
- required to support all successful rule parses that might occur. If
- `trace_mode == trace::on`, a verbose trace of the parse will be
- streamed to `std::cout`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_iter I,
- std::sentinel_for<I> S,
- typename Parser,
- typename GlobalState,
- error_handler<I, S, GlobalState> ErrorHandler,
- typename SkipParser,
- typename Callbacks>
- #else
- template<
- typename I,
- typename S,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser,
- typename Callbacks,
- typename Enable = std::enable_if_t<
- detail::is_parsable_iter_v<I> &&
- detail::is_equality_comparable_with_v<I, S>>>
- #endif
- bool callback_prefix_parse(
- I & first,
- S last,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- Callbacks const & callbacks,
- trace trace_mode = trace::off)
- {
- if constexpr (!detail::is_char8_iter_v<I>) {
- if (trace_mode == trace::on) {
- return detail::callback_skip_parse_impl<true>(
- first,
- last,
- parser,
- skip,
- parser.error_handler_,
- callbacks);
- } else {
- return detail::callback_skip_parse_impl<false>(
- first,
- last,
- parser,
- skip,
- parser.error_handler_,
- callbacks);
- }
- } else {
- auto r =
- BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
- auto f = r.begin();
- auto const l = r.end();
- auto _ = detail::scoped_base_assign(first, f);
- if (trace_mode == trace::on) {
- return detail::callback_skip_parse_impl<true>(
- f, l, parser, skip, parser.error_handler_, callbacks);
- } else {
- return detail::callback_skip_parse_impl<false>(
- f, l, parser, skip, parser.error_handler_, callbacks);
- }
- }
- }
- /** Parses `r` using `parser`, skipping all input recognized by `skip`
- between the application of any two parsers, and returns whether the
- parse was successful. The entire input range `r` must be consumed for
- the parse to be considered successful. When a callback rule `r` is
- successful during the parse, one of two things happens: 1) if `r` has
- an attribute, `callbacks(tag, x)` will be called (where `tag` is
- `decltype(r)::tag_type{}`, and `x` is the attribute produced by `r`);
- or 2) if `r` has no attribute, `callbacks(tag)` will be called.
- `Callbacks` is expected to be an invocable with the correct overloads
- required to support all successful rule parses that might occur. If
- `trace_mode == trace::on`, a verbose trace of the parse will be
- streamed to `std::cout`.
- \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
- where `subrange_of` is an implementation detail that: creates
- subranges out of pointers; trims trailing zeros off of bounded
- arrays (such as string literals); and transcodes to UTF-32 if the
- input is non-`char`. */
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser,
- typename Callbacks>
- #else
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser,
- typename Callbacks,
- typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
- #endif
- bool callback_parse(
- R const & r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- Callbacks const & callbacks,
- trace trace_mode = trace::off)
- #if BOOST_PARSER_USE_CONCEPTS
- // clang-format off
- requires error_handler<
- ErrorHandler,
- std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
- std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
- GlobalState>
- // clang-format on
- #endif
- {
- auto r_ = detail::make_input_subrange(r);
- auto first = r_.begin();
- auto const last = r_.end();
- auto const initial_first = first;
- return detail::if_full_parse(
- initial_first,
- first,
- last,
- parser.error_handler_,
- parser::callback_prefix_parse(
- first, last, parser, skip, callbacks, trace_mode));
- }
- namespace literals {
- /** Returns a literal parser equivalent to `lit(c)`. */
- constexpr auto operator""_l(char c) { return parser::lit(c); }
- #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
- /** Returns a literal parser equivalent to `lit(c)`. */
- constexpr auto operator""_l(char8_t c) { return parser::lit(c); }
- #endif
- /** Returns a literal parser equivalent to `lit(c)`. */
- constexpr auto operator""_l(char32_t c) { return parser::lit(c); }
- /** Returns a literal parser equivalent to `lit(str)`. */
- constexpr auto operator""_l(char const * str, std::size_t)
- {
- return parser::lit(str);
- }
- #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
- /** Returns a literal parser equivalent to `lit(str)`. */
- constexpr auto operator""_l(char8_t const * str, std::size_t)
- {
- return parser::lit(str);
- }
- #endif
- /** Returns a literal parser equivalent to `lit(str)`. */
- constexpr auto operator""_l(char32_t const * str, std::size_t)
- {
- return parser::lit(str);
- }
- /** Returns a character parser equivalent to `char_(c)`. */
- constexpr auto operator""_p(char c) { return char_(c); }
- #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
- /** Returns a character parser equivalent to `char_(c)`. */
- constexpr auto operator""_p(char8_t c) { return char_(c); }
- #endif
- /** Returns a character parser equivalent to `char_(c)`. */
- constexpr auto operator""_p(char32_t c) { return char_(c); }
- /** Returns a string parser equivalent to `string(str)`. */
- constexpr auto operator""_p(char const * str, std::size_t)
- {
- return parser::string(str);
- }
- #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
- /** Returns a string parser equivalent to `string(str)`. */
- constexpr auto operator""_p(char8_t const * str, std::size_t)
- {
- return parser::string(str);
- }
- #endif
- /** Returns a string parser equivalent to `string(str)`. */
- constexpr auto operator""_p(char32_t const * str, std::size_t)
- {
- return parser::string(str);
- }
- }
- namespace detail {
- template<typename R, typename Parser, typename SkipParser>
- struct attribute_impl
- {
- using parser_type = typename Parser::parser_type;
- using global_state_type = typename Parser::global_state_type;
- using error_handler_type = typename Parser::error_handler_type;
- using iterator = detail::iterator_t<R>;
- using sentinel = detail::sentinel_t<R>;
- using context = decltype(detail::make_context<false, false>(
- std::declval<iterator>(),
- std::declval<sentinel>(),
- std::declval<bool &>(),
- std::declval<int &>(),
- std::declval<error_handler_type>(),
- std::declval<global_state_type &>(),
- std::declval<detail::symbol_table_tries_t &>(),
- std::declval<detail::pending_symbol_table_operations_t &>()));
- using type = decltype(std::declval<Parser>()(
- std::declval<iterator &>(),
- std::declval<sentinel>(),
- std::declval<context>(),
- SkipParser{},
- detail::flags::gen_attrs,
- std::declval<bool &>()));
- };
- template<typename Iter, typename Sentinel, typename Parser>
- auto has_attribute(Iter first, Sentinel last, Parser parser)
- {
- using attr_t = typename attribute_impl<
- BOOST_PARSER_SUBRANGE<Iter, Sentinel>,
- Parser>::type;
- return std::integral_constant<bool, !is_nope_v<attr_t>>{};
- }
- template<typename T>
- constexpr wrapper<T> attr_wrapped_final;
- template<>
- inline constexpr wrapper<none> attr_wrapped_final<nope>;
- }
- template<typename R, typename Parser>
- struct attribute
- {
- using initial_type = typename detail::attribute_impl<
- decltype(detail::make_input_subrange(std::declval<R>())),
- Parser>::type;
- using type =
- typename decltype(detail::attr_wrapped_final<initial_type>)::type;
- };
- namespace detail {
- template<typename... Args>
- constexpr void static_assert_merge_attributes(tuple<Args...> parsers)
- {
- using context_t = parse_context<
- false,
- false,
- char const *,
- char const *,
- default_error_handler>;
- using skipper_t = parser_interface<ws_parser<false, false>>;
- using use_parser_t = dummy_use_parser_t<
- char const *,
- char const *,
- context_t,
- skipper_t> const;
- using all_types =
- decltype(hl::transform(parsers, std::declval<use_parser_t>()));
- auto all_types_wrapped = hl::transform(all_types{}, detail::wrap{});
- auto first_non_nope = hl::fold_left(
- all_types_wrapped,
- wrapper<nope>{},
- [=](auto result, auto type) {
- if constexpr (is_nope_v<typename decltype(result)::type>) {
- return type;
- } else {
- return result;
- }
- });
- using first_t = typename decltype(first_non_nope)::type;
- static_assert(
- !is_nope_v<first_t>,
- "It looks like you wrote merge[p1 >> p2 >> ... pn], and none "
- "of the parsers p1, p2, ... pn produces an attribute. Please "
- "fix.");
- if constexpr (is_nope_v<first_t>) {
- [[maybe_unused]] detail::print_type<tuple<Args...>> tuple_types;
- [[maybe_unused]] detail::print_type<all_types> attribute_types;
- }
- hl::for_each(all_types_wrapped, [=](auto type) {
- using t = typename decltype(type)::type;
- if constexpr (!is_nope_v<t>) {
- static_assert(
- std::is_same_v<t, first_t>,
- "If you see an error here, you wrote merge[p1 >> "
- "p2 >> ... pn] where at least one of the types in "
- "ATTR(p1), ATTR(p2), ... ATTR(pn) is not the same "
- "type as one of the others.");
- if constexpr (!std::is_same_v<t, first_t>) {
- [[maybe_unused]] detail::print_type<tuple<Args...>>
- tuple_types(parsers);
- [[maybe_unused]] detail::print_type<all_types>
- attribute_types;
- [[maybe_unused]] detail::print_type<first_t> first_type;
- [[maybe_unused]] detail::print_type<t> this_type;
- }
- }
- });
- }
- }
- }}
- #endif
|