-
Notifications
You must be signed in to change notification settings - Fork 710
Versioned grammars + leading comma support for build-depends #4953
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
f0d7245
to
0763988
Compare
24f4402
to
4533308
Compare
I won't write amend user manual yet, as e.g. |
ping @ezyang could you check Implement availableSince commit. I'll merge it in a week anyway, but if you want to comment on it before, there's time. |
454ec0d
to
ade5d8f
Compare
ade5d8f
to
806be2d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just some minor comments about the design.
import Distribution.Parsec.Class (Parsec (..), ParsecParser) | ||
|
||
-- A class to select how to parse different fields. | ||
class CabalSpecVersion v where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it should be easy to convert this type class to a GADT? Then we could have
cabalSpecVersionOld :: CabalSpecVersion
cabalSpecVersionOld = ...
cabalSpecVersion22 :: CabalSpecVersion
cabalSpecVersion22 = ...
etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you really need data CabalSpecOld = CabalSpecOld / ...
, you can make that a phantom type parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, GADT is not a bad idea. I however abuse implicit dictionary passing, so I'd need a class for that anyway... :)
-- "Booleans" | ||
------------------------------------------------------------------------------- | ||
|
||
data HasElif = HasElif | NoElif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, we could just do something like
data CabalSpecFeature = Elif | CommonStanzas | ...
data CabalSpecVersion where
...
cabalSpecVersionFeatures :: [CabalSpecFeature]
...
hasElif :: CabalSpecVersion -> Bool
hasElif = elem ElIf . cabalSpecVersionFeatures
hasCommonStanzas :: :: CabalSpecVersion -> Bool
...
to make it more consistent with Compiler
and Extension
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, have to think how to deal with expanding feature set. But not now. (maybe in follow-up PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One way is to encode availableSince
using CabalSpecFeature
, then it will definitely make sense!
Cabal/Distribution/Parsec/Class.hs
Outdated
-- | 'parsec' /could/ consume trailing spaces, this function /must/ consume. | ||
lexemeParsec :: ParsecParser a | ||
lexemeParsec = parsec <* P.spaces | ||
parsec22 :: ParsecParser a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a Haddock comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if instead of adding a new method each time the spec is updated we could tag the ParsecParser
with a phantom type corresponding to the spec version. Just a thought, no need to implement it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is that if CabalSpecVersion
dictionary is inlined (in only one place atm!), then all resolution is pointer chasing (which GHC might be able to eliminate, if inliner sees enough), and no branching on version is anywhere (except for availableSince
)
NB: this is speculation, as I haven't benchmarked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I will look at the core, but not now.
So |
The point of benchmark was to validate that the added abstraction doesn't add noticeable slowdown. |
Feel free to merge in the current state and tweak the design in a later separate PR (if you feel like it). |
I'll add missing haddock and rebase when #4962 is merged. |
78f8b71
to
aedb82c
Compare
CabalSpecVersion type-class will allow to gather per-spec conditionals. Currently it's used for selecting parsers / grammatical structure. Leading (or trailing commas) for CommaFSep/CommaVSep fields, i.e. fields with mandatory comma are (atm): - build-depends - build-tool-depends - build-tools - mixins - pkgconfig-depends - reexported-modules - setup-depends
Tag Backpack fields (mixins, signatures) to `availableSince [2,0]`. This "fixes" haskell#4448, as fields are recognised, warned, but parsed as empty if cabal-version < 2.0 (actual cut-off is ! (>= 1.25). For example, a file with cabal-version: >=1.10 library: mixins: foo-indef requires (Foo42 as FooImpl) will be accepted, yet warned, and parsed `mixins` in `BuildInfo` will be an empty list. Also availableSince is removed from `build-tool-depends`, as we **want** to parse (and not warn) it in old Cabal files. It can be thought as added retrospectively to old specs, but old `Cabal` s don't know how to use it.
aedb82c
to
8034e91
Compare
Merged as #4971 |
We need versioned grammars:
availableSince
, that would "fix" cabal-version check doesn't happen early enough #4448 because backpack features won't be parsed. (User will get parse warnings about not-yet-supported spec version).license:
field will change: Consider adopting/support SPDX licence identifiers #2547Leading comma is just a simple extension to experiment with :)
I'm not 100% sure that
singletons
-ish approach is the best, but it has good features:Versioned v => ... -> a
vs.Version -> ... -> a
.MonadReader Version => ... -> m a
.It works, it's easy to see by changing
cabal-version
to2.0
inleading-comma.cabal
. Tests will fail.I'll add negative tests after common-stanza branch is merged.negative test added.cc @23Skidoo @hvr
Surprisingly? this seems to be as performant as current
master
, parsing all Hackage packages starting witha
: (including acme-everything :)this PR
this PR without SPECIALIZED in D.PD.FieldGrammar
master
leading comma for
CommaFSep
/CommaVSep
fields, i.e. fields with mandatory comma are (atm):Please include the following checklist in your PR:
[ci skip]
is used to avoid triggering the build bots.Please also shortly describe how you tested your change. Bonus points for added tests!