Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
4e8ba54
add lexer tokens and rules
leana8959 Sep 25, 2025
df715b0
remove lexer "Whitespace" token
leana8959 Sep 29, 2025
c67466b
implement "Comment" handling
leana8959 Sep 29, 2025
14e384c
temporary fix by dropping comments before parseGenericPackageDescription
leana8959 Sep 29, 2025
6503ce8
make metaFields a map of positions
leana8959 Oct 1, 2025
58ad099
rearrange and simplify field
leana8959 Oct 1, 2025
fa23509
make lexer emit comment wherever they would occur
leana8959 Oct 1, 2025
9d09bb5
stop parser from emitting indentation warning for comments
leana8959 Oct 1, 2025
9a7d664
fix: restore checkIndentation behaviour for Field
leana8959 Oct 3, 2025
f5dca10
test: add dummy tests
leana8959 Oct 3, 2025
c329464
test: accept new golden expressions
leana8959 Oct 3, 2025
edd270c
test: accept new golden expressions
leana8959 Oct 3, 2025
53703c0
test: rename comment test group
leana8959 Oct 7, 2025
2ef72c5
debug: trace tokens
leana8959 Oct 8, 2025
e5d0e91
fix: split comments recursively
leana8959 Oct 8, 2025
a4455b3
fix: consume comments after colon in FieldLayoutOrBraces
leana8959 Oct 8, 2025
3bf77b2
debug: remove tracing
leana8959 Oct 8, 2025
29bf6af
test: update expected
leana8959 Oct 8, 2025
0a887c5
test: improve comment tests
leana8959 Oct 8, 2025
3fc392c
test: correct comment tests
leana8959 Oct 9, 2025
2287f93
test: assert interleaving comment parsing
leana8959 Oct 9, 2025
a61a9e8
fix: correct interleaving comment parsing
leana8959 Oct 9, 2025
d5769d9
test: update expected
leana8959 Oct 9, 2025
bc9bd40
debug: remove tracing
leana8959 Oct 9, 2025
8ad684e
test: assert parsing of fieldline flag
leana8959 Oct 9, 2025
f1abd47
test: update expected
leana8959 Oct 9, 2025
70177ee
fix: correct parsing fieldLine starting with -- as comment
leana8959 Oct 9, 2025
dc92b24
test: update expected
leana8959 Oct 9, 2025
9091f3b
test: remove test case that doesn't pass on upstream
leana8959 Oct 9, 2025
c42a3ba
minor fixes
leana8959 Oct 9, 2025
834d03b
test: ignore comment in test comparison
leana8959 Oct 10, 2025
13bc3a8
docs: improve comments on the grammar
leana8959 Oct 10, 2025
b4546bf
style: whitespace
leana8959 Oct 10, 2025
c965a06
style: fourmolu
leana8959 Oct 10, 2025
e39cc46
ref: simplification
leana8959 Oct 10, 2025
d3a5620
docs: update grammar specification for comments
leana8959 Oct 10, 2025
d03d90d
ref: run hlint
leana8959 Oct 10, 2025
b0e8d87
improve describeToken on comments
leana8959 Oct 10, 2025
8828454
ref: make diff smaller
leana8959 Oct 10, 2025
2ebec82
test: fix no-thunks test
leana8959 Oct 10, 2025
4e0876f
test: fix md5Check test
leana8959 Oct 10, 2025
51fd822
fix compiler errors and warnings
leana8959 Oct 10, 2025
4cee6fd
test: add expectation for failing hackage test
leana8959 Oct 13, 2025
b948bc4
fix hackage test 001
leana8959 Oct 13, 2025
e317efb
fix hackage test
leana8959 Oct 14, 2025
2f68c50
test: disable comments in comparison in roundtrip hackage test
leana8959 Oct 14, 2025
85d3016
refactor parser
leana8959 Oct 14, 2025
b3a1db3
refactor test
leana8959 Oct 14, 2025
d2811d6
style: run fourmolu
leana8959 Oct 14, 2025
0772f15
remove todos
leana8959 Oct 14, 2025
40f9099
test: remove test dependencies
leana8959 Oct 15, 2025
ac9e9bb
test: simplify
leana8959 Oct 15, 2025
fa09f6d
restore accidently formatted cabal
leana8959 Oct 15, 2025
c8c6f65
restore previous debug behaviour
leana8959 Oct 15, 2025
e3b6a66
refactor: don't use liftA2 and liftA3
leana8959 Oct 15, 2025
b8829a5
refactor annotation to ([Comment ann], ann)
leana8959 Oct 20, 2025
d314119
attempt
leana8959 Oct 20, 2025
d4b8b8c
test: update expects
leana8959 Oct 20, 2025
bf19609
fix errors for Deprecated module
leana8959 Oct 20, 2025
7895cd5
fix compilation errors for integration tests
leana8959 Oct 20, 2025
680e639
fix grammar while incorrect output
leana8959 Oct 20, 2025
308ba3e
refactor parser
leana8959 Oct 20, 2025
f276099
style: run fourmolu
leana8959 Oct 20, 2025
6c68e15
fix comment attach post processing
leana8959 Oct 20, 2025
772d35a
refactor
leana8959 Oct 21, 2025
7187c88
fix: only discard element comments at top level
leana8959 Oct 21, 2025
836553f
test: update expected
leana8959 Oct 21, 2025
6027876
fix: derive Eq instance for Comment
leana8959 Oct 21, 2025
fdbd970
use strict either for parser
leana8959 Oct 22, 2025
8372444
fix: doctest
leana8959 Oct 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cabal-syntax/Cabal-syntax.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ build-type: Simple
extra-doc-files:
README.md ChangeLog.md

flag CABAL_PARSEC_DEBUG
description: Enable debug build for the cabal field lexer/parser.
default: False
manual: True

source-repository head
type: git
location: https://github.com/haskell/cabal/
Expand Down Expand Up @@ -59,6 +64,11 @@ library
if impl(ghc >= 8.0) && impl(ghc < 8.8)
ghc-options: -Wnoncanonical-monadfail-instances

if flag(CABAL_PARSEC_DEBUG)
CPP-Options: -DCABAL_PARSEC_DEBUG
build-depends:
vector

build-tool-depends: alex:alex

exposed-modules:
Expand Down
9 changes: 9 additions & 0 deletions Cabal-syntax/src/Distribution/FieldGrammar.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module Distribution.FieldGrammar
, Section (..)
, Fields
, partitionFields
, extractComments
, takeFields
, runFieldParser
, runFieldParser'
Expand All @@ -38,6 +39,7 @@ module Distribution.FieldGrammar
import Distribution.Compat.Prelude
import Prelude ()

import qualified Data.Bifunctor as Bi
import qualified Data.Map.Strict as Map

import Distribution.FieldGrammar.Class
Expand Down Expand Up @@ -99,10 +101,17 @@ partitionFields = finalize . foldl' f (PS mempty mempty mempty)
PS fs (MkSection name sargs sfields : s) ss

-- | Take all fields from the front.
-- Returns a tuple containing the comments, nameless fields, and sections
takeFields :: [Field ann] -> (Fields ann, [Field ann])
takeFields = finalize . spanMaybe match
where
finalize (fs, rest) = (Map.fromListWith (flip (++)) fs, rest)

match (Field (Name ann name) fs) = Just (name, [MkNamelessField ann fs])
match _ = Nothing

extractComments :: (Foldable f, Functor f) => [f (WithComments ann)] -> ([Comment ann], [f ann])
extractComments = Bi.first mconcat . unzip . map extractCommentsStep

extractCommentsStep :: (Foldable f, Functor f) => f (WithComments ann) -> ([Comment ann], f ann)
extractCommentsStep f = (foldMap justComments f, fmap unComments f)
9 changes: 6 additions & 3 deletions Cabal-syntax/src/Distribution/Fields/ConfVar.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Distribution.Fields.ConfVar (parseConditionConfVar, parseConditionConfVar

import Distribution.Compat.CharParsing (char, integral)
import Distribution.Compat.Prelude
import Distribution.Fields.Field (Field (..), SectionArg (..), sectionArgAnn)
import Distribution.Fields.Field (Field (..), SectionArg (..), sectionArgAnn, unComments)
import Distribution.Fields.ParseResult
import Distribution.Fields.Parser (readFields)
import Distribution.Parsec (Parsec (..), runParsecParser)
Expand Down Expand Up @@ -34,8 +34,11 @@ import qualified Text.Parsec.Error as P
import qualified Text.Parsec.Pos as P

parseConditionConfVarFromClause :: B8.ByteString -> Either P.ParseError (Condition ConfVar)
parseConditionConfVarFromClause x =
readFields x >>= \r -> case r of
parseConditionConfVarFromClause x = do
r <- readFields x
let r' :: [Field Position]
r' = map (fmap unComments) r
case r' of
(Section _ xs _ : _) -> P.runParser (parser <* P.eof) () "<condition>" xs
_ -> Left $ P.newErrorMessage (P.Message "No fields in clause") (P.initialPos "<condition>")

Expand Down
26 changes: 22 additions & 4 deletions Cabal-syntax/src/Distribution/Fields/Field.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE StandaloneDeriving #-}

Expand All @@ -17,6 +18,12 @@ module Distribution.Fields.Field
, SectionArg (..)
, sectionArgAnn

-- * Comment
, Comment (..)
, WithComments
, justComments
, unComments

-- * Name
, FieldName
, Name (..)
Expand Down Expand Up @@ -44,11 +51,22 @@ import qualified Data.Foldable1 as F1
-- Cabal file
-------------------------------------------------------------------------------

data Comment ann = Comment !ByteString !ann
deriving (Show, Eq, Generic)

type WithComments ann = ([Comment ann], ann)

unComments :: WithComments ann -> ann
unComments = snd

justComments :: WithComments ann -> [Comment ann]
justComments = fst

-- | A Cabal-like file consists of a series of fields (@foo: bar@) and sections (@library ...@).
data Field ann
= Field !(Name ann) [FieldLine ann]
| Section !(Name ann) [SectionArg ann] [Field ann]
deriving (Eq, Show, Functor, Foldable, Traversable)
deriving (Eq, Show, Functor, Foldable, Traversable, Generic)

-- | @since 3.12.0.0
deriving instance Ord ann => Ord (Field ann)
Expand All @@ -73,7 +91,7 @@ fieldUniverse f@(Field _ _) = [f]
--
-- /Invariant:/ 'ByteString' has no newlines.
data FieldLine ann = FieldLine !ann !ByteString
deriving (Eq, Show, Functor, Foldable, Traversable)
deriving (Eq, Show, Functor, Foldable, Traversable, Generic)

-- | @since 3.12.0.0
deriving instance Ord ann => Ord (FieldLine ann)
Expand All @@ -94,7 +112,7 @@ data SectionArg ann
SecArgStr !ann !ByteString
| -- | everything else, mm. operators (e.g. in if-section conditionals)
SecArgOther !ann !ByteString
deriving (Eq, Show, Functor, Foldable, Traversable)
deriving (Eq, Show, Functor, Foldable, Traversable, Generic)

-- | @since 3.12.0.0
deriving instance Ord ann => Ord (SectionArg ann)
Expand All @@ -115,7 +133,7 @@ type FieldName = ByteString
--
-- /Invariant/: 'ByteString' is lower-case ASCII.
data Name ann = Name !ann !FieldName
deriving (Eq, Show, Functor, Foldable, Traversable)
deriving (Eq, Show, Functor, Foldable, Traversable, Generic)

-- | @since 3.12.0.0
deriving instance Ord ann => Ord (Name ann)
Expand Down
22 changes: 13 additions & 9 deletions Cabal-syntax/src/Distribution/Fields/Lexer.x
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import qualified Data.ByteString.Char8 as B.Char8
import qualified Data.Word as Word

#ifdef CABAL_PARSEC_DEBUG
import Debug.Trace
import qualified Data.Vector as V
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
Expand Down Expand Up @@ -84,8 +83,9 @@ tokens :-
<bol_section, bol_field_layout, bol_field_braces> {
@nbspspacetab* @nl { \pos len inp -> checkWhitespace pos len inp >> adjustPos retPos >> lexToken }
-- no @nl here to allow for comments on last line of the file with no trailing \n
$spacetab* "--" $comment* ; -- TODO: check the lack of @nl works here
-- including counting line numbers
$spacetab* "--" $comment* { toki TokComment }
-- TODO: check the lack of @nl works here
-- including counting line numbers
}

<bol_section> {
Expand All @@ -105,9 +105,8 @@ tokens :-
}

<in_section> {
$spacetab+ ; --TODO: don't allow tab as leading space

"--" $comment* ;
$spacetab+ ; --TODO: don't allow tab as leading space
"--" $comment* { toki TokComment }

@name { toki TokSym }
@string { \pos len inp -> return $! L pos (TokStr (B.take (len - 2) (B.tail inp))) }
Expand Down Expand Up @@ -161,6 +160,7 @@ data Token = TokSym !ByteString -- ^ Haskell-like identifier, number or
| Colon
| OpenBrace
| CloseBrace
| TokComment !ByteString
| EOF
| LexicalError InputStream --TODO: add separate string lexical error
deriving Show
Expand Down Expand Up @@ -230,7 +230,9 @@ lexToken = do
setInput inp'
let !len_bytes = B.length inp - B.length inp'
t <- action pos len_bytes inp
--traceShow t $ return tok
#ifdef CABAL_PARSEC_DEBUG
traceShow t $ return tok
#endif
return t


Expand All @@ -241,10 +243,12 @@ checkPosition pos@(Position lineno colno) inp inp' len_chars = do
let len_bytes = B.length inp - B.length inp'
pos_txt | lineno-1 < V.length text_lines = T.take len_chars (T.drop (colno-1) (text_lines V.! (lineno-1)))
| otherwise = T.empty
real_txt = B.take len_bytes inp
real_txt :: B.ByteString
real_txt = B.take len_bytes inp
when (pos_txt /= T.decodeUtf8 real_txt) $
traceShow (pos, pos_txt, T.decodeUtf8 real_txt) $
traceShow (take 3 (V.toList text_lines)) $ return ()
traceShow (take 3 (V.toList text_lines)) $
return ()
where
getDbgText = Lex $ \s@LexState{ dbgText = txt } -> LexResult s txt
#else
Expand Down
Loading
Loading