Marpa:...austion(3pm)

πŸ“¦
version 12.000000 Β· 2 versions
, in ubuntu stonking

πŸ’– Marpa::R2::Exhaustion πŸ’–

okay bestie, welcome to the Perl documentation section for Marpa::R2::Exhaustion β€” aka Parse exhaustion in the SLIF. she's part of the User Contributed Perl Documentation lineup and honestly? she eats. πŸ’…

✨ Name ✨

Marpa::R2::Exhaustion β€” parse exhaustion in the SLIF. that's the whole vibe.

πŸ¦‹ About this document πŸ¦‹

so this page is one of the reference docs for the recognizer objects of Marpa's SLIF (the Scanless interface). it's the deep-dive, no-skips, full-length discussion of parse exhaustion. grab a boba, we're going in. πŸ§‹


πŸ”₯ Exhaustion πŸ”₯

at its core? parse exhaustion is a simple concept, no cap. the recognizer can hit a point where there is simply no way to continue successfully. like, no matter what it reads next, the parse is gonna fail. when that happens, we say the parse is exhausted. periodt.

now, some people have confused parse exhaustion with parse failure. understandable. but other people have confused parse exhaustion with parse success. also understandable!! because depending on the grammar, there can be a super strong association between parse exhaustion and parse success… it's just that the association can go either way. grammars can be exhaustion-loving or exhaustion-hating, and bestie, both kinds are extremely common in real practical applications. it's giving duality. πŸ™ˆ

πŸ’€ Hate and love πŸ’–

in an exhaustion-hating application, parse exhaustion is typically parse failure. C programs? exhaustion-hating. Perl scripts? exhaustion-hating. most programming languages? yep, exhaustion-hating. if a C program is well-formed, it is always possible to read more input β€” iconic honestly. same goes for a Perl program that doesn't have a "__DATA__" section.

in an exhaustion-loving application, though, parse exhaustion means parse success. the toy example here is the language consisting of balanced parentheses. when the parentheses come into perfect balance, the parse is exhausted β€” because any further input would unbalance the brackets. and the parse succeeds when the parentheses come into perfect balance. so: exhaustion means success. slay. πŸŽ€

any language that balances start and end indicators is gonna tend toward exhaustion-loving. HTML and XML, with their start and end tags, can be seen as exhaustion-loving languages. they're just built different.

for lots of languages though, it's not strictly love or hate. take Perl's "__DATA__" β€” mentioned as a complication in a basically exhaustion-hating language. it is possible for a language to be exhaustion-loving at some points and exhaustion-hating at others. those languages? we call them exhaustion-conflicted. complicated queen energy. πŸ‘‘

🌸 Reading methods 🌸

the methods that may encounter parse exhaustion are the ones that read input: read(), resume(), lexeme_complete(), and lexeme_read(). and β€” not by coincidence, bestie, never by coincidence β€” these are also the event-triggering methods. in this doc, we call them the reading methods. iykyk. ✨

🌈 Synchronous and asynchronous parse exhaustion 🌈

intuitively: parse exhaustion is synchronous if it occurs at a location where control would return to the user anyway, and asynchronous otherwise. so simple.

more precisely, we say parse exhaustion is synchronous if it occurs at a point when control would normally return from SLIF to the application, due to either:

  • the parse reaching end of string (EOS), or
  • the occurrence of a parse event other than an exhaustion event.

Marpa can be set up so that an event occurs on asynchronous exhaustion. and listen β€” note that in the definition above, the occurrence of an exhaustion event does not make the parse exhaustion synchronous. that wording was chosen very deliberately, to avoid a whole paradox situation. think about it: if a parse exhaustion event could make exhaustion synchronous, then it should not occur, because parse exhaustion events only occur on asynchronous parse exhaustion. but if the parse exhaustion event did not occur, then the parse exhaustion would be asynchronous β€” so then a parse exhaustion event should occur. 😭 a real loop. we don't do that here.

in this document, an exhaustion location is a location at which parse exhaustion occurs. πŸ“

πŸ’… Handling parse exhaustion πŸ’…

how parse exhaustion gets handled depends on the setting of the SLIF's "exhaustion" recognizer setting. its value may be "fatal" or "event". ("fatal" is the default, fyi.)

synchronous parse exhaustion is always ignored β€” regardless of the recognizer setting. no exhaustion event is triggered by synchronous parse exhaustion. full stop.

if the "exhaustion" setting is "fatal", asynchronous parse exhaustion is thrown as a fatal error. if the "exhaustion" setting is "event", then an exhaustion event is triggered, returning control to the application β€” and this gets treated by the triggering method as a successful return. cute!

oh and also, heads up: lexeme_complete() and lexeme_read() always ignore parse exhaustion, regardless of the "exhaustion" recognizer setting. why? because these methods read input only at a single location, so every parse exhaustion for them is synchronous. mystery solved. πŸ•΅οΈ

πŸ“ Detecting parse exhaustion πŸ“

the return value of a reading method does not indicate whether exhaustion occurred or not. ngl, in most cases you'll either know from the context whether the parse is exhausted, or you simply will not care. but what if you don't know and you do care?? 😭

those applications that want to know whether a parse is exhausted or not can directly query parse exhaustion status with the exhausted() method. and even when parse exhaustion events are enabled, using exhausted() is the preferred method for detecting exhaustion β€” because it reports both asynchronous and synchronous parse exhaustion. remember, exhaustion events only trigger in cases of asynchronous parse exhaustion. so exhausted() is the main character here. πŸ‘‘

πŸ’œ Exhaustion-conflicted πŸ’œ

exhaustion-conflicted applications are the ones that can't be called exhaustion-loving or exhaustion-hating. maybe that's because their behavior is a combination of the two. or maybe it's because the application's behavior just isn't known yet β€” like, while you're developing an application, it is genuinely convenient to assume it's exhaustion-conflicted. no shame in it.

the SLIF's behavior for exhaustion-conflicted applications has to be aimed at a "lowest common denominator". and honestly it's a good idea for a default to be a lowest common denominator. so by default, the SLIF assumes that an application is exhausted-conflicted. in fact, the default behavior on parse exhaustion usually works well enough that it does not need customizing. she just works. ✨

for a typical application without events, end of parse (EOP) is end of string (EOS). in this case, exhaustion before EOS is a fatal error β€” which is usually exactly what you want. and on return due to EOS, unless the application checks, it will not know whether exhaustion occurred… but usually it does not care. if the application does care, it can check for exhaustion explicitly. easy.

if the application uses events to signal EOP, the case is much the same. on return due to an event, the application will not know if exhaustion occurred, but usually it will not care. and if it does care? it can check for exhaustion explicitly. same as above, bestie.

if the application uses events for other purposes, an event may "hide" exhaustion, so that it is not thrown as an error. typically, the application will soon attempt to continue the reading of input, and when it does, there will be a fatal error. πŸ’€ an application which wants to know about exhaustion immediately β€” either to "fast fail" or for other reasons β€” can check for exhaustion explicitly every time an event triggers.

πŸŽ€ Exhaustion-loving πŸŽ€

for an exhaustion-loving application, everything said above for exhaustion-conflicted applications applies without change. applications that consider it important to confirm that exhaustion did occur at EOP can check for exhaustion explicitly. that's it, that's the whole subsection.

some applications go beyond being exhaustion-loving, and want to use exhaustion to signal the EOP. those are the exhaustion-sensing applications, and they get their own section below. ⬇️

😀 Exhaustion-hating 😀

exhaustion-hating applications are handled reasonably by the default behavior. asynchronous exhaustion will be a fatal error. synchronous exhaustion will cause failure at the next read β€” unless it happens at EOP. by default, exhaustion at EOP will go unreported, but if an application really is exhaustion-hating, the parse will fail, and parse failure will certainly show up when the application tries to evaluate the parse. so it's not sneaking past anybody.

exhaustion-hating applications, if they want to be stricter than this, can check for exhaustion explicitly whenever a reading method returns. one possible annoyance: depending on where it happens, exhaustion may also cause the reading method to throw an exception. applications which want more orthogonality in their exhaustion handling can enable exhaustion events, which will prevent exceptions being thrown due to parse exhaustion. problem solved, no drama. πŸ’…

🧚 Exhaustion-sensing 🧚

sometimes an application, rather than reading an entire input, wants to find the longest occurrence starting at some location. (lexers are typically applications of this kind, fyi.)

looking for exhaustion is one way to try to implement this kind of "longest acceptable input stream" search. but listen β€” exhaustion-sensing is not necessarily the best way, or even a good way, to find the "longest parse". exhaustion may not happen until after the last successful parse β€” sometimes not until long after it. πŸ‘€ completion parse events may be a cleaner way to deal with this. just saying.

applications which do want to use parse exhaustion as part of a strategy for finding the EOP can set the SLIF's "exhaustion" recognizer setting to "event", so that a parse event occurs at parse exhaustion. when the event-triggering method returns, the application can then check for exhaustion explicitly. boom, done. 🌟


Copyright 2022 Jeffrey Kegler
This file is part of Marpa::R2.  Marpa::R2 is free software: you can
redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.

Marpa::R2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser
General Public License along with Marpa::R2.  If not, see
http://www.gnu.org/licenses/.

that's the whole page bestie, you ate it. 🫢 this was perl v5.42.3, dated 2026-08-20, live from the User Contributed Perl Documentation corner of the internet. go forth and detect your exhaustion (explicitly, with exhausted()). mwah. πŸ’–βœ¨πŸ¦‹

πŸ“¦ where this page comes from