diff options
| author | Roman Smrž <roman.smrz@seznam.cz> | 2026-07-05 17:47:54 +0200 |
|---|---|---|
| committer | Roman Smrž <roman.smrz@seznam.cz> | 2026-07-11 15:24:37 +0200 |
| commit | 4d2de6a51f555cb2365e161c082223e7d9f21bc8 (patch) | |
| tree | c4c19abb35253db98f65d249539198496ebce0bc /src/Expression.hs | |
| parent | 0b3b675bfc9e78ee563d526f17184e317a962ae8 (diff) | |
Range expression parsing
Diffstat (limited to 'src/Expression.hs')
| -rw-r--r-- | src/Expression.hs | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/Expression.hs b/src/Expression.hs index 6b1adc9..95ba815 100644 --- a/src/Expression.hs +++ b/src/Expression.hs @@ -9,14 +9,28 @@ module Expression ( evaluateDeclaredRevision, evaluateDeclaredRange, evaluateRevision, evaluateRange, getRangeCommits, getAddedRangeCommits, + + isRangeExpressionDynamic, + isRevisionExpressionDynamic, + + parseRangeExpression, ) where import Control.Concurrent.STM import Control.Monad.IO.Class +import Data.Bifunctor +import Data.Char import Data.Kind +import Data.List.NonEmpty qualified as NE import Data.Maybe +import Data.Proxy import Data.Text (Text) +import Data.Text qualified as T +import Data.Void + +import Text.Megaparsec +import Text.Megaparsec.Char import Job.Types import Output @@ -112,3 +126,63 @@ getAddedRangeCommits repo (CommitRange ar br) (CommitRange ar' br') = do (++) <$> listCommitsFrom repo a'b (catMaybes [ b' ]) -- added by moving B to B' <*> listCommitsFrom repo (catMaybes [ a' ]) (catMaybes [ a, b, b' ]) -- added by moving A to A' + + +isRangeExpressionDynamic :: RangeExpression -> Bool +isRangeExpressionDynamic = \case + RangeExpression x y -> isRevisionExpressionDynamic x || isRevisionExpressionDynamic y + +isRevisionExpressionDynamic :: RevisionExpression -> Bool +isRevisionExpressionDynamic = \case + StaticRef _ -> False + WatchedRef _ -> True + ModifiedRevision _ e -> isRevisionExpressionDynamic e + + +type ExprParser = Parsec Void Text + +parseRangeExpression :: Text -> Either String DeclaredRangeExpression +parseRangeExpression = bimap errorBundlePretty id . runParser parser "" + where + parser :: ExprParser DeclaredRangeExpression + parser = do + rev1 <- parseRevision + expr <- choice + [ do + _ <- string ".." + rev2 <- parseRevision + return $ RangeExpression rev2 rev1 + , do + return $ RangeExpression rev1 (ModifiedRevision "^" rev1) + ] + + (char ':' >> eof) <|> eof + return expr + + parseRevision :: ExprParser DeclaredRevisionExpression + parseRevision = do + tok <- fmap T.concat $ some $ choice + [ takeWhile1P Nothing (\x -> isAlphaNum x || x `elem` [ '_', '-', '/' ]) + , try $ string "." <* notFollowedBy (char '.') + ] + + rev <- choice + [ do + _ <- char '(' + arg <- takeWhileP Nothing (\x -> isAlphaNum x || x `elem` [ '_', '-', '/', '.' ]) + _ <- char ')' + case tok of + "watch" -> return $ WatchedRef arg + _ -> unexpected $ Tokens $ NE.fromList $ chunkToTokens @Text Proxy tok + + , do + return $ StaticRef tok + ] + + choice + [ do + suffix <- takeWhile1P Nothing (\x -> isNumber x || x `elem` [ '~', '^', '@', '{', '}' ]) + return $ ModifiedRevision suffix rev + , do + return rev + ] |