这是一个实现细节,string
解析器在确定是否有足够的输入来成功之前不会完成。这是由于这些解析器的全有或全无行为所导致的(我认为,这通常对性能有益)。
string :: Text -> Parser Text
string s = takeWith (T.length s) (==s)
string s
尝试提取 s
的长度个单位的文本,然后与 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
首先尝试确保有 n
个单位的 Text
可用,并且
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
创建了一个续延,如果没有立即找到足够的输入,它将请求更多的输入(一个Partial
结果)。
你可以通过以下方式获得失败:
Prelude Data.Attoparsec.Text Data.Text> parseOnly (string (pack "module")) (pack "mox")
Left "not enough input"
告诉解析器它不会再得到任何输入(然后从
ensure
中的
demandInput
使其失败),或者稍后。
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"
通过告诉“Partial”结果就是这样,将空的“Text”输入给它。