Использование комбинатора `opt` в uu-parsinglib - PullRequest
2 голосов
/ 01 марта 2012

Я пишу парсер для простого текстового языка шаблонов для моего проекта, и я полностью застрял на opt комбинаторе в uu-parsinglib (версия 2.7.3.2 на случай, если это имеет значение). Есть идеи, как правильно его использовать?

Вот очень упрощенный пример, который показывает мое затруднительное положение.

{-# LANGUAGE FlexibleContexts #-}

import Text.ParserCombinators.UU hiding (pEnd)
import Text.ParserCombinators.UU.Utils
import Text.ParserCombinators.UU.BasicInstances

pIdentifier :: Parser String
pIdentifier = pMany pLetter

pIfClause :: Parser ((String, String), String, Maybe (String, String), String)
pIfClause = (,,,) <$> pIf <*> pIdentifier <*> pOptionalElse <*> pEnd

pIf :: Parser (String, String)
pIf = pBraces ((,) <$> pToken "if " <*> pIdentifier)

pOptionalElse :: Parser (Maybe (String, String))
pOptionalElse = (((\x y -> Just (x, y)) <$> pElse <*> pIdentifier) `opt` Nothing)

pElse :: Parser String
pElse = pBraces (pToken "else")

pEnd :: Parser String
pEnd = pBraces (pToken "end")

main :: IO ()
main = do
  putStrLn $ show $ runParser "works" pIfClause "{if abc}def{else}ghi{end}"
  putStrLn $ show $ runParser "doesn't work" pIfClause "{if abc}def{end}"

Первая строка анализируется правильно, но вторая не получается с ошибкой:

main: Failed parsing 'doesn't work' :
Expected  at position LineColPos 0 12 12 expecting one of [Whitespace, "else"] at LineColPos 0 12 12 :
                              v
                  {if abc}def{end}
                              ^

1 Ответ

2 голосов
/ 01 марта 2012

Документация для opt гласит:

Если p можно распознать, используется возвращаемое значение p.В противном случае используется значение v.Обратите внимание, что по умолчанию opt является жадным.

Что означает жадное средство, объяснено в документации для <<|>:

<< |> - жадная версия <|>.Если его левый парсер может добиться какого-либо прогресса, он фиксирует эту альтернативу.

В вашем случае первый аргумент opt распознает часть ввода, потому что else и end оба начинаются с e.Таким образом, он фиксирует pElse, что приводит к сбою и приводит к сбою всего анализа.

Простой способ решить эту проблему - использовать ... <|> pure Nothing, как следует из документации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...