Запрос комментариев на простой Алекс парсер
Я рассматривал возможность добавления кода в Редактор Haskell Yi и хочу добавить в него режимы git commit и rebase. Я никогда ничего не делал с Алексом раньше, поэтому я решил написать автономный синтаксический анализатор коммитов за пределами Yi, прежде чем пытаться добавить его в Редактор. Я не смог найти много документации по Alex, кроме документов на странице Alex, которые являются действительно светом информации о оболочке монады, которая, похоже, является тем, что эмулирует проект Yi.
Мог бы кто-нибудь прокомментирует мне, что не так (и, надеюсь, правильно) в этом коде? Я довольно новичок в Хаскелле, поэтому любые комментарии там также будут оценены. Идея заключается в том, что это будет правильно обрабатывать строки сообщений, комментарии и строки различий (которые будут находиться под всеми вышеперечисленными при запуске git commit -v
). Я могу добавить поддержку для дифференциации между строкой дайджеста и последующими строками позже, но я хотел остаться простым сейчас.
{
module Main where
}
%wrapper "monad"
$commitChars = [$printablet]
@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}
}
. ;
[nr] ;
{
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!
обзор кода
- я бы использовал синтаксический анализ bytestring. Алекс поддерживает это сейчас. Используйте режим
%wrapper "strict-bytestring"
.either (\_ -> []) id
: Немного странно. Я бы использовал явный случай, с лучшей ошибкой для сбоя синтаксического анализа.- имеет ли он утечку пространства в
alexMonadScanTokens
(по крайней мере, он потребляет стек). Алекс определяетalexScanTokens
для вас, чтобы быть левым сгибом над входом. Я думаю, что вы должны использоватьalexMonadScan
- в тяжелом дежурный парсер, я бы использовал распакованные, строгие байтестринги для типов токенов. Например,
Digest !ByteString
- ваши регексы выглядят отлично.
Резюме, довольно хороший первый ход! Переключитесь на синтаксический анализ bytestring и попробуйте протестировать некоторые большие файлы, чтобы убедиться, что ваш сканер не имеет утечки пространства, предполагая, что вы не используете out-of-the-box
alexScanTokens
.ресурсы
Посмотрите на пакетbytestring-lexing для синтаксического анализатора Alex на основе bytestring. Во-вторых, сам пакет Алекса имеет много хороших примеров, которые могут помочь с идиоматическим разбором:
$ cabal unpack alex $ cd examples