2013-01-11 7 views
13

Sono un po 'confuso da questo comportamento di attoparsec.Perché vedo risultati parziali con attoparsec quando mi aspetto di vedere Failure?

$ ghci 
> :m Data.Attoparsec.Text 
> :m + Data.Text 
> parse (string (pack "module")) (pack "mox") 
Partial _ 
> parse (string (pack "module")) (pack "moxxxx") 
Fail "moxxxx" [] "Failed reading: takeWith" 
> 

Perché sono necessari caratteri aggiuntivi per attivare il fail?

Non dovrebbe non riuscire non appena si incontra la prima "x"?

+0

Per riferimento futuro, ho aperto un ticket e il responsabile Attoparsec ha corretto questo bug: https://github.com/bos/attoparsec/issues/97 –

risposta

13

È un dettaglio di implementazione, un parser string non termina prima di sapere se è disponibile un input sufficiente per il corretto funzionamento. È una conseguenza del comportamento all-or-nothing di questi parser (che, penso, è generalmente buono per le prestazioni).

string :: Text -> Parser Text 
string s = takeWith (T.length s) (==s) 

string s cerca di prendere length s unità di Text, e poi confrontarli con s.

takeWith :: Int -> (Text -> Bool) -> Parser Text 
takeWith n p = do 
    s <- ensure n 
    let h = unsafeTake n s 
     t = unsafeDrop n s 
    if p h 
    then put t >> return h 
    else fail "takeWith" 

takeWith n p primi cerca di assicurare che n unità di Text sono disponibili, e

ensure :: Int -> Parser Text 
ensure !n = T.Parser $ \i0 a0 m0 kf ks -> 
    if lengthAtLeast (unI i0) n 
    then ks i0 a0 m0 (unI i0) 
    else runParser (demandInput >> go n) i0 a0 m0 kf ks 
    where 
    go n' = T.Parser $ \i0 a0 m0 kf ks -> 
     if lengthAtLeast (unI i0) n' 
     then ks i0 a0 m0 (unI i0) 
     else runParser (demandInput >> go n') i0 a0 m0 kf ks 

ensure n crea una continuazione chiedere più pappa di ingresso (un risultato Partial) se non trova abbastanza input immediatamente.

È possibile ottenere un fallimento con

Prelude Data.Attoparsec.Text Data.Text> parseOnly (string (pack "module")) (pack "mox") 
Left "not enough input" 

raccontare il parser fin da subito che non otterrà più di ingresso (allora la demandInput da ensure fa fallire), o poi

Prelude Data.Attoparsec.Text Data.Text> parse (string (pack "module")) (pack "mox") 
Partial _ 
Prelude Data.Attoparsec.Text Data.Text> feed it (pack "") 
Fail "mox" ["demandInput"] "not enough input" 

dicendo al numero Partial che era, alimentandolo con uno Text vuoto.

+0

Grazie - ha senso dopo la spiegazione. – timbod