Запрос комментариев к простому парсеру 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