Запрос комментариев к простому парсеру Alex

Я пытался добавить код в редактор Haskell Yi и хочу добавить в него режимы Git commit и rebase. Я никогда ничего не делал с Алексом раньше, поэтому я решил написать автономный анализатор коммитов за пределами Yi, прежде чем пытаться добавить его в редактор. Я не смог найти много документации по Алексу, кроме документации на странице Алекса, в которой очень мало информации об обёртке монады, которая, похоже, является тем, что эмулирует проект Yi.

Может ли кто-нибудь дать мне комментарии о том, что неправильно (и, надеюсь, правильно) в этом коде? Я довольно новичок в Haskell, поэтому любые комментарии там также будут оценены. Идея состоит в том, что это будет правильно обрабатывать строки сообщений, комментарии и строки различий (которые будут соответствовать всем вышеперечисленным при запуске git commit -v). Я могу добавить поддержку для различия между строкой дайджеста и последующими строками позже, но я хотел пока оставаться простым.


{
module Main where
}

%wrapper "monad"

$commitChars = [$printable\t]
@diffStart = diff\ \-\-git\ $commitChars*

gitCommit :-

 {
^@diffStart$                   {makeAlexAction DiffDeclaration `andBegin` diff}
^\# $commitChars*$             {makeAlexAction Comment}
$commitChars*$                 {makeAlexAction MessageLine}
}

 {
^@diffStart$                   {makeAlexAction DiffDeclaration}
^\- $commitChars*$             {makeAlexAction DiffRemove}
^\+ $commitChars*$             {makeAlexAction DiffAdd}
^$commitChars*$                {makeAlexAction DiffContext}
}

.                                     ;
[\n\r]                                ;

{
data GitCommitToken = Digest String
                    | MessageLine String
                    | Comment String
                    | DiffDeclaration String
                    | DiffAdd String
                    | DiffRemove String
                    | DiffContext String
                    | CommitEOF
                  deriving (Show, Eq)

makeAlexAction ::Monad m => (String -> GitCommitToken) ->AlexInput ->Int ->m GitCommitToken
makeAlexAction cons = \ (_,_,inp) len ->return $cons (take len inp)

alexEOF = return CommitEOF

alexMonadScanTokens ::Alex [GitCommitToken]
alexMonadScanTokens = do                                                                                 
  inp  alexEOF >>= \eof ->return [eof]
    AlexError inp' ->alexError $ "lexical error: " ++ show inp'
    AlexSkip  inp' len ->do
        alexSetInput inp'
        alexMonadScanTokens
    AlexToken inp' len action ->do
        alexSetInput inp'
        token <- action inp len
        tokens <-alexMonadScanTokens
        return $ token : tokens

main = do
     s <- getContents
     mapM_ print $ either (\_ -> []) id (runAlex s alexMonadScanTokens)
}

1 ответ

Решение

Во-первых, спасибо за участие в Haskell и Yi!

Обзор кода

  • Я бы использовал разбор строк. Алекс поддерживает это сейчас. Использовать %wrapper "strict-bytestring" Режим.
  • either (\_ -> []) id: немного странно Я бы использовал явный случай с лучшей ошибкой для ошибки разбора.
  • Есть ли утечка в alexMonadScanTokens (по крайней мере, он потребляет стек). Алекс определяет alexScanTokens для вас, чтобы быть левой складкой над входом. Я думаю, что вы должны использовать alexMonadScan
  • В мощном парсере я бы использовал распакованные, строгие байтовые строки для типов токенов. Например Digest !ByteString
  • Ваши регулярные выражения выглядят хорошо.

Резюме, довольно хорошо с первого раза! Перейдите к синтаксическому анализу bytestring и попробуйте протестировать некоторые большие файлы, чтобы убедиться, что ваш сканер не имеет утечки пространства, при условии, что вы не используете готовый комплект alexScanTokens,

Ресурсы

Посмотрите на пакет bytestring-lexing для парсера на основе байтов. Во-вторых, в самом пакете alex есть много хороших примеров, которые могут помочь с идиоматическим разбором:

  $ cabal unpack alex
  $ cd examples
Другие вопросы по тегам