-
Notifications
You must be signed in to change notification settings - Fork 156
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
Add TH TopEntityGeneration #729
Conversation
It's likely the tests I've written is also version specific due to hardcoding template haskell splices, but I'm not sure on a better way? |
If you split out the code that generates the The test could be something like: expectedTopEntity1 =
Synthesize "topEntity1")
[PortName "in1", PortName "in2"])
(PortName "out")
tests :: TestTree
tests =
testGroup
"topEntityGen"
[ testCase "topEntity1" $
$(createTopEntity 'topEntity1 Nothing) @?= expectedTopEntity1
, ...
] Much more readable and the test is TH version independent. |
Makes sense! I'll get to it in a day or two. |
hey @leonschoorl, any other thoughts on this ? |
Thanks for this, it's wonderful and much closer to what I wanted to (eventually) build! Here's a bikeshed: what about the module name? There is some precedence for naming things For example, I could see this same basic design being used for an implementation of e.g. #248 if (when) I implement it, so you could easily write blackbox modules and have all the crap auto-generated from the declaration you specify, just like here. In that case, we could also add a |
hey @martijnbastiaan any thoughts on this PR ? |
I like it! As the definition of type (name :: k) ::: a = a I wonder if we could use something like: data AutoName and topEntity :: "int" ::: Signal System Int
-> "tuple" ::: ("tup1" ::: Signal System (BitVector 7), "tup2" ::: Signal System (BitVector 9))
-> "simple" ::: Signal System Simple
-> "named" ::: Signal System Named
-> AutoName ::: Signal System Embedded
-> "out" ::: Signal System Bool to autogenerate field names based on the record's field names. Anyway, that might be something to consider in the future. I'll give it a spin tomorrow and report back. For the meantime, could you format you code according to the style guide? It's mostly: buildPorts :: Type -- Type to split at
-> TypeF (Type, Q [PortName]) -> Q [PortName] -- Fold step to buildPorts
:: Type
-- ^ Type to split at
-> TypeF (Type, Q [PortName]) -> Q [PortName]
-- ^ Fold step
Thanks! |
6c96ee9
to
365541f
Compare
@martijnbastiaan I've made some style fixes and rebased. I'm not sure what the failure for 8.8.1 is. Any other changes you can think of for this PR? |
@blaxill Looks good! I'd be happy to include it. I'll look into the GHC 8.8.1 error - I suspect it's another issue with version bounds on dependencies. I've rebased it again and will run it with our own CI. If that works I'll force push to this PR. |
@blaxill what happens if I don't annotate an argument or a result with a name, e.g topEntity :: "int" ::: Signal System Int
-> "tuple" ::: ("tup1" ::: Signal System (BitVector 7), "tup2" ::: Signal System (BitVector 9))
-> "simple" ::: Signal System Simple
-> "named" ::: Signal System Named
-> Signal System Embedded
-> "out" ::: Signal System Bool |
clash-prelude/clash-prelude.cabal
Outdated
@@ -317,14 +319,16 @@ test-suite unittests | |||
base, | |||
hint >= 0.7 && < 0.10, | |||
tasty >= 1.2 && < 1.3, | |||
tasty-hunit | |||
tasty-hunit , | |||
template-haskell >= 2.9.0.0 && < 2.14 |
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 should be template-haskell >= 2.9.0.0 && < 2.16
to work with GHC-8.8
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.
Actually you could just remove the bounds here and cabal will use the bounds places on the Library
That will fail with: tests/Clash/Tests/TopEntityGeneration.hs:90:1: error:
Failed to get a single name for argument 4
a.k.a. AppT (AppT (ConT Clash.Signal.Internal.Signal) (ConT Clash.Signal.Internal.System)) (ConT Clash.Tests.TopEntityGeneration.Embedded)
got name [PortProduct "embedded1" [PortName "simple1",PortName "simple2"],PortName "embedded2"] Additionally: topEntity :: "int" ::: Signal System Int
-> "tuple" ::: ("tup1" ::: Signal System (BitVector 7), "tup2" ::: Signal System (BitVector 9))
-> "simple" ::: Signal System Simple
-> "named" ::: Signal System Named
-> Signal System Int
-> "out" ::: Signal System Bool Will also fail: tests/Clash/Tests/TopEntityGeneration.hs:100:1: error:
Failed to get a single name for argument 4
a.k.a. AppT (AppT (ConT Clash.Signal.Internal.Signal) (ConT Clash.Signal.Internal.System)) (ConT GHC.Types.Int)
got name [] Whereas this will work: data SimpleNamed = SimpleNamed ("simpleNamed" ::: Int)
topEntity :: "int" ::: Signal System Int
-> "tuple" ::: ("tup1" ::: Signal System (BitVector 7), "tup2" ::: Signal System (BitVector 9))
-> "simple" ::: Signal System Simple
-> "named" ::: Signal System Named
-> Signal System SimpleNamed
-> "out" ::: Signal System Bool
======>
{-# ANN topEntity Synthesize
{t_name = "topEntity",
t_inputs = [PortName "int",
(PortProduct "tuple") [PortName "tup1", PortName "tup2"],
(PortProduct "simple")
[PortName "simple1", PortName "simple2"],
(PortProduct "named") [PortName "named1", PortName "named2"],
PortName "simpleNamed"],
t_output = PortName "out"} #-} Some other failure cases might exist when using naming annotations on a subset of parameters in constructors. (E.g. note the PortProduct for "Ops" only gets one PortName child instead of two): data Ops = Ops ("one":::Int) (Bool)
topEntity :: "int" ::: Signal System Int
-> "simple" ::: (Signal System Ops)
-> "out" ::: Signal System Bool
makeTopEntity 'topEntity
======>
{-# ANN topEntity Synthesize
{t_name = "topEntity",
t_inputs = [PortName "int",
(PortProduct "simple") [PortName "one"]],
t_output = PortName "out"} #-} I think it will work correctly if the unnamed child references a type that has annotation though. I'll add a test case for your example. For my failure case its a bit more tricky and the function |
I believe
would be more readable after a |
Looking good @blaxill! I'll merge it after the CI is done testing. |
Hold on one second, I've just realised newtypes aren't supported, but it will only take me a second or two to add support and tests... |
Np! CI won't be finished anytime soon I'm afraid.. |
CI beat me to it :) I'm adding support for basic type/data families, eta tomorrow |
Added support for: - newtypes - One step resolution of type/data family instances - all constructor types
Ok, this has support for one-step (non-recursive) type families, extra tests and better error handling. Assuming you don't want any changes from the latest commit this is good to go for me. |
Haddock generation fails with the new patch. If I had to guess it would be:
causing parse errors (as single quotes are usually used to reference to functions). I think replacing it with:
would be good enough. |
@blaxill I've pushed it to our local CI too to speed it up. If you could give me a heads up when you think it's ready, that'd be great, then I'll squash & merge it. |
Ok, I've added all I can think of. Works locally for me, but I can't promise I've missed another incompatibility with differing base/template haskell versions until CI has finished. Edit: Looks like haddock still might be failing. If you can skip CI on the previous pushes and only do the last that would be preferable. My intermediate commits have bogged down the CI sorry. |
Done! We should be able to move everything to GitLab CI soon (we've been using it for our own branches/prs for a while now), which should improve the experience considerably. |
@martijnbastiaan Looks like its ready to go! |
This is a work in progress to add TH functions to generate Synthesize annotations from Clash's NamedTypes annotations. It's based on an initial implementation by @thoughtpolice here and here. The difference with this version is that it will recursively attempt to find annotations in data types.
The motivation for me is that top entities with a large number of ports require haskell type + synthesize annotation which are verbose and can get out of sync.
Some drawbacks of this in its current state:
Messy implementation (If there is interest in this PR I will work to improve it)Improved somewhatTesting is brittle: I don't know of a better way to test the generated template haskell (see test file)An example:
Let me know what you think/any ideas to make this better