2013-01-11 15 views
13

Jestem trochę zdezorientowany tym zachowaniem attoparsec.Dlaczego widzę częściowe wyniki przy attoparsec, gdy spodziewam się zobaczyć błąd?

$ 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" 
> 

Dlaczego potrzebuję dodatkowych znaków, aby wywołać błąd?

Czy to nie powinno się zawieść zaraz po napotkaniu pierwszego "x"?

+0

W razie potrzeby otworzyłem bilet, a opiekun Attoparsec naprawił ten błąd: https://github.com/bos/attoparsec/issues/97 –

Odpowiedz

13

Jest to szczegół implementacji, parser string nie kończy się, zanim wie, czy jest wystarczająco dużo danych wejściowych, aby mogło dojść do skutku. Jest to konsekwencja działania tych lub wszystkich parserów (co, jak sądzę, jest ogólnie dobre dla wydajności).

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

string s próbuje wziąć length s jednostek z Text, a następnie porównać je z 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 próbuje najpierw upewnić się, że n jednostki Text są dostępne, a

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 tworzy kontynuację prosząc o więcej kleik wejścia (a Partial wynik) jeśli nie znajdzie wystarczające dane wejściowe natychmiast.

Można uzyskać awarię z

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

mówi parser z góry, że nie będzie żadnych więcej wejście (wówczas demandInput z ensure sprawia, że ​​nie), czy później

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" 

, informując o tym, że to było to, podając go pusty Text.

+0

Dzięki - to ma sens po twoim wyjaśnieniu. – timbod