Chcę utworzyć kombinator parsera, który będzie zbierać wszystkie wiersze poniżej bieżącego miejsca, których poziomy wcięcia będą większe lub równe około i
. Myślę, że idea jest prosta:Prawidłowe wycinanie linii wcięcia w uu-parsinglib w Haskell
Spożywać linię - jeśli jej wcięcie jest:
- ok -> zrób to dla kolejnych wierszy
- tak -> fail
rozważmy następujący Kod:
import qualified Text.ParserCombinators.UU as UU
import Text.ParserCombinators.UU hiding(parse)
import Text.ParserCombinators.UU.BasicInstances hiding (Parser)
-- end of line
pEOL = pSym '\n'
pSpace = pSym ' '
pTab = pSym '\t'
indentOf s = case s of
' ' -> 1
'\t' -> 4
-- return the indentation level (number of spaces on the beginning of the line)
pIndent = (+) <$> (indentOf <$> (pSpace <|> pTab)) <*> pIndent `opt` 0
-- returns tuple of (indentation level, result of parsing the second argument)
pIndentLine p = (,) <$> pIndent <*> p <* pEOL
-- SHOULD collect all lines below witch indentations greater or equal i
myParse p i = do
(lind, expr) <- pIndentLine p
if lind < i
then pFail
else do
rest <- myParse p i `opt` []
return $ expr:rest
-- sample inputs
s1 = " a\
\\n a\
\\n"
s2 = " a\
\\na\
\\n"
-- execution
pProgram = myParse (pSym 'a') 1
parse p s = UU.parse ((,) <$> p <*> pEnd) (createStr (LineColPos 0 0 0) s)
main :: IO()
main = do
print $ parse pProgram s1
print $ parse pProgram s2
return()
co daje następujący wynik:
("aa",[])
Test.hs: no correcting alternative found
Wynik dla s1
jest prawidłowy. Wynik dla s2
powinien zużyć najpierw "a" i przestać konsumować. Skąd bierze się ten błąd?
Dziękuję, ale nie ma jeszcze całkowicie rozwiązać mój problem (zaktualizowałem dany kod) - co zrobić, jeśli wcięcia mogą być spacjami lub zakładkami, gdzie karty są 4 spacje? –
dodatkowe 'return []' does ** not ** działa tak, jak chcemy - jeśli zastąpimy 'pFail' przez' return [] 'drugi" a "zostanie zużyty przez parser (zostanie on zużyty i' [] 'zostanie zwrócony) - Nie chcę, aby drugi" a "w przykładzie s2 został zużyty. –
Jeśli chcesz poprawnie obsługiwać tabulatory (i nie zastępować tabulatorów tylko czterema spacjami), będziesz musiał zaprogramować swój własny mały skończony automat stanów, który "wie", co oznacza tabulator. –